telnet.c revision 114911
129088Smarkm/* 229088Smarkm * Copyright (c) 1988, 1990, 1993 329088Smarkm * The Regents of the University of California. All rights reserved. 429088Smarkm * 529088Smarkm * Redistribution and use in source and binary forms, with or without 629088Smarkm * modification, are permitted provided that the following conditions 729088Smarkm * are met: 829088Smarkm * 1. Redistributions of source code must retain the above copyright 929088Smarkm * notice, this list of conditions and the following disclaimer. 1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1129088Smarkm * notice, this list of conditions and the following disclaimer in the 1229088Smarkm * documentation and/or other materials provided with the distribution. 1329088Smarkm * 3. All advertising materials mentioning features or use of this software 1429088Smarkm * must display the following acknowledgement: 1529088Smarkm * This product includes software developed by the University of 1629088Smarkm * California, Berkeley and its contributors. 1729088Smarkm * 4. Neither the name of the University nor the names of its contributors 1829088Smarkm * may be used to endorse or promote products derived from this software 1929088Smarkm * without specific prior written permission. 2029088Smarkm * 2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2429088Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3129088Smarkm * SUCH DAMAGE. 3229088Smarkm */ 3329088Smarkm 34114630Sobrien#if 0 3529088Smarkm#ifndef lint 3629181Smarkmstatic const char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; 3763248Speter#endif 38114630Sobrien#endif 39114630Sobrien#include <sys/cdefs.h> 40114630Sobrien__FBSDID("$FreeBSD: head/contrib/telnet/telnet/telnet.c 114911 2003-05-11 18:17:00Z markm $"); 4129088Smarkm 4229088Smarkm#include <sys/types.h> 4329088Smarkm 4429088Smarkm/* By the way, we need to include curses.h before telnet.h since, 4529088Smarkm * among other things, telnet.h #defines 'DO', which is a variable 4629088Smarkm * declared in curses.h. 4729088Smarkm */ 4829088Smarkm 4929088Smarkm#include <ctype.h> 5087139Smarkm#include <curses.h> 5187139Smarkm#include <signal.h> 5229181Smarkm#include <stdlib.h> 5387139Smarkm#include <term.h> 5429181Smarkm#include <unistd.h> 5587139Smarkm#include <arpa/telnet.h> 5629181Smarkm 5729088Smarkm#include "ring.h" 5829088Smarkm 5929088Smarkm#include "defines.h" 6029088Smarkm#include "externs.h" 6129088Smarkm#include "types.h" 6229088Smarkm#include "general.h" 6329088Smarkm 6487139Smarkm#ifdef AUTHENTICATION 6529181Smarkm#include <libtelnet/auth.h> 6629181Smarkm#endif 6787139Smarkm#ifdef ENCRYPTION 6829181Smarkm#include <libtelnet/encrypt.h> 6929181Smarkm#endif 7029181Smarkm#include <libtelnet/misc.h> 7129088Smarkm 7229088Smarkm#define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x)) 7329088Smarkm 7429088Smarkmstatic unsigned char subbuffer[SUBBUFSIZE], 7529088Smarkm *subpointer, *subend; /* buffer for sub-options */ 7629088Smarkm#define SB_CLEAR() subpointer = subbuffer; 7729088Smarkm#define SB_TERM() { subend = subpointer; SB_CLEAR(); } 7829088Smarkm#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 7929088Smarkm *subpointer++ = (c); \ 8029088Smarkm } 8129088Smarkm 8229088Smarkm#define SB_GET() ((*subpointer++)&0xff) 8329088Smarkm#define SB_PEEK() ((*subpointer)&0xff) 8429088Smarkm#define SB_EOF() (subpointer >= subend) 8529088Smarkm#define SB_LEN() (subend - subpointer) 8629088Smarkm 8729088Smarkmchar options[256]; /* The combined options */ 8829088Smarkmchar do_dont_resp[256]; 8929088Smarkmchar will_wont_resp[256]; 9029088Smarkm 9129088Smarkmint 9229088Smarkm eight = 0, 9329088Smarkm autologin = 0, /* Autologin anyone? */ 9429088Smarkm skiprc = 0, 9529088Smarkm connected, 9629088Smarkm showoptions, 9729088Smarkm ISend, /* trying to send network data in */ 98114911Smarkm telnet_debug = 0, 9929088Smarkm crmod, 10029088Smarkm netdata, /* Print out network data flow */ 10129088Smarkm crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 10229088Smarkm telnetport, 10329088Smarkm SYNCHing, /* we are in TELNET SYNCH mode */ 10429088Smarkm flushout, /* flush output */ 10529088Smarkm autoflush = 0, /* flush output when interrupting? */ 10629088Smarkm autosynch, /* send interrupt characters with SYNCH? */ 10729088Smarkm localflow, /* we handle flow control locally */ 10829088Smarkm restartany, /* if flow control enabled, restart on any character */ 10929088Smarkm localchars, /* we recognize interrupt/quit */ 11029088Smarkm donelclchars, /* the user has set "localchars" */ 11129088Smarkm donebinarytoggle, /* the user has put us in binary */ 11229088Smarkm dontlecho, /* do we suppress local echoing right now? */ 11329181Smarkm globalmode, 11447973Sru doaddrlookup = 1, /* do a reverse address lookup? */ 11529181Smarkm clienteof = 0; 11629088Smarkm 11729088Smarkmchar *prompt = 0; 11881965Smarkm#ifdef ENCRYPTION 11976616Speterchar *line; /* hack around breakage in sra.c :-( !! */ 12081965Smarkm#endif 12129088Smarkm 12229088Smarkmcc_t escape; 12329088Smarkmcc_t rlogin; 12429088Smarkm#ifdef KLUDGELINEMODE 12529088Smarkmcc_t echoc; 12629088Smarkm#endif 12729088Smarkm 12829088Smarkm/* 12929088Smarkm * Telnet receiver states for fsm 13029088Smarkm */ 13129088Smarkm#define TS_DATA 0 13229088Smarkm#define TS_IAC 1 13329088Smarkm#define TS_WILL 2 13429088Smarkm#define TS_WONT 3 13529088Smarkm#define TS_DO 4 13629088Smarkm#define TS_DONT 5 13729088Smarkm#define TS_CR 6 13829088Smarkm#define TS_SB 7 /* sub-option collection */ 13929088Smarkm#define TS_SE 8 /* looking for sub-option end */ 14029088Smarkm 14129088Smarkmstatic int telrcv_state; 14229088Smarkm#ifdef OLD_ENVIRON 14329088Smarkmunsigned char telopt_environ = TELOPT_NEW_ENVIRON; 14429088Smarkm#else 14529088Smarkm# define telopt_environ TELOPT_NEW_ENVIRON 14629088Smarkm#endif 14729088Smarkm 14887139Smarkmjmp_buf toplevel; 14929088Smarkmjmp_buf peerdied; 15029088Smarkm 15129088Smarkmint flushline; 15229088Smarkmint linemode; 15329088Smarkm 15429088Smarkm#ifdef KLUDGELINEMODE 15529088Smarkmint kludgelinemode = 1; 15629088Smarkm#endif 15729088Smarkm 15887139Smarkmstatic int is_unique(char *, char **, char **); 15987139Smarkm 16029088Smarkm/* 16129088Smarkm * The following are some clocks used to decide how to interpret 16229088Smarkm * the relationship between various variables. 16329088Smarkm */ 16429088Smarkm 16529088SmarkmClocks clocks; 16629088Smarkm 16729088Smarkm/* 16829088Smarkm * Initialize telnet environment. 16929088Smarkm */ 17029088Smarkm 17187139Smarkmvoid 17287139Smarkminit_telnet(void) 17329088Smarkm{ 17429088Smarkm env_init(); 17529088Smarkm 17629088Smarkm SB_CLEAR(); 17729088Smarkm ClearArray(options); 17829088Smarkm 17987139Smarkm connected = ISend = localflow = donebinarytoggle = 0; 18087139Smarkm#ifdef AUTHENTICATION 18187139Smarkm#ifdef ENCRYPTION 18229088Smarkm auth_encrypt_connect(connected); 18387139Smarkm#endif 18487139Smarkm#endif 18529088Smarkm restartany = -1; 18629088Smarkm 18729088Smarkm SYNCHing = 0; 18829088Smarkm 18929088Smarkm /* Don't change NetTrace */ 19029088Smarkm 19129088Smarkm escape = CONTROL(']'); 19229088Smarkm rlogin = _POSIX_VDISABLE; 19329088Smarkm#ifdef KLUDGELINEMODE 19429088Smarkm echoc = CONTROL('E'); 19529088Smarkm#endif 19629088Smarkm 19729088Smarkm flushline = 1; 19829088Smarkm telrcv_state = TS_DATA; 19929088Smarkm} 20029088Smarkm 20129088Smarkm 20229088Smarkm/* 20329088Smarkm * These routines are in charge of sending option negotiations 20429088Smarkm * to the other side. 20529088Smarkm * 20629088Smarkm * The basic idea is that we send the negotiation if either side 20729088Smarkm * is in disagreement as to what the current state should be. 20829088Smarkm */ 20929088Smarkm 21087139Smarkmvoid 21187139Smarkmsend_do(int c, int init) 21229088Smarkm{ 21329088Smarkm if (init) { 21429088Smarkm if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 21529088Smarkm my_want_state_is_do(c)) 21629088Smarkm return; 21729088Smarkm set_my_want_state_do(c); 21829088Smarkm do_dont_resp[c]++; 21929088Smarkm } 22029088Smarkm NET2ADD(IAC, DO); 22129088Smarkm NETADD(c); 22229088Smarkm printoption("SENT", DO, c); 22329088Smarkm} 22429088Smarkm 22587139Smarkmvoid 22687139Smarkmsend_dont(int c, int init) 22729088Smarkm{ 22829088Smarkm if (init) { 22929088Smarkm if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 23029088Smarkm my_want_state_is_dont(c)) 23129088Smarkm return; 23229088Smarkm set_my_want_state_dont(c); 23329088Smarkm do_dont_resp[c]++; 23429088Smarkm } 23529088Smarkm NET2ADD(IAC, DONT); 23629088Smarkm NETADD(c); 23729088Smarkm printoption("SENT", DONT, c); 23829088Smarkm} 23929088Smarkm 24087139Smarkmvoid 24187139Smarkmsend_will(int c, int init) 24229088Smarkm{ 24329088Smarkm if (init) { 24429088Smarkm if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 24529088Smarkm my_want_state_is_will(c)) 24629088Smarkm return; 24729088Smarkm set_my_want_state_will(c); 24829088Smarkm will_wont_resp[c]++; 24929088Smarkm } 25029088Smarkm NET2ADD(IAC, WILL); 25129088Smarkm NETADD(c); 25229088Smarkm printoption("SENT", WILL, c); 25329088Smarkm} 25429088Smarkm 25587139Smarkmvoid 25687139Smarkmsend_wont(int c, int init) 25729088Smarkm{ 25829088Smarkm if (init) { 25929088Smarkm if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 26029088Smarkm my_want_state_is_wont(c)) 26129088Smarkm return; 26229088Smarkm set_my_want_state_wont(c); 26329088Smarkm will_wont_resp[c]++; 26429088Smarkm } 26529088Smarkm NET2ADD(IAC, WONT); 26629088Smarkm NETADD(c); 26729088Smarkm printoption("SENT", WONT, c); 26829088Smarkm} 26929088Smarkm 27087139Smarkmvoid 27187139Smarkmwilloption(int option) 27229088Smarkm{ 27329088Smarkm int new_state_ok = 0; 27429088Smarkm 27529088Smarkm if (do_dont_resp[option]) { 27629088Smarkm --do_dont_resp[option]; 27729088Smarkm if (do_dont_resp[option] && my_state_is_do(option)) 27829088Smarkm --do_dont_resp[option]; 27929088Smarkm } 28029088Smarkm 28129088Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 28229088Smarkm 28329088Smarkm switch (option) { 28429088Smarkm 28529088Smarkm case TELOPT_ECHO: 28629088Smarkm case TELOPT_BINARY: 28729088Smarkm case TELOPT_SGA: 28829088Smarkm settimer(modenegotiated); 289103955Smarkm /* FALLTHROUGH */ 29029088Smarkm case TELOPT_STATUS: 29187139Smarkm#ifdef AUTHENTICATION 29229088Smarkm case TELOPT_AUTHENTICATION: 29329088Smarkm#endif 29429088Smarkm#ifdef ENCRYPTION 29529088Smarkm case TELOPT_ENCRYPT: 29629088Smarkm#endif /* ENCRYPTION */ 29729088Smarkm new_state_ok = 1; 29829088Smarkm break; 29929088Smarkm 30029088Smarkm case TELOPT_TM: 30129088Smarkm if (flushout) 30229088Smarkm flushout = 0; 30329088Smarkm /* 30429088Smarkm * Special case for TM. If we get back a WILL, 30529088Smarkm * pretend we got back a WONT. 30629088Smarkm */ 30729088Smarkm set_my_want_state_dont(option); 30829088Smarkm set_my_state_dont(option); 30929088Smarkm return; /* Never reply to TM will's/wont's */ 31029088Smarkm 31129088Smarkm case TELOPT_LINEMODE: 31229088Smarkm default: 31329088Smarkm break; 31429088Smarkm } 31529088Smarkm 31629088Smarkm if (new_state_ok) { 31729088Smarkm set_my_want_state_do(option); 31829088Smarkm send_do(option, 0); 31929088Smarkm setconnmode(0); /* possibly set new tty mode */ 32029088Smarkm } else { 32129088Smarkm do_dont_resp[option]++; 32229088Smarkm send_dont(option, 0); 32329088Smarkm } 32429088Smarkm } 32529088Smarkm set_my_state_do(option); 32629088Smarkm#ifdef ENCRYPTION 32729088Smarkm if (option == TELOPT_ENCRYPT) 32829088Smarkm encrypt_send_support(); 32929088Smarkm#endif /* ENCRYPTION */ 33029088Smarkm} 33129088Smarkm 33287139Smarkmvoid 33387139Smarkmwontoption(int option) 33429088Smarkm{ 33529088Smarkm if (do_dont_resp[option]) { 33629088Smarkm --do_dont_resp[option]; 33729088Smarkm if (do_dont_resp[option] && my_state_is_dont(option)) 33829088Smarkm --do_dont_resp[option]; 33929088Smarkm } 34029088Smarkm 34129088Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 34229088Smarkm 34329088Smarkm switch (option) { 34429088Smarkm 34529088Smarkm#ifdef KLUDGELINEMODE 34629088Smarkm case TELOPT_SGA: 34729088Smarkm if (!kludgelinemode) 34829088Smarkm break; 349103955Smarkm /* FALLTHROUGH */ 35029088Smarkm#endif 35129088Smarkm case TELOPT_ECHO: 35229088Smarkm settimer(modenegotiated); 35329088Smarkm break; 35429088Smarkm 35529088Smarkm case TELOPT_TM: 35629088Smarkm if (flushout) 35729088Smarkm flushout = 0; 35829088Smarkm set_my_want_state_dont(option); 35929088Smarkm set_my_state_dont(option); 36029088Smarkm return; /* Never reply to TM will's/wont's */ 36129088Smarkm 36229088Smarkm default: 36329088Smarkm break; 36429088Smarkm } 36529088Smarkm set_my_want_state_dont(option); 36629088Smarkm if (my_state_is_do(option)) 36729088Smarkm send_dont(option, 0); 36829088Smarkm setconnmode(0); /* Set new tty mode */ 36929088Smarkm } else if (option == TELOPT_TM) { 37029088Smarkm /* 37129088Smarkm * Special case for TM. 37229088Smarkm */ 37329088Smarkm if (flushout) 37429088Smarkm flushout = 0; 37529088Smarkm set_my_want_state_dont(option); 37629088Smarkm } 37729088Smarkm set_my_state_dont(option); 37829088Smarkm} 37929088Smarkm 38087139Smarkmstatic void 38187139Smarkmdooption(int option) 38229088Smarkm{ 38329088Smarkm int new_state_ok = 0; 38429088Smarkm 38529088Smarkm if (will_wont_resp[option]) { 38629088Smarkm --will_wont_resp[option]; 38729088Smarkm if (will_wont_resp[option] && my_state_is_will(option)) 38829088Smarkm --will_wont_resp[option]; 38929088Smarkm } 39029088Smarkm 39129088Smarkm if (will_wont_resp[option] == 0) { 39229088Smarkm if (my_want_state_is_wont(option)) { 39329088Smarkm 39429088Smarkm switch (option) { 39529088Smarkm 39629088Smarkm case TELOPT_TM: 39729088Smarkm /* 39829088Smarkm * Special case for TM. We send a WILL, but pretend 39929088Smarkm * we sent WONT. 40029088Smarkm */ 40129088Smarkm send_will(option, 0); 40229088Smarkm set_my_want_state_wont(TELOPT_TM); 40329088Smarkm set_my_state_wont(TELOPT_TM); 40429088Smarkm return; 40529088Smarkm 40629088Smarkm case TELOPT_BINARY: /* binary mode */ 40729088Smarkm case TELOPT_NAWS: /* window size */ 40829088Smarkm case TELOPT_TSPEED: /* terminal speed */ 40929088Smarkm case TELOPT_LFLOW: /* local flow control */ 41029088Smarkm case TELOPT_TTYPE: /* terminal type option */ 41129088Smarkm case TELOPT_SGA: /* no big deal */ 41229088Smarkm#ifdef ENCRYPTION 41329088Smarkm case TELOPT_ENCRYPT: /* encryption variable option */ 41429088Smarkm#endif /* ENCRYPTION */ 41529088Smarkm new_state_ok = 1; 41629088Smarkm break; 41729088Smarkm 41829088Smarkm case TELOPT_NEW_ENVIRON: /* New environment variable option */ 41929088Smarkm#ifdef OLD_ENVIRON 42029088Smarkm if (my_state_is_will(TELOPT_OLD_ENVIRON)) 42129088Smarkm send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ 42229088Smarkm goto env_common; 42329088Smarkm case TELOPT_OLD_ENVIRON: /* Old environment variable option */ 42429088Smarkm if (my_state_is_will(TELOPT_NEW_ENVIRON)) 42529088Smarkm break; /* Don't enable if new one is in use! */ 42629088Smarkm env_common: 42729088Smarkm telopt_environ = option; 42829088Smarkm#endif 42929088Smarkm new_state_ok = 1; 43029088Smarkm break; 43129088Smarkm 43287139Smarkm#ifdef AUTHENTICATION 43329088Smarkm case TELOPT_AUTHENTICATION: 43429088Smarkm if (autologin) 43529088Smarkm new_state_ok = 1; 43629088Smarkm break; 43729088Smarkm#endif 43829088Smarkm 43929088Smarkm case TELOPT_XDISPLOC: /* X Display location */ 44087139Smarkm if (env_getvalue("DISPLAY")) 44129088Smarkm new_state_ok = 1; 44229088Smarkm break; 44329088Smarkm 44429088Smarkm case TELOPT_LINEMODE: 44529088Smarkm#ifdef KLUDGELINEMODE 44629088Smarkm kludgelinemode = 0; 44729088Smarkm send_do(TELOPT_SGA, 1); 44829088Smarkm#endif 44929088Smarkm set_my_want_state_will(TELOPT_LINEMODE); 45029088Smarkm send_will(option, 0); 45129088Smarkm set_my_state_will(TELOPT_LINEMODE); 45229088Smarkm slc_init(); 45329088Smarkm return; 45429088Smarkm 45529088Smarkm case TELOPT_ECHO: /* We're never going to echo... */ 45629088Smarkm default: 45729088Smarkm break; 45829088Smarkm } 45929088Smarkm 46029088Smarkm if (new_state_ok) { 46129088Smarkm set_my_want_state_will(option); 46229088Smarkm send_will(option, 0); 46329088Smarkm setconnmode(0); /* Set new tty mode */ 46429088Smarkm } else { 46529088Smarkm will_wont_resp[option]++; 46629088Smarkm send_wont(option, 0); 46729088Smarkm } 46829088Smarkm } else { 46929088Smarkm /* 47029088Smarkm * Handle options that need more things done after the 47129088Smarkm * other side has acknowledged the option. 47229088Smarkm */ 47329088Smarkm switch (option) { 47429088Smarkm case TELOPT_LINEMODE: 47529088Smarkm#ifdef KLUDGELINEMODE 47629088Smarkm kludgelinemode = 0; 47729088Smarkm send_do(TELOPT_SGA, 1); 47829088Smarkm#endif 47929088Smarkm set_my_state_will(option); 48029088Smarkm slc_init(); 48129088Smarkm send_do(TELOPT_SGA, 0); 48229088Smarkm return; 48329088Smarkm } 48429088Smarkm } 48529088Smarkm } 48629088Smarkm set_my_state_will(option); 48729088Smarkm} 48829088Smarkm 48987139Smarkmstatic void 49087139Smarkmdontoption(int option) 49129088Smarkm{ 49229088Smarkm 49329088Smarkm if (will_wont_resp[option]) { 49429088Smarkm --will_wont_resp[option]; 49529088Smarkm if (will_wont_resp[option] && my_state_is_wont(option)) 49629088Smarkm --will_wont_resp[option]; 49729088Smarkm } 49829088Smarkm 49929088Smarkm if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 50029088Smarkm switch (option) { 50129088Smarkm case TELOPT_LINEMODE: 50229088Smarkm linemode = 0; /* put us back to the default state */ 50329088Smarkm break; 50429088Smarkm#ifdef OLD_ENVIRON 50529088Smarkm case TELOPT_NEW_ENVIRON: 50629088Smarkm /* 50729088Smarkm * The new environ option wasn't recognized, try 50829088Smarkm * the old one. 50929088Smarkm */ 51029088Smarkm send_will(TELOPT_OLD_ENVIRON, 1); 51129088Smarkm telopt_environ = TELOPT_OLD_ENVIRON; 51229088Smarkm break; 51329088Smarkm#endif 51429088Smarkm } 51529088Smarkm /* we always accept a DONT */ 51629088Smarkm set_my_want_state_wont(option); 51729088Smarkm if (my_state_is_will(option)) 51829088Smarkm send_wont(option, 0); 51929088Smarkm setconnmode(0); /* Set new tty mode */ 52029088Smarkm } 52129088Smarkm set_my_state_wont(option); 52229088Smarkm} 52329088Smarkm 52429088Smarkm/* 52529088Smarkm * Given a buffer returned by tgetent(), this routine will turn 52672089Sasmodai * the pipe separated list of names in the buffer into an array 52729088Smarkm * of pointers to null terminated names. We toss out any bad, 52829088Smarkm * duplicate, or verbose names (names with spaces). 52929088Smarkm */ 53029088Smarkm 53187139Smarkmstatic const char *name_unknown = "UNKNOWN"; 53287139Smarkmstatic const char *unknown[] = { NULL, NULL }; 53329088Smarkm 53487139Smarkmstatic const char ** 53587139Smarkmmklist(char *buf, char *name) 53629088Smarkm{ 53787139Smarkm int n; 53887139Smarkm char c, *cp, **argvp, *cp2, **argv, **avt; 53929088Smarkm 54029088Smarkm if (name) { 54181965Smarkm if (strlen(name) > 40) { 54229088Smarkm name = 0; 54329088Smarkm unknown[0] = name_unknown; 54429088Smarkm } else { 54529088Smarkm unknown[0] = name; 54629088Smarkm upcase(name); 54729088Smarkm } 54829088Smarkm } else 54929088Smarkm unknown[0] = name_unknown; 55029088Smarkm /* 55129088Smarkm * Count up the number of names. 55229088Smarkm */ 55329088Smarkm for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 55429088Smarkm if (*cp == '|') 55529088Smarkm n++; 55629088Smarkm } 55729088Smarkm /* 55829088Smarkm * Allocate an array to put the name pointers into 55929088Smarkm */ 56029088Smarkm argv = (char **)malloc((n+3)*sizeof(char *)); 56129088Smarkm if (argv == 0) 56229088Smarkm return(unknown); 56329088Smarkm 56429088Smarkm /* 56529088Smarkm * Fill up the array of pointers to names. 56629088Smarkm */ 56729088Smarkm *argv = 0; 56829088Smarkm argvp = argv+1; 56929088Smarkm n = 0; 57029088Smarkm for (cp = cp2 = buf; (c = *cp); cp++) { 57129088Smarkm if (c == '|' || c == ':') { 57229088Smarkm *cp++ = '\0'; 57329088Smarkm /* 57429088Smarkm * Skip entries that have spaces or are over 40 57529088Smarkm * characters long. If this is our environment 57629088Smarkm * name, then put it up front. Otherwise, as 57729088Smarkm * long as this is not a duplicate name (case 57829088Smarkm * insensitive) add it to the list. 57929088Smarkm */ 58029088Smarkm if (n || (cp - cp2 > 41)) 58129088Smarkm ; 58229088Smarkm else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 58329088Smarkm *argv = cp2; 58429088Smarkm else if (is_unique(cp2, argv+1, argvp)) 58529088Smarkm *argvp++ = cp2; 58629088Smarkm if (c == ':') 58729088Smarkm break; 58829088Smarkm /* 58929088Smarkm * Skip multiple delimiters. Reset cp2 to 59029088Smarkm * the beginning of the next name. Reset n, 59129088Smarkm * the flag for names with spaces. 59229088Smarkm */ 59329088Smarkm while ((c = *cp) == '|') 59429088Smarkm cp++; 59529088Smarkm cp2 = cp; 59629088Smarkm n = 0; 59729088Smarkm } 59829088Smarkm /* 59929088Smarkm * Skip entries with spaces or non-ascii values. 60029088Smarkm * Convert lower case letters to upper case. 60129088Smarkm */ 60229088Smarkm if ((c == ' ') || !isascii(c)) 60329088Smarkm n = 1; 60429088Smarkm else if (islower(c)) 60529088Smarkm *cp = toupper(c); 60629088Smarkm } 60729088Smarkm 60829088Smarkm /* 60929088Smarkm * Check for an old V6 2 character name. If the second 61029088Smarkm * name points to the beginning of the buffer, and is 61129088Smarkm * only 2 characters long, move it to the end of the array. 61229088Smarkm */ 61329088Smarkm if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 61429088Smarkm --argvp; 61529088Smarkm for (avt = &argv[1]; avt < argvp; avt++) 61629088Smarkm *avt = *(avt+1); 61729088Smarkm *argvp++ = buf; 61829088Smarkm } 61929088Smarkm 62029088Smarkm /* 62129088Smarkm * Duplicate last name, for TTYPE option, and null 62229088Smarkm * terminate the array. If we didn't find a match on 62329088Smarkm * our terminal name, put that name at the beginning. 62429088Smarkm */ 62529088Smarkm cp = *(argvp-1); 62629088Smarkm *argvp++ = cp; 62729088Smarkm *argvp = 0; 62829088Smarkm 62929088Smarkm if (*argv == 0) { 63029088Smarkm if (name) 63129088Smarkm *argv = name; 63229088Smarkm else { 63329088Smarkm --argvp; 63429088Smarkm for (avt = argv; avt < argvp; avt++) 63529088Smarkm *avt = *(avt+1); 63629088Smarkm } 63729088Smarkm } 63829088Smarkm if (*argv) 63987139Smarkm return((const char **)argv); 64029088Smarkm else 64129088Smarkm return(unknown); 64229088Smarkm} 64329088Smarkm 64487139Smarkmstatic int 64587139Smarkmis_unique(char *name, char **as, char **ae) 64629088Smarkm{ 64787139Smarkm char **ap; 64887139Smarkm int n; 64929088Smarkm 65029088Smarkm n = strlen(name) + 1; 65129088Smarkm for (ap = as; ap < ae; ap++) 65229088Smarkm if (strncasecmp(*ap, name, n) == 0) 65329088Smarkm return(0); 65429088Smarkm return (1); 65529088Smarkm} 65629088Smarkm 65729088Smarkm#ifdef TERMCAP 65829088Smarkmchar termbuf[1024]; 65929088Smarkm 66087139Smarkm/*ARGSUSED*/ 66187139Smarkmstatic int 66287139Smarkmsetupterm(char *tname, int fd, int *errp) 66329088Smarkm{ 66429088Smarkm if (tgetent(termbuf, tname) == 1) { 66529088Smarkm termbuf[1023] = '\0'; 66629088Smarkm if (errp) 66729088Smarkm *errp = 1; 66829088Smarkm return(0); 66929088Smarkm } 67029088Smarkm if (errp) 67129088Smarkm *errp = 0; 67229088Smarkm return(-1); 67329088Smarkm} 67429088Smarkm#else 67529088Smarkm#define termbuf ttytype 67629088Smarkmextern char ttytype[]; 67729088Smarkm#endif 67829088Smarkm 67929088Smarkmint resettermname = 1; 68029088Smarkm 68187139Smarkmstatic const char * 68287139Smarkmgettermname(void) 68329088Smarkm{ 68429088Smarkm char *tname; 68587139Smarkm static const char **tnamep = 0; 68687139Smarkm static const char **next; 68729088Smarkm int err; 68829088Smarkm 68929088Smarkm if (resettermname) { 69029088Smarkm resettermname = 0; 69129088Smarkm if (tnamep && tnamep != unknown) 69229088Smarkm free(tnamep); 69387139Smarkm if ((tname = env_getvalue("TERM")) && 69429088Smarkm (setupterm(tname, 1, &err) == 0)) { 69529088Smarkm tnamep = mklist(termbuf, tname); 69629088Smarkm } else { 69781965Smarkm if (tname && (strlen(tname) <= 40)) { 69829088Smarkm unknown[0] = tname; 69929088Smarkm upcase(tname); 70029088Smarkm } else 70129088Smarkm unknown[0] = name_unknown; 70229088Smarkm tnamep = unknown; 70329088Smarkm } 70429088Smarkm next = tnamep; 70529088Smarkm } 70629088Smarkm if (*next == 0) 70729088Smarkm next = tnamep; 70829088Smarkm return(*next++); 70929088Smarkm} 71029088Smarkm/* 71129088Smarkm * suboption() 71229088Smarkm * 71329088Smarkm * Look at the sub-option buffer, and try to be helpful to the other 71429088Smarkm * side. 71529088Smarkm * 71629088Smarkm * Currently we recognize: 71729088Smarkm * 71829088Smarkm * Terminal type, send request. 71929088Smarkm * Terminal speed (send request). 72029088Smarkm * Local flow control (is request). 72129088Smarkm * Linemode 72229088Smarkm */ 72329088Smarkm 72487139Smarkmstatic void 72587139Smarkmsuboption(void) 72629088Smarkm{ 72729088Smarkm unsigned char subchar; 72829088Smarkm 72929088Smarkm printsub('<', subbuffer, SB_LEN()+2); 73029088Smarkm switch (subchar = SB_GET()) { 73129088Smarkm case TELOPT_TTYPE: 73229088Smarkm if (my_want_state_is_wont(TELOPT_TTYPE)) 73329088Smarkm return; 73429088Smarkm if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 73529088Smarkm return; 73629088Smarkm } else { 73787139Smarkm const char *name; 73829088Smarkm unsigned char temp[50]; 73929088Smarkm int len; 74029088Smarkm 74129088Smarkm name = gettermname(); 74229088Smarkm len = strlen(name) + 4 + 2; 74329088Smarkm if (len < NETROOM()) { 74487139Smarkm sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 74529088Smarkm TELQUAL_IS, name, IAC, SE); 74629088Smarkm ring_supply_data(&netoring, temp, len); 74729088Smarkm printsub('>', &temp[2], len-2); 74829088Smarkm } else { 74929088Smarkm ExitString("No room in buffer for terminal type.\n", 1); 75029088Smarkm /*NOTREACHED*/ 75129088Smarkm } 75229088Smarkm } 75329088Smarkm break; 75429088Smarkm case TELOPT_TSPEED: 75529088Smarkm if (my_want_state_is_wont(TELOPT_TSPEED)) 75629088Smarkm return; 75729088Smarkm if (SB_EOF()) 75829088Smarkm return; 75929088Smarkm if (SB_GET() == TELQUAL_SEND) { 76029088Smarkm long ospeed, ispeed; 76129088Smarkm unsigned char temp[50]; 76229088Smarkm int len; 76329088Smarkm 76429088Smarkm TerminalSpeeds(&ispeed, &ospeed); 76529088Smarkm 76629181Smarkm sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, 76729088Smarkm TELQUAL_IS, ospeed, ispeed, IAC, SE); 76829088Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 76929088Smarkm 77029088Smarkm if (len < NETROOM()) { 77129088Smarkm ring_supply_data(&netoring, temp, len); 77229088Smarkm printsub('>', temp+2, len - 2); 77329088Smarkm } 77429088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 77529088Smarkm } 77629088Smarkm break; 77729088Smarkm case TELOPT_LFLOW: 77829088Smarkm if (my_want_state_is_wont(TELOPT_LFLOW)) 77929088Smarkm return; 78029088Smarkm if (SB_EOF()) 78129088Smarkm return; 78229088Smarkm switch(SB_GET()) { 78329088Smarkm case LFLOW_RESTART_ANY: 78429088Smarkm restartany = 1; 78529088Smarkm break; 78629088Smarkm case LFLOW_RESTART_XON: 78729088Smarkm restartany = 0; 78829088Smarkm break; 78929088Smarkm case LFLOW_ON: 79029088Smarkm localflow = 1; 79129088Smarkm break; 79229088Smarkm case LFLOW_OFF: 79329088Smarkm localflow = 0; 79429088Smarkm break; 79529088Smarkm default: 79629088Smarkm return; 79729088Smarkm } 79829088Smarkm setcommandmode(); 79929088Smarkm setconnmode(0); 80029088Smarkm break; 80129088Smarkm 80229088Smarkm case TELOPT_LINEMODE: 80329088Smarkm if (my_want_state_is_wont(TELOPT_LINEMODE)) 80429088Smarkm return; 80529088Smarkm if (SB_EOF()) 80629088Smarkm return; 80729088Smarkm switch (SB_GET()) { 80829088Smarkm case WILL: 80929088Smarkm lm_will(subpointer, SB_LEN()); 81029088Smarkm break; 81129088Smarkm case WONT: 81229088Smarkm lm_wont(subpointer, SB_LEN()); 81329088Smarkm break; 81429088Smarkm case DO: 81529088Smarkm lm_do(subpointer, SB_LEN()); 81629088Smarkm break; 81729088Smarkm case DONT: 81829088Smarkm lm_dont(subpointer, SB_LEN()); 81929088Smarkm break; 82029088Smarkm case LM_SLC: 82129088Smarkm slc(subpointer, SB_LEN()); 82229088Smarkm break; 82329088Smarkm case LM_MODE: 82429088Smarkm lm_mode(subpointer, SB_LEN(), 0); 82529088Smarkm break; 82629088Smarkm default: 82729088Smarkm break; 82829088Smarkm } 82929088Smarkm break; 83029088Smarkm 83129088Smarkm#ifdef OLD_ENVIRON 83229088Smarkm case TELOPT_OLD_ENVIRON: 83329088Smarkm#endif 83429088Smarkm case TELOPT_NEW_ENVIRON: 83529088Smarkm if (SB_EOF()) 83629088Smarkm return; 83729088Smarkm switch(SB_PEEK()) { 83829088Smarkm case TELQUAL_IS: 83929088Smarkm case TELQUAL_INFO: 84029088Smarkm if (my_want_state_is_dont(subchar)) 84129088Smarkm return; 84229088Smarkm break; 84329088Smarkm case TELQUAL_SEND: 84429088Smarkm if (my_want_state_is_wont(subchar)) { 84529088Smarkm return; 84629088Smarkm } 84729088Smarkm break; 84829088Smarkm default: 84929088Smarkm return; 85029088Smarkm } 85129088Smarkm env_opt(subpointer, SB_LEN()); 85229088Smarkm break; 85329088Smarkm 85429088Smarkm case TELOPT_XDISPLOC: 85529088Smarkm if (my_want_state_is_wont(TELOPT_XDISPLOC)) 85629088Smarkm return; 85729088Smarkm if (SB_EOF()) 85829088Smarkm return; 85929088Smarkm if (SB_GET() == TELQUAL_SEND) { 86029088Smarkm unsigned char temp[50], *dp; 86129088Smarkm int len; 86229088Smarkm 86387139Smarkm if ((dp = env_getvalue("DISPLAY")) == NULL || 86467827Skris strlen(dp) > sizeof(temp) - 7) { 86529088Smarkm /* 86629088Smarkm * Something happened, we no longer have a DISPLAY 86767827Skris * variable. Or it is too long. So, turn off the option. 86829088Smarkm */ 86929088Smarkm send_wont(TELOPT_XDISPLOC, 1); 87029088Smarkm break; 87129088Smarkm } 87287139Smarkm snprintf(temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, 87367827Skris TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); 87429088Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 87529088Smarkm 87629088Smarkm if (len < NETROOM()) { 87729088Smarkm ring_supply_data(&netoring, temp, len); 87829088Smarkm printsub('>', temp+2, len - 2); 87929088Smarkm } 88029088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 88129088Smarkm } 88229088Smarkm break; 88329088Smarkm 88487139Smarkm#ifdef AUTHENTICATION 88529088Smarkm case TELOPT_AUTHENTICATION: { 88629088Smarkm if (!autologin) 88729088Smarkm break; 88829088Smarkm if (SB_EOF()) 88929088Smarkm return; 89029088Smarkm switch(SB_GET()) { 89129088Smarkm case TELQUAL_IS: 89229088Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 89329088Smarkm return; 89429088Smarkm auth_is(subpointer, SB_LEN()); 89529088Smarkm break; 89629088Smarkm case TELQUAL_SEND: 89729088Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 89829088Smarkm return; 89929088Smarkm auth_send(subpointer, SB_LEN()); 90029088Smarkm break; 90129088Smarkm case TELQUAL_REPLY: 90229088Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 90329088Smarkm return; 90429088Smarkm auth_reply(subpointer, SB_LEN()); 90529088Smarkm break; 90629088Smarkm case TELQUAL_NAME: 90729088Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 90829088Smarkm return; 90929088Smarkm auth_name(subpointer, SB_LEN()); 91029088Smarkm break; 91129088Smarkm } 91229088Smarkm } 91329088Smarkm break; 91429088Smarkm#endif 91529088Smarkm#ifdef ENCRYPTION 91629088Smarkm case TELOPT_ENCRYPT: 91729088Smarkm if (SB_EOF()) 91829088Smarkm return; 91929088Smarkm switch(SB_GET()) { 92029088Smarkm case ENCRYPT_START: 92129088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 92229088Smarkm return; 92329088Smarkm encrypt_start(subpointer, SB_LEN()); 92429088Smarkm break; 92529088Smarkm case ENCRYPT_END: 92629088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 92729088Smarkm return; 92829088Smarkm encrypt_end(); 92929088Smarkm break; 93029088Smarkm case ENCRYPT_SUPPORT: 93129088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 93229088Smarkm return; 93329088Smarkm encrypt_support(subpointer, SB_LEN()); 93429088Smarkm break; 93529088Smarkm case ENCRYPT_REQSTART: 93629088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 93729088Smarkm return; 93829088Smarkm encrypt_request_start(subpointer, SB_LEN()); 93929088Smarkm break; 94029088Smarkm case ENCRYPT_REQEND: 94129088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 94229088Smarkm return; 94329088Smarkm /* 94429088Smarkm * We can always send an REQEND so that we cannot 94529088Smarkm * get stuck encrypting. We should only get this 94629088Smarkm * if we have been able to get in the correct mode 94729088Smarkm * anyhow. 94829088Smarkm */ 94929088Smarkm encrypt_request_end(); 95029088Smarkm break; 95129088Smarkm case ENCRYPT_IS: 95229088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 95329088Smarkm return; 95429088Smarkm encrypt_is(subpointer, SB_LEN()); 95529088Smarkm break; 95629088Smarkm case ENCRYPT_REPLY: 95729088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 95829088Smarkm return; 95929088Smarkm encrypt_reply(subpointer, SB_LEN()); 96029088Smarkm break; 96129088Smarkm case ENCRYPT_ENC_KEYID: 96229088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 96329088Smarkm return; 96429088Smarkm encrypt_enc_keyid(subpointer, SB_LEN()); 96529088Smarkm break; 96629088Smarkm case ENCRYPT_DEC_KEYID: 96729088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 96829088Smarkm return; 96929088Smarkm encrypt_dec_keyid(subpointer, SB_LEN()); 97029088Smarkm break; 97129088Smarkm default: 97229088Smarkm break; 97329088Smarkm } 97429088Smarkm break; 97529088Smarkm#endif /* ENCRYPTION */ 97629088Smarkm default: 97729088Smarkm break; 97829088Smarkm } 97929088Smarkm} 98029088Smarkm 98129088Smarkmstatic unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 98229088Smarkm 98387139Smarkmvoid 98487139Smarkmlm_will(unsigned char *cmd, int len) 98529088Smarkm{ 98629088Smarkm if (len < 1) { 98729088Smarkm/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 98829088Smarkm return; 98929088Smarkm } 99029088Smarkm switch(cmd[0]) { 99129088Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 99229088Smarkm default: 99329088Smarkm str_lm[3] = DONT; 99429088Smarkm str_lm[4] = cmd[0]; 99587139Smarkm if (NETROOM() > (int)sizeof(str_lm)) { 99629088Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 99729088Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 99829088Smarkm } 99929088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 100029088Smarkm break; 100129088Smarkm } 100229088Smarkm} 100329088Smarkm 100487139Smarkmvoid 100587139Smarkmlm_wont(unsigned char *cmd, int len) 100629088Smarkm{ 100729088Smarkm if (len < 1) { 100829088Smarkm/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 100929088Smarkm return; 101029088Smarkm } 101129088Smarkm switch(cmd[0]) { 101229088Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 101329088Smarkm default: 101429088Smarkm /* We are always DONT, so don't respond */ 101529088Smarkm return; 101629088Smarkm } 101729088Smarkm} 101829088Smarkm 101987139Smarkmvoid 102087139Smarkmlm_do(unsigned char *cmd, int len) 102129088Smarkm{ 102229088Smarkm if (len < 1) { 102329088Smarkm/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 102429088Smarkm return; 102529088Smarkm } 102629088Smarkm switch(cmd[0]) { 102729088Smarkm case LM_FORWARDMASK: 102829088Smarkm default: 102929088Smarkm str_lm[3] = WONT; 103029088Smarkm str_lm[4] = cmd[0]; 103187139Smarkm if (NETROOM() > (int)sizeof(str_lm)) { 103229088Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 103329088Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 103429088Smarkm } 103529088Smarkm/*@*/ else printf("lm_do: not enough room in buffer\n"); 103629088Smarkm break; 103729088Smarkm } 103829088Smarkm} 103929088Smarkm 104087139Smarkmvoid 104187139Smarkmlm_dont(unsigned char *cmd, int len) 104229088Smarkm{ 104329088Smarkm if (len < 1) { 104429088Smarkm/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 104529088Smarkm return; 104629088Smarkm } 104729088Smarkm switch(cmd[0]) { 104829088Smarkm case LM_FORWARDMASK: 104929088Smarkm default: 105029088Smarkm /* we are always WONT, so don't respond */ 105129088Smarkm break; 105229088Smarkm } 105329088Smarkm} 105429088Smarkm 105529088Smarkmstatic unsigned char str_lm_mode[] = { 105629088Smarkm IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 105729088Smarkm}; 105829088Smarkm 105987139Smarkmvoid 106087139Smarkmlm_mode(unsigned char *cmd, int len, int init) 106129088Smarkm{ 106229088Smarkm if (len != 1) 106329088Smarkm return; 106429088Smarkm if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 106529088Smarkm return; 106629088Smarkm if (*cmd&MODE_ACK) 106729088Smarkm return; 106829088Smarkm linemode = *cmd&(MODE_MASK&~MODE_ACK); 106929088Smarkm str_lm_mode[4] = linemode; 107029088Smarkm if (!init) 107129088Smarkm str_lm_mode[4] |= MODE_ACK; 107287139Smarkm if (NETROOM() > (int)sizeof(str_lm_mode)) { 107329088Smarkm ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 107429088Smarkm printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 107529088Smarkm } 107629088Smarkm/*@*/ else printf("lm_mode: not enough room in buffer\n"); 107729088Smarkm setconnmode(0); /* set changed mode */ 107829088Smarkm} 107929088Smarkm 108029088Smarkm 108129088Smarkm 108229088Smarkm/* 108329088Smarkm * slc() 108429088Smarkm * Handle special character suboption of LINEMODE. 108529088Smarkm */ 108629088Smarkm 108729088Smarkmstruct spc { 108829088Smarkm cc_t val; 108929088Smarkm cc_t *valp; 109029088Smarkm char flags; /* Current flags & level */ 109129088Smarkm char mylevel; /* Maximum level & flags */ 109229088Smarkm} spc_data[NSLC+1]; 109329088Smarkm 109429088Smarkm#define SLC_IMPORT 0 109529088Smarkm#define SLC_EXPORT 1 109629088Smarkm#define SLC_RVALUE 2 109729088Smarkmstatic int slc_mode = SLC_EXPORT; 109829088Smarkm 109987139Smarkmvoid 110087139Smarkmslc_init(void) 110129088Smarkm{ 110287139Smarkm struct spc *spcp; 110329088Smarkm 110429088Smarkm localchars = 1; 110529088Smarkm for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 110629088Smarkm spcp->val = 0; 110729088Smarkm spcp->valp = 0; 110829088Smarkm spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 110929088Smarkm } 111029088Smarkm 111129088Smarkm#define initfunc(func, flags) { \ 111229088Smarkm spcp = &spc_data[func]; \ 111329181Smarkm if ((spcp->valp = tcval(func))) { \ 111429088Smarkm spcp->val = *spcp->valp; \ 111529088Smarkm spcp->mylevel = SLC_VARIABLE|flags; \ 111629088Smarkm } else { \ 111729088Smarkm spcp->val = 0; \ 111829088Smarkm spcp->mylevel = SLC_DEFAULT; \ 111929088Smarkm } \ 112029088Smarkm } 112129088Smarkm 112229088Smarkm initfunc(SLC_SYNCH, 0); 112329088Smarkm /* No BRK */ 112429088Smarkm initfunc(SLC_AO, 0); 112529088Smarkm initfunc(SLC_AYT, 0); 112629088Smarkm /* No EOR */ 112729088Smarkm initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 112829088Smarkm initfunc(SLC_EOF, 0); 112929088Smarkm#ifndef SYSV_TERMIO 113029088Smarkm initfunc(SLC_SUSP, SLC_FLUSHIN); 113129088Smarkm#endif 113229088Smarkm initfunc(SLC_EC, 0); 113329088Smarkm initfunc(SLC_EL, 0); 113429088Smarkm#ifndef SYSV_TERMIO 113529088Smarkm initfunc(SLC_EW, 0); 113629088Smarkm initfunc(SLC_RP, 0); 113729088Smarkm initfunc(SLC_LNEXT, 0); 113829088Smarkm#endif 113929088Smarkm initfunc(SLC_XON, 0); 114029088Smarkm initfunc(SLC_XOFF, 0); 114129088Smarkm#ifdef SYSV_TERMIO 114229088Smarkm spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 114329088Smarkm spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 114429088Smarkm#endif 114529088Smarkm initfunc(SLC_FORW1, 0); 114629088Smarkm#ifdef USE_TERMIO 114729088Smarkm initfunc(SLC_FORW2, 0); 114829088Smarkm /* No FORW2 */ 114929088Smarkm#endif 115029088Smarkm 115129088Smarkm initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 115229088Smarkm#undef initfunc 115329088Smarkm 115429088Smarkm if (slc_mode == SLC_EXPORT) 115529088Smarkm slc_export(); 115629088Smarkm else 115729088Smarkm slc_import(1); 115829088Smarkm 115929088Smarkm} 116029088Smarkm 116187139Smarkmvoid 116287139Smarkmslcstate(void) 116329088Smarkm{ 116429088Smarkm printf("Special characters are %s values\n", 116529088Smarkm slc_mode == SLC_IMPORT ? "remote default" : 116629088Smarkm slc_mode == SLC_EXPORT ? "local" : 116729088Smarkm "remote"); 116829088Smarkm} 116929088Smarkm 117087139Smarkmvoid 117187139Smarkmslc_mode_export(void) 117229088Smarkm{ 117329088Smarkm slc_mode = SLC_EXPORT; 117429088Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 117529088Smarkm slc_export(); 117629088Smarkm} 117729088Smarkm 117887139Smarkmvoid 117987139Smarkmslc_mode_import(int def) 118029088Smarkm{ 118129088Smarkm slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 118229088Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 118329088Smarkm slc_import(def); 118429088Smarkm} 118529088Smarkm 118629088Smarkmunsigned char slc_import_val[] = { 118729088Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 118829088Smarkm}; 118929088Smarkmunsigned char slc_import_def[] = { 119029088Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 119129088Smarkm}; 119229088Smarkm 119387139Smarkmvoid 119487139Smarkmslc_import(int def) 119529088Smarkm{ 119687139Smarkm if (NETROOM() > (int)sizeof(slc_import_val)) { 119729088Smarkm if (def) { 119829088Smarkm ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 119929088Smarkm printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 120029088Smarkm } else { 120129088Smarkm ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 120229088Smarkm printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 120329088Smarkm } 120429088Smarkm } 120529088Smarkm/*@*/ else printf("slc_import: not enough room\n"); 120629088Smarkm} 120729088Smarkm 120887139Smarkmvoid 120987139Smarkmslc_export(void) 121029088Smarkm{ 121187139Smarkm struct spc *spcp; 121229088Smarkm 121329088Smarkm TerminalDefaultChars(); 121429088Smarkm 121529088Smarkm slc_start_reply(); 121629088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 121729088Smarkm if (spcp->mylevel != SLC_NOSUPPORT) { 121829088Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 121929088Smarkm spcp->flags = SLC_NOSUPPORT; 122029088Smarkm else 122129088Smarkm spcp->flags = spcp->mylevel; 122229088Smarkm if (spcp->valp) 122329088Smarkm spcp->val = *spcp->valp; 122429088Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 122529088Smarkm } 122629088Smarkm } 122729088Smarkm slc_end_reply(); 122829088Smarkm (void)slc_update(); 122929088Smarkm setconnmode(1); /* Make sure the character values are set */ 123029088Smarkm} 123129088Smarkm 123287139Smarkmvoid 123387139Smarkmslc(unsigned char *cp, int len) 123429088Smarkm{ 123587139Smarkm struct spc *spcp; 123687139Smarkm int func,level; 123729088Smarkm 123829088Smarkm slc_start_reply(); 123929088Smarkm 124029088Smarkm for (; len >= 3; len -=3, cp +=3) { 124129088Smarkm 124229088Smarkm func = cp[SLC_FUNC]; 124329088Smarkm 124429088Smarkm if (func == 0) { 124529088Smarkm /* 124629088Smarkm * Client side: always ignore 0 function. 124729088Smarkm */ 124829088Smarkm continue; 124929088Smarkm } 125029088Smarkm if (func > NSLC) { 125129088Smarkm if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 125229088Smarkm slc_add_reply(func, SLC_NOSUPPORT, 0); 125329088Smarkm continue; 125429088Smarkm } 125529088Smarkm 125629088Smarkm spcp = &spc_data[func]; 125729088Smarkm 125829088Smarkm level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 125929088Smarkm 126029088Smarkm if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 126129088Smarkm ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 126229088Smarkm continue; 126329088Smarkm } 126429088Smarkm 126529088Smarkm if (level == (SLC_DEFAULT|SLC_ACK)) { 126629088Smarkm /* 126729088Smarkm * This is an error condition, the SLC_ACK 126829088Smarkm * bit should never be set for the SLC_DEFAULT 126929088Smarkm * level. Our best guess to recover is to 127029088Smarkm * ignore the SLC_ACK bit. 127129088Smarkm */ 127229088Smarkm cp[SLC_FLAGS] &= ~SLC_ACK; 127329088Smarkm } 127429088Smarkm 127529088Smarkm if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 127629088Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 127729088Smarkm spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 127829088Smarkm continue; 127929088Smarkm } 128029088Smarkm 128129088Smarkm level &= ~SLC_ACK; 128229088Smarkm 128329088Smarkm if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 128429088Smarkm spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 128529088Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 128629088Smarkm } 128729088Smarkm if (level == SLC_DEFAULT) { 128829088Smarkm if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 128929088Smarkm spcp->flags = spcp->mylevel; 129029088Smarkm else 129129088Smarkm spcp->flags = SLC_NOSUPPORT; 129229088Smarkm } 129329088Smarkm slc_add_reply(func, spcp->flags, spcp->val); 129429088Smarkm } 129529088Smarkm slc_end_reply(); 129629088Smarkm if (slc_update()) 129729088Smarkm setconnmode(1); /* set the new character values */ 129829088Smarkm} 129929088Smarkm 130087139Smarkmvoid 130187139Smarkmslc_check(void) 130229088Smarkm{ 130387139Smarkm struct spc *spcp; 130429088Smarkm 130529088Smarkm slc_start_reply(); 130629088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 130729088Smarkm if (spcp->valp && spcp->val != *spcp->valp) { 130829088Smarkm spcp->val = *spcp->valp; 130929088Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 131029088Smarkm spcp->flags = SLC_NOSUPPORT; 131129088Smarkm else 131229088Smarkm spcp->flags = spcp->mylevel; 131329088Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 131429088Smarkm } 131529088Smarkm } 131629088Smarkm slc_end_reply(); 131729088Smarkm setconnmode(1); 131829088Smarkm} 131929088Smarkm 132029088Smarkmunsigned char slc_reply[128]; 132129088Smarkmunsigned char *slc_replyp; 132229088Smarkm 132387139Smarkmvoid 132487139Smarkmslc_start_reply(void) 132529088Smarkm{ 132629088Smarkm slc_replyp = slc_reply; 132729088Smarkm *slc_replyp++ = IAC; 132829088Smarkm *slc_replyp++ = SB; 132929088Smarkm *slc_replyp++ = TELOPT_LINEMODE; 133029088Smarkm *slc_replyp++ = LM_SLC; 133129088Smarkm} 133229088Smarkm 133387139Smarkmvoid 133487139Smarkmslc_add_reply(unsigned char func, unsigned char flags, cc_t value) 133529088Smarkm{ 133629088Smarkm if ((*slc_replyp++ = func) == IAC) 133729088Smarkm *slc_replyp++ = IAC; 133829088Smarkm if ((*slc_replyp++ = flags) == IAC) 133929088Smarkm *slc_replyp++ = IAC; 134029088Smarkm if ((*slc_replyp++ = (unsigned char)value) == IAC) 134129088Smarkm *slc_replyp++ = IAC; 134229088Smarkm} 134329088Smarkm 134487139Smarkmvoid 134587139Smarkmslc_end_reply(void) 134629088Smarkm{ 134787139Smarkm int len; 134829088Smarkm 134929088Smarkm *slc_replyp++ = IAC; 135029088Smarkm *slc_replyp++ = SE; 135129088Smarkm len = slc_replyp - slc_reply; 135229088Smarkm if (len <= 6) 135329088Smarkm return; 135429088Smarkm if (NETROOM() > len) { 135529088Smarkm ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 135629088Smarkm printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 135729088Smarkm } 135829088Smarkm/*@*/else printf("slc_end_reply: not enough room\n"); 135929088Smarkm} 136029088Smarkm 136187139Smarkmint 136287139Smarkmslc_update(void) 136329088Smarkm{ 136487139Smarkm struct spc *spcp; 136529088Smarkm int need_update = 0; 136629088Smarkm 136729088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 136829088Smarkm if (!(spcp->flags&SLC_ACK)) 136929088Smarkm continue; 137029088Smarkm spcp->flags &= ~SLC_ACK; 137129088Smarkm if (spcp->valp && (*spcp->valp != spcp->val)) { 137229088Smarkm *spcp->valp = spcp->val; 137329088Smarkm need_update = 1; 137429088Smarkm } 137529088Smarkm } 137629088Smarkm return(need_update); 137729088Smarkm} 137829088Smarkm 137929088Smarkm#ifdef OLD_ENVIRON 138029088Smarkm# ifdef ENV_HACK 138129088Smarkm/* 138229088Smarkm * Earlier version of telnet/telnetd from the BSD code had 138329088Smarkm * the definitions of VALUE and VAR reversed. To ensure 138429088Smarkm * maximum interoperability, we assume that the server is 138529088Smarkm * an older BSD server, until proven otherwise. The newer 138629088Smarkm * BSD servers should be able to handle either definition, 138729088Smarkm * so it is better to use the wrong values if we don't 138829088Smarkm * know what type of server it is. 138929088Smarkm */ 139029088Smarkmint env_auto = 1; 139129088Smarkmint old_env_var = OLD_ENV_VAR; 139229088Smarkmint old_env_value = OLD_ENV_VALUE; 139329088Smarkm# else 139429088Smarkm# define old_env_var OLD_ENV_VAR 139529088Smarkm# define old_env_value OLD_ENV_VALUE 139629088Smarkm# endif 139729088Smarkm#endif 139829088Smarkm 139987139Smarkmvoid 140087139Smarkmenv_opt(unsigned char *buf, int len) 140129088Smarkm{ 140287139Smarkm unsigned char *ep = 0, *epc = 0; 140387139Smarkm int i; 140429088Smarkm 140529088Smarkm switch(buf[0]&0xff) { 140629088Smarkm case TELQUAL_SEND: 140729088Smarkm env_opt_start(); 140829088Smarkm if (len == 1) { 140929088Smarkm env_opt_add(NULL); 141029088Smarkm } else for (i = 1; i < len; i++) { 141129088Smarkm switch (buf[i]&0xff) { 141229088Smarkm#ifdef OLD_ENVIRON 141329088Smarkm case OLD_ENV_VAR: 141429088Smarkm# ifdef ENV_HACK 141529088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON 141629088Smarkm && env_auto) { 141729088Smarkm /* Server has the same definitions */ 141829088Smarkm old_env_var = OLD_ENV_VAR; 141929088Smarkm old_env_value = OLD_ENV_VALUE; 142029088Smarkm } 1421103955Smarkm /* FALLTHROUGH */ 142229088Smarkm# endif 142329088Smarkm case OLD_ENV_VALUE: 142429088Smarkm /* 142529088Smarkm * Although OLD_ENV_VALUE is not legal, we will 142629088Smarkm * still recognize it, just in case it is an 142729088Smarkm * old server that has VAR & VALUE mixed up... 142829088Smarkm */ 1429103955Smarkm /* FALLTHROUGH */ 143029088Smarkm#else 143129088Smarkm case NEW_ENV_VAR: 143229088Smarkm#endif 143329088Smarkm case ENV_USERVAR: 143429088Smarkm if (ep) { 143529088Smarkm *epc = 0; 143629088Smarkm env_opt_add(ep); 143729088Smarkm } 143829088Smarkm ep = epc = &buf[i+1]; 143929088Smarkm break; 144029088Smarkm case ENV_ESC: 144129088Smarkm i++; 1442103955Smarkm /*FALLTHROUGH*/ 144329088Smarkm default: 144429088Smarkm if (epc) 144529088Smarkm *epc++ = buf[i]; 144629088Smarkm break; 144729088Smarkm } 144829088Smarkm } 144929088Smarkm if (ep) { 145029088Smarkm *epc = 0; 145129088Smarkm env_opt_add(ep); 145229088Smarkm } 145329088Smarkm env_opt_end(1); 145429088Smarkm break; 145529088Smarkm 145629088Smarkm case TELQUAL_IS: 145729088Smarkm case TELQUAL_INFO: 145829088Smarkm /* Ignore for now. We shouldn't get it anyway. */ 145929088Smarkm break; 146029088Smarkm 146129088Smarkm default: 146229088Smarkm break; 146329088Smarkm } 146429088Smarkm} 146529088Smarkm 146629088Smarkm#define OPT_REPLY_SIZE 256 146729088Smarkmunsigned char *opt_reply; 146829088Smarkmunsigned char *opt_replyp; 146929088Smarkmunsigned char *opt_replyend; 147029088Smarkm 147187139Smarkmvoid 147287139Smarkmenv_opt_start(void) 147329088Smarkm{ 147429088Smarkm if (opt_reply) 147529088Smarkm opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 147629088Smarkm else 147729088Smarkm opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 147829088Smarkm if (opt_reply == NULL) { 147929088Smarkm/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 148029088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 148129088Smarkm return; 148229088Smarkm } 148329088Smarkm opt_replyp = opt_reply; 148429088Smarkm opt_replyend = opt_reply + OPT_REPLY_SIZE; 148529088Smarkm *opt_replyp++ = IAC; 148629088Smarkm *opt_replyp++ = SB; 148729088Smarkm *opt_replyp++ = telopt_environ; 148829088Smarkm *opt_replyp++ = TELQUAL_IS; 148929088Smarkm} 149029088Smarkm 149187139Smarkmvoid 149287139Smarkmenv_opt_start_info(void) 149329088Smarkm{ 149429088Smarkm env_opt_start(); 149529088Smarkm if (opt_replyp) 149629088Smarkm opt_replyp[-1] = TELQUAL_INFO; 149729088Smarkm} 149829088Smarkm 149987139Smarkmvoid 150087139Smarkmenv_opt_add(unsigned char *ep) 150129088Smarkm{ 150287139Smarkm unsigned char *vp, c; 150329088Smarkm 150429088Smarkm if (opt_reply == NULL) /*XXX*/ 150529088Smarkm return; /*XXX*/ 150629088Smarkm 150729088Smarkm if (ep == NULL || *ep == '\0') { 150829088Smarkm /* Send user defined variables first. */ 150929088Smarkm env_default(1, 0); 151029181Smarkm while ((ep = env_default(0, 0))) 151129088Smarkm env_opt_add(ep); 151229088Smarkm 151329088Smarkm /* Now add the list of well know variables. */ 151429088Smarkm env_default(1, 1); 151529181Smarkm while ((ep = env_default(0, 1))) 151629088Smarkm env_opt_add(ep); 151729088Smarkm return; 151829088Smarkm } 151929088Smarkm vp = env_getvalue(ep); 152029088Smarkm if (opt_replyp + (vp ? strlen((char *)vp) : 0) + 152129088Smarkm strlen((char *)ep) + 6 > opt_replyend) 152229088Smarkm { 152387139Smarkm int len; 152429088Smarkm opt_replyend += OPT_REPLY_SIZE; 152529088Smarkm len = opt_replyend - opt_reply; 152629088Smarkm opt_reply = (unsigned char *)realloc(opt_reply, len); 152729088Smarkm if (opt_reply == NULL) { 152829088Smarkm/*@*/ printf("env_opt_add: realloc() failed!!!\n"); 152929088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 153029088Smarkm return; 153129088Smarkm } 153229088Smarkm opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 153329088Smarkm opt_replyend = opt_reply + len; 153429088Smarkm } 153529088Smarkm if (opt_welldefined(ep)) 153629088Smarkm#ifdef OLD_ENVIRON 153729088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 153829088Smarkm *opt_replyp++ = old_env_var; 153929088Smarkm else 154029088Smarkm#endif 154129088Smarkm *opt_replyp++ = NEW_ENV_VAR; 154229088Smarkm else 154329088Smarkm *opt_replyp++ = ENV_USERVAR; 154429088Smarkm for (;;) { 154529181Smarkm while ((c = *ep++)) { 154629088Smarkm switch(c&0xff) { 154729088Smarkm case IAC: 154829088Smarkm *opt_replyp++ = IAC; 154929088Smarkm break; 155029088Smarkm case NEW_ENV_VAR: 155129088Smarkm case NEW_ENV_VALUE: 155229088Smarkm case ENV_ESC: 155329088Smarkm case ENV_USERVAR: 155429088Smarkm *opt_replyp++ = ENV_ESC; 155529088Smarkm break; 155629088Smarkm } 155729088Smarkm *opt_replyp++ = c; 155829088Smarkm } 155929181Smarkm if ((ep = vp)) { 156029088Smarkm#ifdef OLD_ENVIRON 156129088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 156229088Smarkm *opt_replyp++ = old_env_value; 156329088Smarkm else 156429088Smarkm#endif 156529088Smarkm *opt_replyp++ = NEW_ENV_VALUE; 156629088Smarkm vp = NULL; 156729088Smarkm } else 156829088Smarkm break; 156929088Smarkm } 157029088Smarkm} 157129088Smarkm 157287139Smarkmint 157387139Smarkmopt_welldefined(const char *ep) 157429088Smarkm{ 157529088Smarkm if ((strcmp(ep, "USER") == 0) || 157629088Smarkm (strcmp(ep, "DISPLAY") == 0) || 157729088Smarkm (strcmp(ep, "PRINTER") == 0) || 157829088Smarkm (strcmp(ep, "SYSTEMTYPE") == 0) || 157929088Smarkm (strcmp(ep, "JOB") == 0) || 158029088Smarkm (strcmp(ep, "ACCT") == 0)) 158129088Smarkm return(1); 158229088Smarkm return(0); 158329088Smarkm} 158487139Smarkm 158587139Smarkmvoid 158687139Smarkmenv_opt_end(int emptyok) 158729088Smarkm{ 158887139Smarkm int len; 158929088Smarkm 159029088Smarkm len = opt_replyp - opt_reply + 2; 159129088Smarkm if (emptyok || len > 6) { 159229088Smarkm *opt_replyp++ = IAC; 159329088Smarkm *opt_replyp++ = SE; 159429088Smarkm if (NETROOM() > len) { 159529088Smarkm ring_supply_data(&netoring, opt_reply, len); 159629088Smarkm printsub('>', &opt_reply[2], len - 2); 159729088Smarkm } 159829088Smarkm/*@*/ else printf("slc_end_reply: not enough room\n"); 159929088Smarkm } 160029088Smarkm if (opt_reply) { 160129088Smarkm free(opt_reply); 160229088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 160329088Smarkm } 160429088Smarkm} 160529088Smarkm 160629088Smarkm 160729088Smarkm 160887139Smarkmint 160987139Smarkmtelrcv(void) 161029088Smarkm{ 161187139Smarkm int c; 161287139Smarkm int scc; 161387139Smarkm unsigned char *sbp; 161429088Smarkm int count; 161529088Smarkm int returnValue = 0; 161629088Smarkm 161729088Smarkm scc = 0; 161829088Smarkm count = 0; 161929088Smarkm while (TTYROOM() > 2) { 162029088Smarkm if (scc == 0) { 162129088Smarkm if (count) { 162229088Smarkm ring_consumed(&netiring, count); 162329088Smarkm returnValue = 1; 162429088Smarkm count = 0; 162529088Smarkm } 162629088Smarkm sbp = netiring.consume; 162729088Smarkm scc = ring_full_consecutive(&netiring); 162829088Smarkm if (scc == 0) { 162929088Smarkm /* No more data coming in */ 163029088Smarkm break; 163129088Smarkm } 163229088Smarkm } 163329088Smarkm 163429088Smarkm c = *sbp++ & 0xff, scc--; count++; 163529088Smarkm#ifdef ENCRYPTION 163629088Smarkm if (decrypt_input) 163729088Smarkm c = (*decrypt_input)(c); 163829088Smarkm#endif /* ENCRYPTION */ 163929088Smarkm 164029088Smarkm switch (telrcv_state) { 164129088Smarkm 164229088Smarkm case TS_CR: 164329088Smarkm telrcv_state = TS_DATA; 164429088Smarkm if (c == '\0') { 164529088Smarkm break; /* Ignore \0 after CR */ 164629088Smarkm } 164729088Smarkm else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 164829088Smarkm TTYADD(c); 164929088Smarkm break; 165029088Smarkm } 1651103955Smarkm /* FALLTHROUGH */ 165229088Smarkm 165329088Smarkm case TS_DATA: 165429088Smarkm if (c == IAC) { 165529088Smarkm telrcv_state = TS_IAC; 165629088Smarkm break; 165729088Smarkm } 165829088Smarkm /* 165929088Smarkm * The 'crmod' hack (see following) is needed 166029088Smarkm * since we can't * set CRMOD on output only. 166129088Smarkm * Machines like MULTICS like to send \r without 166229088Smarkm * \n; since we must turn off CRMOD to get proper 166329088Smarkm * input, the mapping is done here (sigh). 166429088Smarkm */ 166529088Smarkm if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 166629088Smarkm if (scc > 0) { 166729088Smarkm c = *sbp&0xff; 166829088Smarkm#ifdef ENCRYPTION 166929088Smarkm if (decrypt_input) 167029088Smarkm c = (*decrypt_input)(c); 167129088Smarkm#endif /* ENCRYPTION */ 167229088Smarkm if (c == 0) { 167329088Smarkm sbp++, scc--; count++; 167429088Smarkm /* a "true" CR */ 167529088Smarkm TTYADD('\r'); 167629088Smarkm } else if (my_want_state_is_dont(TELOPT_ECHO) && 167729088Smarkm (c == '\n')) { 167829088Smarkm sbp++, scc--; count++; 167929088Smarkm TTYADD('\n'); 168029088Smarkm } else { 168129088Smarkm#ifdef ENCRYPTION 168229088Smarkm if (decrypt_input) 168329088Smarkm (*decrypt_input)(-1); 168429088Smarkm#endif /* ENCRYPTION */ 168529088Smarkm 168629088Smarkm TTYADD('\r'); 168729088Smarkm if (crmod) { 168829088Smarkm TTYADD('\n'); 168929088Smarkm } 169029088Smarkm } 169129088Smarkm } else { 169229088Smarkm telrcv_state = TS_CR; 169329088Smarkm TTYADD('\r'); 169429088Smarkm if (crmod) { 169529088Smarkm TTYADD('\n'); 169629088Smarkm } 169729088Smarkm } 169829088Smarkm } else { 169929088Smarkm TTYADD(c); 170029088Smarkm } 170129088Smarkm continue; 170229088Smarkm 170329088Smarkm case TS_IAC: 170429088Smarkmprocess_iac: 170529088Smarkm switch (c) { 170629088Smarkm 170729088Smarkm case WILL: 170829088Smarkm telrcv_state = TS_WILL; 170929088Smarkm continue; 171029088Smarkm 171129088Smarkm case WONT: 171229088Smarkm telrcv_state = TS_WONT; 171329088Smarkm continue; 171429088Smarkm 171529088Smarkm case DO: 171629088Smarkm telrcv_state = TS_DO; 171729088Smarkm continue; 171829088Smarkm 171929088Smarkm case DONT: 172029088Smarkm telrcv_state = TS_DONT; 172129088Smarkm continue; 172229088Smarkm 172329088Smarkm case DM: 172429088Smarkm /* 172529088Smarkm * We may have missed an urgent notification, 172629088Smarkm * so make sure we flush whatever is in the 172729088Smarkm * buffer currently. 172829088Smarkm */ 172929088Smarkm printoption("RCVD", IAC, DM); 173029088Smarkm SYNCHing = 1; 173129088Smarkm (void) ttyflush(1); 173229088Smarkm SYNCHing = stilloob(); 173329088Smarkm settimer(gotDM); 173429088Smarkm break; 173529088Smarkm 173629088Smarkm case SB: 173729088Smarkm SB_CLEAR(); 173829088Smarkm telrcv_state = TS_SB; 173929088Smarkm continue; 174029088Smarkm 174129088Smarkm case IAC: 174229088Smarkm TTYADD(IAC); 174329088Smarkm break; 174429088Smarkm 174529088Smarkm case NOP: 174629088Smarkm case GA: 174729088Smarkm default: 174829088Smarkm printoption("RCVD", IAC, c); 174929088Smarkm break; 175029088Smarkm } 175129088Smarkm telrcv_state = TS_DATA; 175229088Smarkm continue; 175329088Smarkm 175429088Smarkm case TS_WILL: 175529088Smarkm printoption("RCVD", WILL, c); 175629088Smarkm willoption(c); 175729088Smarkm telrcv_state = TS_DATA; 175829088Smarkm continue; 175929088Smarkm 176029088Smarkm case TS_WONT: 176129088Smarkm printoption("RCVD", WONT, c); 176229088Smarkm wontoption(c); 176329088Smarkm telrcv_state = TS_DATA; 176429088Smarkm continue; 176529088Smarkm 176629088Smarkm case TS_DO: 176729088Smarkm printoption("RCVD", DO, c); 176829088Smarkm dooption(c); 176929088Smarkm if (c == TELOPT_NAWS) { 177029088Smarkm sendnaws(); 177129088Smarkm } else if (c == TELOPT_LFLOW) { 177229088Smarkm localflow = 1; 177329088Smarkm setcommandmode(); 177429088Smarkm setconnmode(0); 177529088Smarkm } 177629088Smarkm telrcv_state = TS_DATA; 177729088Smarkm continue; 177829088Smarkm 177929088Smarkm case TS_DONT: 178029088Smarkm printoption("RCVD", DONT, c); 178129088Smarkm dontoption(c); 178229088Smarkm flushline = 1; 178329088Smarkm setconnmode(0); /* set new tty mode (maybe) */ 178429088Smarkm telrcv_state = TS_DATA; 178529088Smarkm continue; 178629088Smarkm 178729088Smarkm case TS_SB: 178829088Smarkm if (c == IAC) { 178929088Smarkm telrcv_state = TS_SE; 179029088Smarkm } else { 179129088Smarkm SB_ACCUM(c); 179229088Smarkm } 179329088Smarkm continue; 179429088Smarkm 179529088Smarkm case TS_SE: 179629088Smarkm if (c != SE) { 179729088Smarkm if (c != IAC) { 179829088Smarkm /* 179929088Smarkm * This is an error. We only expect to get 180029088Smarkm * "IAC IAC" or "IAC SE". Several things may 180129088Smarkm * have happend. An IAC was not doubled, the 180229088Smarkm * IAC SE was left off, or another option got 180329088Smarkm * inserted into the suboption are all possibilities. 180429088Smarkm * If we assume that the IAC was not doubled, 180529088Smarkm * and really the IAC SE was left off, we could 180629088Smarkm * get into an infinate loop here. So, instead, 180729088Smarkm * we terminate the suboption, and process the 180829088Smarkm * partial suboption if we can. 180929088Smarkm */ 181029088Smarkm SB_ACCUM(IAC); 181129088Smarkm SB_ACCUM(c); 181229088Smarkm subpointer -= 2; 181329088Smarkm SB_TERM(); 181429088Smarkm 181529088Smarkm printoption("In SUBOPTION processing, RCVD", IAC, c); 181629088Smarkm suboption(); /* handle sub-option */ 181729088Smarkm telrcv_state = TS_IAC; 181829088Smarkm goto process_iac; 181929088Smarkm } 182029088Smarkm SB_ACCUM(c); 182129088Smarkm telrcv_state = TS_SB; 182229088Smarkm } else { 182329088Smarkm SB_ACCUM(IAC); 182429088Smarkm SB_ACCUM(SE); 182529088Smarkm subpointer -= 2; 182629088Smarkm SB_TERM(); 182729088Smarkm suboption(); /* handle sub-option */ 182829088Smarkm telrcv_state = TS_DATA; 182929088Smarkm } 183029088Smarkm } 183129088Smarkm } 183229088Smarkm if (count) 183329088Smarkm ring_consumed(&netiring, count); 183429088Smarkm return returnValue||count; 183529088Smarkm} 183629088Smarkm 183729088Smarkmstatic int bol = 1, local = 0; 183829088Smarkm 183987139Smarkmint 184087139Smarkmrlogin_susp(void) 184129088Smarkm{ 184229088Smarkm if (local) { 184329088Smarkm local = 0; 184429088Smarkm bol = 1; 184529088Smarkm command(0, "z\n", 2); 184629088Smarkm return(1); 184729088Smarkm } 184829088Smarkm return(0); 184929088Smarkm} 185029088Smarkm 185187139Smarkmstatic int 185287139Smarkmtelsnd(void) 185329088Smarkm{ 185429088Smarkm int tcc; 185529088Smarkm int count; 185629088Smarkm int returnValue = 0; 185729088Smarkm unsigned char *tbp; 185829088Smarkm 185929088Smarkm tcc = 0; 186029088Smarkm count = 0; 186129088Smarkm while (NETROOM() > 2) { 186287139Smarkm int sc; 186387139Smarkm int c; 186429088Smarkm 186529088Smarkm if (tcc == 0) { 186629088Smarkm if (count) { 186729088Smarkm ring_consumed(&ttyiring, count); 186829088Smarkm returnValue = 1; 186929088Smarkm count = 0; 187029088Smarkm } 187129088Smarkm tbp = ttyiring.consume; 187229088Smarkm tcc = ring_full_consecutive(&ttyiring); 187329088Smarkm if (tcc == 0) { 187429088Smarkm break; 187529088Smarkm } 187629088Smarkm } 187729088Smarkm c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 187829088Smarkm if (rlogin != _POSIX_VDISABLE) { 187929088Smarkm if (bol) { 188029088Smarkm bol = 0; 188129088Smarkm if (sc == rlogin) { 188229088Smarkm local = 1; 188329088Smarkm continue; 188429088Smarkm } 188529088Smarkm } else if (local) { 188629088Smarkm local = 0; 188729088Smarkm if (sc == '.' || c == termEofChar) { 188829088Smarkm bol = 1; 188929088Smarkm command(0, "close\n", 6); 189029088Smarkm continue; 189129088Smarkm } 189229088Smarkm if (sc == termSuspChar) { 189329088Smarkm bol = 1; 189429088Smarkm command(0, "z\n", 2); 189529088Smarkm continue; 189629088Smarkm } 189729088Smarkm if (sc == escape) { 189887139Smarkm command(0, tbp, tcc); 189929088Smarkm bol = 1; 190029088Smarkm count += tcc; 190129088Smarkm tcc = 0; 190229088Smarkm flushline = 1; 190329088Smarkm break; 190429088Smarkm } 190529088Smarkm if (sc != rlogin) { 190629088Smarkm ++tcc; 190729088Smarkm --tbp; 190829088Smarkm --count; 190929088Smarkm c = sc = rlogin; 191029088Smarkm } 191129088Smarkm } 191229088Smarkm if ((sc == '\n') || (sc == '\r')) 191329088Smarkm bol = 1; 191447973Sru } else if (escape != _POSIX_VDISABLE && sc == escape) { 191529088Smarkm /* 191629088Smarkm * Double escape is a pass through of a single escape character. 191729088Smarkm */ 191829088Smarkm if (tcc && strip(*tbp) == escape) { 191929088Smarkm tbp++; 192029088Smarkm tcc--; 192129088Smarkm count++; 192229088Smarkm bol = 0; 192329088Smarkm } else { 192429088Smarkm command(0, (char *)tbp, tcc); 192529088Smarkm bol = 1; 192629088Smarkm count += tcc; 192729088Smarkm tcc = 0; 192829088Smarkm flushline = 1; 192929088Smarkm break; 193029088Smarkm } 193129088Smarkm } else 193229088Smarkm bol = 0; 193329088Smarkm#ifdef KLUDGELINEMODE 193429088Smarkm if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 193529088Smarkm if (tcc > 0 && strip(*tbp) == echoc) { 193629088Smarkm tcc--; tbp++; count++; 193729088Smarkm } else { 193829088Smarkm dontlecho = !dontlecho; 193929088Smarkm settimer(echotoggle); 194029088Smarkm setconnmode(0); 194129088Smarkm flushline = 1; 194229088Smarkm break; 194329088Smarkm } 194429088Smarkm } 194529088Smarkm#endif 194629088Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 194729088Smarkm if (TerminalSpecialChars(sc) == 0) { 194829088Smarkm bol = 1; 194929088Smarkm break; 195029088Smarkm } 195129088Smarkm } 195229088Smarkm if (my_want_state_is_wont(TELOPT_BINARY)) { 195329088Smarkm switch (c) { 195429088Smarkm case '\n': 195529088Smarkm /* 195629088Smarkm * If we are in CRMOD mode (\r ==> \n) 195729088Smarkm * on our local machine, then probably 195829088Smarkm * a newline (unix) is CRLF (TELNET). 195929088Smarkm */ 196029088Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 196129088Smarkm NETADD('\r'); 196229088Smarkm } 196329088Smarkm NETADD('\n'); 196429088Smarkm bol = flushline = 1; 196529088Smarkm break; 196629088Smarkm case '\r': 196729088Smarkm if (!crlf) { 196829088Smarkm NET2ADD('\r', '\0'); 196929088Smarkm } else { 197029088Smarkm NET2ADD('\r', '\n'); 197129088Smarkm } 197229088Smarkm bol = flushline = 1; 197329088Smarkm break; 197429088Smarkm case IAC: 197529088Smarkm NET2ADD(IAC, IAC); 197629088Smarkm break; 197729088Smarkm default: 197829088Smarkm NETADD(c); 197929088Smarkm break; 198029088Smarkm } 198129088Smarkm } else if (c == IAC) { 198229088Smarkm NET2ADD(IAC, IAC); 198329088Smarkm } else { 198429088Smarkm NETADD(c); 198529088Smarkm } 198629088Smarkm } 198729088Smarkm if (count) 198829088Smarkm ring_consumed(&ttyiring, count); 198929088Smarkm return returnValue||count; /* Non-zero if we did anything */ 199029088Smarkm} 199129088Smarkm 199229088Smarkm/* 199329088Smarkm * Scheduler() 199429088Smarkm * 199529088Smarkm * Try to do something. 199629088Smarkm * 199729088Smarkm * If we do something useful, return 1; else return 0. 199829088Smarkm * 199929088Smarkm */ 200029088Smarkm 200187139Smarkmstatic int 200287139SmarkmScheduler(int block) 200329088Smarkm{ 200429088Smarkm /* One wants to be a bit careful about setting returnValue 200529088Smarkm * to one, since a one implies we did some useful work, 200629088Smarkm * and therefore probably won't be called to block next 200729088Smarkm */ 200829088Smarkm int returnValue; 200929088Smarkm int netin, netout, netex, ttyin, ttyout; 201029088Smarkm 201129088Smarkm /* Decide which rings should be processed */ 201229088Smarkm 201329088Smarkm netout = ring_full_count(&netoring) && 201429088Smarkm (flushline || 201529088Smarkm (my_want_state_is_wont(TELOPT_LINEMODE) 201629088Smarkm#ifdef KLUDGELINEMODE 201729088Smarkm && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 201829088Smarkm#endif 201929088Smarkm ) || 202029088Smarkm my_want_state_is_will(TELOPT_BINARY)); 202129088Smarkm ttyout = ring_full_count(&ttyoring); 202229088Smarkm 202329181Smarkm ttyin = ring_empty_count(&ttyiring) && (clienteof == 0); 202429088Smarkm 202529088Smarkm netin = !ISend && ring_empty_count(&netiring); 202629088Smarkm 202729088Smarkm netex = !SYNCHing; 202829088Smarkm 202929088Smarkm /* Call to system code to process rings */ 203029088Smarkm 203129088Smarkm returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 203229088Smarkm 203329088Smarkm /* Now, look at the input rings, looking for work to do. */ 203429088Smarkm 203529088Smarkm if (ring_full_count(&ttyiring)) { 203629088Smarkm returnValue |= telsnd(); 203729088Smarkm } 203829088Smarkm 203929088Smarkm if (ring_full_count(&netiring)) { 204029088Smarkm returnValue |= telrcv(); 204129088Smarkm } 204229088Smarkm return returnValue; 204329088Smarkm} 204429088Smarkm 204587139Smarkm#ifdef AUTHENTICATION 204687139Smarkm#define __unusedhere 204787139Smarkm#else 204887139Smarkm#define __unusedhere __unused 204987139Smarkm#endif 205029088Smarkm/* 205129088Smarkm * Select from tty and network... 205229088Smarkm */ 205387139Smarkmvoid 205487139Smarkmtelnet(char *user __unusedhere) 205529088Smarkm{ 205629088Smarkm sys_telnet_init(); 205729088Smarkm 205887139Smarkm#ifdef AUTHENTICATION 205987139Smarkm#ifdef ENCRYPTION 206029088Smarkm { 206129088Smarkm static char local_host[256] = { 0 }; 206229088Smarkm 206329088Smarkm if (!local_host[0]) { 206429088Smarkm gethostname(local_host, sizeof(local_host)); 206529088Smarkm local_host[sizeof(local_host)-1] = 0; 206629088Smarkm } 206729088Smarkm auth_encrypt_init(local_host, hostname, "TELNET", 0); 206829088Smarkm auth_encrypt_user(user); 206929088Smarkm } 207087139Smarkm#endif 207187139Smarkm#endif 207229088Smarkm if (telnetport) { 207387139Smarkm#ifdef AUTHENTICATION 207429088Smarkm if (autologin) 207529088Smarkm send_will(TELOPT_AUTHENTICATION, 1); 207629088Smarkm#endif 207729088Smarkm#ifdef ENCRYPTION 207829088Smarkm send_do(TELOPT_ENCRYPT, 1); 207929088Smarkm send_will(TELOPT_ENCRYPT, 1); 208029088Smarkm#endif /* ENCRYPTION */ 208129088Smarkm send_do(TELOPT_SGA, 1); 208229088Smarkm send_will(TELOPT_TTYPE, 1); 208329088Smarkm send_will(TELOPT_NAWS, 1); 208429088Smarkm send_will(TELOPT_TSPEED, 1); 208529088Smarkm send_will(TELOPT_LFLOW, 1); 208629088Smarkm send_will(TELOPT_LINEMODE, 1); 208729088Smarkm send_will(TELOPT_NEW_ENVIRON, 1); 208829088Smarkm send_do(TELOPT_STATUS, 1); 208987139Smarkm if (env_getvalue("DISPLAY")) 209029088Smarkm send_will(TELOPT_XDISPLOC, 1); 209129088Smarkm if (eight) 209229088Smarkm tel_enter_binary(eight); 209329088Smarkm } 209429088Smarkm 209529088Smarkm for (;;) { 209629088Smarkm int schedValue; 209729088Smarkm 209829088Smarkm while ((schedValue = Scheduler(0)) != 0) { 209929088Smarkm if (schedValue == -1) { 210029088Smarkm setcommandmode(); 210129088Smarkm return; 210229088Smarkm } 210329088Smarkm } 210429088Smarkm 210529088Smarkm if (Scheduler(1) == -1) { 210629088Smarkm setcommandmode(); 210729088Smarkm return; 210829088Smarkm } 210929088Smarkm } 211029088Smarkm} 211129088Smarkm 211229088Smarkm#if 0 /* XXX - this not being in is a bug */ 211329088Smarkm/* 211429088Smarkm * nextitem() 211529088Smarkm * 211629088Smarkm * Return the address of the next "item" in the TELNET data 211729088Smarkm * stream. This will be the address of the next character if 211829088Smarkm * the current address is a user data character, or it will 211929088Smarkm * be the address of the character following the TELNET command 212029088Smarkm * if the current address is a TELNET IAC ("I Am a Command") 212129088Smarkm * character. 212229088Smarkm */ 212329088Smarkm 212487139Smarkmstatic char * 212587139Smarkmnextitem(char *current) 212629088Smarkm{ 212729088Smarkm if ((*current&0xff) != IAC) { 212829088Smarkm return current+1; 212929088Smarkm } 213029088Smarkm switch (*(current+1)&0xff) { 213129088Smarkm case DO: 213229088Smarkm case DONT: 213329088Smarkm case WILL: 213429088Smarkm case WONT: 213529088Smarkm return current+3; 213629088Smarkm case SB: /* loop forever looking for the SE */ 213729088Smarkm { 213887139Smarkm char *look = current+2; 213929088Smarkm 214029088Smarkm for (;;) { 214129088Smarkm if ((*look++&0xff) == IAC) { 214229088Smarkm if ((*look++&0xff) == SE) { 214329088Smarkm return look; 214429088Smarkm } 214529088Smarkm } 214629088Smarkm } 214729088Smarkm } 214829088Smarkm default: 214929088Smarkm return current+2; 215029088Smarkm } 215129088Smarkm} 215229088Smarkm#endif /* 0 */ 215329088Smarkm 215429088Smarkm/* 215529088Smarkm * netclear() 215629088Smarkm * 215729088Smarkm * We are about to do a TELNET SYNCH operation. Clear 215829088Smarkm * the path to the network. 215929088Smarkm * 216029088Smarkm * Things are a bit tricky since we may have sent the first 216129088Smarkm * byte or so of a previous TELNET command into the network. 216229088Smarkm * So, we have to scan the network buffer from the beginning 216329088Smarkm * until we are up to where we want to be. 216429088Smarkm * 216529088Smarkm * A side effect of what we do, just to keep things 216629088Smarkm * simple, is to clear the urgent data pointer. The principal 216729088Smarkm * caller should be setting the urgent data pointer AFTER calling 216829088Smarkm * us in any case. 216929088Smarkm */ 217029088Smarkm 217187139Smarkmstatic void 217287139Smarkmnetclear(void) 217329088Smarkm{ 217487139Smarkm /* Deleted */ 217529088Smarkm} 217629088Smarkm 217729088Smarkm/* 217829088Smarkm * These routines add various telnet commands to the data stream. 217929088Smarkm */ 218029088Smarkm 218187139Smarkmstatic void 218287139Smarkmdoflush(void) 218329088Smarkm{ 218429088Smarkm NET2ADD(IAC, DO); 218529088Smarkm NETADD(TELOPT_TM); 218629088Smarkm flushline = 1; 218729088Smarkm flushout = 1; 218829088Smarkm (void) ttyflush(1); /* Flush/drop output */ 218929088Smarkm /* do printoption AFTER flush, otherwise the output gets tossed... */ 219029088Smarkm printoption("SENT", DO, TELOPT_TM); 219129088Smarkm} 219229088Smarkm 219387139Smarkmvoid 219487139SmarkmxmitAO(void) 219529088Smarkm{ 219629088Smarkm NET2ADD(IAC, AO); 219729088Smarkm printoption("SENT", IAC, AO); 219829088Smarkm if (autoflush) { 219929088Smarkm doflush(); 220029088Smarkm } 220129088Smarkm} 220229088Smarkm 220387139Smarkmvoid 220487139SmarkmxmitEL(void) 220529088Smarkm{ 220629088Smarkm NET2ADD(IAC, EL); 220729088Smarkm printoption("SENT", IAC, EL); 220829088Smarkm} 220929088Smarkm 221087139Smarkmvoid 221187139SmarkmxmitEC(void) 221229088Smarkm{ 221329088Smarkm NET2ADD(IAC, EC); 221429088Smarkm printoption("SENT", IAC, EC); 221529088Smarkm} 221629088Smarkm 221787139Smarkmint 221887139Smarkmdosynch(char *ch __unused) 221929088Smarkm{ 222029088Smarkm netclear(); /* clear the path to the network */ 222129088Smarkm NETADD(IAC); 222229088Smarkm setneturg(); 222329088Smarkm NETADD(DM); 222429088Smarkm printoption("SENT", IAC, DM); 222529088Smarkm return 1; 222629088Smarkm} 222729088Smarkm 222829088Smarkmint want_status_response = 0; 222929088Smarkm 223087139Smarkmint 223187139Smarkmget_status(char *ch __unused) 223229088Smarkm{ 223329088Smarkm unsigned char tmp[16]; 223487139Smarkm unsigned char *cp; 223529088Smarkm 223629088Smarkm if (my_want_state_is_dont(TELOPT_STATUS)) { 223729088Smarkm printf("Remote side does not support STATUS option\n"); 223829088Smarkm return 0; 223929088Smarkm } 224029088Smarkm cp = tmp; 224129088Smarkm 224229088Smarkm *cp++ = IAC; 224329088Smarkm *cp++ = SB; 224429088Smarkm *cp++ = TELOPT_STATUS; 224529088Smarkm *cp++ = TELQUAL_SEND; 224629088Smarkm *cp++ = IAC; 224729088Smarkm *cp++ = SE; 224829088Smarkm if (NETROOM() >= cp - tmp) { 224929088Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 225029088Smarkm printsub('>', tmp+2, cp - tmp - 2); 225129088Smarkm } 225229088Smarkm ++want_status_response; 225329088Smarkm return 1; 225429088Smarkm} 225529088Smarkm 225687139Smarkmvoid 225787139Smarkmintp(void) 225829088Smarkm{ 225929088Smarkm NET2ADD(IAC, IP); 226029088Smarkm printoption("SENT", IAC, IP); 226129088Smarkm flushline = 1; 226229088Smarkm if (autoflush) { 226329088Smarkm doflush(); 226429088Smarkm } 226529088Smarkm if (autosynch) { 226687139Smarkm dosynch(NULL); 226729088Smarkm } 226829088Smarkm} 226929088Smarkm 227087139Smarkmvoid 227187139Smarkmsendbrk(void) 227229088Smarkm{ 227329088Smarkm NET2ADD(IAC, BREAK); 227429088Smarkm printoption("SENT", IAC, BREAK); 227529088Smarkm flushline = 1; 227629088Smarkm if (autoflush) { 227729088Smarkm doflush(); 227829088Smarkm } 227929088Smarkm if (autosynch) { 228087139Smarkm dosynch(NULL); 228129088Smarkm } 228229088Smarkm} 228329088Smarkm 228487139Smarkmvoid 228587139Smarkmsendabort(void) 228629088Smarkm{ 228729088Smarkm NET2ADD(IAC, ABORT); 228829088Smarkm printoption("SENT", IAC, ABORT); 228929088Smarkm flushline = 1; 229029088Smarkm if (autoflush) { 229129088Smarkm doflush(); 229229088Smarkm } 229329088Smarkm if (autosynch) { 229487139Smarkm dosynch(NULL); 229529088Smarkm } 229629088Smarkm} 229729088Smarkm 229887139Smarkmvoid 229987139Smarkmsendsusp(void) 230029088Smarkm{ 230129088Smarkm NET2ADD(IAC, SUSP); 230229088Smarkm printoption("SENT", IAC, SUSP); 230329088Smarkm flushline = 1; 230429088Smarkm if (autoflush) { 230529088Smarkm doflush(); 230629088Smarkm } 230729088Smarkm if (autosynch) { 230887139Smarkm dosynch(NULL); 230929088Smarkm } 231029088Smarkm} 231129088Smarkm 231287139Smarkmvoid 231387139Smarkmsendeof(void) 231429088Smarkm{ 231529088Smarkm NET2ADD(IAC, xEOF); 231629088Smarkm printoption("SENT", IAC, xEOF); 231729088Smarkm} 231829088Smarkm 231987139Smarkmvoid 232087139Smarkmsendayt(void) 232129088Smarkm{ 232229088Smarkm NET2ADD(IAC, AYT); 232329088Smarkm printoption("SENT", IAC, AYT); 232429088Smarkm} 232529088Smarkm 232629088Smarkm/* 232729088Smarkm * Send a window size update to the remote system. 232829088Smarkm */ 232929088Smarkm 233087139Smarkmvoid 233187139Smarkmsendnaws(void) 233229088Smarkm{ 233329088Smarkm long rows, cols; 233429088Smarkm unsigned char tmp[16]; 233587139Smarkm unsigned char *cp; 233629088Smarkm 233729088Smarkm if (my_state_is_wont(TELOPT_NAWS)) 233829088Smarkm return; 233929088Smarkm 234029088Smarkm#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 234129088Smarkm if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 234229088Smarkm 234329088Smarkm if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 234429088Smarkm return; 234529088Smarkm } 234629088Smarkm 234729088Smarkm cp = tmp; 234829088Smarkm 234929088Smarkm *cp++ = IAC; 235029088Smarkm *cp++ = SB; 235129088Smarkm *cp++ = TELOPT_NAWS; 235229088Smarkm PUTSHORT(cp, cols); 235329088Smarkm PUTSHORT(cp, rows); 235429088Smarkm *cp++ = IAC; 235529088Smarkm *cp++ = SE; 235629088Smarkm if (NETROOM() >= cp - tmp) { 235729088Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 235829088Smarkm printsub('>', tmp+2, cp - tmp - 2); 235929088Smarkm } 236029088Smarkm} 236129088Smarkm 236287139Smarkmvoid 236387139Smarkmtel_enter_binary(int rw) 236429088Smarkm{ 236529088Smarkm if (rw&1) 236629088Smarkm send_do(TELOPT_BINARY, 1); 236729088Smarkm if (rw&2) 236829088Smarkm send_will(TELOPT_BINARY, 1); 236929088Smarkm} 237029088Smarkm 237187139Smarkmvoid 237287139Smarkmtel_leave_binary(int rw) 237329088Smarkm{ 237429088Smarkm if (rw&1) 237529088Smarkm send_dont(TELOPT_BINARY, 1); 237629088Smarkm if (rw&2) 237729088Smarkm send_wont(TELOPT_BINARY, 1); 237829088Smarkm} 2379