133685Sbostic /* 245232Sborman * Copyright (c) 1988, 1990 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 542770Sbostic * %sccs.include.redist.c% 633685Sbostic */ 711758Ssam 821580Sdist #ifndef lint 9*60149Sdab static char sccsid[] = "@(#)telnet.c 5.56 (Berkeley) 05/20/93"; 1033685Sbostic #endif /* not lint */ 1121580Sdist 129217Ssam #include <sys/types.h> 139217Ssam 1432377Sminshall #if defined(unix) 1533804Sminshall #include <signal.h> 1632377Sminshall /* By the way, we need to include curses.h before telnet.h since, 1732377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 1832377Sminshall * declared in curses.h. 1932377Sminshall */ 2032377Sminshall #endif /* defined(unix) */ 2132377Sminshall 2212212Ssam #include <arpa/telnet.h> 2332377Sminshall 2438908Sborman #include <ctype.h> 2538908Sborman 2632381Sminshall #include "ring.h" 2732381Sminshall 2832377Sminshall #include "defines.h" 2932377Sminshall #include "externs.h" 3032377Sminshall #include "types.h" 3132377Sminshall #include "general.h" 3227178Sminshall 3327178Sminshall 3427228Sminshall #define strip(x) ((x)&0x7f) 356000Sroot 3646808Sdab static unsigned char subbuffer[SUBBUFSIZE], 3746808Sdab *subpointer, *subend; /* buffer for sub-options */ 3827676Sminshall #define SB_CLEAR() subpointer = subbuffer; 3946808Sdab #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 4027676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 4127676Sminshall *subpointer++ = (c); \ 4227676Sminshall } 4327676Sminshall 4446808Sdab #define SB_GET() ((*subpointer++)&0xff) 4546808Sdab #define SB_PEEK() ((*subpointer)&0xff) 4646808Sdab #define SB_EOF() (subpointer >= subend) 4746808Sdab #define SB_LEN() (subend - subpointer) 4846808Sdab 4937226Sminshall char options[256]; /* The combined options */ 5038689Sborman char do_dont_resp[256]; 5138689Sborman char will_wont_resp[256]; 526000Sroot 5332377Sminshall int 5446808Sdab eight = 0, 5546808Sdab autologin = 0, /* Autologin anyone? */ 5647608Sdab skiprc = 0, 5732377Sminshall connected, 5832377Sminshall showoptions, 5932377Sminshall In3270, /* Are we in 3270 mode? */ 6032377Sminshall ISend, /* trying to send network data in */ 6132377Sminshall debug = 0, 6232377Sminshall crmod, 6332377Sminshall netdata, /* Print out network data flow */ 6432377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 6534848Sminshall #if defined(TN3270) 6636241Sminshall noasynchtty = 0,/* User specified "-noasynch" on command line */ 6736241Sminshall noasynchnet = 0,/* User specified "-noasynch" on command line */ 6832377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 6934848Sminshall #endif /* defined(TN3270) */ 7033286Sminshall telnetport, 7132531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 7232531Sminshall flushout, /* flush output */ 7332531Sminshall autoflush = 0, /* flush output when interrupting? */ 7432531Sminshall autosynch, /* send interrupt characters with SYNCH? */ 7537219Sminshall localflow, /* we handle flow control locally */ 7657213Sdab restartany, /* if flow control enabled, restart on any character */ 7732531Sminshall localchars, /* we recognize interrupt/quit */ 7832531Sminshall donelclchars, /* the user has set "localchars" */ 7932531Sminshall donebinarytoggle, /* the user has put us in binary */ 8032531Sminshall dontlecho, /* do we suppress local echoing right now? */ 8132531Sminshall globalmode; 8227088Sminshall 8344360Sborman char *prompt = 0; 846000Sroot 8544360Sborman cc_t escape; 8646808Sdab cc_t rlogin; 8744360Sborman #ifdef KLUDGELINEMODE 8844360Sborman cc_t echoc; 8944360Sborman #endif 9027186Sminshall 9127186Sminshall /* 926000Sroot * Telnet receiver states for fsm 936000Sroot */ 946000Sroot #define TS_DATA 0 956000Sroot #define TS_IAC 1 966000Sroot #define TS_WILL 2 976000Sroot #define TS_WONT 3 986000Sroot #define TS_DO 4 996000Sroot #define TS_DONT 5 10027021Sminshall #define TS_CR 6 10127676Sminshall #define TS_SB 7 /* sub-option collection */ 10227676Sminshall #define TS_SE 8 /* looking for sub-option end */ 1036000Sroot 10432377Sminshall static int telrcv_state; 1056000Sroot 10632377Sminshall jmp_buf toplevel = { 0 }; 10732377Sminshall jmp_buf peerdied; 1086000Sroot 10932377Sminshall int flushline; 11038811Sborman int linemode; 11127021Sminshall 11238689Sborman #ifdef KLUDGELINEMODE 11338689Sborman int kludgelinemode = 1; 11438689Sborman #endif 11538689Sborman 11632377Sminshall /* 11732377Sminshall * The following are some clocks used to decide how to interpret 11832377Sminshall * the relationship between various variables. 11932377Sminshall */ 1206000Sroot 12132377Sminshall Clocks clocks; 12232377Sminshall 12338689Sborman #ifdef notdef 12432377Sminshall Modelist modelist[] = { 12532377Sminshall { "telnet command mode", COMMAND_LINE }, 12632377Sminshall { "character-at-a-time mode", 0 }, 12732377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 12832377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 12932377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 13032377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 13132377Sminshall { "3270 mode", 0 }, 13232377Sminshall }; 13338689Sborman #endif 1346000Sroot 13532377Sminshall 13632377Sminshall /* 13732377Sminshall * Initialize telnet environment. 13832377Sminshall */ 1396000Sroot 14046808Sdab void 14132377Sminshall init_telnet() 14232377Sminshall { 14344360Sborman env_init(); 14444360Sborman 14532377Sminshall SB_CLEAR(); 14637226Sminshall ClearArray(options); 1476000Sroot 14837219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 149*60149Sdab #if defined(AUTHENTICATION) || defined(ENCRYPTION) 15046808Sdab auth_encrypt_connect(connected); 151*60149Sdab #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ 15257213Sdab restartany = -1; 1536000Sroot 15432377Sminshall SYNCHing = 0; 1556000Sroot 15632377Sminshall /* Don't change NetTrace */ 1576000Sroot 15832377Sminshall escape = CONTROL(']'); 15946808Sdab rlogin = _POSIX_VDISABLE; 16044360Sborman #ifdef KLUDGELINEMODE 16132377Sminshall echoc = CONTROL('E'); 16244360Sborman #endif 1636000Sroot 16432377Sminshall flushline = 1; 16532377Sminshall telrcv_state = TS_DATA; 16632377Sminshall } 16732554Sminshall 1686000Sroot 16944360Sborman #ifdef notdef 17032554Sminshall #include <varargs.h> 1716000Sroot 17246808Sdab /*VARARGS*/ 17346808Sdab static void 17432554Sminshall printring(va_alist) 17546808Sdab va_dcl 17632554Sminshall { 17732554Sminshall va_list ap; 17832554Sminshall char buffer[100]; /* where things go */ 17932554Sminshall char *ptr; 18032554Sminshall char *format; 18132554Sminshall char *string; 18232554Sminshall Ring *ring; 18332554Sminshall int i; 18432554Sminshall 18532554Sminshall va_start(ap); 18632554Sminshall 18732554Sminshall ring = va_arg(ap, Ring *); 18832554Sminshall format = va_arg(ap, char *); 18932554Sminshall ptr = buffer; 19032554Sminshall 19132554Sminshall while ((i = *format++) != 0) { 19232554Sminshall if (i == '%') { 19332554Sminshall i = *format++; 19432554Sminshall switch (i) { 19532554Sminshall case 'c': 19632554Sminshall *ptr++ = va_arg(ap, int); 19732554Sminshall break; 19832554Sminshall case 's': 19932554Sminshall string = va_arg(ap, char *); 20032554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 20132554Sminshall ring_supply_data(ring, string, strlen(string)); 20232554Sminshall ptr = buffer; 20332554Sminshall break; 20432554Sminshall case 0: 20532554Sminshall ExitString("printring: trailing %%.\n", 1); 20632554Sminshall /*NOTREACHED*/ 20732554Sminshall default: 20832554Sminshall ExitString("printring: unknown format character.\n", 1); 20932554Sminshall /*NOTREACHED*/ 21032554Sminshall } 21132554Sminshall } else { 21232554Sminshall *ptr++ = i; 21332554Sminshall } 21432554Sminshall } 21532554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 21632554Sminshall } 21744360Sborman #endif 21832554Sminshall 21937226Sminshall /* 22037226Sminshall * These routines are in charge of sending option negotiations 22137226Sminshall * to the other side. 22237226Sminshall * 22337226Sminshall * The basic idea is that we send the negotiation if either side 22437226Sminshall * is in disagreement as to what the current state should be. 22537226Sminshall */ 22632554Sminshall 22746808Sdab void 22838689Sborman send_do(c, init) 22946808Sdab register int c, init; 2306000Sroot { 23138689Sborman if (init) { 23238689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 23338689Sborman my_want_state_is_do(c)) 23438689Sborman return; 23538689Sborman set_my_want_state_do(c); 23638689Sborman do_dont_resp[c]++; 23737226Sminshall } 23838689Sborman NET2ADD(IAC, DO); 23938689Sborman NETADD(c); 24046808Sdab printoption("SENT", DO, c); 24137226Sminshall } 24237226Sminshall 24346808Sdab void 24438689Sborman send_dont(c, init) 24546808Sdab register int c, init; 24637226Sminshall { 24738689Sborman if (init) { 24838689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 24938689Sborman my_want_state_is_dont(c)) 25038689Sborman return; 25138689Sborman set_my_want_state_dont(c); 25238689Sborman do_dont_resp[c]++; 25337226Sminshall } 25438689Sborman NET2ADD(IAC, DONT); 25538689Sborman NETADD(c); 25646808Sdab printoption("SENT", DONT, c); 25737226Sminshall } 25837226Sminshall 25946808Sdab void 26038689Sborman send_will(c, init) 26146808Sdab register int c, init; 26237226Sminshall { 26338689Sborman if (init) { 26438689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 26538689Sborman my_want_state_is_will(c)) 26638689Sborman return; 26738689Sborman set_my_want_state_will(c); 26838689Sborman will_wont_resp[c]++; 26937226Sminshall } 27038689Sborman NET2ADD(IAC, WILL); 27138689Sborman NETADD(c); 27246808Sdab printoption("SENT", WILL, c); 27337226Sminshall } 27437226Sminshall 27546808Sdab void 27638689Sborman send_wont(c, init) 27746808Sdab register int c, init; 27837226Sminshall { 27938689Sborman if (init) { 28038689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 28138689Sborman my_want_state_is_wont(c)) 28238689Sborman return; 28338689Sborman set_my_want_state_wont(c); 28438689Sborman will_wont_resp[c]++; 28537226Sminshall } 28638689Sborman NET2ADD(IAC, WONT); 28738689Sborman NETADD(c); 28846808Sdab printoption("SENT", WONT, c); 28937226Sminshall } 29037226Sminshall 29137226Sminshall 29246808Sdab void 29337226Sminshall willoption(option) 29437226Sminshall int option; 29537226Sminshall { 29638689Sborman int new_state_ok = 0; 2976000Sroot 29838689Sborman if (do_dont_resp[option]) { 29938689Sborman --do_dont_resp[option]; 30038689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 30138689Sborman --do_dont_resp[option]; 30238689Sborman } 30337226Sminshall 30438689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 3056000Sroot 30638689Sborman switch (option) { 30738689Sborman 30838689Sborman case TELOPT_ECHO: 30938689Sborman # if defined(TN3270) 31038689Sborman /* 31138689Sborman * The following is a pain in the rear-end. 31238689Sborman * Various IBM servers (some versions of Wiscnet, 31338689Sborman * possibly Fibronics/Spartacus, and who knows who 31438689Sborman * else) will NOT allow us to send "DO SGA" too early 31538689Sborman * in the setup proceedings. On the other hand, 31638689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 31738689Sborman * So, we are stuck. Empirically (but, based on 31838689Sborman * a VERY small sample), the IBM servers don't send 31938689Sborman * out anything about ECHO, so we postpone our sending 32038689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 32138689Sborman * DO send). 32238689Sborman */ 32338689Sborman { 32438689Sborman if (askedSGA == 0) { 32538689Sborman askedSGA = 1; 32638689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 32738689Sborman send_do(TELOPT_SGA, 1); 32832377Sminshall } 32932377Sminshall } 33038689Sborman /* Fall through */ 33138689Sborman case TELOPT_EOR: 33238908Sborman #endif /* defined(TN3270) */ 33338689Sborman case TELOPT_BINARY: 33438689Sborman case TELOPT_SGA: 33527110Sminshall settimer(modenegotiated); 33638908Sborman /* FALL THROUGH */ 33738908Sborman case TELOPT_STATUS: 33857213Sdab #if defined(AUTHENTICATION) 33946808Sdab case TELOPT_AUTHENTICATION: 34046808Sdab #endif 341*60149Sdab #ifdef ENCRYPTION 34246808Sdab case TELOPT_ENCRYPT: 343*60149Sdab #endif /* ENCRYPTION */ 34438689Sborman new_state_ok = 1; 3456000Sroot break; 3466000Sroot 34738689Sborman case TELOPT_TM: 34838689Sborman if (flushout) 34938689Sborman flushout = 0; 35038689Sborman /* 35138689Sborman * Special case for TM. If we get back a WILL, 35238689Sborman * pretend we got back a WONT. 35338689Sborman */ 35438689Sborman set_my_want_state_dont(option); 35538689Sborman set_my_state_dont(option); 35627110Sminshall return; /* Never reply to TM will's/wont's */ 3576000Sroot 35838689Sborman case TELOPT_LINEMODE: 35938689Sborman default: 3606000Sroot break; 36138689Sborman } 36238689Sborman 36338689Sborman if (new_state_ok) { 36438689Sborman set_my_want_state_do(option); 36538689Sborman send_do(option, 0); 36638689Sborman setconnmode(0); /* possibly set new tty mode */ 36738689Sborman } else { 36838689Sborman do_dont_resp[option]++; 36938689Sborman send_dont(option, 0); 37038689Sborman } 3716000Sroot } 37238689Sborman set_my_state_do(option); 373*60149Sdab #ifdef ENCRYPTION 37446808Sdab if (option == TELOPT_ENCRYPT) 37546808Sdab encrypt_send_support(); 376*60149Sdab #endif /* ENCRYPTION */ 3776000Sroot } 3786000Sroot 37946808Sdab void 38037226Sminshall wontoption(option) 38137226Sminshall int option; 3826000Sroot { 38338689Sborman if (do_dont_resp[option]) { 38438689Sborman --do_dont_resp[option]; 38538689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 38638689Sborman --do_dont_resp[option]; 38738689Sborman } 38837226Sminshall 38938689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3906000Sroot 39138689Sborman switch (option) { 39238689Sborman 39338689Sborman #ifdef KLUDGELINEMODE 39438689Sborman case TELOPT_SGA: 39538689Sborman if (!kludgelinemode) 39638689Sborman break; 39738689Sborman /* FALL THROUGH */ 39838689Sborman #endif 39938689Sborman case TELOPT_ECHO: 40027110Sminshall settimer(modenegotiated); 4016000Sroot break; 4026000Sroot 40338689Sborman case TELOPT_TM: 40438689Sborman if (flushout) 40538689Sborman flushout = 0; 40638689Sborman set_my_want_state_dont(option); 40738689Sborman set_my_state_dont(option); 40827110Sminshall return; /* Never reply to TM will's/wont's */ 40927110Sminshall 41038689Sborman default: 41138689Sborman break; 41238689Sborman } 41338689Sborman set_my_want_state_dont(option); 41444360Sborman if (my_state_is_do(option)) 41544360Sborman send_dont(option, 0); 41638689Sborman setconnmode(0); /* Set new tty mode */ 41738689Sborman } else if (option == TELOPT_TM) { 41838689Sborman /* 41938689Sborman * Special case for TM. 42038689Sborman */ 42138689Sborman if (flushout) 42238689Sborman flushout = 0; 42338689Sborman set_my_want_state_dont(option); 4246000Sroot } 42538689Sborman set_my_state_dont(option); 4266000Sroot } 4276000Sroot 42846808Sdab static void 4296000Sroot dooption(option) 4306000Sroot int option; 4316000Sroot { 43238689Sborman int new_state_ok = 0; 4336000Sroot 43438689Sborman if (will_wont_resp[option]) { 43538689Sborman --will_wont_resp[option]; 43638689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 43738689Sborman --will_wont_resp[option]; 43838689Sborman } 43937226Sminshall 44038689Sborman if (will_wont_resp[option] == 0) { 44138689Sborman if (my_want_state_is_wont(option)) { 4426000Sroot 44338689Sborman switch (option) { 44438689Sborman 44538689Sborman case TELOPT_TM: 44638689Sborman /* 44738689Sborman * Special case for TM. We send a WILL, but pretend 44838689Sborman * we sent WONT. 44938689Sborman */ 45038689Sborman send_will(option, 0); 45138689Sborman set_my_want_state_wont(TELOPT_TM); 45238689Sborman set_my_state_wont(TELOPT_TM); 45338689Sborman return; 45438689Sborman 45532377Sminshall # if defined(TN3270) 45638689Sborman case TELOPT_EOR: /* end of record */ 45738908Sborman # endif /* defined(TN3270) */ 45838689Sborman case TELOPT_BINARY: /* binary mode */ 45938689Sborman case TELOPT_NAWS: /* window size */ 46038689Sborman case TELOPT_TSPEED: /* terminal speed */ 46138689Sborman case TELOPT_LFLOW: /* local flow control */ 46238689Sborman case TELOPT_TTYPE: /* terminal type option */ 46338689Sborman case TELOPT_SGA: /* no big deal */ 46444360Sborman case TELOPT_ENVIRON: /* environment variable option */ 465*60149Sdab #ifdef ENCRYPTION 46646808Sdab case TELOPT_ENCRYPT: /* encryption variable option */ 467*60149Sdab #endif /* ENCRYPTION */ 46838689Sborman new_state_ok = 1; 4696000Sroot break; 47057213Sdab #if defined(AUTHENTICATION) 47146808Sdab case TELOPT_AUTHENTICATION: 47246808Sdab if (autologin) 47346808Sdab new_state_ok = 1; 47446808Sdab break; 47546808Sdab #endif 4766000Sroot 47744360Sborman case TELOPT_XDISPLOC: /* X Display location */ 47846808Sdab if (env_getvalue((unsigned char *)"DISPLAY")) 47944360Sborman new_state_ok = 1; 48044360Sborman break; 48144360Sborman 48238689Sborman case TELOPT_LINEMODE: 48338689Sborman #ifdef KLUDGELINEMODE 48438689Sborman kludgelinemode = 0; 48544360Sborman send_do(TELOPT_SGA, 1); 48638689Sborman #endif 48738689Sborman set_my_want_state_will(TELOPT_LINEMODE); 48838689Sborman send_will(option, 0); 48938689Sborman set_my_state_will(TELOPT_LINEMODE); 49038689Sborman slc_init(); 49138689Sborman return; 49238689Sborman 49338689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 49438689Sborman default: 4956000Sroot break; 49638689Sborman } 49738689Sborman 49838689Sborman if (new_state_ok) { 49938689Sborman set_my_want_state_will(option); 50038689Sborman send_will(option, 0); 50145232Sborman setconnmode(0); /* Set new tty mode */ 50238689Sborman } else { 50338689Sborman will_wont_resp[option]++; 50438689Sborman send_wont(option, 0); 50538689Sborman } 50638689Sborman } else { 50738689Sborman /* 50838689Sborman * Handle options that need more things done after the 50938689Sborman * other side has acknowledged the option. 51038689Sborman */ 51138689Sborman switch (option) { 51238689Sborman case TELOPT_LINEMODE: 51338689Sborman #ifdef KLUDGELINEMODE 51438689Sborman kludgelinemode = 0; 51544360Sborman send_do(TELOPT_SGA, 1); 51638689Sborman #endif 51738689Sborman set_my_state_will(option); 51838689Sborman slc_init(); 51944360Sborman send_do(TELOPT_SGA, 0); 52038689Sborman return; 52138689Sborman } 52238689Sborman } 5236000Sroot } 52438689Sborman set_my_state_will(option); 5256000Sroot } 52627676Sminshall 52746808Sdab static void 52838689Sborman dontoption(option) 52938689Sborman int option; 53038689Sborman { 53138689Sborman 53238689Sborman if (will_wont_resp[option]) { 53338689Sborman --will_wont_resp[option]; 53438689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 53538689Sborman --will_wont_resp[option]; 53638689Sborman } 53738689Sborman 53838689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 53938811Sborman switch (option) { 54038811Sborman case TELOPT_LINEMODE: 54138811Sborman linemode = 0; /* put us back to the default state */ 54238811Sborman break; 54338811Sborman } 54438689Sborman /* we always accept a DONT */ 54538689Sborman set_my_want_state_wont(option); 54644360Sborman if (my_state_is_will(option)) 54744360Sborman send_wont(option, 0); 54839529Sborman setconnmode(0); /* Set new tty mode */ 54938689Sborman } 55038689Sborman set_my_state_wont(option); 55138689Sborman } 55238689Sborman 55327676Sminshall /* 55438908Sborman * Given a buffer returned by tgetent(), this routine will turn 55538908Sborman * the pipe seperated list of names in the buffer into an array 55638908Sborman * of pointers to null terminated names. We toss out any bad, 55738908Sborman * duplicate, or verbose names (names with spaces). 55838908Sborman */ 55938908Sborman 56046808Sdab static char *name_unknown = "UNKNOWN"; 56146808Sdab static char *unknown[] = { 0, 0 }; 56238908Sborman 56346808Sdab char ** 56438908Sborman mklist(buf, name) 56546808Sdab char *buf, *name; 56638908Sborman { 56738908Sborman register int n; 56846808Sdab register char c, *cp, **argvp, *cp2, **argv, **avt; 56938908Sborman 57038908Sborman if (name) { 57146808Sdab if (strlen(name) > 40) { 57238908Sborman name = 0; 57346808Sdab unknown[0] = name_unknown; 57446808Sdab } else { 57538908Sborman unknown[0] = name; 57638908Sborman upcase(name); 57738908Sborman } 57846808Sdab } else 57946808Sdab unknown[0] = name_unknown; 58038908Sborman /* 58138908Sborman * Count up the number of names. 58238908Sborman */ 58338908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 58438908Sborman if (*cp == '|') 58538908Sborman n++; 58638908Sborman } 58738908Sborman /* 58838908Sborman * Allocate an array to put the name pointers into 58938908Sborman */ 59038908Sborman argv = (char **)malloc((n+3)*sizeof(char *)); 59138908Sborman if (argv == 0) 59238908Sborman return(unknown); 59338908Sborman 59438908Sborman /* 59538908Sborman * Fill up the array of pointers to names. 59638908Sborman */ 59738908Sborman *argv = 0; 59838908Sborman argvp = argv+1; 59938908Sborman n = 0; 60038908Sborman for (cp = cp2 = buf; (c = *cp); cp++) { 60138908Sborman if (c == '|' || c == ':') { 60238908Sborman *cp++ = '\0'; 60338908Sborman /* 60438908Sborman * Skip entries that have spaces or are over 40 60538908Sborman * characters long. If this is our environment 60638908Sborman * name, then put it up front. Otherwise, as 60738908Sborman * long as this is not a duplicate name (case 60838908Sborman * insensitive) add it to the list. 60938908Sborman */ 61038908Sborman if (n || (cp - cp2 > 41)) 61138908Sborman ; 61238908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 61338908Sborman *argv = cp2; 61438908Sborman else if (is_unique(cp2, argv+1, argvp)) 61538908Sborman *argvp++ = cp2; 61638908Sborman if (c == ':') 61738908Sborman break; 61838908Sborman /* 61938908Sborman * Skip multiple delimiters. Reset cp2 to 62038908Sborman * the beginning of the next name. Reset n, 62138908Sborman * the flag for names with spaces. 62238908Sborman */ 62338908Sborman while ((c = *cp) == '|') 62438908Sborman cp++; 62538908Sborman cp2 = cp; 62638908Sborman n = 0; 62738908Sborman } 62838908Sborman /* 62938908Sborman * Skip entries with spaces or non-ascii values. 63038908Sborman * Convert lower case letters to upper case. 63138908Sborman */ 63238908Sborman if ((c == ' ') || !isascii(c)) 63338908Sborman n = 1; 63438908Sborman else if (islower(c)) 63538908Sborman *cp = toupper(c); 63638908Sborman } 63738908Sborman 63838908Sborman /* 63938908Sborman * Check for an old V6 2 character name. If the second 64038908Sborman * name points to the beginning of the buffer, and is 64138908Sborman * only 2 characters long, move it to the end of the array. 64238908Sborman */ 64338908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 64446808Sdab --argvp; 64546808Sdab for (avt = &argv[1]; avt < argvp; avt++) 64646808Sdab *avt = *(avt+1); 64738908Sborman *argvp++ = buf; 64838908Sborman } 64938908Sborman 65038908Sborman /* 65138908Sborman * Duplicate last name, for TTYPE option, and null 65238908Sborman * terminate the array. If we didn't find a match on 65338908Sborman * our terminal name, put that name at the beginning. 65438908Sborman */ 65538908Sborman cp = *(argvp-1); 65638908Sborman *argvp++ = cp; 65738908Sborman *argvp = 0; 65838908Sborman 65938908Sborman if (*argv == 0) { 66038908Sborman if (name) 66138908Sborman *argv = name; 66246808Sdab else { 66346808Sdab --argvp; 66446808Sdab for (avt = argv; avt < argvp; avt++) 66546808Sdab *avt = *(avt+1); 66646808Sdab } 66738908Sborman } 66838908Sborman if (*argv) 66938908Sborman return(argv); 67038908Sborman else 67138908Sborman return(unknown); 67238908Sborman } 67338908Sborman 67446808Sdab int 67538908Sborman is_unique(name, as, ae) 67646808Sdab register char *name, **as, **ae; 67738908Sborman { 67838908Sborman register char **ap; 67938908Sborman register int n; 68038908Sborman 68138908Sborman n = strlen(name) + 1; 68238908Sborman for (ap = as; ap < ae; ap++) 68338908Sborman if (strncasecmp(*ap, name, n) == 0) 68438908Sborman return(0); 68538908Sborman return (1); 68638908Sborman } 68738908Sborman 68838908Sborman #ifdef TERMCAP 68939529Sborman char termbuf[1024]; 69046808Sdab 69146808Sdab /*ARGSUSED*/ 69246808Sdab int 69338908Sborman setupterm(tname, fd, errp) 69446808Sdab char *tname; 69546808Sdab int fd, *errp; 69638908Sborman { 69739529Sborman if (tgetent(termbuf, tname) == 1) { 69839529Sborman termbuf[1023] = '\0'; 69938908Sborman if (errp) 70038908Sborman *errp = 1; 70138908Sborman return(0); 70238908Sborman } 70338908Sborman if (errp) 70438908Sborman *errp = 0; 70538908Sborman return(-1); 70638908Sborman } 70739529Sborman #else 70839529Sborman #define termbuf ttytype 70939529Sborman extern char ttytype[]; 71038908Sborman #endif 71138908Sborman 71246808Sdab int resettermname = 1; 71346808Sdab 71446808Sdab char * 71538908Sborman gettermname() 71638908Sborman { 71738908Sborman char *tname; 71846808Sdab static char **tnamep = 0; 71938908Sborman static char **next; 72038908Sborman int err; 72138908Sborman 72246808Sdab if (resettermname) { 72346808Sdab resettermname = 0; 72446808Sdab if (tnamep && tnamep != unknown) 72546808Sdab free(tnamep); 72646808Sdab if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && 72738908Sborman (setupterm(tname, 1, &err) == 0)) { 72839529Sborman tnamep = mklist(termbuf, tname); 72938908Sborman } else { 73038908Sborman if (tname && (strlen(tname) <= 40)) { 73138908Sborman unknown[0] = tname; 73238908Sborman upcase(tname); 73346808Sdab } else 73446808Sdab unknown[0] = name_unknown; 73538908Sborman tnamep = unknown; 73638908Sborman } 73738908Sborman next = tnamep; 73838908Sborman } 73938908Sborman if (*next == 0) 74038908Sborman next = tnamep; 74138908Sborman return(*next++); 74238908Sborman } 74338908Sborman /* 74427676Sminshall * suboption() 74527676Sminshall * 74627676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 74727676Sminshall * side. 74827676Sminshall * 74927676Sminshall * Currently we recognize: 75027676Sminshall * 75127676Sminshall * Terminal type, send request. 75237219Sminshall * Terminal speed (send request). 75337219Sminshall * Local flow control (is request). 75438689Sborman * Linemode 75527676Sminshall */ 75627676Sminshall 75746808Sdab static void 75827676Sminshall suboption() 75927676Sminshall { 76046808Sdab printsub('<', subbuffer, SB_LEN()+2); 76146808Sdab switch (SB_GET()) { 76227676Sminshall case TELOPT_TTYPE: 76338689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 76438689Sborman return; 76546808Sdab if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 76646808Sdab return; 76727676Sminshall } else { 76827676Sminshall char *name; 76946808Sdab unsigned char temp[50]; 77027676Sminshall int len; 77127676Sminshall 77232377Sminshall #if defined(TN3270) 77332531Sminshall if (tn3270_ttype()) { 77432377Sminshall return; 77532377Sminshall } 77632377Sminshall #endif /* defined(TN3270) */ 77738908Sborman name = gettermname(); 77838908Sborman len = strlen(name) + 4 + 2; 77938908Sborman if (len < NETROOM()) { 78046808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 78138908Sborman TELQUAL_IS, name, IAC, SE); 78238689Sborman ring_supply_data(&netoring, temp, len); 78338908Sborman printsub('>', &temp[2], len-2); 78432377Sminshall } else { 78537226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 78632377Sminshall /*NOTREACHED*/ 78727676Sminshall } 78827676Sminshall } 78937219Sminshall break; 79037219Sminshall case TELOPT_TSPEED: 79138689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 79238689Sborman return; 79346808Sdab if (SB_EOF()) 79446808Sdab return; 79546808Sdab if (SB_GET() == TELQUAL_SEND) { 79645232Sborman long ospeed, ispeed; 79746808Sdab unsigned char temp[50]; 79837219Sminshall int len; 79927676Sminshall 80037219Sminshall TerminalSpeeds(&ispeed, &ospeed); 80137219Sminshall 80246808Sdab sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 80338689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 80446808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 80537219Sminshall 80638689Sborman if (len < NETROOM()) { 80738689Sborman ring_supply_data(&netoring, temp, len); 80838689Sborman printsub('>', temp+2, len - 2); 80937219Sminshall } 81044360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 81137219Sminshall } 81237219Sminshall break; 81337219Sminshall case TELOPT_LFLOW: 81438689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 81538689Sborman return; 81646808Sdab if (SB_EOF()) 81746808Sdab return; 81846808Sdab switch(SB_GET()) { 81957213Sdab case LFLOW_RESTART_ANY: 82057213Sdab restartany = 1; 82157213Sdab break; 82257213Sdab case LFLOW_RESTART_XON: 82357213Sdab restartany = 0; 82457213Sdab break; 82557213Sdab case LFLOW_ON: 82637219Sminshall localflow = 1; 82746808Sdab break; 82857213Sdab case LFLOW_OFF: 82937219Sminshall localflow = 0; 83046808Sdab break; 83146808Sdab default: 83246808Sdab return; 83337219Sminshall } 83437219Sminshall setcommandmode(); 83538689Sborman setconnmode(0); 83637219Sminshall break; 83738689Sborman 83838689Sborman case TELOPT_LINEMODE: 83938689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 84038689Sborman return; 84146808Sdab if (SB_EOF()) 84246808Sdab return; 84346808Sdab switch (SB_GET()) { 84438689Sborman case WILL: 84546808Sdab lm_will(subpointer, SB_LEN()); 84638689Sborman break; 84738689Sborman case WONT: 84846808Sdab lm_wont(subpointer, SB_LEN()); 84938689Sborman break; 85038689Sborman case DO: 85146808Sdab lm_do(subpointer, SB_LEN()); 85238689Sborman break; 85338689Sborman case DONT: 85446808Sdab lm_dont(subpointer, SB_LEN()); 85538689Sborman break; 85638689Sborman case LM_SLC: 85746808Sdab slc(subpointer, SB_LEN()); 85838689Sborman break; 85938689Sborman case LM_MODE: 86046808Sdab lm_mode(subpointer, SB_LEN(), 0); 86138689Sborman break; 86238689Sborman default: 86344360Sborman break; 86444360Sborman } 86544360Sborman break; 86644360Sborman 86744360Sborman case TELOPT_ENVIRON: 86846808Sdab if (SB_EOF()) 86946808Sdab return; 87046808Sdab switch(SB_PEEK()) { 87144360Sborman case TELQUAL_IS: 87244360Sborman case TELQUAL_INFO: 87344360Sborman if (my_want_state_is_dont(TELOPT_ENVIRON)) 87444360Sborman return; 87544360Sborman break; 87644360Sborman case TELQUAL_SEND: 87744360Sborman if (my_want_state_is_wont(TELOPT_ENVIRON)) { 87844360Sborman return; 87944360Sborman } 88044360Sborman break; 88144360Sborman default: 88244360Sborman return; 88344360Sborman } 88446808Sdab env_opt(subpointer, SB_LEN()); 88544360Sborman break; 88644360Sborman 88744360Sborman case TELOPT_XDISPLOC: 88844360Sborman if (my_want_state_is_wont(TELOPT_XDISPLOC)) 88944360Sborman return; 89046808Sdab if (SB_EOF()) 89146808Sdab return; 89246808Sdab if (SB_GET() == TELQUAL_SEND) { 89346808Sdab unsigned char temp[50], *dp; 89444360Sborman int len; 89544360Sborman 89646808Sdab if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { 89744360Sborman /* 89844360Sborman * Something happened, we no longer have a DISPLAY 89944360Sborman * variable. So, turn off the option. 90044360Sborman */ 90144360Sborman send_wont(TELOPT_XDISPLOC, 1); 90238689Sborman break; 90344360Sborman } 90446808Sdab sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, 90544360Sborman TELQUAL_IS, dp, IAC, SE); 90646808Sdab len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 90744360Sborman 90844360Sborman if (len < NETROOM()) { 90944360Sborman ring_supply_data(&netoring, temp, len); 91044360Sborman printsub('>', temp+2, len - 2); 91144360Sborman } 91244360Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 91338689Sborman } 91444360Sborman break; 91543319Skfall 91657213Sdab #if defined(AUTHENTICATION) 91746808Sdab case TELOPT_AUTHENTICATION: { 91846808Sdab if (!autologin) 91946808Sdab break; 92046808Sdab if (SB_EOF()) 92146808Sdab return; 92246808Sdab switch(SB_GET()) { 92346808Sdab case TELQUAL_IS: 92446808Sdab if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 92546808Sdab return; 92646808Sdab auth_is(subpointer, SB_LEN()); 92746808Sdab break; 92846808Sdab case TELQUAL_SEND: 92946808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 93046808Sdab return; 93146808Sdab auth_send(subpointer, SB_LEN()); 93246808Sdab break; 93346808Sdab case TELQUAL_REPLY: 93446808Sdab if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 93546808Sdab return; 93646808Sdab auth_reply(subpointer, SB_LEN()); 93746808Sdab break; 93847608Sdab case TELQUAL_NAME: 93947608Sdab if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 94047608Sdab return; 94147608Sdab auth_name(subpointer, SB_LEN()); 94247608Sdab break; 94343319Skfall } 94446808Sdab } 94546808Sdab break; 94643319Skfall #endif 947*60149Sdab #ifdef ENCRYPTION 94846808Sdab case TELOPT_ENCRYPT: 94946808Sdab if (SB_EOF()) 95046808Sdab return; 95146808Sdab switch(SB_GET()) { 95246808Sdab case ENCRYPT_START: 95346808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 95446808Sdab return; 95547608Sdab encrypt_start(subpointer, SB_LEN()); 95646808Sdab break; 95746808Sdab case ENCRYPT_END: 95846808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 95946808Sdab return; 96046808Sdab encrypt_end(); 96146808Sdab break; 96246808Sdab case ENCRYPT_SUPPORT: 96346808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 96446808Sdab return; 96546808Sdab encrypt_support(subpointer, SB_LEN()); 96646808Sdab break; 96746808Sdab case ENCRYPT_REQSTART: 96846808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 96946808Sdab return; 97047608Sdab encrypt_request_start(subpointer, SB_LEN()); 97146808Sdab break; 97246808Sdab case ENCRYPT_REQEND: 97346808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 97446808Sdab return; 97546808Sdab /* 97646808Sdab * We can always send an REQEND so that we cannot 97746808Sdab * get stuck encrypting. We should only get this 97846808Sdab * if we have been able to get in the correct mode 97946808Sdab * anyhow. 98046808Sdab */ 98146808Sdab encrypt_request_end(); 98246808Sdab break; 98346808Sdab case ENCRYPT_IS: 98446808Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 98546808Sdab return; 98646808Sdab encrypt_is(subpointer, SB_LEN()); 98746808Sdab break; 98846808Sdab case ENCRYPT_REPLY: 98946808Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 99046808Sdab return; 99146808Sdab encrypt_reply(subpointer, SB_LEN()); 99246808Sdab break; 99347608Sdab case ENCRYPT_ENC_KEYID: 99447608Sdab if (my_want_state_is_dont(TELOPT_ENCRYPT)) 99547608Sdab return; 99647608Sdab encrypt_enc_keyid(subpointer, SB_LEN()); 99747608Sdab break; 99847608Sdab case ENCRYPT_DEC_KEYID: 99947608Sdab if (my_want_state_is_wont(TELOPT_ENCRYPT)) 100047608Sdab return; 100147608Sdab encrypt_dec_keyid(subpointer, SB_LEN()); 100247608Sdab break; 100346808Sdab default: 100446808Sdab break; 100546808Sdab } 100646808Sdab break; 1007*60149Sdab #endif /* ENCRYPTION */ 100827676Sminshall default: 100927676Sminshall break; 101027676Sminshall } 101127676Sminshall } 101238689Sborman 101346808Sdab static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 101438689Sborman 101546808Sdab void 101638689Sborman lm_will(cmd, len) 101746808Sdab unsigned char *cmd; 101846808Sdab int len; 101938689Sborman { 102044360Sborman if (len < 1) { 102144360Sborman /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 102244360Sborman return; 102344360Sborman } 102438689Sborman switch(cmd[0]) { 102538689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 102638689Sborman default: 102738689Sborman str_lm[3] = DONT; 102838689Sborman str_lm[4] = cmd[0]; 102938689Sborman if (NETROOM() > sizeof(str_lm)) { 103038689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 103138689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 103238689Sborman } 103338689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 103438689Sborman break; 103538689Sborman } 103638689Sborman } 103738689Sborman 103846808Sdab void 103938689Sborman lm_wont(cmd, len) 104046808Sdab unsigned char *cmd; 104146808Sdab int len; 104238689Sborman { 104344360Sborman if (len < 1) { 104444360Sborman /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 104544360Sborman return; 104644360Sborman } 104738689Sborman switch(cmd[0]) { 104838689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 104938689Sborman default: 105038689Sborman /* We are always DONT, so don't respond */ 105138689Sborman return; 105238689Sborman } 105338689Sborman } 105438689Sborman 105546808Sdab void 105638689Sborman lm_do(cmd, len) 105746808Sdab unsigned char *cmd; 105846808Sdab int len; 105938689Sborman { 106044360Sborman if (len < 1) { 106144360Sborman /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 106244360Sborman return; 106344360Sborman } 106438689Sborman switch(cmd[0]) { 106538689Sborman case LM_FORWARDMASK: 106638689Sborman default: 106738689Sborman str_lm[3] = WONT; 106838689Sborman str_lm[4] = cmd[0]; 106938689Sborman if (NETROOM() > sizeof(str_lm)) { 107038689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 107138689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 107238689Sborman } 107338689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 107438689Sborman break; 107538689Sborman } 107638689Sborman } 107738689Sborman 107846808Sdab void 107938689Sborman lm_dont(cmd, len) 108046808Sdab unsigned char *cmd; 108146808Sdab int len; 108238689Sborman { 108344360Sborman if (len < 1) { 108444360Sborman /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 108544360Sborman return; 108644360Sborman } 108738689Sborman switch(cmd[0]) { 108838689Sborman case LM_FORWARDMASK: 108938689Sborman default: 109038689Sborman /* we are always WONT, so don't respond */ 109138689Sborman break; 109238689Sborman } 109338689Sborman } 109438689Sborman 109546808Sdab static unsigned char str_lm_mode[] = { 109646808Sdab IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 109746808Sdab }; 109838689Sborman 109946808Sdab void 110038689Sborman lm_mode(cmd, len, init) 110146808Sdab unsigned char *cmd; 110246808Sdab int len, init; 110338689Sborman { 110438689Sborman if (len != 1) 110538689Sborman return; 110644360Sborman if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 110738689Sborman return; 110838689Sborman if (*cmd&MODE_ACK) 110938689Sborman return; 111044360Sborman linemode = *cmd&(MODE_MASK&~MODE_ACK); 111138689Sborman str_lm_mode[4] = linemode; 111238689Sborman if (!init) 111338689Sborman str_lm_mode[4] |= MODE_ACK; 111438689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 111538689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 111638689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 111738689Sborman } 111838689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 111938689Sborman setconnmode(0); /* set changed mode */ 112038689Sborman } 112138689Sborman 112232377Sminshall 112327088Sminshall 112438689Sborman /* 112538689Sborman * slc() 112638689Sborman * Handle special character suboption of LINEMODE. 112738689Sborman */ 112838689Sborman 112938689Sborman struct spc { 113040245Sborman cc_t val; 113140245Sborman cc_t *valp; 113238689Sborman char flags; /* Current flags & level */ 113338689Sborman char mylevel; /* Maximum level & flags */ 113438689Sborman } spc_data[NSLC+1]; 113538689Sborman 113638689Sborman #define SLC_IMPORT 0 113738689Sborman #define SLC_EXPORT 1 113838689Sborman #define SLC_RVALUE 2 113938689Sborman static int slc_mode = SLC_EXPORT; 114038689Sborman 114146808Sdab void 114238689Sborman slc_init() 114338689Sborman { 114438689Sborman register struct spc *spcp; 114538689Sborman 114638689Sborman localchars = 1; 114738689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 114838689Sborman spcp->val = 0; 114938689Sborman spcp->valp = 0; 115038689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 115138689Sborman } 115238689Sborman 115338689Sborman #define initfunc(func, flags) { \ 115438689Sborman spcp = &spc_data[func]; \ 115538689Sborman if (spcp->valp = tcval(func)) { \ 115638689Sborman spcp->val = *spcp->valp; \ 115738689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 115838689Sborman } else { \ 115938689Sborman spcp->val = 0; \ 116038689Sborman spcp->mylevel = SLC_DEFAULT; \ 116138689Sborman } \ 116238689Sborman } 116338689Sborman 116438689Sborman initfunc(SLC_SYNCH, 0); 116538689Sborman /* No BRK */ 116638689Sborman initfunc(SLC_AO, 0); 116738689Sborman initfunc(SLC_AYT, 0); 116838689Sborman /* No EOR */ 116938689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 117038689Sborman initfunc(SLC_EOF, 0); 117139529Sborman #ifndef SYSV_TERMIO 117238689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 117338689Sborman #endif 117438689Sborman initfunc(SLC_EC, 0); 117538689Sborman initfunc(SLC_EL, 0); 117639529Sborman #ifndef SYSV_TERMIO 117738689Sborman initfunc(SLC_EW, 0); 117838689Sborman initfunc(SLC_RP, 0); 117938689Sborman initfunc(SLC_LNEXT, 0); 118038689Sborman #endif 118138689Sborman initfunc(SLC_XON, 0); 118238689Sborman initfunc(SLC_XOFF, 0); 118339529Sborman #ifdef SYSV_TERMIO 118438689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 118538689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 118638689Sborman #endif 118744360Sborman initfunc(SLC_FORW1, 0); 118844360Sborman #ifdef USE_TERMIO 118944360Sborman initfunc(SLC_FORW2, 0); 119038689Sborman /* No FORW2 */ 119144360Sborman #endif 119238689Sborman 119338689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 119438689Sborman #undef initfunc 119538689Sborman 119638689Sborman if (slc_mode == SLC_EXPORT) 119738689Sborman slc_export(); 119838689Sborman else 119938689Sborman slc_import(1); 120038689Sborman 120138689Sborman } 120238689Sborman 120346808Sdab void 120438689Sborman slcstate() 120538689Sborman { 120638689Sborman printf("Special characters are %s values\n", 120738689Sborman slc_mode == SLC_IMPORT ? "remote default" : 120838689Sborman slc_mode == SLC_EXPORT ? "local" : 120938689Sborman "remote"); 121038689Sborman } 121138689Sborman 121246808Sdab void 121338689Sborman slc_mode_export() 121438689Sborman { 121538689Sborman slc_mode = SLC_EXPORT; 121638689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 121738689Sborman slc_export(); 121838689Sborman } 121938689Sborman 122046808Sdab void 122138689Sborman slc_mode_import(def) 122246808Sdab int def; 122338689Sborman { 122438689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 122538689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 122638689Sborman slc_import(def); 122738689Sborman } 122838689Sborman 122946808Sdab unsigned char slc_import_val[] = { 123038689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 123138689Sborman }; 123246808Sdab unsigned char slc_import_def[] = { 123338689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 123438689Sborman }; 123538689Sborman 123646808Sdab void 123738689Sborman slc_import(def) 123846808Sdab int def; 123938689Sborman { 124038689Sborman if (NETROOM() > sizeof(slc_import_val)) { 124138689Sborman if (def) { 124238689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 124338689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 124438689Sborman } else { 124538689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 124638689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 124738689Sborman } 124838689Sborman } 124938689Sborman /*@*/ else printf("slc_import: not enough room\n"); 125038689Sborman } 125138689Sborman 125246808Sdab void 125338689Sborman slc_export() 125438689Sborman { 125538689Sborman register struct spc *spcp; 125638689Sborman 125738689Sborman TerminalDefaultChars(); 125838689Sborman 125938689Sborman slc_start_reply(); 126038689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 126138689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 126245232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 126345232Sborman spcp->flags = SLC_NOSUPPORT; 126445232Sborman else 126545232Sborman spcp->flags = spcp->mylevel; 126638689Sborman if (spcp->valp) 126738689Sborman spcp->val = *spcp->valp; 126845232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 126938689Sborman } 127038689Sborman } 127138689Sborman slc_end_reply(); 127246808Sdab (void)slc_update(); 127346808Sdab setconnmode(1); /* Make sure the character values are set */ 127438689Sborman } 127538689Sborman 127646808Sdab void 127738689Sborman slc(cp, len) 127846808Sdab register unsigned char *cp; 127946808Sdab int len; 128038689Sborman { 128138689Sborman register struct spc *spcp; 128238689Sborman register int func,level; 128338689Sborman 128438689Sborman slc_start_reply(); 128538689Sborman 128638689Sborman for (; len >= 3; len -=3, cp +=3) { 128738689Sborman 128838689Sborman func = cp[SLC_FUNC]; 128938689Sborman 129038689Sborman if (func == 0) { 129138689Sborman /* 129238689Sborman * Client side: always ignore 0 function. 129338689Sborman */ 129438689Sborman continue; 129538689Sborman } 129638689Sborman if (func > NSLC) { 129745232Sborman if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 129838689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 129938689Sborman continue; 130038689Sborman } 130138689Sborman 130238689Sborman spcp = &spc_data[func]; 130338689Sborman 130438689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 130538689Sborman 130640245Sborman if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 130738689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 130838689Sborman continue; 130938689Sborman } 131038689Sborman 131138689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 131238689Sborman /* 131338689Sborman * This is an error condition, the SLC_ACK 131438689Sborman * bit should never be set for the SLC_DEFAULT 131538689Sborman * level. Our best guess to recover is to 131638689Sborman * ignore the SLC_ACK bit. 131738689Sborman */ 131838689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 131938689Sborman } 132038689Sborman 132138689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 132240245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 132338689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 132438689Sborman continue; 132538689Sborman } 132638689Sborman 132738689Sborman level &= ~SLC_ACK; 132838689Sborman 132938689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 133038689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 133140245Sborman spcp->val = (cc_t)cp[SLC_VALUE]; 133238689Sborman } 133338689Sborman if (level == SLC_DEFAULT) { 133438689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 133538689Sborman spcp->flags = spcp->mylevel; 133638689Sborman else 133738689Sborman spcp->flags = SLC_NOSUPPORT; 133838689Sborman } 133938689Sborman slc_add_reply(func, spcp->flags, spcp->val); 134038689Sborman } 134138689Sborman slc_end_reply(); 134238689Sborman if (slc_update()) 134338689Sborman setconnmode(1); /* set the new character values */ 134438689Sborman } 134538689Sborman 134646808Sdab void 134738689Sborman slc_check() 134838689Sborman { 134938689Sborman register struct spc *spcp; 135038689Sborman 135138689Sborman slc_start_reply(); 135238689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 135338689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 135438689Sborman spcp->val = *spcp->valp; 135545232Sborman if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 135645232Sborman spcp->flags = SLC_NOSUPPORT; 135745232Sborman else 135845232Sborman spcp->flags = spcp->mylevel; 135945232Sborman slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 136038689Sborman } 136138689Sborman } 136238689Sborman slc_end_reply(); 136338689Sborman setconnmode(1); 136438689Sborman } 136538689Sborman 136638689Sborman 136738689Sborman unsigned char slc_reply[128]; 136838689Sborman unsigned char *slc_replyp; 136946808Sdab 137046808Sdab void 137138689Sborman slc_start_reply() 137238689Sborman { 137338689Sborman slc_replyp = slc_reply; 137438689Sborman *slc_replyp++ = IAC; 137538689Sborman *slc_replyp++ = SB; 137638689Sborman *slc_replyp++ = TELOPT_LINEMODE; 137738689Sborman *slc_replyp++ = LM_SLC; 137838689Sborman } 137938689Sborman 138046808Sdab void 138138689Sborman slc_add_reply(func, flags, value) 138246808Sdab unsigned char func; 138346808Sdab unsigned char flags; 138446808Sdab cc_t value; 138538689Sborman { 138638689Sborman if ((*slc_replyp++ = func) == IAC) 138738689Sborman *slc_replyp++ = IAC; 138838689Sborman if ((*slc_replyp++ = flags) == IAC) 138938689Sborman *slc_replyp++ = IAC; 139040245Sborman if ((*slc_replyp++ = (unsigned char)value) == IAC) 139138689Sborman *slc_replyp++ = IAC; 139238689Sborman } 139338689Sborman 139446808Sdab void 139538689Sborman slc_end_reply() 139638689Sborman { 139738689Sborman register int len; 139838689Sborman 139938689Sborman *slc_replyp++ = IAC; 140038689Sborman *slc_replyp++ = SE; 140138689Sborman len = slc_replyp - slc_reply; 140238689Sborman if (len <= 6) 140338689Sborman return; 140438689Sborman if (NETROOM() > len) { 140538689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 140638689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 140738689Sborman } 140838689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 140938689Sborman } 141038689Sborman 141146808Sdab int 141238689Sborman slc_update() 141338689Sborman { 141438689Sborman register struct spc *spcp; 141538689Sborman int need_update = 0; 141638689Sborman 141738689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 141838689Sborman if (!(spcp->flags&SLC_ACK)) 141938689Sborman continue; 142038689Sborman spcp->flags &= ~SLC_ACK; 142138689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 142238689Sborman *spcp->valp = spcp->val; 142338689Sborman need_update = 1; 142438689Sborman } 142538689Sborman } 142638689Sborman return(need_update); 142738689Sborman } 142838689Sborman 142958972Sdab #ifdef ENV_HACK 143058972Sdab /* 143158972Sdab * Earlier version of telnet/telnetd from the BSD code had 143258972Sdab * the definitions of VALUE and VAR reversed. To ensure 143358972Sdab * maximum interoperability, we assume that the server is 143458972Sdab * an older BSD server, until proven otherwise. The newer 143558972Sdab * BSD servers should be able to handle either definition, 143658972Sdab * so it is better to use the wrong values if we don't 143758972Sdab * know what type of server it is. 143858972Sdab */ 143958972Sdab int env_auto = 1; 144058972Sdab int env_var = ENV_VALUE; 144158972Sdab int env_value = ENV_VAR; 144258972Sdab #else 144358972Sdab #define env_var ENV_VAR 144458972Sdab #define env_value ENV_VALUE 144558972Sdab #endif 144658972Sdab 144746808Sdab void 144844360Sborman env_opt(buf, len) 144946808Sdab register unsigned char *buf; 145046808Sdab register int len; 145144360Sborman { 145246808Sdab register unsigned char *ep = 0, *epc = 0; 145344360Sborman register int i; 145444360Sborman 145545232Sborman switch(buf[0]&0xff) { 145644360Sborman case TELQUAL_SEND: 145744360Sborman env_opt_start(); 145844360Sborman if (len == 1) { 145944360Sborman env_opt_add(NULL); 146044360Sborman } else for (i = 1; i < len; i++) { 146145232Sborman switch (buf[i]&0xff) { 146258972Sdab case ENV_VAR: 146358972Sdab #ifdef ENV_HACK 146458972Sdab if (env_auto) { 146558972Sdab /* The server has correct definitions */ 146658972Sdab env_var = ENV_VAR; 146758972Sdab env_value = ENV_VALUE; 146858972Sdab } 146958972Sdab /* FALL THROUGH */ 147058972Sdab #endif 147144360Sborman case ENV_VALUE: 147258972Sdab /* 147358972Sdab * Although ENV_VALUE is not legal, we will 147458972Sdab * still recognize it, just in case it is an 147558972Sdab * old server that has VAR & VALUE mixed up... 147658972Sdab */ 147758972Sdab /* FALL THROUGH */ 147858972Sdab case ENV_USERVAR: 147944360Sborman if (ep) { 148044360Sborman *epc = 0; 148144360Sborman env_opt_add(ep); 148244360Sborman } 148344360Sborman ep = epc = &buf[i+1]; 148444360Sborman break; 148544360Sborman case ENV_ESC: 148644360Sborman i++; 148744360Sborman /*FALL THROUGH*/ 148844360Sborman default: 148944360Sborman if (epc) 149044360Sborman *epc++ = buf[i]; 149144360Sborman break; 149244360Sborman } 149344360Sborman } 149458972Sdab if (ep) { 149558972Sdab *epc = 0; 149658972Sdab env_opt_add(ep); 149758972Sdab } 149844360Sborman env_opt_end(1); 149944360Sborman break; 150044360Sborman 150144360Sborman case TELQUAL_IS: 150244360Sborman case TELQUAL_INFO: 150344360Sborman /* Ignore for now. We shouldn't get it anyway. */ 150444360Sborman break; 150544360Sborman 150644360Sborman default: 150744360Sborman break; 150844360Sborman } 150944360Sborman } 151044360Sborman 151144360Sborman #define OPT_REPLY_SIZE 256 151244360Sborman unsigned char *opt_reply; 151344360Sborman unsigned char *opt_replyp; 151444360Sborman unsigned char *opt_replyend; 151544360Sborman 151646808Sdab void 151744360Sborman env_opt_start() 151844360Sborman { 151944360Sborman if (opt_reply) 152044360Sborman opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 152144360Sborman else 152244360Sborman opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 152344360Sborman if (opt_reply == NULL) { 152444360Sborman /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 152544360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 152644360Sborman return; 152744360Sborman } 152844360Sborman opt_replyp = opt_reply; 152944360Sborman opt_replyend = opt_reply + OPT_REPLY_SIZE; 153044360Sborman *opt_replyp++ = IAC; 153144360Sborman *opt_replyp++ = SB; 153244360Sborman *opt_replyp++ = TELOPT_ENVIRON; 153344360Sborman *opt_replyp++ = TELQUAL_IS; 153444360Sborman } 153544360Sborman 153646808Sdab void 153744360Sborman env_opt_start_info() 153844360Sborman { 153944360Sborman env_opt_start(); 154044360Sborman if (opt_replyp) 154144360Sborman opt_replyp[-1] = TELQUAL_INFO; 154244360Sborman } 154344360Sborman 154446808Sdab void 154544360Sborman env_opt_add(ep) 154646808Sdab register unsigned char *ep; 154744360Sborman { 154846808Sdab register unsigned char *vp, c; 154944360Sborman 155044360Sborman if (opt_reply == NULL) /*XXX*/ 155144360Sborman return; /*XXX*/ 155244360Sborman 155344360Sborman if (ep == NULL || *ep == '\0') { 155457213Sdab /* Send user defined variables first. */ 155557213Sdab env_default(1, 0); 155657213Sdab while (ep = env_default(0, 0)) 155744360Sborman env_opt_add(ep); 155857213Sdab 155957213Sdab /* Now add the list of well know variables. */ 156057213Sdab env_default(1, 1); 156157213Sdab while (ep = env_default(0, 1)) 156257213Sdab env_opt_add(ep); 156344360Sborman return; 156444360Sborman } 156544360Sborman vp = env_getvalue(ep); 156646808Sdab if (opt_replyp + (vp ? strlen((char *)vp) : 0) + 156746808Sdab strlen((char *)ep) + 6 > opt_replyend) 156846808Sdab { 156944360Sborman register int len; 157044360Sborman opt_replyend += OPT_REPLY_SIZE; 157144360Sborman len = opt_replyend - opt_reply; 157244360Sborman opt_reply = (unsigned char *)realloc(opt_reply, len); 157344360Sborman if (opt_reply == NULL) { 157444360Sborman /*@*/ printf("env_opt_add: realloc() failed!!!\n"); 157544360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 157644360Sborman return; 157744360Sborman } 157844360Sborman opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 157944360Sborman opt_replyend = opt_reply + len; 158044360Sborman } 158157213Sdab if (opt_welldefined(ep)) 158258972Sdab *opt_replyp++ = env_var; 158357213Sdab else 158457213Sdab *opt_replyp++ = ENV_USERVAR; 158544360Sborman for (;;) { 158644360Sborman while (c = *ep++) { 158745232Sborman switch(c&0xff) { 158844360Sborman case IAC: 158944360Sborman *opt_replyp++ = IAC; 159044360Sborman break; 159144360Sborman case ENV_VALUE: 159244360Sborman case ENV_VAR: 159344360Sborman case ENV_ESC: 159457213Sdab case ENV_USERVAR: 159544360Sborman *opt_replyp++ = ENV_ESC; 159644360Sborman break; 159744360Sborman } 159844360Sborman *opt_replyp++ = c; 159944360Sborman } 160044360Sborman if (ep = vp) { 160158972Sdab *opt_replyp++ = env_value; 160244360Sborman vp = NULL; 160344360Sborman } else 160444360Sborman break; 160544360Sborman } 160644360Sborman } 160744360Sborman 160857213Sdab int 160957213Sdab opt_welldefined(ep) 161057213Sdab char *ep; 161157213Sdab { 161257213Sdab if ((strcmp(ep, "USER") == 0) || 161357213Sdab (strcmp(ep, "DISPLAY") == 0) || 161457213Sdab (strcmp(ep, "PRINTER") == 0) || 161557213Sdab (strcmp(ep, "SYSTEMTYPE") == 0) || 161657213Sdab (strcmp(ep, "JOB") == 0) || 161757213Sdab (strcmp(ep, "ACCT") == 0)) 161857213Sdab return(1); 161957213Sdab return(0); 162057213Sdab } 162146808Sdab void 162244360Sborman env_opt_end(emptyok) 162346808Sdab register int emptyok; 162444360Sborman { 162544360Sborman register int len; 162644360Sborman 162744360Sborman len = opt_replyp - opt_reply + 2; 162844360Sborman if (emptyok || len > 6) { 162944360Sborman *opt_replyp++ = IAC; 163044360Sborman *opt_replyp++ = SE; 163144360Sborman if (NETROOM() > len) { 163244360Sborman ring_supply_data(&netoring, opt_reply, len); 163344360Sborman printsub('>', &opt_reply[2], len - 2); 163444360Sborman } 163544360Sborman /*@*/ else printf("slc_end_reply: not enough room\n"); 163644360Sborman } 163744360Sborman if (opt_reply) { 163844360Sborman free(opt_reply); 163944360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 164044360Sborman } 164144360Sborman } 164244360Sborman 164338689Sborman 164438689Sborman 164546808Sdab int 164632377Sminshall telrcv() 164727110Sminshall { 164832377Sminshall register int c; 164932385Sminshall register int scc; 165046808Sdab register unsigned char *sbp; 165132385Sminshall int count; 165232385Sminshall int returnValue = 0; 165327088Sminshall 165432385Sminshall scc = 0; 165532385Sminshall count = 0; 165632385Sminshall while (TTYROOM() > 2) { 165732385Sminshall if (scc == 0) { 165832385Sminshall if (count) { 165932528Sminshall ring_consumed(&netiring, count); 166032385Sminshall returnValue = 1; 166132385Sminshall count = 0; 166232385Sminshall } 166332528Sminshall sbp = netiring.consume; 166432528Sminshall scc = ring_full_consecutive(&netiring); 166532385Sminshall if (scc == 0) { 166632385Sminshall /* No more data coming in */ 166732385Sminshall break; 166832385Sminshall } 166932385Sminshall } 167032385Sminshall 167132385Sminshall c = *sbp++ & 0xff, scc--; count++; 1672*60149Sdab #ifdef ENCRYPTION 167346808Sdab if (decrypt_input) 167446808Sdab c = (*decrypt_input)(c); 1675*60149Sdab #endif /* ENCRYPTION */ 167632385Sminshall 167732377Sminshall switch (telrcv_state) { 167827110Sminshall 167932377Sminshall case TS_CR: 168032377Sminshall telrcv_state = TS_DATA; 168135518Sminshall if (c == '\0') { 168235518Sminshall break; /* Ignore \0 after CR */ 168339529Sborman } 168439529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 168535518Sminshall TTYADD(c); 168635518Sminshall break; 168732377Sminshall } 168835518Sminshall /* Else, fall through */ 168927088Sminshall 169032377Sminshall case TS_DATA: 169132377Sminshall if (c == IAC) { 169232377Sminshall telrcv_state = TS_IAC; 169333804Sminshall break; 169432377Sminshall } 169532377Sminshall # if defined(TN3270) 169632377Sminshall if (In3270) { 169732377Sminshall *Ifrontp++ = c; 169832385Sminshall while (scc > 0) { 169932385Sminshall c = *sbp++ & 0377, scc--; count++; 1700*60149Sdab #ifdef ENCRYPTION 170146808Sdab if (decrypt_input) 170246808Sdab c = (*decrypt_input)(c); 1703*60149Sdab #endif /* ENCRYPTION */ 170432377Sminshall if (c == IAC) { 170532377Sminshall telrcv_state = TS_IAC; 170634304Sminshall break; 170732377Sminshall } 170832377Sminshall *Ifrontp++ = c; 170932377Sminshall } 171032377Sminshall } else 171132377Sminshall # endif /* defined(TN3270) */ 171235518Sminshall /* 171335518Sminshall * The 'crmod' hack (see following) is needed 171435518Sminshall * since we can't * set CRMOD on output only. 171535518Sminshall * Machines like MULTICS like to send \r without 171635518Sminshall * \n; since we must turn off CRMOD to get proper 171735518Sminshall * input, the mapping is done here (sigh). 171835518Sminshall */ 171938689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 172035518Sminshall if (scc > 0) { 172135518Sminshall c = *sbp&0xff; 1722*60149Sdab #ifdef ENCRYPTION 172346808Sdab if (decrypt_input) 172446808Sdab c = (*decrypt_input)(c); 1725*60149Sdab #endif /* ENCRYPTION */ 172635518Sminshall if (c == 0) { 172735518Sminshall sbp++, scc--; count++; 172835518Sminshall /* a "true" CR */ 172932377Sminshall TTYADD('\r'); 173038689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 173135518Sminshall (c == '\n')) { 173235518Sminshall sbp++, scc--; count++; 173332377Sminshall TTYADD('\n'); 173435518Sminshall } else { 1735*60149Sdab #ifdef ENCRYPTION 173646808Sdab if (decrypt_input) 173746808Sdab (*decrypt_input)(-1); 1738*60149Sdab #endif /* ENCRYPTION */ 173946808Sdab 174035518Sminshall TTYADD('\r'); 174135518Sminshall if (crmod) { 174235518Sminshall TTYADD('\n'); 174332377Sminshall } 174432377Sminshall } 174535518Sminshall } else { 174635518Sminshall telrcv_state = TS_CR; 174735518Sminshall TTYADD('\r'); 174835518Sminshall if (crmod) { 174935518Sminshall TTYADD('\n'); 175035518Sminshall } 175132377Sminshall } 175232377Sminshall } else { 175332377Sminshall TTYADD(c); 175432377Sminshall } 175532377Sminshall continue; 175627088Sminshall 175732377Sminshall case TS_IAC: 175838689Sborman process_iac: 175932377Sminshall switch (c) { 176032377Sminshall 176132377Sminshall case WILL: 176232377Sminshall telrcv_state = TS_WILL; 176332377Sminshall continue; 176427261Sminshall 176532377Sminshall case WONT: 176632377Sminshall telrcv_state = TS_WONT; 176732377Sminshall continue; 176827261Sminshall 176932377Sminshall case DO: 177032377Sminshall telrcv_state = TS_DO; 177132377Sminshall continue; 177227261Sminshall 177332377Sminshall case DONT: 177432377Sminshall telrcv_state = TS_DONT; 177532377Sminshall continue; 177627261Sminshall 177732377Sminshall case DM: 177832377Sminshall /* 177932377Sminshall * We may have missed an urgent notification, 178032377Sminshall * so make sure we flush whatever is in the 178132377Sminshall * buffer currently. 178232377Sminshall */ 178346808Sdab printoption("RCVD", IAC, DM); 178432377Sminshall SYNCHing = 1; 178544360Sborman (void) ttyflush(1); 178632554Sminshall SYNCHing = stilloob(); 178732377Sminshall settimer(gotDM); 178832377Sminshall break; 178927088Sminshall 179032377Sminshall case SB: 179132377Sminshall SB_CLEAR(); 179232377Sminshall telrcv_state = TS_SB; 179332377Sminshall continue; 179427261Sminshall 179532377Sminshall # if defined(TN3270) 179632377Sminshall case EOR: 179732377Sminshall if (In3270) { 179832377Sminshall if (Ibackp == Ifrontp) { 179932377Sminshall Ibackp = Ifrontp = Ibuf; 180032377Sminshall ISend = 0; /* should have been! */ 180132377Sminshall } else { 180244360Sborman Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 180332377Sminshall ISend = 1; 180427088Sminshall } 180527088Sminshall } 180646808Sdab printoption("RCVD", IAC, EOR); 180727088Sminshall break; 180832377Sminshall # endif /* defined(TN3270) */ 180932377Sminshall 181032377Sminshall case IAC: 181132377Sminshall # if !defined(TN3270) 181232377Sminshall TTYADD(IAC); 181332377Sminshall # else /* !defined(TN3270) */ 181432377Sminshall if (In3270) { 181532377Sminshall *Ifrontp++ = IAC; 181632377Sminshall } else { 181732377Sminshall TTYADD(IAC); 181832377Sminshall } 181932377Sminshall # endif /* !defined(TN3270) */ 182027088Sminshall break; 182132377Sminshall 182244360Sborman case NOP: 182344360Sborman case GA: 182427088Sminshall default: 182546808Sdab printoption("RCVD", IAC, c); 182627088Sminshall break; 182727088Sminshall } 182832377Sminshall telrcv_state = TS_DATA; 182932377Sminshall continue; 183027088Sminshall 183132377Sminshall case TS_WILL: 183246808Sdab printoption("RCVD", WILL, c); 183338689Sborman willoption(c); 183432377Sminshall SetIn3270(); 183532377Sminshall telrcv_state = TS_DATA; 183632377Sminshall continue; 183727110Sminshall 183832377Sminshall case TS_WONT: 183946808Sdab printoption("RCVD", WONT, c); 184038689Sborman wontoption(c); 184132377Sminshall SetIn3270(); 184232377Sminshall telrcv_state = TS_DATA; 184332377Sminshall continue; 184427088Sminshall 184532377Sminshall case TS_DO: 184646808Sdab printoption("RCVD", DO, c); 184737226Sminshall dooption(c); 184832377Sminshall SetIn3270(); 184937219Sminshall if (c == TELOPT_NAWS) { 185037219Sminshall sendnaws(); 185137219Sminshall } else if (c == TELOPT_LFLOW) { 185237219Sminshall localflow = 1; 185337219Sminshall setcommandmode(); 185438689Sborman setconnmode(0); 185537219Sminshall } 185632377Sminshall telrcv_state = TS_DATA; 185732377Sminshall continue; 185827088Sminshall 185932377Sminshall case TS_DONT: 186046808Sdab printoption("RCVD", DONT, c); 186138689Sborman dontoption(c); 186237226Sminshall flushline = 1; 186338689Sborman setconnmode(0); /* set new tty mode (maybe) */ 186432377Sminshall SetIn3270(); 186532377Sminshall telrcv_state = TS_DATA; 186632377Sminshall continue; 186727088Sminshall 186832377Sminshall case TS_SB: 186932377Sminshall if (c == IAC) { 187032377Sminshall telrcv_state = TS_SE; 187132377Sminshall } else { 187232377Sminshall SB_ACCUM(c); 187332377Sminshall } 187432377Sminshall continue; 187527088Sminshall 187632377Sminshall case TS_SE: 187732377Sminshall if (c != SE) { 187832377Sminshall if (c != IAC) { 187938689Sborman /* 188038689Sborman * This is an error. We only expect to get 188138689Sborman * "IAC IAC" or "IAC SE". Several things may 188238689Sborman * have happend. An IAC was not doubled, the 188338689Sborman * IAC SE was left off, or another option got 188438689Sborman * inserted into the suboption are all possibilities. 188538689Sborman * If we assume that the IAC was not doubled, 188638689Sborman * and really the IAC SE was left off, we could 188738689Sborman * get into an infinate loop here. So, instead, 188838689Sborman * we terminate the suboption, and process the 188938689Sborman * partial suboption if we can. 189038689Sborman */ 189132377Sminshall SB_ACCUM(IAC); 189238689Sborman SB_ACCUM(c); 189346808Sdab subpointer -= 2; 189446808Sdab SB_TERM(); 189546808Sdab 189646808Sdab printoption("In SUBOPTION processing, RCVD", IAC, c); 189738689Sborman suboption(); /* handle sub-option */ 189838689Sborman SetIn3270(); 189938689Sborman telrcv_state = TS_IAC; 190038689Sborman goto process_iac; 190132377Sminshall } 190232377Sminshall SB_ACCUM(c); 190332377Sminshall telrcv_state = TS_SB; 190432377Sminshall } else { 190538689Sborman SB_ACCUM(IAC); 190638689Sborman SB_ACCUM(SE); 190746808Sdab subpointer -= 2; 190846808Sdab SB_TERM(); 190932377Sminshall suboption(); /* handle sub-option */ 191032377Sminshall SetIn3270(); 191132377Sminshall telrcv_state = TS_DATA; 191232377Sminshall } 191327088Sminshall } 191427088Sminshall } 191532667Sminshall if (count) 191632667Sminshall ring_consumed(&netiring, count); 191732385Sminshall return returnValue||count; 191827088Sminshall } 191932385Sminshall 192046808Sdab static int bol = 1, local = 0; 192146808Sdab 192246808Sdab int 192346808Sdab rlogin_susp() 192446808Sdab { 192546808Sdab if (local) { 192646808Sdab local = 0; 192746808Sdab bol = 1; 192846808Sdab command(0, "z\n", 2); 192946808Sdab return(1); 193046808Sdab } 193146808Sdab return(0); 193246808Sdab } 193346808Sdab 193446808Sdab static int 193532554Sminshall telsnd() 193632385Sminshall { 193732385Sminshall int tcc; 193832385Sminshall int count; 193932385Sminshall int returnValue = 0; 194046808Sdab unsigned char *tbp; 194132385Sminshall 194232385Sminshall tcc = 0; 194332385Sminshall count = 0; 194432385Sminshall while (NETROOM() > 2) { 194532385Sminshall register int sc; 194632385Sminshall register int c; 194732385Sminshall 194832385Sminshall if (tcc == 0) { 194932385Sminshall if (count) { 195032528Sminshall ring_consumed(&ttyiring, count); 195132385Sminshall returnValue = 1; 195232385Sminshall count = 0; 195332385Sminshall } 195432528Sminshall tbp = ttyiring.consume; 195532528Sminshall tcc = ring_full_consecutive(&ttyiring); 195632385Sminshall if (tcc == 0) { 195732385Sminshall break; 195832385Sminshall } 195932385Sminshall } 196032385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 196146808Sdab if (rlogin != _POSIX_VDISABLE) { 196246808Sdab if (bol) { 196346808Sdab bol = 0; 196446808Sdab if (sc == rlogin) { 196546808Sdab local = 1; 196646808Sdab continue; 196746808Sdab } 196846808Sdab } else if (local) { 196946808Sdab local = 0; 197046808Sdab if (sc == '.' || c == termEofChar) { 197146808Sdab bol = 1; 197246808Sdab command(0, "close\n", 6); 197346808Sdab continue; 197446808Sdab } 197546808Sdab if (sc == termSuspChar) { 197646808Sdab bol = 1; 197746808Sdab command(0, "z\n", 2); 197846808Sdab continue; 197946808Sdab } 198046808Sdab if (sc == escape) { 198146808Sdab command(0, (char *)tbp, tcc); 198246808Sdab bol = 1; 198346808Sdab count += tcc; 198446808Sdab tcc = 0; 198546808Sdab flushline = 1; 198646808Sdab break; 198746808Sdab } 198846808Sdab if (sc != rlogin) { 198946808Sdab ++tcc; 199046808Sdab --tbp; 199146808Sdab --count; 199246808Sdab c = sc = rlogin; 199346808Sdab } 199446808Sdab } 199546808Sdab if ((sc == '\n') || (sc == '\r')) 199646808Sdab bol = 1; 199746808Sdab } else if (sc == escape) { 199838689Sborman /* 199938689Sborman * Double escape is a pass through of a single escape character. 200038689Sborman */ 200138689Sborman if (tcc && strip(*tbp) == escape) { 200238689Sborman tbp++; 200338689Sborman tcc--; 200438689Sborman count++; 200546808Sdab bol = 0; 200638689Sborman } else { 200746808Sdab command(0, (char *)tbp, tcc); 200846808Sdab bol = 1; 200938689Sborman count += tcc; 201038689Sborman tcc = 0; 201138689Sborman flushline = 1; 201238689Sborman break; 201338689Sborman } 201446808Sdab } else 201546808Sdab bol = 0; 201638689Sborman #ifdef KLUDGELINEMODE 201738689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 201832385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 201932385Sminshall tcc--; tbp++; count++; 202032385Sminshall } else { 202132385Sminshall dontlecho = !dontlecho; 202232385Sminshall settimer(echotoggle); 202338689Sborman setconnmode(0); 202432385Sminshall flushline = 1; 202532385Sminshall break; 202632385Sminshall } 202732385Sminshall } 202838689Sborman #endif 202938689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 203032385Sminshall if (TerminalSpecialChars(sc) == 0) { 203146808Sdab bol = 1; 203232385Sminshall break; 203332385Sminshall } 203432385Sminshall } 203538689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 203632385Sminshall switch (c) { 203732385Sminshall case '\n': 203832385Sminshall /* 203932385Sminshall * If we are in CRMOD mode (\r ==> \n) 204032385Sminshall * on our local machine, then probably 204132385Sminshall * a newline (unix) is CRLF (TELNET). 204232385Sminshall */ 204332385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 204432385Sminshall NETADD('\r'); 204532385Sminshall } 204632385Sminshall NETADD('\n'); 204746808Sdab bol = flushline = 1; 204832385Sminshall break; 204932385Sminshall case '\r': 205032385Sminshall if (!crlf) { 205132385Sminshall NET2ADD('\r', '\0'); 205232385Sminshall } else { 205332385Sminshall NET2ADD('\r', '\n'); 205432385Sminshall } 205546808Sdab bol = flushline = 1; 205632385Sminshall break; 205732385Sminshall case IAC: 205832385Sminshall NET2ADD(IAC, IAC); 205932385Sminshall break; 206032385Sminshall default: 206132385Sminshall NETADD(c); 206232385Sminshall break; 206332385Sminshall } 206432385Sminshall } else if (c == IAC) { 206532385Sminshall NET2ADD(IAC, IAC); 206632385Sminshall } else { 206732385Sminshall NETADD(c); 206832385Sminshall } 206932385Sminshall } 207032667Sminshall if (count) 207132667Sminshall ring_consumed(&ttyiring, count); 207232385Sminshall return returnValue||count; /* Non-zero if we did anything */ 207332385Sminshall } 207432377Sminshall 207527088Sminshall /* 207632377Sminshall * Scheduler() 207732377Sminshall * 207832377Sminshall * Try to do something. 207932377Sminshall * 208032377Sminshall * If we do something useful, return 1; else return 0. 208132377Sminshall * 208227110Sminshall */ 208327110Sminshall 208427110Sminshall 208546808Sdab int 208632377Sminshall Scheduler(block) 208746808Sdab int block; /* should we block in the select ? */ 208827110Sminshall { 208932377Sminshall /* One wants to be a bit careful about setting returnValue 209032377Sminshall * to one, since a one implies we did some useful work, 209132377Sminshall * and therefore probably won't be called to block next 209232377Sminshall * time (TN3270 mode only). 209332377Sminshall */ 209432531Sminshall int returnValue; 209532531Sminshall int netin, netout, netex, ttyin, ttyout; 209627110Sminshall 209732531Sminshall /* Decide which rings should be processed */ 209832531Sminshall 209932531Sminshall netout = ring_full_count(&netoring) && 210038689Sborman (flushline || 210138689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 210238689Sborman #ifdef KLUDGELINEMODE 210338689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 210438689Sborman #endif 210538689Sborman ) || 210638689Sborman my_want_state_is_will(TELOPT_BINARY)); 210732531Sminshall ttyout = ring_full_count(&ttyoring); 210832531Sminshall 210932377Sminshall #if defined(TN3270) 211032531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 211132377Sminshall #else /* defined(TN3270) */ 211232531Sminshall ttyin = ring_empty_count(&ttyiring); 211332377Sminshall #endif /* defined(TN3270) */ 211432531Sminshall 211532531Sminshall #if defined(TN3270) 211632531Sminshall netin = ring_empty_count(&netiring); 211732377Sminshall # else /* !defined(TN3270) */ 211832531Sminshall netin = !ISend && ring_empty_count(&netiring); 211932377Sminshall # endif /* !defined(TN3270) */ 212032531Sminshall 212132531Sminshall netex = !SYNCHing; 212232531Sminshall 212332531Sminshall /* If we have seen a signal recently, reset things */ 212432377Sminshall # if defined(TN3270) && defined(unix) 212532377Sminshall if (HaveInput) { 212632377Sminshall HaveInput = 0; 212744360Sborman (void) signal(SIGIO, inputAvailable); 212832377Sminshall } 212932377Sminshall #endif /* defined(TN3270) && defined(unix) */ 213032377Sminshall 213132531Sminshall /* Call to system code to process rings */ 213227178Sminshall 213332531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 213427178Sminshall 213532531Sminshall /* Now, look at the input rings, looking for work to do. */ 213632377Sminshall 213732531Sminshall if (ring_full_count(&ttyiring)) { 213832377Sminshall # if defined(TN3270) 213932377Sminshall if (In3270) { 214034848Sminshall int c; 214134848Sminshall 214233804Sminshall c = DataFromTerminal(ttyiring.consume, 214332528Sminshall ring_full_consecutive(&ttyiring)); 214432377Sminshall if (c) { 214532377Sminshall returnValue = 1; 214632667Sminshall ring_consumed(&ttyiring, c); 214732377Sminshall } 214832377Sminshall } else { 214932377Sminshall # endif /* defined(TN3270) */ 215032554Sminshall returnValue |= telsnd(); 215132377Sminshall # if defined(TN3270) 215227178Sminshall } 215332531Sminshall # endif /* defined(TN3270) */ 215427178Sminshall } 215532377Sminshall 215632528Sminshall if (ring_full_count(&netiring)) { 215732377Sminshall # if !defined(TN3270) 215832385Sminshall returnValue |= telrcv(); 215932377Sminshall # else /* !defined(TN3270) */ 216032377Sminshall returnValue = Push3270(); 216132377Sminshall # endif /* !defined(TN3270) */ 216232377Sminshall } 216332377Sminshall return returnValue; 216427178Sminshall } 216527178Sminshall 216627178Sminshall /* 216732377Sminshall * Select from tty and network... 216827088Sminshall */ 216946808Sdab void 217046808Sdab telnet(user) 217146808Sdab char *user; 217227088Sminshall { 217332531Sminshall sys_telnet_init(); 217427088Sminshall 2175*60149Sdab #if defined(AUTHENTICATION) || defined(ENCRYPTION) 217646808Sdab { 217746808Sdab static char local_host[256] = { 0 }; 217846808Sdab 217946808Sdab if (!local_host[0]) { 218057213Sdab gethostname(local_host, sizeof(local_host)); 218146808Sdab local_host[sizeof(local_host)-1] = 0; 218246808Sdab } 218346808Sdab auth_encrypt_init(local_host, hostname, "TELNET", 0); 218446808Sdab auth_encrypt_user(user); 218546808Sdab } 2186*60149Sdab #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ 218732377Sminshall # if !defined(TN3270) 218832377Sminshall if (telnetport) { 218957213Sdab #if defined(AUTHENTICATION) 219046808Sdab if (autologin) 219146808Sdab send_will(TELOPT_AUTHENTICATION, 1); 219246808Sdab #endif 2193*60149Sdab #ifdef ENCRYPTION 219446808Sdab send_do(TELOPT_ENCRYPT, 1); 219546808Sdab send_will(TELOPT_ENCRYPT, 1); 2196*60149Sdab #endif /* ENCRYPTION */ 219738689Sborman send_do(TELOPT_SGA, 1); 219838689Sborman send_will(TELOPT_TTYPE, 1); 219938689Sborman send_will(TELOPT_NAWS, 1); 220038689Sborman send_will(TELOPT_TSPEED, 1); 220138689Sborman send_will(TELOPT_LFLOW, 1); 220238689Sborman send_will(TELOPT_LINEMODE, 1); 220346808Sdab send_will(TELOPT_ENVIRON, 1); 220438908Sborman send_do(TELOPT_STATUS, 1); 220546808Sdab if (env_getvalue((unsigned char *)"DISPLAY")) 220644360Sborman send_will(TELOPT_XDISPLOC, 1); 220746808Sdab if (eight) 220846808Sdab tel_enter_binary(eight); 220927178Sminshall } 221032377Sminshall # endif /* !defined(TN3270) */ 221127088Sminshall 221232377Sminshall # if !defined(TN3270) 221332377Sminshall for (;;) { 221432385Sminshall int schedValue; 221532385Sminshall 221632385Sminshall while ((schedValue = Scheduler(0)) != 0) { 221732385Sminshall if (schedValue == -1) { 221832385Sminshall setcommandmode(); 221932385Sminshall return; 222032385Sminshall } 222132385Sminshall } 222232385Sminshall 222332531Sminshall if (Scheduler(1) == -1) { 222432377Sminshall setcommandmode(); 222532377Sminshall return; 222632377Sminshall } 222732377Sminshall } 222832377Sminshall # else /* !defined(TN3270) */ 222932377Sminshall for (;;) { 223032377Sminshall int schedValue; 223127088Sminshall 223232377Sminshall while (!In3270 && !shell_active) { 223332531Sminshall if (Scheduler(1) == -1) { 223432377Sminshall setcommandmode(); 223532377Sminshall return; 223632377Sminshall } 223727088Sminshall } 223832377Sminshall 223932377Sminshall while ((schedValue = Scheduler(0)) != 0) { 224032377Sminshall if (schedValue == -1) { 224132377Sminshall setcommandmode(); 224232377Sminshall return; 224332377Sminshall } 224427088Sminshall } 224532377Sminshall /* If there is data waiting to go out to terminal, don't 224632377Sminshall * schedule any more data for the terminal. 224732377Sminshall */ 224834304Sminshall if (ring_full_count(&ttyoring)) { 224932377Sminshall schedValue = 1; 225027088Sminshall } else { 225132377Sminshall if (shell_active) { 225232377Sminshall if (shell_continue() == 0) { 225332377Sminshall ConnectScreen(); 225427088Sminshall } 225532377Sminshall } else if (In3270) { 225632377Sminshall schedValue = DoTerminalOutput(); 225732377Sminshall } 225827088Sminshall } 225932377Sminshall if (schedValue && (shell_active == 0)) { 226032531Sminshall if (Scheduler(1) == -1) { 226132377Sminshall setcommandmode(); 226232377Sminshall return; 226332377Sminshall } 226427088Sminshall } 226532377Sminshall } 226632377Sminshall # endif /* !defined(TN3270) */ 226727088Sminshall } 226832377Sminshall 226934848Sminshall #if 0 /* XXX - this not being in is a bug */ 227027088Sminshall /* 227132554Sminshall * nextitem() 227232554Sminshall * 227332554Sminshall * Return the address of the next "item" in the TELNET data 227432554Sminshall * stream. This will be the address of the next character if 227532554Sminshall * the current address is a user data character, or it will 227632554Sminshall * be the address of the character following the TELNET command 227732554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 227832554Sminshall * character. 227932554Sminshall */ 228032554Sminshall 228146808Sdab static char * 228232554Sminshall nextitem(current) 228346808Sdab char *current; 228432554Sminshall { 228532554Sminshall if ((*current&0xff) != IAC) { 228632554Sminshall return current+1; 228732554Sminshall } 228832554Sminshall switch (*(current+1)&0xff) { 228932554Sminshall case DO: 229032554Sminshall case DONT: 229132554Sminshall case WILL: 229232554Sminshall case WONT: 229332554Sminshall return current+3; 229432554Sminshall case SB: /* loop forever looking for the SE */ 229532554Sminshall { 229632554Sminshall register char *look = current+2; 229732554Sminshall 229832554Sminshall for (;;) { 229932554Sminshall if ((*look++&0xff) == IAC) { 230032554Sminshall if ((*look++&0xff) == SE) { 230132554Sminshall return look; 230232554Sminshall } 230332554Sminshall } 230432554Sminshall } 230532554Sminshall } 230632554Sminshall default: 230732554Sminshall return current+2; 230832554Sminshall } 230932554Sminshall } 231034848Sminshall #endif /* 0 */ 231132554Sminshall 231232554Sminshall /* 231332554Sminshall * netclear() 231432554Sminshall * 231532554Sminshall * We are about to do a TELNET SYNCH operation. Clear 231632554Sminshall * the path to the network. 231732554Sminshall * 231832554Sminshall * Things are a bit tricky since we may have sent the first 231932554Sminshall * byte or so of a previous TELNET command into the network. 232032554Sminshall * So, we have to scan the network buffer from the beginning 232132554Sminshall * until we are up to where we want to be. 232232554Sminshall * 232332554Sminshall * A side effect of what we do, just to keep things 232432554Sminshall * simple, is to clear the urgent data pointer. The principal 232532554Sminshall * caller should be setting the urgent data pointer AFTER calling 232632554Sminshall * us in any case. 232732554Sminshall */ 232832554Sminshall 232946808Sdab static void 233032554Sminshall netclear() 233132554Sminshall { 233232554Sminshall #if 0 /* XXX */ 233332554Sminshall register char *thisitem, *next; 233432554Sminshall char *good; 233532554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 233632554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 233732554Sminshall 233832554Sminshall thisitem = netobuf; 233932554Sminshall 234032554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 234132554Sminshall thisitem = next; 234232554Sminshall } 234332554Sminshall 234432554Sminshall /* Now, thisitem is first before/at boundary. */ 234532554Sminshall 234632554Sminshall good = netobuf; /* where the good bytes go */ 234732554Sminshall 234832554Sminshall while (netoring.add > thisitem) { 234932554Sminshall if (wewant(thisitem)) { 235032554Sminshall int length; 235132554Sminshall 235232554Sminshall next = thisitem; 235332554Sminshall do { 235432554Sminshall next = nextitem(next); 235532554Sminshall } while (wewant(next) && (nfrontp > next)); 235632554Sminshall length = next-thisitem; 235732554Sminshall memcpy(good, thisitem, length); 235832554Sminshall good += length; 235932554Sminshall thisitem = next; 236032554Sminshall } else { 236132554Sminshall thisitem = nextitem(thisitem); 236232554Sminshall } 236332554Sminshall } 236432554Sminshall 236532554Sminshall #endif /* 0 */ 236632554Sminshall } 236732554Sminshall 236832554Sminshall /* 236932377Sminshall * These routines add various telnet commands to the data stream. 237027088Sminshall */ 237132377Sminshall 237246808Sdab static void 237332554Sminshall doflush() 237432554Sminshall { 237532554Sminshall NET2ADD(IAC, DO); 237632554Sminshall NETADD(TELOPT_TM); 237732554Sminshall flushline = 1; 237832554Sminshall flushout = 1; 237944360Sborman (void) ttyflush(1); /* Flush/drop output */ 238032554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 238146808Sdab printoption("SENT", DO, TELOPT_TM); 238232554Sminshall } 238332554Sminshall 238446808Sdab void 238532377Sminshall xmitAO() 238627088Sminshall { 238732377Sminshall NET2ADD(IAC, AO); 238846808Sdab printoption("SENT", IAC, AO); 238932377Sminshall if (autoflush) { 239032377Sminshall doflush(); 239132377Sminshall } 239232377Sminshall } 239327088Sminshall 239432377Sminshall 239546808Sdab void 239632377Sminshall xmitEL() 239727088Sminshall { 239832377Sminshall NET2ADD(IAC, EL); 239946808Sdab printoption("SENT", IAC, EL); 240027088Sminshall } 240127088Sminshall 240246808Sdab void 240332377Sminshall xmitEC() 240427088Sminshall { 240532377Sminshall NET2ADD(IAC, EC); 240646808Sdab printoption("SENT", IAC, EC); 240727088Sminshall } 240827088Sminshall 240932377Sminshall 241046808Sdab int 241132377Sminshall dosynch() 241227088Sminshall { 241332377Sminshall netclear(); /* clear the path to the network */ 241433294Sminshall NETADD(IAC); 241533294Sminshall setneturg(); 241633294Sminshall NETADD(DM); 241746808Sdab printoption("SENT", IAC, DM); 241846808Sdab return 1; 241927088Sminshall } 242027088Sminshall 242146808Sdab int want_status_response = 0; 242246808Sdab 242346808Sdab int 242438908Sborman get_status() 242538908Sborman { 242646808Sdab unsigned char tmp[16]; 242746808Sdab register unsigned char *cp; 242838908Sborman 242938908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 243038908Sborman printf("Remote side does not support STATUS option\n"); 243146808Sdab return 0; 243238908Sborman } 243338908Sborman cp = tmp; 243438908Sborman 243538908Sborman *cp++ = IAC; 243638908Sborman *cp++ = SB; 243738908Sborman *cp++ = TELOPT_STATUS; 243838908Sborman *cp++ = TELQUAL_SEND; 243938908Sborman *cp++ = IAC; 244038908Sborman *cp++ = SE; 244138908Sborman if (NETROOM() >= cp - tmp) { 244238908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 244338908Sborman printsub('>', tmp+2, cp - tmp - 2); 244438908Sborman } 244546808Sdab ++want_status_response; 244646808Sdab return 1; 244738908Sborman } 244838908Sborman 244946808Sdab void 245032377Sminshall intp() 245127088Sminshall { 245232377Sminshall NET2ADD(IAC, IP); 245346808Sdab printoption("SENT", IAC, IP); 245432377Sminshall flushline = 1; 245532377Sminshall if (autoflush) { 245632377Sminshall doflush(); 245732377Sminshall } 245832377Sminshall if (autosynch) { 245932377Sminshall dosynch(); 246032377Sminshall } 246127088Sminshall } 246227186Sminshall 246346808Sdab void 246432377Sminshall sendbrk() 246527186Sminshall { 246632377Sminshall NET2ADD(IAC, BREAK); 246746808Sdab printoption("SENT", IAC, BREAK); 246832377Sminshall flushline = 1; 246932377Sminshall if (autoflush) { 247032377Sminshall doflush(); 247132377Sminshall } 247232377Sminshall if (autosynch) { 247332377Sminshall dosynch(); 247432377Sminshall } 247527186Sminshall } 247638689Sborman 247746808Sdab void 247838689Sborman sendabort() 247938689Sborman { 248038689Sborman NET2ADD(IAC, ABORT); 248146808Sdab printoption("SENT", IAC, ABORT); 248238689Sborman flushline = 1; 248338689Sborman if (autoflush) { 248438689Sborman doflush(); 248538689Sborman } 248638689Sborman if (autosynch) { 248738689Sborman dosynch(); 248838689Sborman } 248938689Sborman } 249038689Sborman 249146808Sdab void 249238689Sborman sendsusp() 249338689Sborman { 249438689Sborman NET2ADD(IAC, SUSP); 249546808Sdab printoption("SENT", IAC, SUSP); 249638689Sborman flushline = 1; 249738689Sborman if (autoflush) { 249838689Sborman doflush(); 249938689Sborman } 250038689Sborman if (autosynch) { 250138689Sborman dosynch(); 250238689Sborman } 250338689Sborman } 250438689Sborman 250546808Sdab void 250638689Sborman sendeof() 250738689Sborman { 250838908Sborman NET2ADD(IAC, xEOF); 250946808Sdab printoption("SENT", IAC, xEOF); 251038689Sborman } 251138689Sborman 251246808Sdab void 251345232Sborman sendayt() 251445232Sborman { 251545232Sborman NET2ADD(IAC, AYT); 251646808Sdab printoption("SENT", IAC, AYT); 251745232Sborman } 251845232Sborman 251937219Sminshall /* 252037219Sminshall * Send a window size update to the remote system. 252137219Sminshall */ 252237219Sminshall 252346808Sdab void 252437219Sminshall sendnaws() 252537219Sminshall { 252637219Sminshall long rows, cols; 252738689Sborman unsigned char tmp[16]; 252838689Sborman register unsigned char *cp; 252937219Sminshall 253038689Sborman if (my_state_is_wont(TELOPT_NAWS)) 253138689Sborman return; 253237219Sminshall 253338689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 253438689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 253538689Sborman 253637219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 253737219Sminshall return; 253837219Sminshall } 253937219Sminshall 254038689Sborman cp = tmp; 254138689Sborman 254238689Sborman *cp++ = IAC; 254338689Sborman *cp++ = SB; 254438689Sborman *cp++ = TELOPT_NAWS; 254538689Sborman PUTSHORT(cp, cols); 254638689Sborman PUTSHORT(cp, rows); 254738689Sborman *cp++ = IAC; 254838689Sborman *cp++ = SE; 254938689Sborman if (NETROOM() >= cp - tmp) { 255038689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 255138689Sborman printsub('>', tmp+2, cp - tmp - 2); 255237219Sminshall } 255337219Sminshall } 255437226Sminshall 255546808Sdab void 255638908Sborman tel_enter_binary(rw) 255746808Sdab int rw; 255837226Sminshall { 255938908Sborman if (rw&1) 256038908Sborman send_do(TELOPT_BINARY, 1); 256138908Sborman if (rw&2) 256238908Sborman send_will(TELOPT_BINARY, 1); 256337226Sminshall } 256437226Sminshall 256546808Sdab void 256638908Sborman tel_leave_binary(rw) 256746808Sdab int rw; 256837226Sminshall { 256938908Sborman if (rw&1) 257038908Sborman send_dont(TELOPT_BINARY, 1); 257138908Sborman if (rw&2) 257238908Sborman send_wont(TELOPT_BINARY, 1); 257337226Sminshall } 2574