133685Sbostic /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 533685Sbostic * Redistribution and use in source and binary forms are permitted 634898Sbostic * provided that the above copyright notice and this paragraph are 734898Sbostic * duplicated in all such forms and that any documentation, 834898Sbostic * advertising materials, and other materials related to such 934898Sbostic * distribution and use acknowledge that the software was developed 1034898Sbostic * by the University of California, Berkeley. The name of the 1134898Sbostic * University may not be used to endorse or promote products derived 1234898Sbostic * from this software without specific prior written permission. 1334898Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434898Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534898Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633685Sbostic */ 1711758Ssam 1821580Sdist #ifndef lint 19*39529Sborman static char sccsid[] = "@(#)telnet.c 5.44 (Berkeley) 11/14/89"; 2033685Sbostic #endif /* not lint */ 2121580Sdist 229217Ssam #include <sys/types.h> 239217Ssam 2432377Sminshall #if defined(unix) 2533804Sminshall #include <signal.h> 2632377Sminshall /* By the way, we need to include curses.h before telnet.h since, 2732377Sminshall * among other things, telnet.h #defines 'DO', which is a variable 2832377Sminshall * declared in curses.h. 2932377Sminshall */ 3032377Sminshall #endif /* defined(unix) */ 3132377Sminshall 3212212Ssam #include <arpa/telnet.h> 3332377Sminshall 3432377Sminshall #if defined(unix) 3527186Sminshall #include <strings.h> 3632377Sminshall #else /* defined(unix) */ 3732377Sminshall #include <string.h> 3832377Sminshall #endif /* defined(unix) */ 399217Ssam 4038908Sborman #include <ctype.h> 4138908Sborman 4232381Sminshall #include "ring.h" 4332381Sminshall 4432377Sminshall #include "defines.h" 4532377Sminshall #include "externs.h" 4632377Sminshall #include "types.h" 4732377Sminshall #include "general.h" 4827178Sminshall 4927178Sminshall 5027228Sminshall #define strip(x) ((x)&0x7f) 516000Sroot 5227088Sminshall 5332377Sminshall static char subbuffer[SUBBUFSIZE], 5432377Sminshall *subpointer, *subend; /* buffer for sub-options */ 5527676Sminshall #define SB_CLEAR() subpointer = subbuffer; 5627676Sminshall #define SB_TERM() subend = subpointer; 5727676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 5827676Sminshall *subpointer++ = (c); \ 5927676Sminshall } 6027676Sminshall 6137226Sminshall char options[256]; /* The combined options */ 6238689Sborman char do_dont_resp[256]; 6338689Sborman char will_wont_resp[256]; 646000Sroot 6532377Sminshall int 6632377Sminshall connected, 6732377Sminshall showoptions, 6832377Sminshall In3270, /* Are we in 3270 mode? */ 6932377Sminshall ISend, /* trying to send network data in */ 7032377Sminshall debug = 0, 7132377Sminshall crmod, 7232377Sminshall netdata, /* Print out network data flow */ 7332377Sminshall crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 7434848Sminshall #if defined(TN3270) 7536241Sminshall noasynchtty = 0,/* User specified "-noasynch" on command line */ 7636241Sminshall noasynchnet = 0,/* User specified "-noasynch" on command line */ 7732377Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 7834848Sminshall #endif /* defined(TN3270) */ 7933286Sminshall telnetport, 8032531Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 8132531Sminshall flushout, /* flush output */ 8232531Sminshall autoflush = 0, /* flush output when interrupting? */ 8332531Sminshall autosynch, /* send interrupt characters with SYNCH? */ 8437219Sminshall localflow, /* we handle flow control locally */ 8532531Sminshall localchars, /* we recognize interrupt/quit */ 8632531Sminshall donelclchars, /* the user has set "localchars" */ 8732531Sminshall donebinarytoggle, /* the user has put us in binary */ 8832531Sminshall dontlecho, /* do we suppress local echoing right now? */ 8932531Sminshall globalmode; 9027088Sminshall 9132377Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 926000Sroot 93*39529Sborman unsigned char 9432377Sminshall *prompt = 0, 9532377Sminshall escape, 9632377Sminshall echoc; 9727186Sminshall 9827186Sminshall /* 996000Sroot * Telnet receiver states for fsm 1006000Sroot */ 1016000Sroot #define TS_DATA 0 1026000Sroot #define TS_IAC 1 1036000Sroot #define TS_WILL 2 1046000Sroot #define TS_WONT 3 1056000Sroot #define TS_DO 4 1066000Sroot #define TS_DONT 5 10727021Sminshall #define TS_CR 6 10827676Sminshall #define TS_SB 7 /* sub-option collection */ 10927676Sminshall #define TS_SE 8 /* looking for sub-option end */ 1106000Sroot 11132377Sminshall static int telrcv_state; 1126000Sroot 11332377Sminshall jmp_buf toplevel = { 0 }; 11432377Sminshall jmp_buf peerdied; 1156000Sroot 11632377Sminshall int flushline; 11738811Sborman int linemode; 11827021Sminshall 11938689Sborman #ifdef KLUDGELINEMODE 12038689Sborman int kludgelinemode = 1; 12138689Sborman #endif 12238689Sborman 12332377Sminshall /* 12432377Sminshall * The following are some clocks used to decide how to interpret 12532377Sminshall * the relationship between various variables. 12632377Sminshall */ 1276000Sroot 12832377Sminshall Clocks clocks; 12932377Sminshall 13038689Sborman #ifdef notdef 13132377Sminshall Modelist modelist[] = { 13232377Sminshall { "telnet command mode", COMMAND_LINE }, 13332377Sminshall { "character-at-a-time mode", 0 }, 13432377Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 13532377Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 13632377Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 13732377Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 13832377Sminshall { "3270 mode", 0 }, 13932377Sminshall }; 14038689Sborman #endif 1416000Sroot 14232377Sminshall 14332377Sminshall /* 14432377Sminshall * Initialize telnet environment. 14532377Sminshall */ 1466000Sroot 14732377Sminshall init_telnet() 14832377Sminshall { 14932377Sminshall SB_CLEAR(); 15037226Sminshall ClearArray(options); 1516000Sroot 15237219Sminshall connected = In3270 = ISend = localflow = donebinarytoggle = 0; 1536000Sroot 15432377Sminshall SYNCHing = 0; 1556000Sroot 15632377Sminshall /* Don't change NetTrace */ 1576000Sroot 15832377Sminshall escape = CONTROL(']'); 15932377Sminshall echoc = CONTROL('E'); 1606000Sroot 16132377Sminshall flushline = 1; 16232377Sminshall telrcv_state = TS_DATA; 16332377Sminshall } 16432554Sminshall 1656000Sroot 16632554Sminshall #include <varargs.h> 1676000Sroot 16834848Sminshall /*VARARGS*/ 16932554Sminshall static void 17032554Sminshall printring(va_alist) 17132554Sminshall va_dcl 17232554Sminshall { 17332554Sminshall va_list ap; 17432554Sminshall char buffer[100]; /* where things go */ 17532554Sminshall char *ptr; 17632554Sminshall char *format; 17732554Sminshall char *string; 17832554Sminshall Ring *ring; 17932554Sminshall int i; 18032554Sminshall 18132554Sminshall va_start(ap); 18232554Sminshall 18332554Sminshall ring = va_arg(ap, Ring *); 18432554Sminshall format = va_arg(ap, char *); 18532554Sminshall ptr = buffer; 18632554Sminshall 18732554Sminshall while ((i = *format++) != 0) { 18832554Sminshall if (i == '%') { 18932554Sminshall i = *format++; 19032554Sminshall switch (i) { 19132554Sminshall case 'c': 19232554Sminshall *ptr++ = va_arg(ap, int); 19332554Sminshall break; 19432554Sminshall case 's': 19532554Sminshall string = va_arg(ap, char *); 19632554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 19732554Sminshall ring_supply_data(ring, string, strlen(string)); 19832554Sminshall ptr = buffer; 19932554Sminshall break; 20032554Sminshall case 0: 20132554Sminshall ExitString("printring: trailing %%.\n", 1); 20232554Sminshall /*NOTREACHED*/ 20332554Sminshall default: 20432554Sminshall ExitString("printring: unknown format character.\n", 1); 20532554Sminshall /*NOTREACHED*/ 20632554Sminshall } 20732554Sminshall } else { 20832554Sminshall *ptr++ = i; 20932554Sminshall } 21032554Sminshall } 21132554Sminshall ring_supply_data(ring, buffer, ptr-buffer); 21232554Sminshall } 21332554Sminshall 21437226Sminshall /* 21537226Sminshall * These routines are in charge of sending option negotiations 21637226Sminshall * to the other side. 21737226Sminshall * 21837226Sminshall * The basic idea is that we send the negotiation if either side 21937226Sminshall * is in disagreement as to what the current state should be. 22037226Sminshall */ 22132554Sminshall 22238689Sborman send_do(c, init) 22338689Sborman register int c, init; 2246000Sroot { 22538689Sborman if (init) { 22638689Sborman if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 22738689Sborman my_want_state_is_do(c)) 22838689Sborman return; 22938689Sborman set_my_want_state_do(c); 23038689Sborman do_dont_resp[c]++; 23137226Sminshall } 23238689Sborman NET2ADD(IAC, DO); 23338689Sborman NETADD(c); 23438689Sborman printoption("SENT", "do", c); 23537226Sminshall } 23637226Sminshall 23737226Sminshall void 23838689Sborman send_dont(c, init) 23938689Sborman register int c, init; 24037226Sminshall { 24138689Sborman if (init) { 24238689Sborman if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 24338689Sborman my_want_state_is_dont(c)) 24438689Sborman return; 24538689Sborman set_my_want_state_dont(c); 24638689Sborman do_dont_resp[c]++; 24737226Sminshall } 24838689Sborman NET2ADD(IAC, DONT); 24938689Sborman NETADD(c); 25038689Sborman printoption("SENT", "dont", c); 25137226Sminshall } 25237226Sminshall 25337226Sminshall void 25438689Sborman send_will(c, init) 25538689Sborman register int c, init; 25637226Sminshall { 25738689Sborman if (init) { 25838689Sborman if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 25938689Sborman my_want_state_is_will(c)) 26038689Sborman return; 26138689Sborman set_my_want_state_will(c); 26238689Sborman will_wont_resp[c]++; 26337226Sminshall } 26438689Sborman NET2ADD(IAC, WILL); 26538689Sborman NETADD(c); 26638689Sborman printoption("SENT", "will", c); 26737226Sminshall } 26837226Sminshall 26937226Sminshall void 27038689Sborman send_wont(c, init) 27138689Sborman register int c, init; 27237226Sminshall { 27338689Sborman if (init) { 27438689Sborman if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 27538689Sborman my_want_state_is_wont(c)) 27638689Sborman return; 27738689Sborman set_my_want_state_wont(c); 27838689Sborman will_wont_resp[c]++; 27937226Sminshall } 28038689Sborman NET2ADD(IAC, WONT); 28138689Sborman NETADD(c); 28238689Sborman printoption("SENT", "wont", c); 28337226Sminshall } 28437226Sminshall 28537226Sminshall 28637226Sminshall void 28737226Sminshall willoption(option) 28837226Sminshall int option; 28937226Sminshall { 2906000Sroot char *fmt; 29138689Sborman int new_state_ok = 0; 2926000Sroot 29338689Sborman if (do_dont_resp[option]) { 29438689Sborman --do_dont_resp[option]; 29538689Sborman if (do_dont_resp[option] && my_state_is_do(option)) 29638689Sborman --do_dont_resp[option]; 29738689Sborman } 29837226Sminshall 29938689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 3006000Sroot 30138689Sborman switch (option) { 30238689Sborman 30338689Sborman case TELOPT_ECHO: 30438689Sborman # if defined(TN3270) 30538689Sborman /* 30638689Sborman * The following is a pain in the rear-end. 30738689Sborman * Various IBM servers (some versions of Wiscnet, 30838689Sborman * possibly Fibronics/Spartacus, and who knows who 30938689Sborman * else) will NOT allow us to send "DO SGA" too early 31038689Sborman * in the setup proceedings. On the other hand, 31138689Sborman * 4.2 servers (telnetd) won't set SGA correctly. 31238689Sborman * So, we are stuck. Empirically (but, based on 31338689Sborman * a VERY small sample), the IBM servers don't send 31438689Sborman * out anything about ECHO, so we postpone our sending 31538689Sborman * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 31638689Sborman * DO send). 31738689Sborman */ 31838689Sborman { 31938689Sborman if (askedSGA == 0) { 32038689Sborman askedSGA = 1; 32138689Sborman if (my_want_state_is_dont(TELOPT_SGA)) 32238689Sborman send_do(TELOPT_SGA, 1); 32332377Sminshall } 32432377Sminshall } 32538689Sborman /* Fall through */ 32638689Sborman case TELOPT_EOR: 32738908Sborman #endif /* defined(TN3270) */ 32838689Sborman case TELOPT_BINARY: 32938689Sborman case TELOPT_SGA: 33027110Sminshall settimer(modenegotiated); 33138908Sborman /* FALL THROUGH */ 33238908Sborman case TELOPT_STATUS: 33338689Sborman new_state_ok = 1; 3346000Sroot break; 3356000Sroot 33638689Sborman case TELOPT_TM: 33738689Sborman if (flushout) 33838689Sborman flushout = 0; 33938689Sborman /* 34038689Sborman * Special case for TM. If we get back a WILL, 34138689Sborman * pretend we got back a WONT. 34238689Sborman */ 34338689Sborman set_my_want_state_dont(option); 34438689Sborman set_my_state_dont(option); 34527110Sminshall return; /* Never reply to TM will's/wont's */ 3466000Sroot 34738689Sborman case TELOPT_LINEMODE: 34838689Sborman default: 3496000Sroot break; 35038689Sborman } 35138689Sborman 35238689Sborman if (new_state_ok) { 35338689Sborman set_my_want_state_do(option); 35438689Sborman send_do(option, 0); 35538689Sborman setconnmode(0); /* possibly set new tty mode */ 35638689Sborman } else { 35738689Sborman do_dont_resp[option]++; 35838689Sborman send_dont(option, 0); 35938689Sborman } 3606000Sroot } 36138689Sborman set_my_state_do(option); 3626000Sroot } 3636000Sroot 36432377Sminshall void 36537226Sminshall wontoption(option) 36637226Sminshall int option; 3676000Sroot { 3686000Sroot char *fmt; 3696000Sroot 37038689Sborman if (do_dont_resp[option]) { 37138689Sborman --do_dont_resp[option]; 37238689Sborman if (do_dont_resp[option] && my_state_is_dont(option)) 37338689Sborman --do_dont_resp[option]; 37438689Sborman } 37537226Sminshall 37638689Sborman if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 3776000Sroot 37838689Sborman switch (option) { 37938689Sborman 38038689Sborman #ifdef KLUDGELINEMODE 38138689Sborman case TELOPT_SGA: 38238689Sborman if (!kludgelinemode) 38338689Sborman break; 38438689Sborman /* FALL THROUGH */ 38538689Sborman #endif 38638689Sborman case TELOPT_ECHO: 38727110Sminshall settimer(modenegotiated); 3886000Sroot break; 3896000Sroot 39038689Sborman case TELOPT_TM: 39138689Sborman if (flushout) 39238689Sborman flushout = 0; 39338689Sborman set_my_want_state_dont(option); 39438689Sborman set_my_state_dont(option); 39527110Sminshall return; /* Never reply to TM will's/wont's */ 39627110Sminshall 39738689Sborman default: 39838689Sborman break; 39938689Sborman } 40038689Sborman set_my_want_state_dont(option); 40138689Sborman send_dont(option, 0); 40238689Sborman setconnmode(0); /* Set new tty mode */ 40338689Sborman } else if (option == TELOPT_TM) { 40438689Sborman /* 40538689Sborman * Special case for TM. 40638689Sborman */ 40738689Sborman if (flushout) 40838689Sborman flushout = 0; 40938689Sborman set_my_want_state_dont(option); 4106000Sroot } 41138689Sborman set_my_state_dont(option); 4126000Sroot } 4136000Sroot 41432377Sminshall static void 4156000Sroot dooption(option) 4166000Sroot int option; 4176000Sroot { 4186000Sroot char *fmt; 41938689Sborman int new_state_ok = 0; 4206000Sroot 42138689Sborman if (will_wont_resp[option]) { 42238689Sborman --will_wont_resp[option]; 42338689Sborman if (will_wont_resp[option] && my_state_is_will(option)) 42438689Sborman --will_wont_resp[option]; 42538689Sborman } 42637226Sminshall 42738689Sborman if (will_wont_resp[option] == 0) { 42838689Sborman if (my_want_state_is_wont(option)) { 4296000Sroot 43038689Sborman switch (option) { 43138689Sborman 43238689Sborman case TELOPT_TM: 43338689Sborman /* 43438689Sborman * Special case for TM. We send a WILL, but pretend 43538689Sborman * we sent WONT. 43638689Sborman */ 43738689Sborman send_will(option, 0); 43838689Sborman set_my_want_state_wont(TELOPT_TM); 43938689Sborman set_my_state_wont(TELOPT_TM); 44038689Sborman return; 44138689Sborman 44232377Sminshall # if defined(TN3270) 44338689Sborman case TELOPT_EOR: /* end of record */ 44438908Sborman # endif /* defined(TN3270) */ 44538689Sborman case TELOPT_BINARY: /* binary mode */ 44638689Sborman case TELOPT_NAWS: /* window size */ 44738689Sborman case TELOPT_TSPEED: /* terminal speed */ 44838689Sborman case TELOPT_LFLOW: /* local flow control */ 44938689Sborman case TELOPT_TTYPE: /* terminal type option */ 45038689Sborman case TELOPT_SGA: /* no big deal */ 45138689Sborman new_state_ok = 1; 4526000Sroot break; 4536000Sroot 45438689Sborman case TELOPT_LINEMODE: 45538689Sborman #ifdef KLUDGELINEMODE 45638689Sborman kludgelinemode = 0; 45738689Sborman #endif 45838689Sborman set_my_want_state_will(TELOPT_LINEMODE); 45938689Sborman send_will(option, 0); 46038689Sborman set_my_state_will(TELOPT_LINEMODE); 46138689Sborman slc_init(); 46238689Sborman return; 46338689Sborman 46438689Sborman case TELOPT_ECHO: /* We're never going to echo... */ 46538689Sborman default: 4666000Sroot break; 46738689Sborman } 46838689Sborman 46938689Sborman if (new_state_ok) { 47038689Sborman set_my_want_state_will(option); 47138689Sborman send_will(option, 0); 47238689Sborman } else { 47338689Sborman will_wont_resp[option]++; 47438689Sborman send_wont(option, 0); 47538689Sborman } 47638689Sborman } else { 47738689Sborman /* 47838689Sborman * Handle options that need more things done after the 47938689Sborman * other side has acknowledged the option. 48038689Sborman */ 48138689Sborman switch (option) { 48238689Sborman case TELOPT_LINEMODE: 48338689Sborman #ifdef KLUDGELINEMODE 48438689Sborman kludgelinemode = 0; 48538689Sborman #endif 48638689Sborman set_my_state_will(option); 48738689Sborman slc_init(); 48838689Sborman return; 48938689Sborman } 49038689Sborman } 4916000Sroot } 49238689Sborman set_my_state_will(option); 4936000Sroot } 49427676Sminshall 49538689Sborman static void 49638689Sborman dontoption(option) 49738689Sborman int option; 49838689Sborman { 49938689Sborman 50038689Sborman if (will_wont_resp[option]) { 50138689Sborman --will_wont_resp[option]; 50238689Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 50338689Sborman --will_wont_resp[option]; 50438689Sborman } 50538689Sborman 50638689Sborman if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 50738811Sborman switch (option) { 50838811Sborman case TELOPT_LINEMODE: 50938811Sborman linemode = 0; /* put us back to the default state */ 51038811Sborman break; 51138811Sborman } 51238689Sborman /* we always accept a DONT */ 51338689Sborman set_my_want_state_wont(option); 51438689Sborman send_wont(option, 0); 515*39529Sborman setconnmode(0); /* Set new tty mode */ 51638689Sborman } 51738689Sborman set_my_state_wont(option); 51838689Sborman } 51938689Sborman 52027676Sminshall /* 52138908Sborman * Given a buffer returned by tgetent(), this routine will turn 52238908Sborman * the pipe seperated list of names in the buffer into an array 52338908Sborman * of pointers to null terminated names. We toss out any bad, 52438908Sborman * duplicate, or verbose names (names with spaces). 52538908Sborman */ 52638908Sborman 52738908Sborman static char *unknown[] = { "UNKNOWN", 0 }; 52838908Sborman 52938908Sborman char ** 53038908Sborman mklist(buf, name) 53138908Sborman char *buf, *name; 53238908Sborman { 53338908Sborman register int n; 53438908Sborman register char c, *cp, **argvp, *cp2, **argv; 53538908Sborman char *malloc(); 53638908Sborman 53738908Sborman if (name) { 53838908Sborman if (strlen(name) > 40) 53938908Sborman name = 0; 54038908Sborman else { 54138908Sborman unknown[0] = name; 54238908Sborman upcase(name); 54338908Sborman } 54438908Sborman } 54538908Sborman /* 54638908Sborman * Count up the number of names. 54738908Sborman */ 54838908Sborman for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 54938908Sborman if (*cp == '|') 55038908Sborman n++; 55138908Sborman } 55238908Sborman /* 55338908Sborman * Allocate an array to put the name pointers into 55438908Sborman */ 55538908Sborman argv = (char **)malloc((n+3)*sizeof(char *)); 55638908Sborman if (argv == 0) 55738908Sborman return(unknown); 55838908Sborman 55938908Sborman /* 56038908Sborman * Fill up the array of pointers to names. 56138908Sborman */ 56238908Sborman *argv = 0; 56338908Sborman argvp = argv+1; 56438908Sborman n = 0; 56538908Sborman for (cp = cp2 = buf; (c = *cp); cp++) { 56638908Sborman if (c == '|' || c == ':') { 56738908Sborman *cp++ = '\0'; 56838908Sborman /* 56938908Sborman * Skip entries that have spaces or are over 40 57038908Sborman * characters long. If this is our environment 57138908Sborman * name, then put it up front. Otherwise, as 57238908Sborman * long as this is not a duplicate name (case 57338908Sborman * insensitive) add it to the list. 57438908Sborman */ 57538908Sborman if (n || (cp - cp2 > 41)) 57638908Sborman ; 57738908Sborman else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 57838908Sborman *argv = cp2; 57938908Sborman else if (is_unique(cp2, argv+1, argvp)) 58038908Sborman *argvp++ = cp2; 58138908Sborman if (c == ':') 58238908Sborman break; 58338908Sborman /* 58438908Sborman * Skip multiple delimiters. Reset cp2 to 58538908Sborman * the beginning of the next name. Reset n, 58638908Sborman * the flag for names with spaces. 58738908Sborman */ 58838908Sborman while ((c = *cp) == '|') 58938908Sborman cp++; 59038908Sborman cp2 = cp; 59138908Sborman n = 0; 59238908Sborman } 59338908Sborman /* 59438908Sborman * Skip entries with spaces or non-ascii values. 59538908Sborman * Convert lower case letters to upper case. 59638908Sborman */ 59738908Sborman if ((c == ' ') || !isascii(c)) 59838908Sborman n = 1; 59938908Sborman else if (islower(c)) 60038908Sborman *cp = toupper(c); 60138908Sborman } 60238908Sborman 60338908Sborman /* 60438908Sborman * Check for an old V6 2 character name. If the second 60538908Sborman * name points to the beginning of the buffer, and is 60638908Sborman * only 2 characters long, move it to the end of the array. 60738908Sborman */ 60838908Sborman if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 60938908Sborman *argvp++ = buf; 61038908Sborman cp = *argv++; 61138908Sborman *argv = cp; 61238908Sborman } 61338908Sborman 61438908Sborman /* 61538908Sborman * Duplicate last name, for TTYPE option, and null 61638908Sborman * terminate the array. If we didn't find a match on 61738908Sborman * our terminal name, put that name at the beginning. 61838908Sborman */ 61938908Sborman cp = *(argvp-1); 62038908Sborman *argvp++ = cp; 62138908Sborman *argvp = 0; 62238908Sborman 62338908Sborman if (*argv == 0) { 62438908Sborman if (name) 62538908Sborman *argv = name; 62638908Sborman else 62738908Sborman argv++; 62838908Sborman } 62938908Sborman if (*argv) 63038908Sborman return(argv); 63138908Sborman else 63238908Sborman return(unknown); 63338908Sborman } 63438908Sborman 63538908Sborman is_unique(name, as, ae) 63638908Sborman register char *name, **as, **ae; 63738908Sborman { 63838908Sborman register char **ap; 63938908Sborman register int n; 64038908Sborman 64138908Sborman n = strlen(name) + 1; 64238908Sborman for (ap = as; ap < ae; ap++) 64338908Sborman if (strncasecmp(*ap, name, n) == 0) 64438908Sborman return(0); 64538908Sborman return (1); 64638908Sborman } 64738908Sborman 64838908Sborman #ifdef TERMCAP 649*39529Sborman char termbuf[1024]; 65038908Sborman setupterm(tname, fd, errp) 65138908Sborman char *tname; 65238908Sborman int fd, *errp; 65338908Sborman { 654*39529Sborman if (tgetent(termbuf, tname) == 1) { 655*39529Sborman termbuf[1023] = '\0'; 65638908Sborman if (errp) 65738908Sborman *errp = 1; 65838908Sborman return(0); 65938908Sborman } 66038908Sborman if (errp) 66138908Sborman *errp = 0; 66238908Sborman return(-1); 66338908Sborman } 664*39529Sborman #else 665*39529Sborman #define termbuf ttytype 666*39529Sborman extern char ttytype[]; 66738908Sborman #endif 66838908Sborman 66938908Sborman char * 67038908Sborman gettermname() 67138908Sborman { 67238908Sborman char *tname; 67338908Sborman static int first = 1; 67438908Sborman static char **tnamep; 67538908Sborman static char **next; 67638908Sborman char *getenv(); 67738908Sborman int err; 67838908Sborman 67938908Sborman if (first) { 68038908Sborman first = 0; 68138908Sborman if ((tname = getenv("TERM")) && 68238908Sborman (setupterm(tname, 1, &err) == 0)) { 683*39529Sborman tnamep = mklist(termbuf, tname); 68438908Sborman } else { 68538908Sborman if (tname && (strlen(tname) <= 40)) { 68638908Sborman unknown[0] = tname; 68738908Sborman upcase(tname); 68838908Sborman } 68938908Sborman tnamep = unknown; 69038908Sborman } 69138908Sborman next = tnamep; 69238908Sborman } 69338908Sborman if (*next == 0) 69438908Sborman next = tnamep; 69538908Sborman return(*next++); 69638908Sborman } 69738908Sborman /* 69827676Sminshall * suboption() 69927676Sminshall * 70027676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 70127676Sminshall * side. 70227676Sminshall * 70327676Sminshall * Currently we recognize: 70427676Sminshall * 70527676Sminshall * Terminal type, send request. 70637219Sminshall * Terminal speed (send request). 70737219Sminshall * Local flow control (is request). 70838689Sborman * Linemode 70927676Sminshall */ 71027676Sminshall 71132377Sminshall static void 71227676Sminshall suboption() 71327676Sminshall { 71438689Sborman printsub('<', subbuffer, subend-subbuffer+2); 71527676Sminshall switch (subbuffer[0]&0xff) { 71627676Sminshall case TELOPT_TTYPE: 71738689Sborman if (my_want_state_is_wont(TELOPT_TTYPE)) 71838689Sborman return; 71927676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 72027676Sminshall ; 72127676Sminshall } else { 72227676Sminshall char *name; 72332377Sminshall extern char *getenv(); 72438908Sborman char temp[50]; 72527676Sminshall int len; 72627676Sminshall 72732377Sminshall #if defined(TN3270) 72832531Sminshall if (tn3270_ttype()) { 72932377Sminshall return; 73032377Sminshall } 73132377Sminshall #endif /* defined(TN3270) */ 73238908Sborman name = gettermname(); 73338908Sborman len = strlen(name) + 4 + 2; 73438908Sborman if (len < NETROOM()) { 73538908Sborman sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 73638908Sborman TELQUAL_IS, name, IAC, SE); 73738689Sborman ring_supply_data(&netoring, temp, len); 73838908Sborman printsub('>', &temp[2], len-2); 73932377Sminshall } else { 74037226Sminshall ExitString("No room in buffer for terminal type.\n", 1); 74132377Sminshall /*NOTREACHED*/ 74227676Sminshall } 74327676Sminshall } 74437219Sminshall break; 74537219Sminshall case TELOPT_TSPEED: 74638689Sborman if (my_want_state_is_wont(TELOPT_TSPEED)) 74738689Sborman return; 74837219Sminshall if ((subbuffer[1]&0xff) == TELQUAL_SEND) { 74938689Sborman long ospeed,ispeed; 75038689Sborman char temp[50]; 75137219Sminshall int len; 75227676Sminshall 75337219Sminshall TerminalSpeeds(&ispeed, &ospeed); 75437219Sminshall 75538689Sborman sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, 75638689Sborman TELQUAL_IS, ospeed, ispeed, IAC, SE); 75738689Sborman len = strlen(temp+4) + 4; /* temp[3] is 0 ... */ 75837219Sminshall 75938689Sborman if (len < NETROOM()) { 76038689Sborman ring_supply_data(&netoring, temp, len); 76138689Sborman printsub('>', temp+2, len - 2); 76237219Sminshall } 76337219Sminshall } 76437219Sminshall break; 76537219Sminshall case TELOPT_LFLOW: 76638689Sborman if (my_want_state_is_wont(TELOPT_LFLOW)) 76738689Sborman return; 76837219Sminshall if ((subbuffer[1]&0xff) == 1) { 76937219Sminshall localflow = 1; 77037219Sminshall } else if ((subbuffer[1]&0xff) == 0) { 77137219Sminshall localflow = 0; 77237219Sminshall } 77337219Sminshall setcommandmode(); 77438689Sborman setconnmode(0); 77537219Sminshall break; 77638689Sborman 77738689Sborman case TELOPT_LINEMODE: 77838689Sborman if (my_want_state_is_wont(TELOPT_LINEMODE)) 77938689Sborman return; 78038689Sborman switch (subbuffer[1]&0xff) { 78138689Sborman case WILL: 78238689Sborman lm_will(&subbuffer[2], subend - &subbuffer[2]); 78338689Sborman break; 78438689Sborman case WONT: 78538689Sborman lm_wont(&subbuffer[2], subend - &subbuffer[2]); 78638689Sborman break; 78738689Sborman case DO: 78838689Sborman lm_do(&subbuffer[2], subend - &subbuffer[2]); 78938689Sborman break; 79038689Sborman case DONT: 79138689Sborman lm_dont(&subbuffer[2], subend - &subbuffer[2]); 79238689Sborman break; 79338689Sborman case LM_SLC: 79438689Sborman slc(&subbuffer[2], subend - &subbuffer[2]); 79538689Sborman break; 79638689Sborman case LM_MODE: 79738689Sborman lm_mode(&subbuffer[2], subend - &subbuffer[2], 0); 79838689Sborman break; 79938689Sborman default: 80038689Sborman break; 80138689Sborman } 80238689Sborman break; 80327676Sminshall default: 80427676Sminshall break; 80527676Sminshall } 80627676Sminshall } 80738689Sborman 80838689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 80938689Sborman 81038689Sborman lm_will(cmd, len) 81138689Sborman char *cmd; 81238689Sborman { 81338689Sborman switch(cmd[0]) { 81438689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 81538689Sborman default: 81638689Sborman str_lm[3] = DONT; 81738689Sborman str_lm[4] = cmd[0]; 81838689Sborman if (NETROOM() > sizeof(str_lm)) { 81938689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 82038689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 82138689Sborman } 82238689Sborman /*@*/ else printf("lm_will: not enough room in buffer\n"); 82338689Sborman break; 82438689Sborman } 82538689Sborman } 82638689Sborman 82738689Sborman lm_wont(cmd, len) 82838689Sborman char *cmd; 82938689Sborman { 83038689Sborman switch(cmd[0]) { 83138689Sborman case LM_FORWARDMASK: /* We shouldn't ever get this... */ 83238689Sborman default: 83338689Sborman /* We are always DONT, so don't respond */ 83438689Sborman return; 83538689Sborman } 83638689Sborman } 83738689Sborman 83838689Sborman lm_do(cmd, len) 83938689Sborman char *cmd; 84038689Sborman { 84138689Sborman switch(cmd[0]) { 84238689Sborman case LM_FORWARDMASK: 84338689Sborman default: 84438689Sborman str_lm[3] = WONT; 84538689Sborman str_lm[4] = cmd[0]; 84638689Sborman if (NETROOM() > sizeof(str_lm)) { 84738689Sborman ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 84838689Sborman printsub('>', &str_lm[2], sizeof(str_lm)-2); 84938689Sborman } 85038689Sborman /*@*/ else printf("lm_do: not enough room in buffer\n"); 85138689Sborman break; 85238689Sborman } 85338689Sborman } 85438689Sborman 85538689Sborman lm_dont(cmd, len) 85638689Sborman char *cmd; 85738689Sborman { 85838689Sborman switch(cmd[0]) { 85938689Sborman case LM_FORWARDMASK: 86038689Sborman default: 86138689Sborman /* we are always WONT, so don't respond */ 86238689Sborman break; 86338689Sborman } 86438689Sborman } 86538689Sborman 86638689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; 86738689Sborman 86838689Sborman lm_mode(cmd, len, init) 86938689Sborman char *cmd; 87038689Sborman int len, init; 87138689Sborman { 87238689Sborman if (len != 1) 87338689Sborman return; 87438689Sborman if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd) 87538689Sborman return; 87638689Sborman if (*cmd&MODE_ACK) 87738689Sborman return; 87838689Sborman linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG)); 87938689Sborman str_lm_mode[4] = linemode; 88038689Sborman if (!init) 88138689Sborman str_lm_mode[4] |= MODE_ACK; 88238689Sborman if (NETROOM() > sizeof(str_lm_mode)) { 88338689Sborman ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 88438689Sborman printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 88538689Sborman } 88638689Sborman /*@*/ else printf("lm_mode: not enough room in buffer\n"); 88738689Sborman setconnmode(0); /* set changed mode */ 88838689Sborman } 88938689Sborman 89032377Sminshall 89127088Sminshall 89238689Sborman /* 89338689Sborman * slc() 89438689Sborman * Handle special character suboption of LINEMODE. 89538689Sborman */ 89638689Sborman 89738689Sborman struct spc { 89838689Sborman char val; 89938689Sborman char *valp; 90038689Sborman char flags; /* Current flags & level */ 90138689Sborman char mylevel; /* Maximum level & flags */ 90238689Sborman } spc_data[NSLC+1]; 90338689Sborman 90438689Sborman #define SLC_IMPORT 0 90538689Sborman #define SLC_EXPORT 1 90638689Sborman #define SLC_RVALUE 2 90738689Sborman static int slc_mode = SLC_EXPORT; 90838689Sborman 90938689Sborman slc_init() 91038689Sborman { 91138689Sborman register struct spc *spcp; 91238689Sborman extern char *tcval(); 91338689Sborman 91438689Sborman localchars = 1; 91538689Sborman for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 91638689Sborman spcp->val = 0; 91738689Sborman spcp->valp = 0; 91838689Sborman spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 91938689Sborman } 92038689Sborman 92138689Sborman #define initfunc(func, flags) { \ 92238689Sborman spcp = &spc_data[func]; \ 92338689Sborman if (spcp->valp = tcval(func)) { \ 92438689Sborman spcp->val = *spcp->valp; \ 92538689Sborman spcp->mylevel = SLC_VARIABLE|flags; \ 92638689Sborman } else { \ 92738689Sborman spcp->val = 0; \ 92838689Sborman spcp->mylevel = SLC_DEFAULT; \ 92938689Sborman } \ 93038689Sborman } 93138689Sborman 93238689Sborman initfunc(SLC_SYNCH, 0); 93338689Sborman /* No BRK */ 93438689Sborman initfunc(SLC_AO, 0); 93538689Sborman initfunc(SLC_AYT, 0); 93638689Sborman /* No EOR */ 93738689Sborman initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 93838689Sborman initfunc(SLC_EOF, 0); 939*39529Sborman #ifndef SYSV_TERMIO 94038689Sborman initfunc(SLC_SUSP, SLC_FLUSHIN); 94138689Sborman #endif 94238689Sborman initfunc(SLC_EC, 0); 94338689Sborman initfunc(SLC_EL, 0); 944*39529Sborman #ifndef SYSV_TERMIO 94538689Sborman initfunc(SLC_EW, 0); 94638689Sborman initfunc(SLC_RP, 0); 94738689Sborman initfunc(SLC_LNEXT, 0); 94838689Sborman #endif 94938689Sborman initfunc(SLC_XON, 0); 95038689Sborman initfunc(SLC_XOFF, 0); 951*39529Sborman #ifdef SYSV_TERMIO 95238689Sborman spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 95338689Sborman spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 95438689Sborman #endif 95538689Sborman /* No FORW1 */ 95638689Sborman /* No FORW2 */ 95738689Sborman 95838689Sborman initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 95938689Sborman #undef initfunc 96038689Sborman 96138689Sborman if (slc_mode == SLC_EXPORT) 96238689Sborman slc_export(); 96338689Sborman else 96438689Sborman slc_import(1); 96538689Sborman 96638689Sborman } 96738689Sborman 96838689Sborman slcstate() 96938689Sborman { 97038689Sborman printf("Special characters are %s values\n", 97138689Sborman slc_mode == SLC_IMPORT ? "remote default" : 97238689Sborman slc_mode == SLC_EXPORT ? "local" : 97338689Sborman "remote"); 97438689Sborman } 97538689Sborman 97638689Sborman slc_mode_export() 97738689Sborman { 97838689Sborman slc_mode = SLC_EXPORT; 97938689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 98038689Sborman slc_export(); 98138689Sborman } 98238689Sborman 98338689Sborman slc_mode_import(def) 98438689Sborman { 98538689Sborman slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 98638689Sborman if (my_state_is_will(TELOPT_LINEMODE)) 98738689Sborman slc_import(def); 98838689Sborman } 98938689Sborman 99038689Sborman char slc_import_val[] = { 99138689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 99238689Sborman }; 99338689Sborman char slc_import_def[] = { 99438689Sborman IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 99538689Sborman }; 99638689Sborman 99738689Sborman slc_import(def) 99838689Sborman int def; 99938689Sborman { 100038689Sborman if (NETROOM() > sizeof(slc_import_val)) { 100138689Sborman if (def) { 100238689Sborman ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 100338689Sborman printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 100438689Sborman } else { 100538689Sborman ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 100638689Sborman printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 100738689Sborman } 100838689Sborman } 100938689Sborman /*@*/ else printf("slc_import: not enough room\n"); 101038689Sborman } 101138689Sborman 101238689Sborman slc_export() 101338689Sborman { 101438689Sborman register struct spc *spcp; 101538689Sborman 101638689Sborman TerminalDefaultChars(); 101738689Sborman 101838689Sborman slc_start_reply(); 101938689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 102038689Sborman if (spcp->mylevel != SLC_NOSUPPORT) { 102138689Sborman spcp->flags = spcp->mylevel; 102238689Sborman if (spcp->valp) 102338689Sborman spcp->val = *spcp->valp; 102438689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 102538689Sborman } 102638689Sborman } 102738689Sborman slc_end_reply(); 102838689Sborman if (slc_update()) 102938689Sborman setconnmode(1); /* set the new character values */ 103038689Sborman } 103138689Sborman 103238689Sborman slc(cp, len) 103338689Sborman register char *cp; 103438689Sborman int len; 103538689Sborman { 103638689Sborman register struct spc *spcp; 103738689Sborman register int func,level; 103838689Sborman 103938689Sborman slc_start_reply(); 104038689Sborman 104138689Sborman for (; len >= 3; len -=3, cp +=3) { 104238689Sborman 104338689Sborman func = cp[SLC_FUNC]; 104438689Sborman 104538689Sborman if (func == 0) { 104638689Sborman /* 104738689Sborman * Client side: always ignore 0 function. 104838689Sborman */ 104938689Sborman continue; 105038689Sborman } 105138689Sborman if (func > NSLC) { 105238689Sborman if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT) 105338689Sborman slc_add_reply(func, SLC_NOSUPPORT, 0); 105438689Sborman continue; 105538689Sborman } 105638689Sborman 105738689Sborman spcp = &spc_data[func]; 105838689Sborman 105938689Sborman level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 106038689Sborman 106138689Sborman if ((cp[SLC_VALUE] == spcp->val) && 106238689Sborman ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 106338689Sborman continue; 106438689Sborman } 106538689Sborman 106638689Sborman if (level == (SLC_DEFAULT|SLC_ACK)) { 106738689Sborman /* 106838689Sborman * This is an error condition, the SLC_ACK 106938689Sborman * bit should never be set for the SLC_DEFAULT 107038689Sborman * level. Our best guess to recover is to 107138689Sborman * ignore the SLC_ACK bit. 107238689Sborman */ 107338689Sborman cp[SLC_FLAGS] &= ~SLC_ACK; 107438689Sborman } 107538689Sborman 107638689Sborman if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 107738689Sborman spcp->val = cp[SLC_VALUE]; 107838689Sborman spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 107938689Sborman continue; 108038689Sborman } 108138689Sborman 108238689Sborman level &= ~SLC_ACK; 108338689Sborman 108438689Sborman if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 108538689Sborman spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 108638689Sborman spcp->val = cp[SLC_VALUE]; 108738689Sborman } 108838689Sborman if (level == SLC_DEFAULT) { 108938689Sborman if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 109038689Sborman spcp->flags = spcp->mylevel; 109138689Sborman else 109238689Sborman spcp->flags = SLC_NOSUPPORT; 109338689Sborman } 109438689Sborman slc_add_reply(func, spcp->flags, spcp->val); 109538689Sborman } 109638689Sborman slc_end_reply(); 109738689Sborman if (slc_update()) 109838689Sborman setconnmode(1); /* set the new character values */ 109938689Sborman } 110038689Sborman 110138689Sborman slc_check() 110238689Sborman { 110338689Sborman register struct spc *spcp; 110438689Sborman 110538689Sborman slc_start_reply(); 110638689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 110738689Sborman if (spcp->valp && spcp->val != *spcp->valp) { 110838689Sborman spcp->val = *spcp->valp; 110938689Sborman slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val); 111038689Sborman } 111138689Sborman } 111238689Sborman slc_end_reply(); 111338689Sborman setconnmode(1); 111438689Sborman } 111538689Sborman 111638689Sborman 111738689Sborman unsigned char slc_reply[128]; 111838689Sborman unsigned char *slc_replyp; 111938689Sborman slc_start_reply() 112038689Sborman { 112138689Sborman slc_replyp = slc_reply; 112238689Sborman *slc_replyp++ = IAC; 112338689Sborman *slc_replyp++ = SB; 112438689Sborman *slc_replyp++ = TELOPT_LINEMODE; 112538689Sborman *slc_replyp++ = LM_SLC; 112638689Sborman } 112738689Sborman 112838689Sborman slc_add_reply(func, flags, value) 112938689Sborman char func; 113038689Sborman char flags; 113138689Sborman char value; 113238689Sborman { 113338689Sborman if ((*slc_replyp++ = func) == IAC) 113438689Sborman *slc_replyp++ = IAC; 113538689Sborman if ((*slc_replyp++ = flags) == IAC) 113638689Sborman *slc_replyp++ = IAC; 113738689Sborman if ((*slc_replyp++ = value) == IAC) 113838689Sborman *slc_replyp++ = IAC; 113938689Sborman } 114038689Sborman 114138689Sborman slc_end_reply() 114238689Sborman { 114338689Sborman register char *cp; 114438689Sborman register int len; 114538689Sborman 114638689Sborman *slc_replyp++ = IAC; 114738689Sborman *slc_replyp++ = SE; 114838689Sborman len = slc_replyp - slc_reply; 114938689Sborman if (len <= 6) 115038689Sborman return; 115138689Sborman if (NETROOM() > len) { 115238689Sborman ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 115338689Sborman printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 115438689Sborman } 115538689Sborman /*@*/else printf("slc_end_reply: not enough room\n"); 115638689Sborman } 115738689Sborman 115838689Sborman slc_update() 115938689Sborman { 116038689Sborman register struct spc *spcp; 116138689Sborman int need_update = 0; 116238689Sborman 116338689Sborman for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 116438689Sborman if (!(spcp->flags&SLC_ACK)) 116538689Sborman continue; 116638689Sborman spcp->flags &= ~SLC_ACK; 116738689Sborman if (spcp->valp && (*spcp->valp != spcp->val)) { 116838689Sborman *spcp->valp = spcp->val; 116938689Sborman need_update = 1; 117038689Sborman } 117138689Sborman } 117238689Sborman return(need_update); 117338689Sborman } 117438689Sborman 117538689Sborman 117638689Sborman 117733804Sminshall int 117832377Sminshall telrcv() 117927110Sminshall { 118032377Sminshall register int c; 118132385Sminshall register int scc; 118232385Sminshall register char *sbp; 118332385Sminshall int count; 118432385Sminshall int returnValue = 0; 118527088Sminshall 118632385Sminshall scc = 0; 118732385Sminshall count = 0; 118832385Sminshall while (TTYROOM() > 2) { 118932385Sminshall if (scc == 0) { 119032385Sminshall if (count) { 119132528Sminshall ring_consumed(&netiring, count); 119232385Sminshall returnValue = 1; 119332385Sminshall count = 0; 119432385Sminshall } 119532528Sminshall sbp = netiring.consume; 119632528Sminshall scc = ring_full_consecutive(&netiring); 119732385Sminshall if (scc == 0) { 119832385Sminshall /* No more data coming in */ 119932385Sminshall break; 120032385Sminshall } 120132385Sminshall } 120232385Sminshall 120332385Sminshall c = *sbp++ & 0xff, scc--; count++; 120432385Sminshall 120532377Sminshall switch (telrcv_state) { 120627110Sminshall 120732377Sminshall case TS_CR: 120832377Sminshall telrcv_state = TS_DATA; 120935518Sminshall if (c == '\0') { 121035518Sminshall break; /* Ignore \0 after CR */ 1211*39529Sborman } 1212*39529Sborman else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 121335518Sminshall TTYADD(c); 121435518Sminshall break; 121532377Sminshall } 121635518Sminshall /* Else, fall through */ 121727088Sminshall 121832377Sminshall case TS_DATA: 121932377Sminshall if (c == IAC) { 122032377Sminshall telrcv_state = TS_IAC; 122133804Sminshall break; 122232377Sminshall } 122332377Sminshall # if defined(TN3270) 122432377Sminshall if (In3270) { 122532377Sminshall *Ifrontp++ = c; 122632385Sminshall while (scc > 0) { 122732385Sminshall c = *sbp++ & 0377, scc--; count++; 122832377Sminshall if (c == IAC) { 122932377Sminshall telrcv_state = TS_IAC; 123034304Sminshall break; 123132377Sminshall } 123232377Sminshall *Ifrontp++ = c; 123332377Sminshall } 123432377Sminshall } else 123532377Sminshall # endif /* defined(TN3270) */ 123635518Sminshall /* 123735518Sminshall * The 'crmod' hack (see following) is needed 123835518Sminshall * since we can't * set CRMOD on output only. 123935518Sminshall * Machines like MULTICS like to send \r without 124035518Sminshall * \n; since we must turn off CRMOD to get proper 124135518Sminshall * input, the mapping is done here (sigh). 124235518Sminshall */ 124338689Sborman if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 124435518Sminshall if (scc > 0) { 124535518Sminshall c = *sbp&0xff; 124635518Sminshall if (c == 0) { 124735518Sminshall sbp++, scc--; count++; 124835518Sminshall /* a "true" CR */ 124932377Sminshall TTYADD('\r'); 125038689Sborman } else if (my_want_state_is_dont(TELOPT_ECHO) && 125135518Sminshall (c == '\n')) { 125235518Sminshall sbp++, scc--; count++; 125332377Sminshall TTYADD('\n'); 125435518Sminshall } else { 125535518Sminshall TTYADD('\r'); 125635518Sminshall if (crmod) { 125735518Sminshall TTYADD('\n'); 125832377Sminshall } 125932377Sminshall } 126035518Sminshall } else { 126135518Sminshall telrcv_state = TS_CR; 126235518Sminshall TTYADD('\r'); 126335518Sminshall if (crmod) { 126435518Sminshall TTYADD('\n'); 126535518Sminshall } 126632377Sminshall } 126732377Sminshall } else { 126832377Sminshall TTYADD(c); 126932377Sminshall } 127032377Sminshall continue; 127127088Sminshall 127232377Sminshall case TS_IAC: 127338689Sborman process_iac: 127432377Sminshall switch (c) { 127532377Sminshall 127632377Sminshall case WILL: 127732377Sminshall telrcv_state = TS_WILL; 127832377Sminshall continue; 127927261Sminshall 128032377Sminshall case WONT: 128132377Sminshall telrcv_state = TS_WONT; 128232377Sminshall continue; 128327261Sminshall 128432377Sminshall case DO: 128532377Sminshall telrcv_state = TS_DO; 128632377Sminshall continue; 128727261Sminshall 128832377Sminshall case DONT: 128932377Sminshall telrcv_state = TS_DONT; 129032377Sminshall continue; 129127261Sminshall 129232377Sminshall case DM: 129332377Sminshall /* 129432377Sminshall * We may have missed an urgent notification, 129532377Sminshall * so make sure we flush whatever is in the 129632377Sminshall * buffer currently. 129732377Sminshall */ 129832377Sminshall SYNCHing = 1; 129932377Sminshall ttyflush(1); 130032554Sminshall SYNCHing = stilloob(); 130132377Sminshall settimer(gotDM); 130232377Sminshall break; 130327088Sminshall 130432377Sminshall case NOP: 130532377Sminshall case GA: 130632377Sminshall break; 130727088Sminshall 130832377Sminshall case SB: 130932377Sminshall SB_CLEAR(); 131032377Sminshall telrcv_state = TS_SB; 131138689Sborman printoption("RCVD", "IAC", SB); 131232377Sminshall continue; 131327261Sminshall 131432377Sminshall # if defined(TN3270) 131532377Sminshall case EOR: 131632377Sminshall if (In3270) { 131732377Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 131832377Sminshall if (Ibackp == Ifrontp) { 131932377Sminshall Ibackp = Ifrontp = Ibuf; 132032377Sminshall ISend = 0; /* should have been! */ 132132377Sminshall } else { 132232377Sminshall ISend = 1; 132327088Sminshall } 132427088Sminshall } 132527088Sminshall break; 132632377Sminshall # endif /* defined(TN3270) */ 132732377Sminshall 132832377Sminshall case IAC: 132932377Sminshall # if !defined(TN3270) 133032377Sminshall TTYADD(IAC); 133132377Sminshall # else /* !defined(TN3270) */ 133232377Sminshall if (In3270) { 133332377Sminshall *Ifrontp++ = IAC; 133432377Sminshall } else { 133532377Sminshall TTYADD(IAC); 133632377Sminshall } 133732377Sminshall # endif /* !defined(TN3270) */ 133827088Sminshall break; 133932377Sminshall 134027088Sminshall default: 134127088Sminshall break; 134227088Sminshall } 134332377Sminshall telrcv_state = TS_DATA; 134432377Sminshall continue; 134527088Sminshall 134632377Sminshall case TS_WILL: 134737226Sminshall printoption("RCVD", "will", c); 134838689Sborman willoption(c); 134932377Sminshall SetIn3270(); 135032377Sminshall telrcv_state = TS_DATA; 135132377Sminshall continue; 135227110Sminshall 135332377Sminshall case TS_WONT: 135437226Sminshall printoption("RCVD", "wont", c); 135538689Sborman wontoption(c); 135632377Sminshall SetIn3270(); 135732377Sminshall telrcv_state = TS_DATA; 135832377Sminshall continue; 135927088Sminshall 136032377Sminshall case TS_DO: 136137226Sminshall printoption("RCVD", "do", c); 136237226Sminshall dooption(c); 136332377Sminshall SetIn3270(); 136437219Sminshall if (c == TELOPT_NAWS) { 136537219Sminshall sendnaws(); 136637219Sminshall } else if (c == TELOPT_LFLOW) { 136737219Sminshall localflow = 1; 136837219Sminshall setcommandmode(); 136938689Sborman setconnmode(0); 137037219Sminshall } 137132377Sminshall telrcv_state = TS_DATA; 137232377Sminshall continue; 137327088Sminshall 137432377Sminshall case TS_DONT: 137537226Sminshall printoption("RCVD", "dont", c); 137638689Sborman dontoption(c); 137737226Sminshall flushline = 1; 137838689Sborman setconnmode(0); /* set new tty mode (maybe) */ 137932377Sminshall SetIn3270(); 138032377Sminshall telrcv_state = TS_DATA; 138132377Sminshall continue; 138227088Sminshall 138332377Sminshall case TS_SB: 138432377Sminshall if (c == IAC) { 138532377Sminshall telrcv_state = TS_SE; 138632377Sminshall } else { 138732377Sminshall SB_ACCUM(c); 138832377Sminshall } 138932377Sminshall continue; 139027088Sminshall 139132377Sminshall case TS_SE: 139232377Sminshall if (c != SE) { 139332377Sminshall if (c != IAC) { 139438689Sborman /* 139538689Sborman * This is an error. We only expect to get 139638689Sborman * "IAC IAC" or "IAC SE". Several things may 139738689Sborman * have happend. An IAC was not doubled, the 139838689Sborman * IAC SE was left off, or another option got 139938689Sborman * inserted into the suboption are all possibilities. 140038689Sborman * If we assume that the IAC was not doubled, 140138689Sborman * and really the IAC SE was left off, we could 140238689Sborman * get into an infinate loop here. So, instead, 140338689Sborman * we terminate the suboption, and process the 140438689Sborman * partial suboption if we can. 140538689Sborman */ 140638689Sborman SB_TERM(); 140732377Sminshall SB_ACCUM(IAC); 140838689Sborman SB_ACCUM(c); 140938689Sborman printoption("In SUBOPTION processing, RCVD", "IAC", c); 141038689Sborman suboption(); /* handle sub-option */ 141138689Sborman SetIn3270(); 141238689Sborman telrcv_state = TS_IAC; 141338689Sborman goto process_iac; 141432377Sminshall } 141532377Sminshall SB_ACCUM(c); 141632377Sminshall telrcv_state = TS_SB; 141732377Sminshall } else { 141832377Sminshall SB_TERM(); 141938689Sborman SB_ACCUM(IAC); 142038689Sborman SB_ACCUM(SE); 142132377Sminshall suboption(); /* handle sub-option */ 142232377Sminshall SetIn3270(); 142332377Sminshall telrcv_state = TS_DATA; 142432377Sminshall } 142527088Sminshall } 142627088Sminshall } 142732667Sminshall if (count) 142832667Sminshall ring_consumed(&netiring, count); 142932385Sminshall return returnValue||count; 143027088Sminshall } 143132385Sminshall 143232385Sminshall static int 143332554Sminshall telsnd() 143432385Sminshall { 143532385Sminshall int tcc; 143632385Sminshall int count; 143732385Sminshall int returnValue = 0; 143832385Sminshall char *tbp; 143932385Sminshall 144032385Sminshall tcc = 0; 144132385Sminshall count = 0; 144232385Sminshall while (NETROOM() > 2) { 144332385Sminshall register int sc; 144432385Sminshall register int c; 144532385Sminshall 144632385Sminshall if (tcc == 0) { 144732385Sminshall if (count) { 144832528Sminshall ring_consumed(&ttyiring, count); 144932385Sminshall returnValue = 1; 145032385Sminshall count = 0; 145132385Sminshall } 145232528Sminshall tbp = ttyiring.consume; 145332528Sminshall tcc = ring_full_consecutive(&ttyiring); 145432385Sminshall if (tcc == 0) { 145532385Sminshall break; 145632385Sminshall } 145732385Sminshall } 145832385Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 145932385Sminshall if (sc == escape) { 146038689Sborman /* 146138689Sborman * Double escape is a pass through of a single escape character. 146238689Sborman */ 146338689Sborman if (tcc && strip(*tbp) == escape) { 146438689Sborman tbp++; 146538689Sborman tcc--; 146638689Sborman count++; 146738689Sborman } else { 146838689Sborman command(0, tbp, tcc); 146938689Sborman count += tcc; 147038689Sborman tcc = 0; 147138689Sborman flushline = 1; 147238689Sborman break; 147338689Sborman } 147438689Sborman } 147538689Sborman #ifdef KLUDGELINEMODE 147638689Sborman if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 147732385Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 147832385Sminshall tcc--; tbp++; count++; 147932385Sminshall } else { 148032385Sminshall dontlecho = !dontlecho; 148132385Sminshall settimer(echotoggle); 148238689Sborman setconnmode(0); 148332385Sminshall flushline = 1; 148432385Sminshall break; 148532385Sminshall } 148632385Sminshall } 148738689Sborman #endif 148838689Sborman if (MODE_LOCAL_CHARS(globalmode)) { 148932385Sminshall if (TerminalSpecialChars(sc) == 0) { 149032385Sminshall break; 149132385Sminshall } 149232385Sminshall } 149338689Sborman if (my_want_state_is_wont(TELOPT_BINARY)) { 149432385Sminshall switch (c) { 149532385Sminshall case '\n': 149632385Sminshall /* 149732385Sminshall * If we are in CRMOD mode (\r ==> \n) 149832385Sminshall * on our local machine, then probably 149932385Sminshall * a newline (unix) is CRLF (TELNET). 150032385Sminshall */ 150132385Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 150232385Sminshall NETADD('\r'); 150332385Sminshall } 150432385Sminshall NETADD('\n'); 150532385Sminshall flushline = 1; 150632385Sminshall break; 150732385Sminshall case '\r': 150832385Sminshall if (!crlf) { 150932385Sminshall NET2ADD('\r', '\0'); 151032385Sminshall } else { 151132385Sminshall NET2ADD('\r', '\n'); 151232385Sminshall } 151332385Sminshall flushline = 1; 151432385Sminshall break; 151532385Sminshall case IAC: 151632385Sminshall NET2ADD(IAC, IAC); 151732385Sminshall break; 151832385Sminshall default: 151932385Sminshall NETADD(c); 152032385Sminshall break; 152132385Sminshall } 152232385Sminshall } else if (c == IAC) { 152332385Sminshall NET2ADD(IAC, IAC); 152432385Sminshall } else { 152532385Sminshall NETADD(c); 152632385Sminshall } 152732385Sminshall } 152832667Sminshall if (count) 152932667Sminshall ring_consumed(&ttyiring, count); 153032385Sminshall return returnValue||count; /* Non-zero if we did anything */ 153132385Sminshall } 153232377Sminshall 153327088Sminshall /* 153432377Sminshall * Scheduler() 153532377Sminshall * 153632377Sminshall * Try to do something. 153732377Sminshall * 153832377Sminshall * If we do something useful, return 1; else return 0. 153932377Sminshall * 154027110Sminshall */ 154127110Sminshall 154227110Sminshall 154332377Sminshall int 154432377Sminshall Scheduler(block) 154532377Sminshall int block; /* should we block in the select ? */ 154627110Sminshall { 154732377Sminshall /* One wants to be a bit careful about setting returnValue 154832377Sminshall * to one, since a one implies we did some useful work, 154932377Sminshall * and therefore probably won't be called to block next 155032377Sminshall * time (TN3270 mode only). 155132377Sminshall */ 155232531Sminshall int returnValue; 155332531Sminshall int netin, netout, netex, ttyin, ttyout; 155427110Sminshall 155532531Sminshall /* Decide which rings should be processed */ 155632531Sminshall 155732531Sminshall netout = ring_full_count(&netoring) && 155838689Sborman (flushline || 155938689Sborman (my_want_state_is_wont(TELOPT_LINEMODE) 156038689Sborman #ifdef KLUDGELINEMODE 156138689Sborman && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 156238689Sborman #endif 156338689Sborman ) || 156438689Sborman my_want_state_is_will(TELOPT_BINARY)); 156532531Sminshall ttyout = ring_full_count(&ttyoring); 156632531Sminshall 156732377Sminshall #if defined(TN3270) 156832531Sminshall ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); 156932377Sminshall #else /* defined(TN3270) */ 157032531Sminshall ttyin = ring_empty_count(&ttyiring); 157132377Sminshall #endif /* defined(TN3270) */ 157232531Sminshall 157332531Sminshall #if defined(TN3270) 157432531Sminshall netin = ring_empty_count(&netiring); 157532377Sminshall # else /* !defined(TN3270) */ 157632531Sminshall netin = !ISend && ring_empty_count(&netiring); 157732377Sminshall # endif /* !defined(TN3270) */ 157832531Sminshall 157932531Sminshall netex = !SYNCHing; 158032531Sminshall 158132531Sminshall /* If we have seen a signal recently, reset things */ 158232377Sminshall # if defined(TN3270) && defined(unix) 158332377Sminshall if (HaveInput) { 158432377Sminshall HaveInput = 0; 158532377Sminshall signal(SIGIO, inputAvailable); 158632377Sminshall } 158732377Sminshall #endif /* defined(TN3270) && defined(unix) */ 158832377Sminshall 158932531Sminshall /* Call to system code to process rings */ 159027178Sminshall 159132531Sminshall returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 159227178Sminshall 159332531Sminshall /* Now, look at the input rings, looking for work to do. */ 159432377Sminshall 159532531Sminshall if (ring_full_count(&ttyiring)) { 159632377Sminshall # if defined(TN3270) 159732377Sminshall if (In3270) { 159834848Sminshall int c; 159934848Sminshall 160033804Sminshall c = DataFromTerminal(ttyiring.consume, 160132528Sminshall ring_full_consecutive(&ttyiring)); 160232377Sminshall if (c) { 160332377Sminshall returnValue = 1; 160432667Sminshall ring_consumed(&ttyiring, c); 160532377Sminshall } 160632377Sminshall } else { 160732377Sminshall # endif /* defined(TN3270) */ 160832554Sminshall returnValue |= telsnd(); 160932377Sminshall # if defined(TN3270) 161027178Sminshall } 161132531Sminshall # endif /* defined(TN3270) */ 161227178Sminshall } 161332377Sminshall 161432528Sminshall if (ring_full_count(&netiring)) { 161532377Sminshall # if !defined(TN3270) 161632385Sminshall returnValue |= telrcv(); 161732377Sminshall # else /* !defined(TN3270) */ 161832377Sminshall returnValue = Push3270(); 161932377Sminshall # endif /* !defined(TN3270) */ 162032377Sminshall } 162132377Sminshall return returnValue; 162227178Sminshall } 162327178Sminshall 162427178Sminshall /* 162532377Sminshall * Select from tty and network... 162627088Sminshall */ 162732377Sminshall void 162832377Sminshall telnet() 162927088Sminshall { 163032531Sminshall sys_telnet_init(); 163127088Sminshall 163232377Sminshall # if !defined(TN3270) 163332377Sminshall if (telnetport) { 163438689Sborman send_do(TELOPT_SGA, 1); 163538689Sborman send_will(TELOPT_TTYPE, 1); 163638689Sborman send_will(TELOPT_NAWS, 1); 163738689Sborman send_will(TELOPT_TSPEED, 1); 163838689Sborman send_will(TELOPT_LFLOW, 1); 163938689Sborman send_will(TELOPT_LINEMODE, 1); 164038908Sborman send_do(TELOPT_STATUS, 1); 164127178Sminshall } 164232377Sminshall # endif /* !defined(TN3270) */ 164327088Sminshall 164432377Sminshall # if !defined(TN3270) 164532377Sminshall for (;;) { 164632385Sminshall int schedValue; 164732385Sminshall 164832385Sminshall while ((schedValue = Scheduler(0)) != 0) { 164932385Sminshall if (schedValue == -1) { 165032385Sminshall setcommandmode(); 165132385Sminshall return; 165232385Sminshall } 165332385Sminshall } 165432385Sminshall 165532531Sminshall if (Scheduler(1) == -1) { 165632377Sminshall setcommandmode(); 165732377Sminshall return; 165832377Sminshall } 165932377Sminshall } 166032377Sminshall # else /* !defined(TN3270) */ 166132377Sminshall for (;;) { 166232377Sminshall int schedValue; 166327088Sminshall 166432377Sminshall while (!In3270 && !shell_active) { 166532531Sminshall if (Scheduler(1) == -1) { 166632377Sminshall setcommandmode(); 166732377Sminshall return; 166832377Sminshall } 166927088Sminshall } 167032377Sminshall 167132377Sminshall while ((schedValue = Scheduler(0)) != 0) { 167232377Sminshall if (schedValue == -1) { 167332377Sminshall setcommandmode(); 167432377Sminshall return; 167532377Sminshall } 167627088Sminshall } 167732377Sminshall /* If there is data waiting to go out to terminal, don't 167832377Sminshall * schedule any more data for the terminal. 167932377Sminshall */ 168034304Sminshall if (ring_full_count(&ttyoring)) { 168132377Sminshall schedValue = 1; 168227088Sminshall } else { 168332377Sminshall if (shell_active) { 168432377Sminshall if (shell_continue() == 0) { 168532377Sminshall ConnectScreen(); 168627088Sminshall } 168732377Sminshall } else if (In3270) { 168832377Sminshall schedValue = DoTerminalOutput(); 168932377Sminshall } 169027088Sminshall } 169132377Sminshall if (schedValue && (shell_active == 0)) { 169232531Sminshall if (Scheduler(1) == -1) { 169332377Sminshall setcommandmode(); 169432377Sminshall return; 169532377Sminshall } 169627088Sminshall } 169732377Sminshall } 169832377Sminshall # endif /* !defined(TN3270) */ 169927088Sminshall } 170032377Sminshall 170134848Sminshall #if 0 /* XXX - this not being in is a bug */ 170227088Sminshall /* 170332554Sminshall * nextitem() 170432554Sminshall * 170532554Sminshall * Return the address of the next "item" in the TELNET data 170632554Sminshall * stream. This will be the address of the next character if 170732554Sminshall * the current address is a user data character, or it will 170832554Sminshall * be the address of the character following the TELNET command 170932554Sminshall * if the current address is a TELNET IAC ("I Am a Command") 171032554Sminshall * character. 171132554Sminshall */ 171232554Sminshall 171332554Sminshall static char * 171432554Sminshall nextitem(current) 171532554Sminshall char *current; 171632554Sminshall { 171732554Sminshall if ((*current&0xff) != IAC) { 171832554Sminshall return current+1; 171932554Sminshall } 172032554Sminshall switch (*(current+1)&0xff) { 172132554Sminshall case DO: 172232554Sminshall case DONT: 172332554Sminshall case WILL: 172432554Sminshall case WONT: 172532554Sminshall return current+3; 172632554Sminshall case SB: /* loop forever looking for the SE */ 172732554Sminshall { 172832554Sminshall register char *look = current+2; 172932554Sminshall 173032554Sminshall for (;;) { 173132554Sminshall if ((*look++&0xff) == IAC) { 173232554Sminshall if ((*look++&0xff) == SE) { 173332554Sminshall return look; 173432554Sminshall } 173532554Sminshall } 173632554Sminshall } 173732554Sminshall } 173832554Sminshall default: 173932554Sminshall return current+2; 174032554Sminshall } 174132554Sminshall } 174234848Sminshall #endif /* 0 */ 174332554Sminshall 174432554Sminshall /* 174532554Sminshall * netclear() 174632554Sminshall * 174732554Sminshall * We are about to do a TELNET SYNCH operation. Clear 174832554Sminshall * the path to the network. 174932554Sminshall * 175032554Sminshall * Things are a bit tricky since we may have sent the first 175132554Sminshall * byte or so of a previous TELNET command into the network. 175232554Sminshall * So, we have to scan the network buffer from the beginning 175332554Sminshall * until we are up to where we want to be. 175432554Sminshall * 175532554Sminshall * A side effect of what we do, just to keep things 175632554Sminshall * simple, is to clear the urgent data pointer. The principal 175732554Sminshall * caller should be setting the urgent data pointer AFTER calling 175832554Sminshall * us in any case. 175932554Sminshall */ 176032554Sminshall 176132554Sminshall static void 176232554Sminshall netclear() 176332554Sminshall { 176432554Sminshall #if 0 /* XXX */ 176532554Sminshall register char *thisitem, *next; 176632554Sminshall char *good; 176732554Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 176832554Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 176932554Sminshall 177032554Sminshall thisitem = netobuf; 177132554Sminshall 177232554Sminshall while ((next = nextitem(thisitem)) <= netobuf.send) { 177332554Sminshall thisitem = next; 177432554Sminshall } 177532554Sminshall 177632554Sminshall /* Now, thisitem is first before/at boundary. */ 177732554Sminshall 177832554Sminshall good = netobuf; /* where the good bytes go */ 177932554Sminshall 178032554Sminshall while (netoring.add > thisitem) { 178132554Sminshall if (wewant(thisitem)) { 178232554Sminshall int length; 178332554Sminshall 178432554Sminshall next = thisitem; 178532554Sminshall do { 178632554Sminshall next = nextitem(next); 178732554Sminshall } while (wewant(next) && (nfrontp > next)); 178832554Sminshall length = next-thisitem; 178932554Sminshall memcpy(good, thisitem, length); 179032554Sminshall good += length; 179132554Sminshall thisitem = next; 179232554Sminshall } else { 179332554Sminshall thisitem = nextitem(thisitem); 179432554Sminshall } 179532554Sminshall } 179632554Sminshall 179732554Sminshall #endif /* 0 */ 179832554Sminshall } 179932554Sminshall 180032554Sminshall /* 180132377Sminshall * These routines add various telnet commands to the data stream. 180227088Sminshall */ 180332377Sminshall 180432554Sminshall static void 180532554Sminshall doflush() 180632554Sminshall { 180732554Sminshall NET2ADD(IAC, DO); 180832554Sminshall NETADD(TELOPT_TM); 180932554Sminshall flushline = 1; 181032554Sminshall flushout = 1; 181132554Sminshall ttyflush(1); /* Flush/drop output */ 181232554Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 181337226Sminshall printoption("SENT", "do", TELOPT_TM); 181432554Sminshall } 181532554Sminshall 181632377Sminshall void 181732377Sminshall xmitAO() 181827088Sminshall { 181932377Sminshall NET2ADD(IAC, AO); 182038908Sborman printoption("SENT", "IAC", AO); 182132377Sminshall if (autoflush) { 182232377Sminshall doflush(); 182332377Sminshall } 182432377Sminshall } 182527088Sminshall 182632377Sminshall 182732377Sminshall void 182832377Sminshall xmitEL() 182927088Sminshall { 183032377Sminshall NET2ADD(IAC, EL); 183138908Sborman printoption("SENT", "IAC", EL); 183227088Sminshall } 183327088Sminshall 183432377Sminshall void 183532377Sminshall xmitEC() 183627088Sminshall { 183732377Sminshall NET2ADD(IAC, EC); 183838908Sborman printoption("SENT", "IAC", EC); 183927088Sminshall } 184027088Sminshall 184132377Sminshall 184232377Sminshall #if defined(NOT43) 184332377Sminshall int 184432377Sminshall #else /* defined(NOT43) */ 184532377Sminshall void 184632377Sminshall #endif /* defined(NOT43) */ 184732377Sminshall dosynch() 184827088Sminshall { 184932377Sminshall netclear(); /* clear the path to the network */ 185033294Sminshall NETADD(IAC); 185133294Sminshall setneturg(); 185233294Sminshall NETADD(DM); 185338908Sborman printoption("SENT", "IAC", DM); 185427088Sminshall 185532377Sminshall #if defined(NOT43) 185632377Sminshall return 0; 185732377Sminshall #endif /* defined(NOT43) */ 185827088Sminshall } 185927088Sminshall 186032377Sminshall void 186138908Sborman get_status() 186238908Sborman { 186338908Sborman char tmp[16]; 186438908Sborman register char *cp; 186538908Sborman 186638908Sborman if (my_want_state_is_dont(TELOPT_STATUS)) { 186738908Sborman printf("Remote side does not support STATUS option\n"); 186838908Sborman return; 186938908Sborman } 187038908Sborman if (!showoptions) 187138908Sborman printf("You will not see the response unless you set \"options\"\n"); 187238908Sborman 187338908Sborman cp = tmp; 187438908Sborman 187538908Sborman *cp++ = IAC; 187638908Sborman *cp++ = SB; 187738908Sborman *cp++ = TELOPT_STATUS; 187838908Sborman *cp++ = TELQUAL_SEND; 187938908Sborman *cp++ = IAC; 188038908Sborman *cp++ = SE; 188138908Sborman if (NETROOM() >= cp - tmp) { 188238908Sborman ring_supply_data(&netoring, tmp, cp-tmp); 188338908Sborman printsub('>', tmp+2, cp - tmp - 2); 188438908Sborman } 188538908Sborman } 188638908Sborman 188738908Sborman void 188832377Sminshall intp() 188927088Sminshall { 189032377Sminshall NET2ADD(IAC, IP); 189138908Sborman printoption("SENT", "IAC", IP); 189232377Sminshall flushline = 1; 189332377Sminshall if (autoflush) { 189432377Sminshall doflush(); 189532377Sminshall } 189632377Sminshall if (autosynch) { 189732377Sminshall dosynch(); 189832377Sminshall } 189927088Sminshall } 190027186Sminshall 190132377Sminshall void 190232377Sminshall sendbrk() 190327186Sminshall { 190432377Sminshall NET2ADD(IAC, BREAK); 190538908Sborman printoption("SENT", "IAC", BREAK); 190632377Sminshall flushline = 1; 190732377Sminshall if (autoflush) { 190832377Sminshall doflush(); 190932377Sminshall } 191032377Sminshall if (autosynch) { 191132377Sminshall dosynch(); 191232377Sminshall } 191327186Sminshall } 191438689Sborman 191538689Sborman void 191638689Sborman sendabort() 191738689Sborman { 191838689Sborman NET2ADD(IAC, ABORT); 191938908Sborman printoption("SENT", "IAC", ABORT); 192038689Sborman flushline = 1; 192138689Sborman if (autoflush) { 192238689Sborman doflush(); 192338689Sborman } 192438689Sborman if (autosynch) { 192538689Sborman dosynch(); 192638689Sborman } 192738689Sborman } 192838689Sborman 192938689Sborman void 193038689Sborman sendsusp() 193138689Sborman { 193238689Sborman NET2ADD(IAC, SUSP); 193338908Sborman printoption("SENT", "IAC", SUSP); 193438689Sborman flushline = 1; 193538689Sborman if (autoflush) { 193638689Sborman doflush(); 193738689Sborman } 193838689Sborman if (autosynch) { 193938689Sborman dosynch(); 194038689Sborman } 194138689Sborman } 194238689Sborman 194338689Sborman void 194438689Sborman sendeof() 194538689Sborman { 194638908Sborman NET2ADD(IAC, xEOF); 194738908Sborman printoption("SENT", "IAC", xEOF); 194838689Sborman } 194938689Sborman 195037219Sminshall /* 195137219Sminshall * Send a window size update to the remote system. 195237219Sminshall */ 195337219Sminshall 195437219Sminshall void 195537219Sminshall sendnaws() 195637219Sminshall { 195737219Sminshall long rows, cols; 195838689Sborman unsigned char tmp[16]; 195938689Sborman register unsigned char *cp; 196037219Sminshall 196138689Sborman if (my_state_is_wont(TELOPT_NAWS)) 196238689Sborman return; 196337219Sminshall 196438689Sborman #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 196538689Sborman if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 196638689Sborman 196737219Sminshall if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 196837219Sminshall return; 196937219Sminshall } 197037219Sminshall 197138689Sborman cp = tmp; 197238689Sborman 197338689Sborman *cp++ = IAC; 197438689Sborman *cp++ = SB; 197538689Sborman *cp++ = TELOPT_NAWS; 197638689Sborman PUTSHORT(cp, cols); 197738689Sborman PUTSHORT(cp, rows); 197838689Sborman *cp++ = IAC; 197938689Sborman *cp++ = SE; 198038689Sborman if (NETROOM() >= cp - tmp) { 198138689Sborman ring_supply_data(&netoring, tmp, cp-tmp); 198238689Sborman printsub('>', tmp+2, cp - tmp - 2); 198337219Sminshall } 198437219Sminshall } 198537226Sminshall 198638908Sborman tel_enter_binary(rw) 198738908Sborman int rw; 198837226Sminshall { 198938908Sborman if (rw&1) 199038908Sborman send_do(TELOPT_BINARY, 1); 199138908Sborman if (rw&2) 199238908Sborman send_will(TELOPT_BINARY, 1); 199337226Sminshall } 199437226Sminshall 199538908Sborman tel_leave_binary(rw) 199638908Sborman int rw; 199737226Sminshall { 199838908Sborman if (rw&1) 199938908Sborman send_dont(TELOPT_BINARY, 1); 200038908Sborman if (rw&2) 200138908Sborman send_wont(TELOPT_BINARY, 1); 200237226Sminshall } 2003