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*57213Sdab static char sccsid[] = "@(#)telnet.c 5.54 (Berkeley) 12/18/92"; 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 */ 76*57213Sdab 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*57213Sdab #if defined(ENCRYPTION) || defined(AUTHENTICATION) 15046808Sdab auth_encrypt_connect(connected); 15146808Sdab #endif 152*57213Sdab 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: 338*57213Sdab #if defined(AUTHENTICATION) 33946808Sdab case TELOPT_AUTHENTICATION: 34046808Sdab #endif 341*57213Sdab #if defined(ENCRYPTION) 34246808Sdab case TELOPT_ENCRYPT: 34346808Sdab #endif 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*57213Sdab #if defined(ENCRYPTION) 37446808Sdab if (option == TELOPT_ENCRYPT) 37546808Sdab encrypt_send_support(); 37646808Sdab #endif 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*57213Sdab #if defined(ENCRYPTION) 46646808Sdab case TELOPT_ENCRYPT: /* encryption variable option */ 46746808Sdab #endif 46838689Sborman new_state_ok = 1; 4696000Sroot break; 470*57213Sdab #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()) { 819*57213Sdab case LFLOW_RESTART_ANY: 820*57213Sdab restartany = 1; 821*57213Sdab break; 822*57213Sdab case LFLOW_RESTART_XON: 823*57213Sdab restartany = 0; 824*57213Sdab break; 825*57213Sdab case LFLOW_ON: 82637219Sminshall localflow = 1; 82746808Sdab break; 828*57213Sdab 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 916*57213Sdab #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*57213Sdab #if defined(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; 100743319Skfall #endif 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 142946808Sdab void 143044360Sborman env_opt(buf, len) 143146808Sdab register unsigned char *buf; 143246808Sdab register int len; 143344360Sborman { 143446808Sdab register unsigned char *ep = 0, *epc = 0; 143544360Sborman register int i; 143644360Sborman 143745232Sborman switch(buf[0]&0xff) { 143844360Sborman case TELQUAL_SEND: 143944360Sborman env_opt_start(); 144044360Sborman if (len == 1) { 144144360Sborman env_opt_add(NULL); 144244360Sborman } else for (i = 1; i < len; i++) { 144345232Sborman switch (buf[i]&0xff) { 144444360Sborman case ENV_VALUE: 144544360Sborman if (ep) { 144644360Sborman *epc = 0; 144744360Sborman env_opt_add(ep); 144844360Sborman } 144944360Sborman ep = epc = &buf[i+1]; 145044360Sborman break; 145144360Sborman case ENV_ESC: 145244360Sborman i++; 145344360Sborman /*FALL THROUGH*/ 145444360Sborman default: 145544360Sborman if (epc) 145644360Sborman *epc++ = buf[i]; 145744360Sborman break; 145844360Sborman } 145944360Sborman if (ep) { 146044360Sborman *epc = 0; 146144360Sborman env_opt_add(ep); 146244360Sborman } 146344360Sborman } 146444360Sborman env_opt_end(1); 146544360Sborman break; 146644360Sborman 146744360Sborman case TELQUAL_IS: 146844360Sborman case TELQUAL_INFO: 146944360Sborman /* Ignore for now. We shouldn't get it anyway. */ 147044360Sborman break; 147144360Sborman 147244360Sborman default: 147344360Sborman break; 147444360Sborman } 147544360Sborman } 147644360Sborman 147744360Sborman #define OPT_REPLY_SIZE 256 147844360Sborman unsigned char *opt_reply; 147944360Sborman unsigned char *opt_replyp; 148044360Sborman unsigned char *opt_replyend; 148144360Sborman 148246808Sdab void 148344360Sborman env_opt_start() 148444360Sborman { 148544360Sborman if (opt_reply) 148644360Sborman opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 148744360Sborman else 148844360Sborman opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 148944360Sborman if (opt_reply == NULL) { 149044360Sborman /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 149144360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 149244360Sborman return; 149344360Sborman } 149444360Sborman opt_replyp = opt_reply; 149544360Sborman opt_replyend = opt_reply + OPT_REPLY_SIZE; 149644360Sborman *opt_replyp++ = IAC; 149744360Sborman *opt_replyp++ = SB; 149844360Sborman *opt_replyp++ = TELOPT_ENVIRON; 149944360Sborman *opt_replyp++ = TELQUAL_IS; 150044360Sborman } 150144360Sborman 150246808Sdab void 150344360Sborman env_opt_start_info() 150444360Sborman { 150544360Sborman env_opt_start(); 150644360Sborman if (opt_replyp) 150744360Sborman opt_replyp[-1] = TELQUAL_INFO; 150844360Sborman } 150944360Sborman 151046808Sdab void 151144360Sborman env_opt_add(ep) 151246808Sdab register unsigned char *ep; 151344360Sborman { 151446808Sdab register unsigned char *vp, c; 151544360Sborman 151644360Sborman if (opt_reply == NULL) /*XXX*/ 151744360Sborman return; /*XXX*/ 151844360Sborman 151944360Sborman if (ep == NULL || *ep == '\0') { 1520*57213Sdab /* Send user defined variables first. */ 1521*57213Sdab env_default(1, 0); 1522*57213Sdab while (ep = env_default(0, 0)) 152344360Sborman env_opt_add(ep); 1524*57213Sdab 1525*57213Sdab /* Now add the list of well know variables. */ 1526*57213Sdab env_default(1, 1); 1527*57213Sdab while (ep = env_default(0, 1)) 1528*57213Sdab env_opt_add(ep); 152944360Sborman return; 153044360Sborman } 153144360Sborman vp = env_getvalue(ep); 153246808Sdab if (opt_replyp + (vp ? strlen((char *)vp) : 0) + 153346808Sdab strlen((char *)ep) + 6 > opt_replyend) 153446808Sdab { 153544360Sborman register int len; 153644360Sborman opt_replyend += OPT_REPLY_SIZE; 153744360Sborman len = opt_replyend - opt_reply; 153844360Sborman opt_reply = (unsigned char *)realloc(opt_reply, len); 153944360Sborman if (opt_reply == NULL) { 154044360Sborman /*@*/ printf("env_opt_add: realloc() failed!!!\n"); 154144360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 154244360Sborman return; 154344360Sborman } 154444360Sborman opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 154544360Sborman opt_replyend = opt_reply + len; 154644360Sborman } 1547*57213Sdab if (opt_welldefined(ep)) 1548*57213Sdab *opt_replyp++ = ENV_VAR; 1549*57213Sdab else 1550*57213Sdab *opt_replyp++ = ENV_USERVAR; 155144360Sborman for (;;) { 155244360Sborman while (c = *ep++) { 155345232Sborman switch(c&0xff) { 155444360Sborman case IAC: 155544360Sborman *opt_replyp++ = IAC; 155644360Sborman break; 155744360Sborman case ENV_VALUE: 155844360Sborman case ENV_VAR: 155944360Sborman case ENV_ESC: 1560*57213Sdab case ENV_USERVAR: 156144360Sborman *opt_replyp++ = ENV_ESC; 156244360Sborman break; 156344360Sborman } 156444360Sborman *opt_replyp++ = c; 156544360Sborman } 156644360Sborman if (ep = vp) { 156744360Sborman *opt_replyp++ = ENV_VALUE; 156844360Sborman vp = NULL; 156944360Sborman } else 157044360Sborman break; 157144360Sborman } 157244360Sborman } 157344360Sborman 1574*57213Sdab int 1575*57213Sdab opt_welldefined(ep) 1576*57213Sdab char *ep; 1577*57213Sdab { 1578*57213Sdab if ((strcmp(ep, "USER") == 0) || 1579*57213Sdab (strcmp(ep, "DISPLAY") == 0) || 1580*57213Sdab (strcmp(ep, "PRINTER") == 0) || 1581*57213Sdab (strcmp(ep, "SYSTEMTYPE") == 0) || 1582*57213Sdab (strcmp(ep, "JOB") == 0) || 1583*57213Sdab (strcmp(ep, "ACCT") == 0)) 1584*57213Sdab return(1); 1585*57213Sdab return(0); 1586*57213Sdab } 158746808Sdab void 158844360Sborman env_opt_end(emptyok) 158946808Sdab register int emptyok; 159044360Sborman { 159144360Sborman register int len; 159244360Sborman 159344360Sborman len = opt_replyp - opt_reply + 2; 159444360Sborman if (emptyok || len > 6) { 159544360Sborman *opt_replyp++ = IAC; 159644360Sborman *opt_replyp++ = SE; 159744360Sborman if (NETROOM() > len) { 159844360Sborman ring_supply_data(&netoring, opt_reply, len); 159944360Sborman printsub('>', &opt_reply[2], len - 2); 160044360Sborman } 160144360Sborman /*@*/ else printf("slc_end_reply: not enough room\n"); 160244360Sborman } 160344360Sborman if (opt_reply) { 160444360Sborman free(opt_reply); 160544360Sborman opt_reply = opt_replyp = opt_replyend = NULL; 160644360Sborman } 160744360Sborman } 160844360Sborman 160938689Sborman 161038689Sborman 161146808Sdab int 161232377Sminshall telrcv() 161327110Sminshall { 161432377Sminshall register int c; 161532385Sminshall register int scc; 161646808Sdab register unsigned char *sbp; 161732385Sminshall int count; 161832385Sminshall int returnValue = 0; 161927088Sminshall 162032385Sminshall scc = 0; 162132385Sminshall count = 0; 162232385Sminshall while (TTYROOM() > 2) { 162332385Sminshall if (scc == 0) { 162432385Sminshall if (count) { 162532528Sminshall ring_consumed(&netiring, count); 162632385Sminshall returnValue = 1; 162732385Sminshall count = 0; 162832385Sminshall } 162932528Sminshall sbp = netiring.consume; 163032528Sminshall scc = ring_full_consecutive(&netiring); 163132385Sminshall if (scc == 0) { 163232385Sminshall /* No more data coming in */ 163332385Sminshall break; 163432385Sminshall } 163532385Sminshall } 163632385Sminshall 163732385Sminshall c = *sbp++ & 0xff, scc--; count++; 1638*57213Sdab #if defined(ENCRYPTION) 163946808Sdab if (decrypt_input) 164046808Sdab c = (*decrypt_input)(c); 164146808Sdab #endif 164232385Sminshall 164332377Sminshall switch (telrcv_state) { 164427110Sminshall 164532377Sminshall case TS_CR: 164632377Sminshall telrcv_state = TS_DATA; 164735518Sminshall if (c == '\0') { 164835518Sminshall break; /* Ignore \0 after CR */ 164939529Sborman } 165039529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 165135518Sminshall TTYADD(c); 165235518Sminshall break; 165332377Sminshall } 165435518Sminshall /* Else, fall through */ 165527088Sminshall 165632377Sminshall case TS_DATA: 165732377Sminshall if (c == IAC) { 165832377Sminshall telrcv_state = TS_IAC; 165933804Sminshall break; 166032377Sminshall } 166132377Sminshall # if defined(TN3270) 166232377Sminshall if (In3270) { 166332377Sminshall *Ifrontp++ = c; 166432385Sminshall while (scc > 0) { 166532385Sminshall c = *sbp++ & 0377, scc--; count++; 1666*57213Sdab #if defined(ENCRYPTION) 166746808Sdab if (decrypt_input) 166846808Sdab c = (*decrypt_input)(c); 166946808Sdab #endif 167032377Sminshall if (c == IAC) { 167132377Sminshall telrcv_state = TS_IAC; 167234304Sminshall break; 167332377Sminshall } 167432377Sminshall *Ifrontp++ = c; 167532377Sminshall } 167632377Sminshall } else 167732377Sminshall # endif /* defined(TN3270) */ 167835518Sminshall /* 167935518Sminshall * The 'crmod' hack (see following) is needed 168035518Sminshall * since we can't * set CRMOD on output only. 168135518Sminshall * Machines like MULTICS like to send \r without 168235518Sminshall * \n; since we must turn off CRMOD to get proper 168335518Sminshall * input, the mapping is done here (sigh). 168435518Sminshall */ 168538689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 168635518Sminshall if (scc > 0) { 168735518Sminshall c = *sbp&0xff; 1688*57213Sdab #if defined(ENCRYPTION) 168946808Sdab if (decrypt_input) 169046808Sdab c = (*decrypt_input)(c); 169146808Sdab #endif 169235518Sminshall if (c == 0) { 169335518Sminshall sbp++, scc--; count++; 169435518Sminshall /* a "true" CR */ 169532377Sminshall TTYADD('\r'); 169638689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 169735518Sminshall (c == '\n')) { 169835518Sminshall sbp++, scc--; count++; 169932377Sminshall TTYADD('\n'); 170035518Sminshall } else { 1701*57213Sdab #if defined(ENCRYPTION) 170246808Sdab if (decrypt_input) 170346808Sdab (*decrypt_input)(-1); 170446808Sdab #endif 170546808Sdab 170635518Sminshall TTYADD('\r'); 170735518Sminshall if (crmod) { 170835518Sminshall TTYADD('\n'); 170932377Sminshall } 171032377Sminshall } 171135518Sminshall } else { 171235518Sminshall telrcv_state = TS_CR; 171335518Sminshall TTYADD('\r'); 171435518Sminshall if (crmod) { 171535518Sminshall TTYADD('\n'); 171635518Sminshall } 171732377Sminshall } 171832377Sminshall } else { 171932377Sminshall TTYADD(c); 172032377Sminshall } 172132377Sminshall continue; 172227088Sminshall 172332377Sminshall case TS_IAC: 172438689Sborman process_iac: 172532377Sminshall switch (c) { 172632377Sminshall 172732377Sminshall case WILL: 172832377Sminshall telrcv_state = TS_WILL; 172932377Sminshall continue; 173027261Sminshall 173132377Sminshall case WONT: 173232377Sminshall telrcv_state = TS_WONT; 173332377Sminshall continue; 173427261Sminshall 173532377Sminshall case DO: 173632377Sminshall telrcv_state = TS_DO; 173732377Sminshall continue; 173827261Sminshall 173932377Sminshall case DONT: 174032377Sminshall telrcv_state = TS_DONT; 174132377Sminshall continue; 174227261Sminshall 174332377Sminshall case DM: 174432377Sminshall /* 174532377Sminshall * We may have missed an urgent notification, 174632377Sminshall * so make sure we flush whatever is in the 174732377Sminshall * buffer currently. 174832377Sminshall */ 174946808Sdab printoption("RCVD", IAC, DM); 175032377Sminshall SYNCHing = 1; 175144360Sborman (void) ttyflush(1); 175232554Sminshall SYNCHing = stilloob(); 175332377Sminshall settimer(gotDM); 175432377Sminshall break; 175527088Sminshall 175632377Sminshall case SB: 175732377Sminshall SB_CLEAR(); 175832377Sminshall telrcv_state = TS_SB; 175932377Sminshall continue; 176027261Sminshall 176132377Sminshall # if defined(TN3270) 176232377Sminshall case EOR: 176332377Sminshall if (In3270) { 176432377Sminshall if (Ibackp == Ifrontp) { 176532377Sminshall Ibackp = Ifrontp = Ibuf; 176632377Sminshall ISend = 0; /* should have been! */ 176732377Sminshall } else { 176844360Sborman Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 176932377Sminshall ISend = 1; 177027088Sminshall } 177127088Sminshall } 177246808Sdab printoption("RCVD", IAC, EOR); 177327088Sminshall break; 177432377Sminshall # endif /* defined(TN3270) */ 177532377Sminshall 177632377Sminshall case IAC: 177732377Sminshall # if !defined(TN3270) 177832377Sminshall TTYADD(IAC); 177932377Sminshall # else /* !defined(TN3270) */ 178032377Sminshall if (In3270) { 178132377Sminshall *Ifrontp++ = IAC; 178232377Sminshall } else { 178332377Sminshall TTYADD(IAC); 178432377Sminshall } 178532377Sminshall # endif /* !defined(TN3270) */ 178627088Sminshall break; 178732377Sminshall 178844360Sborman case NOP: 178944360Sborman case GA: 179027088Sminshall default: 179146808Sdab printoption("RCVD", IAC, c); 179227088Sminshall break; 179327088Sminshall } 179432377Sminshall telrcv_state = TS_DATA; 179532377Sminshall continue; 179627088Sminshall 179732377Sminshall case TS_WILL: 179846808Sdab printoption("RCVD", WILL, c); 179938689Sborman willoption(c); 180032377Sminshall SetIn3270(); 180132377Sminshall telrcv_state = TS_DATA; 180232377Sminshall continue; 180327110Sminshall 180432377Sminshall case TS_WONT: 180546808Sdab printoption("RCVD", WONT, c); 180638689Sborman wontoption(c); 180732377Sminshall SetIn3270(); 180832377Sminshall telrcv_state = TS_DATA; 180932377Sminshall continue; 181027088Sminshall 181132377Sminshall case TS_DO: 181246808Sdab printoption("RCVD", DO, c); 181337226Sminshall dooption(c); 181432377Sminshall SetIn3270(); 181537219Sminshall if (c == TELOPT_NAWS) { 181637219Sminshall sendnaws(); 181737219Sminshall } else if (c == TELOPT_LFLOW) { 181837219Sminshall localflow = 1; 181937219Sminshall setcommandmode(); 182038689Sborman setconnmode(0); 182137219Sminshall } 182232377Sminshall telrcv_state = TS_DATA; 182332377Sminshall continue; 182427088Sminshall 182532377Sminshall case TS_DONT: 182646808Sdab printoption("RCVD", DONT, c); 182738689Sborman dontoption(c); 182837226Sminshall flushline = 1; 182938689Sborman setconnmode(0); /* set new tty mode (maybe) */ 183032377Sminshall SetIn3270(); 183132377Sminshall telrcv_state = TS_DATA; 183232377Sminshall continue; 183327088Sminshall 183432377Sminshall case TS_SB: 183532377Sminshall if (c == IAC) { 183632377Sminshall telrcv_state = TS_SE; 183732377Sminshall } else { 183832377Sminshall SB_ACCUM(c); 183932377Sminshall } 184032377Sminshall continue; 184127088Sminshall 184232377Sminshall case TS_SE: 184332377Sminshall if (c != SE) { 184432377Sminshall if (c != IAC) { 184538689Sborman /* 184638689Sborman * This is an error. We only expect to get 184738689Sborman * "IAC IAC" or "IAC SE". Several things may 184838689Sborman * have happend. An IAC was not doubled, the 184938689Sborman * IAC SE was left off, or another option got 185038689Sborman * inserted into the suboption are all possibilities. 185138689Sborman * If we assume that the IAC was not doubled, 185238689Sborman * and really the IAC SE was left off, we could 185338689Sborman * get into an infinate loop here. So, instead, 185438689Sborman * we terminate the suboption, and process the 185538689Sborman * partial suboption if we can. 185638689Sborman */ 185732377Sminshall SB_ACCUM(IAC); 185838689Sborman SB_ACCUM(c); 185946808Sdab subpointer -= 2; 186046808Sdab SB_TERM(); 186146808Sdab 186246808Sdab printoption("In SUBOPTION processing, RCVD", IAC, c); 186338689Sborman suboption(); /* handle sub-option */ 186438689Sborman SetIn3270(); 186538689Sborman telrcv_state = TS_IAC; 186638689Sborman goto process_iac; 186732377Sminshall } 186832377Sminshall SB_ACCUM(c); 186932377Sminshall telrcv_state = TS_SB; 187032377Sminshall } else { 187138689Sborman SB_ACCUM(IAC); 187238689Sborman SB_ACCUM(SE); 187346808Sdab subpointer -= 2; 187446808Sdab SB_TERM(); 187532377Sminshall suboption(); /* handle sub-option */ 187632377Sminshall SetIn3270(); 187732377Sminshall telrcv_state = TS_DATA; 187832377Sminshall } 187927088Sminshall } 188027088Sminshall } 188132667Sminshall if (count) 188232667Sminshall ring_consumed(&netiring, count); 188332385Sminshall return returnValue||count; 188427088Sminshall } 188532385Sminshall 188646808Sdab static int bol = 1, local = 0; 188746808Sdab 188846808Sdab int 188946808Sdab rlogin_susp() 189046808Sdab { 189146808Sdab if (local) { 189246808Sdab local = 0; 189346808Sdab bol = 1; 189446808Sdab command(0, "z\n", 2); 189546808Sdab return(1); 189646808Sdab } 189746808Sdab return(0); 189846808Sdab } 189946808Sdab 190046808Sdab static int 190132554Sminshall telsnd() 190232385Sminshall { 190332385Sminshall int tcc; 190432385Sminshall int count; 190532385Sminshall int returnValue = 0; 190646808Sdab unsigned char *tbp; 190732385Sminshall 190832385Sminshall tcc = 0; 190932385Sminshall count = 0; 191032385Sminshall while (NETROOM() > 2) { 191132385Sminshall register int sc; 191232385Sminshall register int c; 191332385Sminshall 191432385Sminshall if (tcc == 0) { 191532385Sminshall if (count) { 191632528Sminshall ring_consumed(&ttyiring, count); 191732385Sminshall returnValue = 1; 191832385Sminshall count = 0; 191932385Sminshall } 192032528Sminshall tbp = ttyiring.consume; 192132528Sminshall tcc = ring_full_consecutive(&ttyiring); 192232385Sminshall if (tcc == 0) { 192332385Sminshall break; 192432385Sminshall } 192532385Sminshall } 192632385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 192746808Sdab if (rlogin != _POSIX_VDISABLE) { 192846808Sdab if (bol) { 192946808Sdab bol = 0; 193046808Sdab if (sc == rlogin) { 193146808Sdab local = 1; 193246808Sdab continue; 193346808Sdab } 193446808Sdab } else if (local) { 193546808Sdab local = 0; 193646808Sdab if (sc == '.' || c == termEofChar) { 193746808Sdab bol = 1; 193846808Sdab command(0, "close\n", 6); 193946808Sdab continue; 194046808Sdab } 194146808Sdab if (sc == termSuspChar) { 194246808Sdab bol = 1; 194346808Sdab command(0, "z\n", 2); 194446808Sdab continue; 194546808Sdab } 194646808Sdab if (sc == escape) { 194746808Sdab command(0, (char *)tbp, tcc); 194846808Sdab bol = 1; 194946808Sdab count += tcc; 195046808Sdab tcc = 0; 195146808Sdab flushline = 1; 195246808Sdab break; 195346808Sdab } 195446808Sdab if (sc != rlogin) { 195546808Sdab ++tcc; 195646808Sdab --tbp; 195746808Sdab --count; 195846808Sdab c = sc = rlogin; 195946808Sdab } 196046808Sdab } 196146808Sdab if ((sc == '\n') || (sc == '\r')) 196246808Sdab bol = 1; 196346808Sdab } else if (sc == escape) { 196438689Sborman /* 196538689Sborman * Double escape is a pass through of a single escape character. 196638689Sborman */ 196738689Sborman if (tcc && strip(*tbp) == escape) { 196838689Sborman tbp++; 196938689Sborman tcc--; 197038689Sborman count++; 197146808Sdab bol = 0; 197238689Sborman } else { 197346808Sdab command(0, (char *)tbp, tcc); 197446808Sdab bol = 1; 197538689Sborman count += tcc; 197638689Sborman tcc = 0; 197738689Sborman flushline = 1; 197838689Sborman break; 197938689Sborman } 198046808Sdab } else 198146808Sdab bol = 0; 198238689Sborman #ifdef KLUDGELINEMODE 198338689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 198432385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 198532385Sminshall tcc--; tbp++; count++; 198632385Sminshall } else { 198732385Sminshall dontlecho = !dontlecho; 198832385Sminshall settimer(echotoggle); 198938689Sborman setconnmode(0); 199032385Sminshall flushline = 1; 199132385Sminshall break; 199232385Sminshall } 199332385Sminshall } 199438689Sborman #endif 199538689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 199632385Sminshall if (TerminalSpecialChars(sc) == 0) { 199746808Sdab bol = 1; 199832385Sminshall break; 199932385Sminshall } 200032385Sminshall } 200138689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 200232385Sminshall switch (c) { 200332385Sminshall case '\n': 200432385Sminshall /* 200532385Sminshall * If we are in CRMOD mode (\r ==> \n) 200632385Sminshall * on our local machine, then probably 200732385Sminshall * a newline (unix) is CRLF (TELNET). 200832385Sminshall */ 200932385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 201032385Sminshall NETADD('\r'); 201132385Sminshall } 201232385Sminshall NETADD('\n'); 201346808Sdab bol = flushline = 1; 201432385Sminshall break; 201532385Sminshall case '\r': 201632385Sminshall if (!crlf) { 201732385Sminshall NET2ADD('\r', '\0'); 201832385Sminshall } else { 201932385Sminshall NET2ADD('\r', '\n'); 202032385Sminshall } 202146808Sdab bol = flushline = 1; 202232385Sminshall break; 202332385Sminshall case IAC: 202432385Sminshall NET2ADD(IAC, IAC); 202532385Sminshall break; 202632385Sminshall default: 202732385Sminshall NETADD(c); 202832385Sminshall break; 202932385Sminshall } 203032385Sminshall } else if (c == IAC) { 203132385Sminshall NET2ADD(IAC, IAC); 203232385Sminshall } else { 203332385Sminshall NETADD(c); 203432385Sminshall } 203532385Sminshall } 203632667Sminshall if (count) 203732667Sminshall ring_consumed(&ttyiring, count); 203832385Sminshall return returnValue||count; /* Non-zero if we did anything */ 203932385Sminshall } 204032377Sminshall 204127088Sminshall /* 204232377Sminshall * Scheduler() 204332377Sminshall * 204432377Sminshall * Try to do something. 204532377Sminshall * 204632377Sminshall * If we do something useful, return 1; else return 0. 204732377Sminshall * 204827110Sminshall */ 204927110Sminshall 205027110Sminshall 205146808Sdab int 205232377Sminshall Scheduler(block) 205346808Sdab int block; /* should we block in the select ? */ 205427110Sminshall { 205532377Sminshall /* One wants to be a bit careful about setting returnValue 205632377Sminshall * to one, since a one implies we did some useful work, 205732377Sminshall * and therefore probably won't be called to block next 205832377Sminshall * time (TN3270 mode only). 205932377Sminshall */ 206032531Sminshall int returnValue; 206132531Sminshall int netin, netout, netex, ttyin, ttyout; 206227110Sminshall 206332531Sminshall /* Decide which rings should be processed */ 206432531Sminshall 206532531Sminshall netout = ring_full_count(&netoring) && 206638689Sborman (flushline || 206738689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 206838689Sborman #ifdef KLUDGELINEMODE 206938689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 207038689Sborman #endif 207138689Sborman ) || 207238689Sborman my_want_state_is_will(TELOPT_BINARY)); 207332531Sminshall ttyout = ring_full_count(&ttyoring); 207432531Sminshall 207532377Sminshall #if defined(TN3270) 207632531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 207732377Sminshall #else /* defined(TN3270) */ 207832531Sminshall ttyin = ring_empty_count(&ttyiring); 207932377Sminshall #endif /* defined(TN3270) */ 208032531Sminshall 208132531Sminshall #if defined(TN3270) 208232531Sminshall netin = ring_empty_count(&netiring); 208332377Sminshall # else /* !defined(TN3270) */ 208432531Sminshall netin = !ISend && ring_empty_count(&netiring); 208532377Sminshall # endif /* !defined(TN3270) */ 208632531Sminshall 208732531Sminshall netex = !SYNCHing; 208832531Sminshall 208932531Sminshall /* If we have seen a signal recently, reset things */ 209032377Sminshall # if defined(TN3270) && defined(unix) 209132377Sminshall if (HaveInput) { 209232377Sminshall HaveInput = 0; 209344360Sborman (void) signal(SIGIO, inputAvailable); 209432377Sminshall } 209532377Sminshall #endif /* defined(TN3270) && defined(unix) */ 209632377Sminshall 209732531Sminshall /* Call to system code to process rings */ 209827178Sminshall 209932531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 210027178Sminshall 210132531Sminshall /* Now, look at the input rings, looking for work to do. */ 210232377Sminshall 210332531Sminshall if (ring_full_count(&ttyiring)) { 210432377Sminshall # if defined(TN3270) 210532377Sminshall if (In3270) { 210634848Sminshall int c; 210734848Sminshall 210833804Sminshall c = DataFromTerminal(ttyiring.consume, 210932528Sminshall ring_full_consecutive(&ttyiring)); 211032377Sminshall if (c) { 211132377Sminshall returnValue = 1; 211232667Sminshall ring_consumed(&ttyiring, c); 211332377Sminshall } 211432377Sminshall } else { 211532377Sminshall # endif /* defined(TN3270) */ 211632554Sminshall returnValue |= telsnd(); 211732377Sminshall # if defined(TN3270) 211827178Sminshall } 211932531Sminshall # endif /* defined(TN3270) */ 212027178Sminshall } 212132377Sminshall 212232528Sminshall if (ring_full_count(&netiring)) { 212332377Sminshall # if !defined(TN3270) 212432385Sminshall returnValue |= telrcv(); 212532377Sminshall # else /* !defined(TN3270) */ 212632377Sminshall returnValue = Push3270(); 212732377Sminshall # endif /* !defined(TN3270) */ 212832377Sminshall } 212932377Sminshall return returnValue; 213027178Sminshall } 213127178Sminshall 213227178Sminshall /* 213332377Sminshall * Select from tty and network... 213427088Sminshall */ 213546808Sdab void 213646808Sdab telnet(user) 213746808Sdab char *user; 213827088Sminshall { 213932531Sminshall sys_telnet_init(); 214027088Sminshall 2141*57213Sdab #if defined(ENCRYPTION) || defined(AUTHENTICATION) 214246808Sdab { 214346808Sdab static char local_host[256] = { 0 }; 214446808Sdab 214546808Sdab if (!local_host[0]) { 2146*57213Sdab gethostname(local_host, sizeof(local_host)); 214746808Sdab local_host[sizeof(local_host)-1] = 0; 214846808Sdab } 214946808Sdab auth_encrypt_init(local_host, hostname, "TELNET", 0); 215046808Sdab auth_encrypt_user(user); 215146808Sdab } 215246808Sdab #endif 215332377Sminshall # if !defined(TN3270) 215432377Sminshall if (telnetport) { 2155*57213Sdab #if defined(AUTHENTICATION) 215646808Sdab if (autologin) 215746808Sdab send_will(TELOPT_AUTHENTICATION, 1); 215846808Sdab #endif 2159*57213Sdab #if defined(ENCRYPTION) 216046808Sdab send_do(TELOPT_ENCRYPT, 1); 216146808Sdab send_will(TELOPT_ENCRYPT, 1); 216246808Sdab #endif 216338689Sborman send_do(TELOPT_SGA, 1); 216438689Sborman send_will(TELOPT_TTYPE, 1); 216538689Sborman send_will(TELOPT_NAWS, 1); 216638689Sborman send_will(TELOPT_TSPEED, 1); 216738689Sborman send_will(TELOPT_LFLOW, 1); 216838689Sborman send_will(TELOPT_LINEMODE, 1); 216946808Sdab send_will(TELOPT_ENVIRON, 1); 217038908Sborman send_do(TELOPT_STATUS, 1); 217146808Sdab if (env_getvalue((unsigned char *)"DISPLAY")) 217244360Sborman send_will(TELOPT_XDISPLOC, 1); 217346808Sdab if (eight) 217446808Sdab tel_enter_binary(eight); 217527178Sminshall } 217632377Sminshall # endif /* !defined(TN3270) */ 217727088Sminshall 217832377Sminshall # if !defined(TN3270) 217932377Sminshall for (;;) { 218032385Sminshall int schedValue; 218132385Sminshall 218232385Sminshall while ((schedValue = Scheduler(0)) != 0) { 218332385Sminshall if (schedValue == -1) { 218432385Sminshall setcommandmode(); 218532385Sminshall return; 218632385Sminshall } 218732385Sminshall } 218832385Sminshall 218932531Sminshall if (Scheduler(1) == -1) { 219032377Sminshall setcommandmode(); 219132377Sminshall return; 219232377Sminshall } 219332377Sminshall } 219432377Sminshall # else /* !defined(TN3270) */ 219532377Sminshall for (;;) { 219632377Sminshall int schedValue; 219727088Sminshall 219832377Sminshall while (!In3270 && !shell_active) { 219932531Sminshall if (Scheduler(1) == -1) { 220032377Sminshall setcommandmode(); 220132377Sminshall return; 220232377Sminshall } 220327088Sminshall } 220432377Sminshall 220532377Sminshall while ((schedValue = Scheduler(0)) != 0) { 220632377Sminshall if (schedValue == -1) { 220732377Sminshall setcommandmode(); 220832377Sminshall return; 220932377Sminshall } 221027088Sminshall } 221132377Sminshall /* If there is data waiting to go out to terminal, don't 221232377Sminshall * schedule any more data for the terminal. 221332377Sminshall */ 221434304Sminshall if (ring_full_count(&ttyoring)) { 221532377Sminshall schedValue = 1; 221627088Sminshall } else { 221732377Sminshall if (shell_active) { 221832377Sminshall if (shell_continue() == 0) { 221932377Sminshall ConnectScreen(); 222027088Sminshall } 222132377Sminshall } else if (In3270) { 222232377Sminshall schedValue = DoTerminalOutput(); 222332377Sminshall } 222427088Sminshall } 222532377Sminshall if (schedValue && (shell_active == 0)) { 222632531Sminshall if (Scheduler(1) == -1) { 222732377Sminshall setcommandmode(); 222832377Sminshall return; 222932377Sminshall } 223027088Sminshall } 223132377Sminshall } 223232377Sminshall # endif /* !defined(TN3270) */ 223327088Sminshall } 223432377Sminshall 223534848Sminshall #if 0 /* XXX - this not being in is a bug */ 223627088Sminshall /* 223732554Sminshall * nextitem() 223832554Sminshall * 223932554Sminshall * Return the address of the next "item" in the TELNET data 224032554Sminshall * stream. This will be the address of the next character if 224132554Sminshall * the current address is a user data character, or it will 224232554Sminshall * be the address of the character following the TELNET command 224332554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 224432554Sminshall * character. 224532554Sminshall */ 224632554Sminshall 224746808Sdab static char * 224832554Sminshall nextitem(current) 224946808Sdab char *current; 225032554Sminshall { 225132554Sminshall if ((*current&0xff) != IAC) { 225232554Sminshall return current+1; 225332554Sminshall } 225432554Sminshall switch (*(current+1)&0xff) { 225532554Sminshall case DO: 225632554Sminshall case DONT: 225732554Sminshall case WILL: 225832554Sminshall case WONT: 225932554Sminshall return current+3; 226032554Sminshall case SB: /* loop forever looking for the SE */ 226132554Sminshall { 226232554Sminshall register char *look = current+2; 226332554Sminshall 226432554Sminshall for (;;) { 226532554Sminshall if ((*look++&0xff) == IAC) { 226632554Sminshall if ((*look++&0xff) == SE) { 226732554Sminshall return look; 226832554Sminshall } 226932554Sminshall } 227032554Sminshall } 227132554Sminshall } 227232554Sminshall default: 227332554Sminshall return current+2; 227432554Sminshall } 227532554Sminshall } 227634848Sminshall #endif /* 0 */ 227732554Sminshall 227832554Sminshall /* 227932554Sminshall * netclear() 228032554Sminshall * 228132554Sminshall * We are about to do a TELNET SYNCH operation. Clear 228232554Sminshall * the path to the network. 228332554Sminshall * 228432554Sminshall * Things are a bit tricky since we may have sent the first 228532554Sminshall * byte or so of a previous TELNET command into the network. 228632554Sminshall * So, we have to scan the network buffer from the beginning 228732554Sminshall * until we are up to where we want to be. 228832554Sminshall * 228932554Sminshall * A side effect of what we do, just to keep things 229032554Sminshall * simple, is to clear the urgent data pointer. The principal 229132554Sminshall * caller should be setting the urgent data pointer AFTER calling 229232554Sminshall * us in any case. 229332554Sminshall */ 229432554Sminshall 229546808Sdab static void 229632554Sminshall netclear() 229732554Sminshall { 229832554Sminshall #if 0 /* XXX */ 229932554Sminshall register char *thisitem, *next; 230032554Sminshall char *good; 230132554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 230232554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 230332554Sminshall 230432554Sminshall thisitem = netobuf; 230532554Sminshall 230632554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 230732554Sminshall thisitem = next; 230832554Sminshall } 230932554Sminshall 231032554Sminshall /* Now, thisitem is first before/at boundary. */ 231132554Sminshall 231232554Sminshall good = netobuf; /* where the good bytes go */ 231332554Sminshall 231432554Sminshall while (netoring.add > thisitem) { 231532554Sminshall if (wewant(thisitem)) { 231632554Sminshall int length; 231732554Sminshall 231832554Sminshall next = thisitem; 231932554Sminshall do { 232032554Sminshall next = nextitem(next); 232132554Sminshall } while (wewant(next) && (nfrontp > next)); 232232554Sminshall length = next-thisitem; 232332554Sminshall memcpy(good, thisitem, length); 232432554Sminshall good += length; 232532554Sminshall thisitem = next; 232632554Sminshall } else { 232732554Sminshall thisitem = nextitem(thisitem); 232832554Sminshall } 232932554Sminshall } 233032554Sminshall 233132554Sminshall #endif /* 0 */ 233232554Sminshall } 233332554Sminshall 233432554Sminshall /* 233532377Sminshall * These routines add various telnet commands to the data stream. 233627088Sminshall */ 233732377Sminshall 233846808Sdab static void 233932554Sminshall doflush() 234032554Sminshall { 234132554Sminshall NET2ADD(IAC, DO); 234232554Sminshall NETADD(TELOPT_TM); 234332554Sminshall flushline = 1; 234432554Sminshall flushout = 1; 234544360Sborman (void) ttyflush(1); /* Flush/drop output */ 234632554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 234746808Sdab printoption("SENT", DO, TELOPT_TM); 234832554Sminshall } 234932554Sminshall 235046808Sdab void 235132377Sminshall xmitAO() 235227088Sminshall { 235332377Sminshall NET2ADD(IAC, AO); 235446808Sdab printoption("SENT", IAC, AO); 235532377Sminshall if (autoflush) { 235632377Sminshall doflush(); 235732377Sminshall } 235832377Sminshall } 235927088Sminshall 236032377Sminshall 236146808Sdab void 236232377Sminshall xmitEL() 236327088Sminshall { 236432377Sminshall NET2ADD(IAC, EL); 236546808Sdab printoption("SENT", IAC, EL); 236627088Sminshall } 236727088Sminshall 236846808Sdab void 236932377Sminshall xmitEC() 237027088Sminshall { 237132377Sminshall NET2ADD(IAC, EC); 237246808Sdab printoption("SENT", IAC, EC); 237327088Sminshall } 237427088Sminshall 237532377Sminshall 237646808Sdab int 237732377Sminshall dosynch() 237827088Sminshall { 237932377Sminshall netclear(); /* clear the path to the network */ 238033294Sminshall NETADD(IAC); 238133294Sminshall setneturg(); 238233294Sminshall NETADD(DM); 238346808Sdab printoption("SENT", IAC, DM); 238446808Sdab return 1; 238527088Sminshall } 238627088Sminshall 238746808Sdab int want_status_response = 0; 238846808Sdab 238946808Sdab int 239038908Sborman get_status() 239138908Sborman { 239246808Sdab unsigned char tmp[16]; 239346808Sdab register unsigned char *cp; 239438908Sborman 239538908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 239638908Sborman printf("Remote side does not support STATUS option\n"); 239746808Sdab return 0; 239838908Sborman } 239938908Sborman cp = tmp; 240038908Sborman 240138908Sborman *cp++ = IAC; 240238908Sborman *cp++ = SB; 240338908Sborman *cp++ = TELOPT_STATUS; 240438908Sborman *cp++ = TELQUAL_SEND; 240538908Sborman *cp++ = IAC; 240638908Sborman *cp++ = SE; 240738908Sborman if (NETROOM() >= cp - tmp) { 240838908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 240938908Sborman printsub('>', tmp+2, cp - tmp - 2); 241038908Sborman } 241146808Sdab ++want_status_response; 241246808Sdab return 1; 241338908Sborman } 241438908Sborman 241546808Sdab void 241632377Sminshall intp() 241727088Sminshall { 241832377Sminshall NET2ADD(IAC, IP); 241946808Sdab printoption("SENT", IAC, IP); 242032377Sminshall flushline = 1; 242132377Sminshall if (autoflush) { 242232377Sminshall doflush(); 242332377Sminshall } 242432377Sminshall if (autosynch) { 242532377Sminshall dosynch(); 242632377Sminshall } 242727088Sminshall } 242827186Sminshall 242946808Sdab void 243032377Sminshall sendbrk() 243127186Sminshall { 243232377Sminshall NET2ADD(IAC, BREAK); 243346808Sdab printoption("SENT", IAC, BREAK); 243432377Sminshall flushline = 1; 243532377Sminshall if (autoflush) { 243632377Sminshall doflush(); 243732377Sminshall } 243832377Sminshall if (autosynch) { 243932377Sminshall dosynch(); 244032377Sminshall } 244127186Sminshall } 244238689Sborman 244346808Sdab void 244438689Sborman sendabort() 244538689Sborman { 244638689Sborman NET2ADD(IAC, ABORT); 244746808Sdab printoption("SENT", IAC, ABORT); 244838689Sborman flushline = 1; 244938689Sborman if (autoflush) { 245038689Sborman doflush(); 245138689Sborman } 245238689Sborman if (autosynch) { 245338689Sborman dosynch(); 245438689Sborman } 245538689Sborman } 245638689Sborman 245746808Sdab void 245838689Sborman sendsusp() 245938689Sborman { 246038689Sborman NET2ADD(IAC, SUSP); 246146808Sdab printoption("SENT", IAC, SUSP); 246238689Sborman flushline = 1; 246338689Sborman if (autoflush) { 246438689Sborman doflush(); 246538689Sborman } 246638689Sborman if (autosynch) { 246738689Sborman dosynch(); 246838689Sborman } 246938689Sborman } 247038689Sborman 247146808Sdab void 247238689Sborman sendeof() 247338689Sborman { 247438908Sborman NET2ADD(IAC, xEOF); 247546808Sdab printoption("SENT", IAC, xEOF); 247638689Sborman } 247738689Sborman 247846808Sdab void 247945232Sborman sendayt() 248045232Sborman { 248145232Sborman NET2ADD(IAC, AYT); 248246808Sdab printoption("SENT", IAC, AYT); 248345232Sborman } 248445232Sborman 248537219Sminshall /* 248637219Sminshall * Send a window size update to the remote system. 248737219Sminshall */ 248837219Sminshall 248946808Sdab void 249037219Sminshall sendnaws() 249137219Sminshall { 249237219Sminshall long rows, cols; 249338689Sborman unsigned char tmp[16]; 249438689Sborman register unsigned char *cp; 249537219Sminshall 249638689Sborman if (my_state_is_wont(TELOPT_NAWS)) 249738689Sborman return; 249837219Sminshall 249938689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 250038689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 250138689Sborman 250237219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 250337219Sminshall return; 250437219Sminshall } 250537219Sminshall 250638689Sborman cp = tmp; 250738689Sborman 250838689Sborman *cp++ = IAC; 250938689Sborman *cp++ = SB; 251038689Sborman *cp++ = TELOPT_NAWS; 251138689Sborman PUTSHORT(cp, cols); 251238689Sborman PUTSHORT(cp, rows); 251338689Sborman *cp++ = IAC; 251438689Sborman *cp++ = SE; 251538689Sborman if (NETROOM() >= cp - tmp) { 251638689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 251738689Sborman printsub('>', tmp+2, cp - tmp - 2); 251837219Sminshall } 251937219Sminshall } 252037226Sminshall 252146808Sdab void 252238908Sborman tel_enter_binary(rw) 252346808Sdab int rw; 252437226Sminshall { 252538908Sborman if (rw&1) 252638908Sborman send_do(TELOPT_BINARY, 1); 252738908Sborman if (rw&2) 252838908Sborman send_will(TELOPT_BINARY, 1); 252937226Sminshall } 253037226Sminshall 253146808Sdab void 253238908Sborman tel_leave_binary(rw) 253346808Sdab int rw; 253437226Sminshall { 253538908Sborman if (rw&1) 253638908Sborman send_dont(TELOPT_BINARY, 1); 253738908Sborman if (rw&2) 253838908Sborman send_wont(TELOPT_BINARY, 1); 253937226Sminshall } 2540