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$"); 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> 55275508Sngie#include <arpa/inet.h> 5687139Smarkm#include <arpa/telnet.h> 5729181Smarkm 5829088Smarkm#include "ring.h" 5929088Smarkm 6029088Smarkm#include "defines.h" 6129088Smarkm#include "externs.h" 6229088Smarkm#include "types.h" 6329088Smarkm#include "general.h" 6429088Smarkm 6587139Smarkm#ifdef AUTHENTICATION 6629181Smarkm#include <libtelnet/auth.h> 6729181Smarkm#endif 6887139Smarkm#ifdef ENCRYPTION 6929181Smarkm#include <libtelnet/encrypt.h> 7029181Smarkm#endif 7129181Smarkm#include <libtelnet/misc.h> 72275508Sngie 7329088Smarkm#define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x)) 7429088Smarkm 7529088Smarkmstatic unsigned char subbuffer[SUBBUFSIZE], 7629088Smarkm *subpointer, *subend; /* buffer for sub-options */ 7729088Smarkm#define SB_CLEAR() subpointer = subbuffer; 7829088Smarkm#define SB_TERM() { subend = subpointer; SB_CLEAR(); } 7929088Smarkm#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 8029088Smarkm *subpointer++ = (c); \ 8129088Smarkm } 8229088Smarkm 8329088Smarkm#define SB_GET() ((*subpointer++)&0xff) 8429088Smarkm#define SB_PEEK() ((*subpointer)&0xff) 8529088Smarkm#define SB_EOF() (subpointer >= subend) 8629088Smarkm#define SB_LEN() (subend - subpointer) 8729088Smarkm 8829088Smarkmchar options[256]; /* The combined options */ 8929088Smarkmchar do_dont_resp[256]; 9029088Smarkmchar will_wont_resp[256]; 9129088Smarkm 9229088Smarkmint 9329088Smarkm eight = 0, 9429088Smarkm autologin = 0, /* Autologin anyone? */ 9529088Smarkm skiprc = 0, 9629088Smarkm connected, 9729088Smarkm showoptions, 9829088Smarkm ISend, /* trying to send network data in */ 99114911Smarkm telnet_debug = 0, 10029088Smarkm crmod, 10129088Smarkm netdata, /* Print out network data flow */ 10229088Smarkm crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 10329088Smarkm telnetport, 10429088Smarkm SYNCHing, /* we are in TELNET SYNCH mode */ 10529088Smarkm flushout, /* flush output */ 10629088Smarkm autoflush = 0, /* flush output when interrupting? */ 10729088Smarkm autosynch, /* send interrupt characters with SYNCH? */ 10829088Smarkm localflow, /* we handle flow control locally */ 10929088Smarkm restartany, /* if flow control enabled, restart on any character */ 11029088Smarkm localchars, /* we recognize interrupt/quit */ 11129088Smarkm donelclchars, /* the user has set "localchars" */ 11229088Smarkm donebinarytoggle, /* the user has put us in binary */ 11329088Smarkm dontlecho, /* do we suppress local echoing right now? */ 11429181Smarkm globalmode, 11547973Sru doaddrlookup = 1, /* do a reverse address lookup? */ 11629181Smarkm clienteof = 0; 11729088Smarkm 11829088Smarkmchar *prompt = 0; 11981965Smarkm#ifdef ENCRYPTION 12076616Speterchar *line; /* hack around breakage in sra.c :-( !! */ 12181965Smarkm#endif 12229088Smarkm 12329088Smarkmcc_t escape; 12429088Smarkmcc_t rlogin; 12529088Smarkm#ifdef KLUDGELINEMODE 12629088Smarkmcc_t echoc; 12729088Smarkm#endif 12829088Smarkm 12929088Smarkm/* 13029088Smarkm * Telnet receiver states for fsm 13129088Smarkm */ 13229088Smarkm#define TS_DATA 0 13329088Smarkm#define TS_IAC 1 13429088Smarkm#define TS_WILL 2 13529088Smarkm#define TS_WONT 3 13629088Smarkm#define TS_DO 4 13729088Smarkm#define TS_DONT 5 13829088Smarkm#define TS_CR 6 13929088Smarkm#define TS_SB 7 /* sub-option collection */ 14029088Smarkm#define TS_SE 8 /* looking for sub-option end */ 14129088Smarkm 14229088Smarkmstatic int telrcv_state; 14329088Smarkm#ifdef OLD_ENVIRON 14429088Smarkmunsigned char telopt_environ = TELOPT_NEW_ENVIRON; 14529088Smarkm#else 14629088Smarkm# define telopt_environ TELOPT_NEW_ENVIRON 14729088Smarkm#endif 14829088Smarkm 14987139Smarkmjmp_buf toplevel; 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; 166275508Sngie 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 201275508Sngie 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 210275508Sngieunsigned char ComPortBaudRate[256]; 211275508Sngie 21287139Smarkmvoid 213275508SngieDoBaudRate(char *arg) 214275508Sngie{ 215275508Sngie char *temp, temp2[10]; 216275508Sngie int i; 217275508Sngie uint32_t baudrate; 218275508Sngie 219275508Sngie errno = 0; 220275508Sngie baudrate = (uint32_t)strtol(arg, &temp, 10); 221275508Sngie if (temp[0] != '\0' || (baudrate == 0 && errno != 0)) 222275508Sngie ExitString("Invalid baud rate provided.\n", 1); 223275508Sngie 224275508Sngie for (i = 1; termspeeds[i].speed != -1; i++) 225275508Sngie if (baudrate == termspeeds[i].speed) 226275508Sngie break; 227275508Sngie if (termspeeds[i].speed == -1) 228275508Sngie ExitString("Invalid baud rate provided.\n", 1); 229275508Sngie 230275508Sngie strlcpy(ComPortBaudRate, arg, sizeof(ComPortBaudRate)); 231275508Sngie 232275508Sngie if (NETROOM() < sizeof(temp2)) { 233275508Sngie ExitString("No room in buffer for baud rate.\n", 1); 234275508Sngie /* NOTREACHED */ 235275508Sngie } 236275508Sngie 237275508Sngie snprintf(temp2, sizeof(temp2), "%c%c%c%c....%c%c", IAC, SB, TELOPT_COMPORT, 238275508Sngie COMPORT_SET_BAUDRATE, IAC, SE); 239275508Sngie 240275508Sngie baudrate = htonl(baudrate); 241275508Sngie memcpy(&temp2[4], &baudrate, sizeof(baudrate)); 242275508Sngie ring_supply_data(&netoring, temp2, sizeof(temp2)); 243275508Sngie printsub('>', &temp[2], sizeof(temp2) - 2); 244275508Sngie} 245275508Sngie 246275508Sngievoid 24787139Smarkmsend_do(int c, int init) 24829088Smarkm{ 24929088Smarkm if (init) { 25029088Smarkm if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 25129088Smarkm my_want_state_is_do(c)) 25229088Smarkm return; 25329088Smarkm set_my_want_state_do(c); 25429088Smarkm do_dont_resp[c]++; 25529088Smarkm } 256142790Stobez if (telnetport < 0) 257142790Stobez return; 25829088Smarkm NET2ADD(IAC, DO); 25929088Smarkm NETADD(c); 26029088Smarkm printoption("SENT", DO, c); 26129088Smarkm} 26229088Smarkm 26387139Smarkmvoid 26487139Smarkmsend_dont(int c, int init) 26529088Smarkm{ 26629088Smarkm if (init) { 26729088Smarkm if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 26829088Smarkm my_want_state_is_dont(c)) 26929088Smarkm return; 27029088Smarkm set_my_want_state_dont(c); 27129088Smarkm do_dont_resp[c]++; 27229088Smarkm } 273142790Stobez if (telnetport < 0) 274142790Stobez return; 27529088Smarkm NET2ADD(IAC, DONT); 27629088Smarkm NETADD(c); 27729088Smarkm printoption("SENT", DONT, c); 27829088Smarkm} 27929088Smarkm 28087139Smarkmvoid 28187139Smarkmsend_will(int c, int init) 28229088Smarkm{ 28329088Smarkm if (init) { 28429088Smarkm if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 28529088Smarkm my_want_state_is_will(c)) 28629088Smarkm return; 28729088Smarkm set_my_want_state_will(c); 28829088Smarkm will_wont_resp[c]++; 28929088Smarkm } 290142790Stobez if (telnetport < 0) 291142790Stobez return; 29229088Smarkm NET2ADD(IAC, WILL); 29329088Smarkm NETADD(c); 29429088Smarkm printoption("SENT", WILL, c); 29529088Smarkm} 29629088Smarkm 29787139Smarkmvoid 29887139Smarkmsend_wont(int c, int init) 29929088Smarkm{ 30029088Smarkm if (init) { 30129088Smarkm if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 30229088Smarkm my_want_state_is_wont(c)) 30329088Smarkm return; 30429088Smarkm set_my_want_state_wont(c); 30529088Smarkm will_wont_resp[c]++; 30629088Smarkm } 307142790Stobez if (telnetport < 0) 308142790Stobez return; 30929088Smarkm NET2ADD(IAC, WONT); 31029088Smarkm NETADD(c); 31129088Smarkm printoption("SENT", WONT, c); 31229088Smarkm} 31329088Smarkm 31487139Smarkmvoid 31587139Smarkmwilloption(int option) 31629088Smarkm{ 31729088Smarkm int new_state_ok = 0; 31829088Smarkm 31929088Smarkm if (do_dont_resp[option]) { 32029088Smarkm --do_dont_resp[option]; 32129088Smarkm if (do_dont_resp[option] && my_state_is_do(option)) 32229088Smarkm --do_dont_resp[option]; 32329088Smarkm } 32429088Smarkm 32529088Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 32629088Smarkm 32729088Smarkm switch (option) { 32829088Smarkm 32929088Smarkm case TELOPT_ECHO: 33029088Smarkm case TELOPT_BINARY: 33129088Smarkm case TELOPT_SGA: 33229088Smarkm settimer(modenegotiated); 333103955Smarkm /* FALLTHROUGH */ 33429088Smarkm case TELOPT_STATUS: 33587139Smarkm#ifdef AUTHENTICATION 33629088Smarkm case TELOPT_AUTHENTICATION: 33729088Smarkm#endif 33829088Smarkm#ifdef ENCRYPTION 33929088Smarkm case TELOPT_ENCRYPT: 34029088Smarkm#endif /* ENCRYPTION */ 34129088Smarkm new_state_ok = 1; 34229088Smarkm break; 34329088Smarkm 34429088Smarkm case TELOPT_TM: 34529088Smarkm if (flushout) 34629088Smarkm flushout = 0; 34729088Smarkm /* 34829088Smarkm * Special case for TM. If we get back a WILL, 34929088Smarkm * pretend we got back a WONT. 35029088Smarkm */ 35129088Smarkm set_my_want_state_dont(option); 35229088Smarkm set_my_state_dont(option); 35329088Smarkm return; /* Never reply to TM will's/wont's */ 35429088Smarkm 35529088Smarkm case TELOPT_LINEMODE: 35629088Smarkm default: 35729088Smarkm break; 35829088Smarkm } 35929088Smarkm 36029088Smarkm if (new_state_ok) { 36129088Smarkm set_my_want_state_do(option); 36229088Smarkm send_do(option, 0); 36329088Smarkm setconnmode(0); /* possibly set new tty mode */ 36429088Smarkm } else { 36529088Smarkm do_dont_resp[option]++; 36629088Smarkm send_dont(option, 0); 36729088Smarkm } 36829088Smarkm } 36929088Smarkm set_my_state_do(option); 37029088Smarkm#ifdef ENCRYPTION 37129088Smarkm if (option == TELOPT_ENCRYPT) 37229088Smarkm encrypt_send_support(); 37329088Smarkm#endif /* ENCRYPTION */ 37429088Smarkm} 37529088Smarkm 37687139Smarkmvoid 37787139Smarkmwontoption(int option) 37829088Smarkm{ 37929088Smarkm if (do_dont_resp[option]) { 38029088Smarkm --do_dont_resp[option]; 38129088Smarkm if (do_dont_resp[option] && my_state_is_dont(option)) 38229088Smarkm --do_dont_resp[option]; 38329088Smarkm } 38429088Smarkm 38529088Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 38629088Smarkm 38729088Smarkm switch (option) { 38829088Smarkm 38929088Smarkm#ifdef KLUDGELINEMODE 39029088Smarkm case TELOPT_SGA: 39129088Smarkm if (!kludgelinemode) 39229088Smarkm break; 393103955Smarkm /* FALLTHROUGH */ 39429088Smarkm#endif 39529088Smarkm case TELOPT_ECHO: 39629088Smarkm settimer(modenegotiated); 39729088Smarkm break; 39829088Smarkm 39929088Smarkm case TELOPT_TM: 40029088Smarkm if (flushout) 40129088Smarkm flushout = 0; 40229088Smarkm set_my_want_state_dont(option); 40329088Smarkm set_my_state_dont(option); 40429088Smarkm return; /* Never reply to TM will's/wont's */ 40529088Smarkm 40629088Smarkm default: 40729088Smarkm break; 40829088Smarkm } 40929088Smarkm set_my_want_state_dont(option); 41029088Smarkm if (my_state_is_do(option)) 41129088Smarkm send_dont(option, 0); 41229088Smarkm setconnmode(0); /* Set new tty mode */ 41329088Smarkm } else if (option == TELOPT_TM) { 41429088Smarkm /* 41529088Smarkm * Special case for TM. 41629088Smarkm */ 41729088Smarkm if (flushout) 41829088Smarkm flushout = 0; 41929088Smarkm set_my_want_state_dont(option); 42029088Smarkm } 42129088Smarkm set_my_state_dont(option); 42229088Smarkm} 42329088Smarkm 42487139Smarkmstatic void 42587139Smarkmdooption(int option) 42629088Smarkm{ 42729088Smarkm int new_state_ok = 0; 42829088Smarkm 42929088Smarkm if (will_wont_resp[option]) { 43029088Smarkm --will_wont_resp[option]; 43129088Smarkm if (will_wont_resp[option] && my_state_is_will(option)) 43229088Smarkm --will_wont_resp[option]; 43329088Smarkm } 43429088Smarkm 43529088Smarkm if (will_wont_resp[option] == 0) { 43629088Smarkm if (my_want_state_is_wont(option)) { 43729088Smarkm 43829088Smarkm switch (option) { 43929088Smarkm 44029088Smarkm case TELOPT_TM: 44129088Smarkm /* 44229088Smarkm * Special case for TM. We send a WILL, but pretend 44329088Smarkm * we sent WONT. 44429088Smarkm */ 44529088Smarkm send_will(option, 0); 44629088Smarkm set_my_want_state_wont(TELOPT_TM); 44729088Smarkm set_my_state_wont(TELOPT_TM); 44829088Smarkm return; 44929088Smarkm 45029088Smarkm case TELOPT_BINARY: /* binary mode */ 45129088Smarkm case TELOPT_NAWS: /* window size */ 45229088Smarkm case TELOPT_TSPEED: /* terminal speed */ 45329088Smarkm case TELOPT_LFLOW: /* local flow control */ 45429088Smarkm case TELOPT_TTYPE: /* terminal type option */ 45529088Smarkm case TELOPT_SGA: /* no big deal */ 45629088Smarkm#ifdef ENCRYPTION 45729088Smarkm case TELOPT_ENCRYPT: /* encryption variable option */ 45829088Smarkm#endif /* ENCRYPTION */ 45929088Smarkm new_state_ok = 1; 46029088Smarkm break; 46129088Smarkm 46229088Smarkm case TELOPT_NEW_ENVIRON: /* New environment variable option */ 46329088Smarkm#ifdef OLD_ENVIRON 46429088Smarkm if (my_state_is_will(TELOPT_OLD_ENVIRON)) 46529088Smarkm send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ 46629088Smarkm goto env_common; 46729088Smarkm case TELOPT_OLD_ENVIRON: /* Old environment variable option */ 46829088Smarkm if (my_state_is_will(TELOPT_NEW_ENVIRON)) 46929088Smarkm break; /* Don't enable if new one is in use! */ 47029088Smarkm env_common: 47129088Smarkm telopt_environ = option; 47229088Smarkm#endif 47329088Smarkm new_state_ok = 1; 47429088Smarkm break; 47529088Smarkm 47687139Smarkm#ifdef AUTHENTICATION 47729088Smarkm case TELOPT_AUTHENTICATION: 47829088Smarkm if (autologin) 47929088Smarkm new_state_ok = 1; 48029088Smarkm break; 48129088Smarkm#endif 48229088Smarkm 48329088Smarkm case TELOPT_XDISPLOC: /* X Display location */ 48487139Smarkm if (env_getvalue("DISPLAY")) 48529088Smarkm new_state_ok = 1; 48629088Smarkm break; 48729088Smarkm 48829088Smarkm case TELOPT_LINEMODE: 48929088Smarkm#ifdef KLUDGELINEMODE 49029088Smarkm kludgelinemode = 0; 49129088Smarkm send_do(TELOPT_SGA, 1); 49229088Smarkm#endif 49329088Smarkm set_my_want_state_will(TELOPT_LINEMODE); 49429088Smarkm send_will(option, 0); 49529088Smarkm set_my_state_will(TELOPT_LINEMODE); 49629088Smarkm slc_init(); 49729088Smarkm return; 49829088Smarkm 49929088Smarkm case TELOPT_ECHO: /* We're never going to echo... */ 50029088Smarkm default: 50129088Smarkm break; 50229088Smarkm } 50329088Smarkm 50429088Smarkm if (new_state_ok) { 50529088Smarkm set_my_want_state_will(option); 50629088Smarkm send_will(option, 0); 50729088Smarkm setconnmode(0); /* Set new tty mode */ 50829088Smarkm } else { 50929088Smarkm will_wont_resp[option]++; 51029088Smarkm send_wont(option, 0); 51129088Smarkm } 51229088Smarkm } else { 51329088Smarkm /* 51429088Smarkm * Handle options that need more things done after the 51529088Smarkm * other side has acknowledged the option. 51629088Smarkm */ 51729088Smarkm switch (option) { 51829088Smarkm case TELOPT_LINEMODE: 51929088Smarkm#ifdef KLUDGELINEMODE 52029088Smarkm kludgelinemode = 0; 52129088Smarkm send_do(TELOPT_SGA, 1); 52229088Smarkm#endif 52329088Smarkm set_my_state_will(option); 52429088Smarkm slc_init(); 52529088Smarkm send_do(TELOPT_SGA, 0); 52629088Smarkm return; 52729088Smarkm } 52829088Smarkm } 52929088Smarkm } 53029088Smarkm set_my_state_will(option); 53129088Smarkm} 53229088Smarkm 53387139Smarkmstatic void 53487139Smarkmdontoption(int option) 53529088Smarkm{ 53629088Smarkm 53729088Smarkm if (will_wont_resp[option]) { 53829088Smarkm --will_wont_resp[option]; 53929088Smarkm if (will_wont_resp[option] && my_state_is_wont(option)) 54029088Smarkm --will_wont_resp[option]; 54129088Smarkm } 54229088Smarkm 54329088Smarkm if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 54429088Smarkm switch (option) { 54529088Smarkm case TELOPT_LINEMODE: 54629088Smarkm linemode = 0; /* put us back to the default state */ 54729088Smarkm break; 54829088Smarkm#ifdef OLD_ENVIRON 54929088Smarkm case TELOPT_NEW_ENVIRON: 55029088Smarkm /* 55129088Smarkm * The new environ option wasn't recognized, try 55229088Smarkm * the old one. 55329088Smarkm */ 55429088Smarkm send_will(TELOPT_OLD_ENVIRON, 1); 55529088Smarkm telopt_environ = TELOPT_OLD_ENVIRON; 55629088Smarkm break; 55729088Smarkm#endif 55829088Smarkm } 55929088Smarkm /* we always accept a DONT */ 56029088Smarkm set_my_want_state_wont(option); 56129088Smarkm if (my_state_is_will(option)) 56229088Smarkm send_wont(option, 0); 56329088Smarkm setconnmode(0); /* Set new tty mode */ 56429088Smarkm } 56529088Smarkm set_my_state_wont(option); 56629088Smarkm} 56729088Smarkm 56829088Smarkm/* 56929088Smarkm * Given a buffer returned by tgetent(), this routine will turn 57072089Sasmodai * the pipe separated list of names in the buffer into an array 57129088Smarkm * of pointers to null terminated names. We toss out any bad, 57229088Smarkm * duplicate, or verbose names (names with spaces). 57329088Smarkm */ 57429088Smarkm 57587139Smarkmstatic const char *name_unknown = "UNKNOWN"; 57687139Smarkmstatic const char *unknown[] = { NULL, NULL }; 57729088Smarkm 57887139Smarkmstatic const char ** 57987139Smarkmmklist(char *buf, char *name) 58029088Smarkm{ 58187139Smarkm int n; 58287139Smarkm char c, *cp, **argvp, *cp2, **argv, **avt; 58329088Smarkm 58429088Smarkm if (name) { 58581965Smarkm if (strlen(name) > 40) { 58629088Smarkm name = 0; 58729088Smarkm unknown[0] = name_unknown; 58829088Smarkm } else { 58929088Smarkm unknown[0] = name; 59029088Smarkm upcase(name); 59129088Smarkm } 59229088Smarkm } else 59329088Smarkm unknown[0] = name_unknown; 59429088Smarkm /* 59529088Smarkm * Count up the number of names. 59629088Smarkm */ 59729088Smarkm for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 59829088Smarkm if (*cp == '|') 59929088Smarkm n++; 60029088Smarkm } 60129088Smarkm /* 60229088Smarkm * Allocate an array to put the name pointers into 60329088Smarkm */ 60429088Smarkm argv = (char **)malloc((n+3)*sizeof(char *)); 60529088Smarkm if (argv == 0) 60629088Smarkm return(unknown); 60729088Smarkm 60829088Smarkm /* 60929088Smarkm * Fill up the array of pointers to names. 61029088Smarkm */ 61129088Smarkm *argv = 0; 61229088Smarkm argvp = argv+1; 61329088Smarkm n = 0; 61429088Smarkm for (cp = cp2 = buf; (c = *cp); cp++) { 61529088Smarkm if (c == '|' || c == ':') { 61629088Smarkm *cp++ = '\0'; 61729088Smarkm /* 61829088Smarkm * Skip entries that have spaces or are over 40 61929088Smarkm * characters long. If this is our environment 62029088Smarkm * name, then put it up front. Otherwise, as 62129088Smarkm * long as this is not a duplicate name (case 62229088Smarkm * insensitive) add it to the list. 62329088Smarkm */ 62429088Smarkm if (n || (cp - cp2 > 41)) 62529088Smarkm ; 62629088Smarkm else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 62729088Smarkm *argv = cp2; 62829088Smarkm else if (is_unique(cp2, argv+1, argvp)) 62929088Smarkm *argvp++ = cp2; 63029088Smarkm if (c == ':') 63129088Smarkm break; 63229088Smarkm /* 63329088Smarkm * Skip multiple delimiters. Reset cp2 to 63429088Smarkm * the beginning of the next name. Reset n, 63529088Smarkm * the flag for names with spaces. 63629088Smarkm */ 63729088Smarkm while ((c = *cp) == '|') 63829088Smarkm cp++; 63929088Smarkm cp2 = cp; 64029088Smarkm n = 0; 64129088Smarkm } 64229088Smarkm /* 64329088Smarkm * Skip entries with spaces or non-ascii values. 64429088Smarkm * Convert lower case letters to upper case. 64529088Smarkm */ 64629088Smarkm if ((c == ' ') || !isascii(c)) 64729088Smarkm n = 1; 64829088Smarkm else if (islower(c)) 64929088Smarkm *cp = toupper(c); 65029088Smarkm } 65129088Smarkm 65229088Smarkm /* 65329088Smarkm * Check for an old V6 2 character name. If the second 65429088Smarkm * name points to the beginning of the buffer, and is 65529088Smarkm * only 2 characters long, move it to the end of the array. 65629088Smarkm */ 65729088Smarkm if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 65829088Smarkm --argvp; 65929088Smarkm for (avt = &argv[1]; avt < argvp; avt++) 66029088Smarkm *avt = *(avt+1); 66129088Smarkm *argvp++ = buf; 66229088Smarkm } 66329088Smarkm 66429088Smarkm /* 66529088Smarkm * Duplicate last name, for TTYPE option, and null 66629088Smarkm * terminate the array. If we didn't find a match on 66729088Smarkm * our terminal name, put that name at the beginning. 66829088Smarkm */ 66929088Smarkm cp = *(argvp-1); 67029088Smarkm *argvp++ = cp; 67129088Smarkm *argvp = 0; 67229088Smarkm 67329088Smarkm if (*argv == 0) { 67429088Smarkm if (name) 67529088Smarkm *argv = name; 67629088Smarkm else { 67729088Smarkm --argvp; 67829088Smarkm for (avt = argv; avt < argvp; avt++) 67929088Smarkm *avt = *(avt+1); 68029088Smarkm } 68129088Smarkm } 68229088Smarkm if (*argv) 68387139Smarkm return((const char **)argv); 68429088Smarkm else 68529088Smarkm return(unknown); 68629088Smarkm} 68729088Smarkm 68887139Smarkmstatic int 68987139Smarkmis_unique(char *name, char **as, char **ae) 69029088Smarkm{ 69187139Smarkm char **ap; 69287139Smarkm int n; 69329088Smarkm 69429088Smarkm n = strlen(name) + 1; 69529088Smarkm for (ap = as; ap < ae; ap++) 69629088Smarkm if (strncasecmp(*ap, name, n) == 0) 69729088Smarkm return(0); 69829088Smarkm return (1); 69929088Smarkm} 70029088Smarkm 70129088Smarkm#ifdef TERMCAP 70229088Smarkmchar termbuf[1024]; 70329088Smarkm 70487139Smarkm/*ARGSUSED*/ 70587139Smarkmstatic int 70687139Smarkmsetupterm(char *tname, int fd, int *errp) 70729088Smarkm{ 70829088Smarkm if (tgetent(termbuf, tname) == 1) { 70929088Smarkm termbuf[1023] = '\0'; 71029088Smarkm if (errp) 71129088Smarkm *errp = 1; 71229088Smarkm return(0); 71329088Smarkm } 71429088Smarkm if (errp) 71529088Smarkm *errp = 0; 71629088Smarkm return(-1); 71729088Smarkm} 71829088Smarkm#else 71929088Smarkm#define termbuf ttytype 72029088Smarkmextern char ttytype[]; 72129088Smarkm#endif 72229088Smarkm 72329088Smarkmint resettermname = 1; 72429088Smarkm 72587139Smarkmstatic const char * 72687139Smarkmgettermname(void) 72729088Smarkm{ 72829088Smarkm char *tname; 72987139Smarkm static const char **tnamep = 0; 73087139Smarkm static const char **next; 73129088Smarkm int err; 73229088Smarkm 73329088Smarkm if (resettermname) { 73429088Smarkm resettermname = 0; 73529088Smarkm if (tnamep && tnamep != unknown) 73629088Smarkm free(tnamep); 73787139Smarkm if ((tname = env_getvalue("TERM")) && 73829088Smarkm (setupterm(tname, 1, &err) == 0)) { 73929088Smarkm tnamep = mklist(termbuf, tname); 74029088Smarkm } else { 74181965Smarkm if (tname && (strlen(tname) <= 40)) { 74229088Smarkm unknown[0] = tname; 74329088Smarkm upcase(tname); 74429088Smarkm } else 74529088Smarkm unknown[0] = name_unknown; 74629088Smarkm tnamep = unknown; 74729088Smarkm } 74829088Smarkm next = tnamep; 74929088Smarkm } 75029088Smarkm if (*next == 0) 75129088Smarkm next = tnamep; 75229088Smarkm return(*next++); 75329088Smarkm} 75429088Smarkm/* 75529088Smarkm * suboption() 75629088Smarkm * 75729088Smarkm * Look at the sub-option buffer, and try to be helpful to the other 75829088Smarkm * side. 75929088Smarkm * 76029088Smarkm * Currently we recognize: 76129088Smarkm * 76229088Smarkm * Terminal type, send request. 76329088Smarkm * Terminal speed (send request). 76429088Smarkm * Local flow control (is request). 76529088Smarkm * Linemode 76629088Smarkm */ 76729088Smarkm 76887139Smarkmstatic void 76987139Smarkmsuboption(void) 77029088Smarkm{ 77129088Smarkm unsigned char subchar; 77229088Smarkm 77329088Smarkm printsub('<', subbuffer, SB_LEN()+2); 77429088Smarkm switch (subchar = SB_GET()) { 77529088Smarkm case TELOPT_TTYPE: 77629088Smarkm if (my_want_state_is_wont(TELOPT_TTYPE)) 77729088Smarkm return; 77829088Smarkm if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 77929088Smarkm return; 78029088Smarkm } else { 78187139Smarkm const char *name; 78229088Smarkm unsigned char temp[50]; 78329088Smarkm int len; 78429088Smarkm 78529088Smarkm name = gettermname(); 78629088Smarkm len = strlen(name) + 4 + 2; 78729088Smarkm if (len < NETROOM()) { 78887139Smarkm sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 78929088Smarkm TELQUAL_IS, name, IAC, SE); 79029088Smarkm ring_supply_data(&netoring, temp, len); 79129088Smarkm printsub('>', &temp[2], len-2); 79229088Smarkm } else { 79329088Smarkm ExitString("No room in buffer for terminal type.\n", 1); 79429088Smarkm /*NOTREACHED*/ 79529088Smarkm } 79629088Smarkm } 79729088Smarkm break; 79829088Smarkm case TELOPT_TSPEED: 79929088Smarkm if (my_want_state_is_wont(TELOPT_TSPEED)) 80029088Smarkm return; 80129088Smarkm if (SB_EOF()) 80229088Smarkm return; 80329088Smarkm if (SB_GET() == TELQUAL_SEND) { 80429088Smarkm long ospeed, ispeed; 80529088Smarkm unsigned char temp[50]; 80629088Smarkm int len; 80729088Smarkm 80829088Smarkm TerminalSpeeds(&ispeed, &ospeed); 80929088Smarkm 81029181Smarkm sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, 81129088Smarkm TELQUAL_IS, ospeed, ispeed, IAC, SE); 81229088Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 81329088Smarkm 81429088Smarkm if (len < NETROOM()) { 81529088Smarkm ring_supply_data(&netoring, temp, len); 81629088Smarkm printsub('>', temp+2, len - 2); 81729088Smarkm } 81829088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 81929088Smarkm } 82029088Smarkm break; 82129088Smarkm case TELOPT_LFLOW: 82229088Smarkm if (my_want_state_is_wont(TELOPT_LFLOW)) 82329088Smarkm return; 82429088Smarkm if (SB_EOF()) 82529088Smarkm return; 82629088Smarkm switch(SB_GET()) { 82729088Smarkm case LFLOW_RESTART_ANY: 82829088Smarkm restartany = 1; 82929088Smarkm break; 83029088Smarkm case LFLOW_RESTART_XON: 83129088Smarkm restartany = 0; 83229088Smarkm break; 83329088Smarkm case LFLOW_ON: 83429088Smarkm localflow = 1; 83529088Smarkm break; 83629088Smarkm case LFLOW_OFF: 83729088Smarkm localflow = 0; 83829088Smarkm break; 83929088Smarkm default: 84029088Smarkm return; 84129088Smarkm } 84229088Smarkm setcommandmode(); 84329088Smarkm setconnmode(0); 84429088Smarkm break; 84529088Smarkm 84629088Smarkm case TELOPT_LINEMODE: 84729088Smarkm if (my_want_state_is_wont(TELOPT_LINEMODE)) 84829088Smarkm return; 84929088Smarkm if (SB_EOF()) 85029088Smarkm return; 85129088Smarkm switch (SB_GET()) { 85229088Smarkm case WILL: 85329088Smarkm lm_will(subpointer, SB_LEN()); 85429088Smarkm break; 85529088Smarkm case WONT: 85629088Smarkm lm_wont(subpointer, SB_LEN()); 85729088Smarkm break; 85829088Smarkm case DO: 85929088Smarkm lm_do(subpointer, SB_LEN()); 86029088Smarkm break; 86129088Smarkm case DONT: 86229088Smarkm lm_dont(subpointer, SB_LEN()); 86329088Smarkm break; 86429088Smarkm case LM_SLC: 86529088Smarkm slc(subpointer, SB_LEN()); 86629088Smarkm break; 86729088Smarkm case LM_MODE: 86829088Smarkm lm_mode(subpointer, SB_LEN(), 0); 86929088Smarkm break; 87029088Smarkm default: 87129088Smarkm break; 87229088Smarkm } 87329088Smarkm break; 87429088Smarkm 87529088Smarkm#ifdef OLD_ENVIRON 87629088Smarkm case TELOPT_OLD_ENVIRON: 87729088Smarkm#endif 87829088Smarkm case TELOPT_NEW_ENVIRON: 87929088Smarkm if (SB_EOF()) 88029088Smarkm return; 88129088Smarkm switch(SB_PEEK()) { 88229088Smarkm case TELQUAL_IS: 88329088Smarkm case TELQUAL_INFO: 88429088Smarkm if (my_want_state_is_dont(subchar)) 88529088Smarkm return; 88629088Smarkm break; 88729088Smarkm case TELQUAL_SEND: 88829088Smarkm if (my_want_state_is_wont(subchar)) { 88929088Smarkm return; 89029088Smarkm } 89129088Smarkm break; 89229088Smarkm default: 89329088Smarkm return; 89429088Smarkm } 89529088Smarkm env_opt(subpointer, SB_LEN()); 89629088Smarkm break; 89729088Smarkm 89829088Smarkm case TELOPT_XDISPLOC: 89929088Smarkm if (my_want_state_is_wont(TELOPT_XDISPLOC)) 90029088Smarkm return; 90129088Smarkm if (SB_EOF()) 90229088Smarkm return; 90329088Smarkm if (SB_GET() == TELQUAL_SEND) { 90429088Smarkm unsigned char temp[50], *dp; 90529088Smarkm int len; 90629088Smarkm 90787139Smarkm if ((dp = env_getvalue("DISPLAY")) == NULL || 90867827Skris strlen(dp) > sizeof(temp) - 7) { 90929088Smarkm /* 91029088Smarkm * Something happened, we no longer have a DISPLAY 91167827Skris * variable. Or it is too long. So, turn off the option. 91229088Smarkm */ 91329088Smarkm send_wont(TELOPT_XDISPLOC, 1); 91429088Smarkm break; 91529088Smarkm } 91687139Smarkm snprintf(temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, 91767827Skris TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); 91829088Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 91929088Smarkm 92029088Smarkm if (len < NETROOM()) { 92129088Smarkm ring_supply_data(&netoring, temp, len); 92229088Smarkm printsub('>', temp+2, len - 2); 92329088Smarkm } 92429088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 92529088Smarkm } 92629088Smarkm break; 92729088Smarkm 92887139Smarkm#ifdef AUTHENTICATION 92929088Smarkm case TELOPT_AUTHENTICATION: { 93029088Smarkm if (!autologin) 93129088Smarkm break; 93229088Smarkm if (SB_EOF()) 93329088Smarkm return; 93429088Smarkm switch(SB_GET()) { 93529088Smarkm case TELQUAL_IS: 93629088Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 93729088Smarkm return; 93829088Smarkm auth_is(subpointer, SB_LEN()); 93929088Smarkm break; 94029088Smarkm case TELQUAL_SEND: 94129088Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 94229088Smarkm return; 94329088Smarkm auth_send(subpointer, SB_LEN()); 94429088Smarkm break; 94529088Smarkm case TELQUAL_REPLY: 94629088Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 94729088Smarkm return; 94829088Smarkm auth_reply(subpointer, SB_LEN()); 94929088Smarkm break; 95029088Smarkm case TELQUAL_NAME: 95129088Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 95229088Smarkm return; 95329088Smarkm auth_name(subpointer, SB_LEN()); 95429088Smarkm break; 95529088Smarkm } 95629088Smarkm } 95729088Smarkm break; 95829088Smarkm#endif 95929088Smarkm#ifdef ENCRYPTION 96029088Smarkm case TELOPT_ENCRYPT: 96129088Smarkm if (SB_EOF()) 96229088Smarkm return; 96329088Smarkm switch(SB_GET()) { 96429088Smarkm case ENCRYPT_START: 96529088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 96629088Smarkm return; 96729088Smarkm encrypt_start(subpointer, SB_LEN()); 96829088Smarkm break; 96929088Smarkm case ENCRYPT_END: 97029088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 97129088Smarkm return; 97229088Smarkm encrypt_end(); 97329088Smarkm break; 97429088Smarkm case ENCRYPT_SUPPORT: 97529088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 97629088Smarkm return; 97729088Smarkm encrypt_support(subpointer, SB_LEN()); 97829088Smarkm break; 97929088Smarkm case ENCRYPT_REQSTART: 98029088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 98129088Smarkm return; 98229088Smarkm encrypt_request_start(subpointer, SB_LEN()); 98329088Smarkm break; 98429088Smarkm case ENCRYPT_REQEND: 98529088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 98629088Smarkm return; 98729088Smarkm /* 98829088Smarkm * We can always send an REQEND so that we cannot 98929088Smarkm * get stuck encrypting. We should only get this 99029088Smarkm * if we have been able to get in the correct mode 99129088Smarkm * anyhow. 99229088Smarkm */ 99329088Smarkm encrypt_request_end(); 99429088Smarkm break; 99529088Smarkm case ENCRYPT_IS: 99629088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 99729088Smarkm return; 99829088Smarkm encrypt_is(subpointer, SB_LEN()); 99929088Smarkm break; 100029088Smarkm case ENCRYPT_REPLY: 100129088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 100229088Smarkm return; 100329088Smarkm encrypt_reply(subpointer, SB_LEN()); 100429088Smarkm break; 100529088Smarkm case ENCRYPT_ENC_KEYID: 100629088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 100729088Smarkm return; 100829088Smarkm encrypt_enc_keyid(subpointer, SB_LEN()); 100929088Smarkm break; 101029088Smarkm case ENCRYPT_DEC_KEYID: 101129088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 101229088Smarkm return; 101329088Smarkm encrypt_dec_keyid(subpointer, SB_LEN()); 101429088Smarkm break; 101529088Smarkm default: 101629088Smarkm break; 101729088Smarkm } 101829088Smarkm break; 101929088Smarkm#endif /* ENCRYPTION */ 102029088Smarkm default: 102129088Smarkm break; 102229088Smarkm } 102329088Smarkm} 102429088Smarkm 102529088Smarkmstatic unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 102629088Smarkm 102787139Smarkmvoid 102887139Smarkmlm_will(unsigned char *cmd, int len) 102929088Smarkm{ 103029088Smarkm if (len < 1) { 103129088Smarkm/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 103229088Smarkm return; 103329088Smarkm } 103429088Smarkm switch(cmd[0]) { 103529088Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 103629088Smarkm default: 103729088Smarkm str_lm[3] = DONT; 103829088Smarkm str_lm[4] = cmd[0]; 103987139Smarkm if (NETROOM() > (int)sizeof(str_lm)) { 104029088Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 104129088Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 104229088Smarkm } 104329088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 104429088Smarkm break; 104529088Smarkm } 104629088Smarkm} 104729088Smarkm 104887139Smarkmvoid 104987139Smarkmlm_wont(unsigned char *cmd, int len) 105029088Smarkm{ 105129088Smarkm if (len < 1) { 105229088Smarkm/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 105329088Smarkm return; 105429088Smarkm } 105529088Smarkm switch(cmd[0]) { 105629088Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 105729088Smarkm default: 105829088Smarkm /* We are always DONT, so don't respond */ 105929088Smarkm return; 106029088Smarkm } 106129088Smarkm} 106229088Smarkm 106387139Smarkmvoid 106487139Smarkmlm_do(unsigned char *cmd, int len) 106529088Smarkm{ 106629088Smarkm if (len < 1) { 106729088Smarkm/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 106829088Smarkm return; 106929088Smarkm } 107029088Smarkm switch(cmd[0]) { 107129088Smarkm case LM_FORWARDMASK: 107229088Smarkm default: 107329088Smarkm str_lm[3] = WONT; 107429088Smarkm str_lm[4] = cmd[0]; 107587139Smarkm if (NETROOM() > (int)sizeof(str_lm)) { 107629088Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 107729088Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 107829088Smarkm } 107929088Smarkm/*@*/ else printf("lm_do: not enough room in buffer\n"); 108029088Smarkm break; 108129088Smarkm } 108229088Smarkm} 108329088Smarkm 108487139Smarkmvoid 108587139Smarkmlm_dont(unsigned char *cmd, int len) 108629088Smarkm{ 108729088Smarkm if (len < 1) { 108829088Smarkm/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 108929088Smarkm return; 109029088Smarkm } 109129088Smarkm switch(cmd[0]) { 109229088Smarkm case LM_FORWARDMASK: 109329088Smarkm default: 109429088Smarkm /* we are always WONT, so don't respond */ 109529088Smarkm break; 109629088Smarkm } 109729088Smarkm} 109829088Smarkm 109929088Smarkmstatic unsigned char str_lm_mode[] = { 110029088Smarkm IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 110129088Smarkm}; 110229088Smarkm 110387139Smarkmvoid 110487139Smarkmlm_mode(unsigned char *cmd, int len, int init) 110529088Smarkm{ 110629088Smarkm if (len != 1) 110729088Smarkm return; 110829088Smarkm if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 110929088Smarkm return; 111029088Smarkm if (*cmd&MODE_ACK) 111129088Smarkm return; 111229088Smarkm linemode = *cmd&(MODE_MASK&~MODE_ACK); 111329088Smarkm str_lm_mode[4] = linemode; 111429088Smarkm if (!init) 111529088Smarkm str_lm_mode[4] |= MODE_ACK; 111687139Smarkm if (NETROOM() > (int)sizeof(str_lm_mode)) { 111729088Smarkm ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 111829088Smarkm printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 111929088Smarkm } 112029088Smarkm/*@*/ else printf("lm_mode: not enough room in buffer\n"); 112129088Smarkm setconnmode(0); /* set changed mode */ 112229088Smarkm} 112329088Smarkm 112429088Smarkm 1125275508Sngie 112629088Smarkm/* 112729088Smarkm * slc() 112829088Smarkm * Handle special character suboption of LINEMODE. 112929088Smarkm */ 113029088Smarkm 113129088Smarkmstruct spc { 113229088Smarkm cc_t val; 113329088Smarkm cc_t *valp; 113429088Smarkm char flags; /* Current flags & level */ 113529088Smarkm char mylevel; /* Maximum level & flags */ 113629088Smarkm} spc_data[NSLC+1]; 113729088Smarkm 113829088Smarkm#define SLC_IMPORT 0 113929088Smarkm#define SLC_EXPORT 1 114029088Smarkm#define SLC_RVALUE 2 114129088Smarkmstatic int slc_mode = SLC_EXPORT; 114229088Smarkm 114387139Smarkmvoid 114487139Smarkmslc_init(void) 114529088Smarkm{ 114687139Smarkm struct spc *spcp; 114729088Smarkm 114829088Smarkm localchars = 1; 114929088Smarkm for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 115029088Smarkm spcp->val = 0; 115129088Smarkm spcp->valp = 0; 115229088Smarkm spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 115329088Smarkm } 115429088Smarkm 115529088Smarkm#define initfunc(func, flags) { \ 115629088Smarkm spcp = &spc_data[func]; \ 115729181Smarkm if ((spcp->valp = tcval(func))) { \ 115829088Smarkm spcp->val = *spcp->valp; \ 115929088Smarkm spcp->mylevel = SLC_VARIABLE|flags; \ 116029088Smarkm } else { \ 116129088Smarkm spcp->val = 0; \ 116229088Smarkm spcp->mylevel = SLC_DEFAULT; \ 116329088Smarkm } \ 116429088Smarkm } 116529088Smarkm 116629088Smarkm initfunc(SLC_SYNCH, 0); 116729088Smarkm /* No BRK */ 116829088Smarkm initfunc(SLC_AO, 0); 116929088Smarkm initfunc(SLC_AYT, 0); 117029088Smarkm /* No EOR */ 117129088Smarkm initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 117229088Smarkm initfunc(SLC_EOF, 0); 117329088Smarkm#ifndef SYSV_TERMIO 117429088Smarkm initfunc(SLC_SUSP, SLC_FLUSHIN); 117529088Smarkm#endif 117629088Smarkm initfunc(SLC_EC, 0); 117729088Smarkm initfunc(SLC_EL, 0); 117829088Smarkm#ifndef SYSV_TERMIO 117929088Smarkm initfunc(SLC_EW, 0); 118029088Smarkm initfunc(SLC_RP, 0); 118129088Smarkm initfunc(SLC_LNEXT, 0); 118229088Smarkm#endif 118329088Smarkm initfunc(SLC_XON, 0); 118429088Smarkm initfunc(SLC_XOFF, 0); 118529088Smarkm#ifdef SYSV_TERMIO 118629088Smarkm spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 118729088Smarkm spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 118829088Smarkm#endif 118929088Smarkm initfunc(SLC_FORW1, 0); 119029088Smarkm#ifdef USE_TERMIO 119129088Smarkm initfunc(SLC_FORW2, 0); 119229088Smarkm /* No FORW2 */ 119329088Smarkm#endif 119429088Smarkm 119529088Smarkm initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 119629088Smarkm#undef initfunc 119729088Smarkm 119829088Smarkm if (slc_mode == SLC_EXPORT) 119929088Smarkm slc_export(); 120029088Smarkm else 120129088Smarkm slc_import(1); 120229088Smarkm 120329088Smarkm} 120429088Smarkm 120587139Smarkmvoid 120687139Smarkmslcstate(void) 120729088Smarkm{ 120829088Smarkm printf("Special characters are %s values\n", 120929088Smarkm slc_mode == SLC_IMPORT ? "remote default" : 121029088Smarkm slc_mode == SLC_EXPORT ? "local" : 121129088Smarkm "remote"); 121229088Smarkm} 121329088Smarkm 121487139Smarkmvoid 121587139Smarkmslc_mode_export(void) 121629088Smarkm{ 121729088Smarkm slc_mode = SLC_EXPORT; 121829088Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 121929088Smarkm slc_export(); 122029088Smarkm} 122129088Smarkm 122287139Smarkmvoid 122387139Smarkmslc_mode_import(int def) 122429088Smarkm{ 122529088Smarkm slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 122629088Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 122729088Smarkm slc_import(def); 122829088Smarkm} 122929088Smarkm 123029088Smarkmunsigned char slc_import_val[] = { 123129088Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 123229088Smarkm}; 123329088Smarkmunsigned char slc_import_def[] = { 123429088Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 123529088Smarkm}; 123629088Smarkm 123787139Smarkmvoid 123887139Smarkmslc_import(int def) 123929088Smarkm{ 124087139Smarkm if (NETROOM() > (int)sizeof(slc_import_val)) { 124129088Smarkm if (def) { 124229088Smarkm ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 124329088Smarkm printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 124429088Smarkm } else { 124529088Smarkm ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 124629088Smarkm printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 124729088Smarkm } 124829088Smarkm } 124929088Smarkm/*@*/ else printf("slc_import: not enough room\n"); 125029088Smarkm} 125129088Smarkm 125287139Smarkmvoid 125387139Smarkmslc_export(void) 125429088Smarkm{ 125587139Smarkm struct spc *spcp; 125629088Smarkm 125729088Smarkm TerminalDefaultChars(); 125829088Smarkm 125929088Smarkm slc_start_reply(); 126029088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 126129088Smarkm if (spcp->mylevel != SLC_NOSUPPORT) { 126229088Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 126329088Smarkm spcp->flags = SLC_NOSUPPORT; 126429088Smarkm else 126529088Smarkm spcp->flags = spcp->mylevel; 126629088Smarkm if (spcp->valp) 126729088Smarkm spcp->val = *spcp->valp; 126829088Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 126929088Smarkm } 127029088Smarkm } 127129088Smarkm slc_end_reply(); 127229088Smarkm (void)slc_update(); 127329088Smarkm setconnmode(1); /* Make sure the character values are set */ 127429088Smarkm} 127529088Smarkm 127687139Smarkmvoid 127787139Smarkmslc(unsigned char *cp, int len) 127829088Smarkm{ 127987139Smarkm struct spc *spcp; 128087139Smarkm int func,level; 128129088Smarkm 128229088Smarkm slc_start_reply(); 128329088Smarkm 128429088Smarkm for (; len >= 3; len -=3, cp +=3) { 128529088Smarkm 128629088Smarkm func = cp[SLC_FUNC]; 128729088Smarkm 128829088Smarkm if (func == 0) { 128929088Smarkm /* 129029088Smarkm * Client side: always ignore 0 function. 129129088Smarkm */ 129229088Smarkm continue; 129329088Smarkm } 129429088Smarkm if (func > NSLC) { 129529088Smarkm if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 129629088Smarkm slc_add_reply(func, SLC_NOSUPPORT, 0); 129729088Smarkm continue; 129829088Smarkm } 129929088Smarkm 130029088Smarkm spcp = &spc_data[func]; 130129088Smarkm 130229088Smarkm level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 130329088Smarkm 130429088Smarkm if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 130529088Smarkm ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 130629088Smarkm continue; 130729088Smarkm } 130829088Smarkm 130929088Smarkm if (level == (SLC_DEFAULT|SLC_ACK)) { 131029088Smarkm /* 131129088Smarkm * This is an error condition, the SLC_ACK 131229088Smarkm * bit should never be set for the SLC_DEFAULT 131329088Smarkm * level. Our best guess to recover is to 131429088Smarkm * ignore the SLC_ACK bit. 131529088Smarkm */ 131629088Smarkm cp[SLC_FLAGS] &= ~SLC_ACK; 131729088Smarkm } 131829088Smarkm 131929088Smarkm if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 132029088Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 132129088Smarkm spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 132229088Smarkm continue; 132329088Smarkm } 132429088Smarkm 132529088Smarkm level &= ~SLC_ACK; 132629088Smarkm 132729088Smarkm if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 132829088Smarkm spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 132929088Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 133029088Smarkm } 133129088Smarkm if (level == SLC_DEFAULT) { 133229088Smarkm if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 133329088Smarkm spcp->flags = spcp->mylevel; 133429088Smarkm else 133529088Smarkm spcp->flags = SLC_NOSUPPORT; 133629088Smarkm } 133729088Smarkm slc_add_reply(func, spcp->flags, spcp->val); 133829088Smarkm } 133929088Smarkm slc_end_reply(); 134029088Smarkm if (slc_update()) 134129088Smarkm setconnmode(1); /* set the new character values */ 134229088Smarkm} 134329088Smarkm 134487139Smarkmvoid 134587139Smarkmslc_check(void) 134629088Smarkm{ 134787139Smarkm struct spc *spcp; 134829088Smarkm 134929088Smarkm slc_start_reply(); 135029088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 135129088Smarkm if (spcp->valp && spcp->val != *spcp->valp) { 135229088Smarkm spcp->val = *spcp->valp; 135329088Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 135429088Smarkm spcp->flags = SLC_NOSUPPORT; 135529088Smarkm else 135629088Smarkm spcp->flags = spcp->mylevel; 135729088Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 135829088Smarkm } 135929088Smarkm } 136029088Smarkm slc_end_reply(); 136129088Smarkm setconnmode(1); 136229088Smarkm} 136329088Smarkm 136429088Smarkmunsigned char slc_reply[128]; 1365144231Snectarunsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)]; 136629088Smarkmunsigned char *slc_replyp; 136729088Smarkm 136887139Smarkmvoid 136987139Smarkmslc_start_reply(void) 137029088Smarkm{ 137129088Smarkm slc_replyp = slc_reply; 137229088Smarkm *slc_replyp++ = IAC; 137329088Smarkm *slc_replyp++ = SB; 137429088Smarkm *slc_replyp++ = TELOPT_LINEMODE; 137529088Smarkm *slc_replyp++ = LM_SLC; 137629088Smarkm} 137729088Smarkm 137887139Smarkmvoid 137987139Smarkmslc_add_reply(unsigned char func, unsigned char flags, cc_t value) 138029088Smarkm{ 1381144231Snectar /* A sequence of up to 6 bytes my be written for this member of the SLC 1382144231Snectar * suboption list by this function. The end of negotiation command, 1383144231Snectar * which is written by slc_end_reply(), will require 2 additional 1384144231Snectar * bytes. Do not proceed unless there is sufficient space for these 1385144231Snectar * items. 1386144231Snectar */ 1387144231Snectar if (&slc_replyp[6+2] > slc_reply_eom) 1388144231Snectar return; 138929088Smarkm if ((*slc_replyp++ = func) == IAC) 139029088Smarkm *slc_replyp++ = IAC; 139129088Smarkm if ((*slc_replyp++ = flags) == IAC) 139229088Smarkm *slc_replyp++ = IAC; 139329088Smarkm if ((*slc_replyp++ = (unsigned char)value) == IAC) 139429088Smarkm *slc_replyp++ = IAC; 139529088Smarkm} 139629088Smarkm 139787139Smarkmvoid 139887139Smarkmslc_end_reply(void) 139929088Smarkm{ 140087139Smarkm int len; 140129088Smarkm 1402144231Snectar /* The end of negotiation command requires 2 bytes. */ 1403144231Snectar if (&slc_replyp[2] > slc_reply_eom) 1404144231Snectar return; 140529088Smarkm *slc_replyp++ = IAC; 140629088Smarkm *slc_replyp++ = SE; 140729088Smarkm len = slc_replyp - slc_reply; 140829088Smarkm if (len <= 6) 140929088Smarkm return; 141029088Smarkm if (NETROOM() > len) { 141129088Smarkm ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 141229088Smarkm printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 141329088Smarkm } 141429088Smarkm/*@*/else printf("slc_end_reply: not enough room\n"); 141529088Smarkm} 141629088Smarkm 141787139Smarkmint 141887139Smarkmslc_update(void) 141929088Smarkm{ 142087139Smarkm struct spc *spcp; 142129088Smarkm int need_update = 0; 142229088Smarkm 142329088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 142429088Smarkm if (!(spcp->flags&SLC_ACK)) 142529088Smarkm continue; 142629088Smarkm spcp->flags &= ~SLC_ACK; 142729088Smarkm if (spcp->valp && (*spcp->valp != spcp->val)) { 142829088Smarkm *spcp->valp = spcp->val; 142929088Smarkm need_update = 1; 143029088Smarkm } 143129088Smarkm } 143229088Smarkm return(need_update); 143329088Smarkm} 143429088Smarkm 143529088Smarkm#ifdef OLD_ENVIRON 143629088Smarkm# ifdef ENV_HACK 143729088Smarkm/* 143829088Smarkm * Earlier version of telnet/telnetd from the BSD code had 143929088Smarkm * the definitions of VALUE and VAR reversed. To ensure 144029088Smarkm * maximum interoperability, we assume that the server is 144129088Smarkm * an older BSD server, until proven otherwise. The newer 144229088Smarkm * BSD servers should be able to handle either definition, 144329088Smarkm * so it is better to use the wrong values if we don't 144429088Smarkm * know what type of server it is. 144529088Smarkm */ 144629088Smarkmint env_auto = 1; 144729088Smarkmint old_env_var = OLD_ENV_VAR; 144829088Smarkmint old_env_value = OLD_ENV_VALUE; 144929088Smarkm# else 145029088Smarkm# define old_env_var OLD_ENV_VAR 145129088Smarkm# define old_env_value OLD_ENV_VALUE 145229088Smarkm# endif 145329088Smarkm#endif 145429088Smarkm 145587139Smarkmvoid 145687139Smarkmenv_opt(unsigned char *buf, int len) 145729088Smarkm{ 145887139Smarkm unsigned char *ep = 0, *epc = 0; 145987139Smarkm int i; 146029088Smarkm 146129088Smarkm switch(buf[0]&0xff) { 146229088Smarkm case TELQUAL_SEND: 146329088Smarkm env_opt_start(); 146429088Smarkm if (len == 1) { 146529088Smarkm env_opt_add(NULL); 146629088Smarkm } else for (i = 1; i < len; i++) { 146729088Smarkm switch (buf[i]&0xff) { 146829088Smarkm#ifdef OLD_ENVIRON 146929088Smarkm case OLD_ENV_VAR: 147029088Smarkm# ifdef ENV_HACK 147129088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON 147229088Smarkm && env_auto) { 147329088Smarkm /* Server has the same definitions */ 147429088Smarkm old_env_var = OLD_ENV_VAR; 147529088Smarkm old_env_value = OLD_ENV_VALUE; 147629088Smarkm } 1477103955Smarkm /* FALLTHROUGH */ 147829088Smarkm# endif 147929088Smarkm case OLD_ENV_VALUE: 148029088Smarkm /* 148129088Smarkm * Although OLD_ENV_VALUE is not legal, we will 148229088Smarkm * still recognize it, just in case it is an 148329088Smarkm * old server that has VAR & VALUE mixed up... 148429088Smarkm */ 1485103955Smarkm /* FALLTHROUGH */ 148629088Smarkm#else 148729088Smarkm case NEW_ENV_VAR: 148829088Smarkm#endif 148929088Smarkm case ENV_USERVAR: 149029088Smarkm if (ep) { 149129088Smarkm *epc = 0; 149229088Smarkm env_opt_add(ep); 149329088Smarkm } 149429088Smarkm ep = epc = &buf[i+1]; 149529088Smarkm break; 149629088Smarkm case ENV_ESC: 149729088Smarkm i++; 1498103955Smarkm /*FALLTHROUGH*/ 149929088Smarkm default: 150029088Smarkm if (epc) 150129088Smarkm *epc++ = buf[i]; 150229088Smarkm break; 150329088Smarkm } 150429088Smarkm } 150529088Smarkm if (ep) { 150629088Smarkm *epc = 0; 150729088Smarkm env_opt_add(ep); 150829088Smarkm } 150929088Smarkm env_opt_end(1); 151029088Smarkm break; 151129088Smarkm 151229088Smarkm case TELQUAL_IS: 151329088Smarkm case TELQUAL_INFO: 151429088Smarkm /* Ignore for now. We shouldn't get it anyway. */ 151529088Smarkm break; 151629088Smarkm 151729088Smarkm default: 151829088Smarkm break; 151929088Smarkm } 152029088Smarkm} 152129088Smarkm 1522144231Snectar#define OPT_REPLY_SIZE (2 * SUBBUFSIZE) 1523144231Snectarunsigned char *opt_reply = NULL; 152429088Smarkmunsigned char *opt_replyp; 152529088Smarkmunsigned char *opt_replyend; 152629088Smarkm 152787139Smarkmvoid 152887139Smarkmenv_opt_start(void) 152929088Smarkm{ 153029088Smarkm if (opt_reply) 153129088Smarkm opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 153229088Smarkm else 153329088Smarkm opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 153429088Smarkm if (opt_reply == NULL) { 153529088Smarkm/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 153629088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 153729088Smarkm return; 153829088Smarkm } 153929088Smarkm opt_replyp = opt_reply; 154029088Smarkm opt_replyend = opt_reply + OPT_REPLY_SIZE; 154129088Smarkm *opt_replyp++ = IAC; 154229088Smarkm *opt_replyp++ = SB; 154329088Smarkm *opt_replyp++ = telopt_environ; 154429088Smarkm *opt_replyp++ = TELQUAL_IS; 154529088Smarkm} 154629088Smarkm 154787139Smarkmvoid 154887139Smarkmenv_opt_start_info(void) 154929088Smarkm{ 155029088Smarkm env_opt_start(); 155129088Smarkm if (opt_replyp) 155229088Smarkm opt_replyp[-1] = TELQUAL_INFO; 155329088Smarkm} 155429088Smarkm 155587139Smarkmvoid 155687139Smarkmenv_opt_add(unsigned char *ep) 155729088Smarkm{ 155887139Smarkm unsigned char *vp, c; 155929088Smarkm 156029088Smarkm if (opt_reply == NULL) /*XXX*/ 156129088Smarkm return; /*XXX*/ 156229088Smarkm 156329088Smarkm if (ep == NULL || *ep == '\0') { 156429088Smarkm /* Send user defined variables first. */ 156529088Smarkm env_default(1, 0); 156629181Smarkm while ((ep = env_default(0, 0))) 156729088Smarkm env_opt_add(ep); 156829088Smarkm 156929088Smarkm /* Now add the list of well know variables. */ 157029088Smarkm env_default(1, 1); 157129181Smarkm while ((ep = env_default(0, 1))) 157229088Smarkm env_opt_add(ep); 157329088Smarkm return; 157429088Smarkm } 157529088Smarkm vp = env_getvalue(ep); 1576144231Snectar if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) + 1577144231Snectar 2 * strlen((char *)ep) + 6 > opt_replyend) 1578144231Snectar { 157987139Smarkm int len; 158029088Smarkm opt_replyend += OPT_REPLY_SIZE; 158129088Smarkm len = opt_replyend - opt_reply; 158229088Smarkm opt_reply = (unsigned char *)realloc(opt_reply, len); 158329088Smarkm if (opt_reply == NULL) { 158429088Smarkm/*@*/ printf("env_opt_add: realloc() failed!!!\n"); 158529088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 158629088Smarkm return; 158729088Smarkm } 158829088Smarkm opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 158929088Smarkm opt_replyend = opt_reply + len; 159029088Smarkm } 159129088Smarkm if (opt_welldefined(ep)) 159229088Smarkm#ifdef OLD_ENVIRON 159329088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 159429088Smarkm *opt_replyp++ = old_env_var; 159529088Smarkm else 159629088Smarkm#endif 159729088Smarkm *opt_replyp++ = NEW_ENV_VAR; 159829088Smarkm else 159929088Smarkm *opt_replyp++ = ENV_USERVAR; 160029088Smarkm for (;;) { 160129181Smarkm while ((c = *ep++)) { 1602144231Snectar if (opt_replyp + (2 + 2) > opt_replyend) 1603144231Snectar return; 160429088Smarkm switch(c&0xff) { 160529088Smarkm case IAC: 160629088Smarkm *opt_replyp++ = IAC; 160729088Smarkm break; 160829088Smarkm case NEW_ENV_VAR: 160929088Smarkm case NEW_ENV_VALUE: 161029088Smarkm case ENV_ESC: 161129088Smarkm case ENV_USERVAR: 161229088Smarkm *opt_replyp++ = ENV_ESC; 161329088Smarkm break; 161429088Smarkm } 161529088Smarkm *opt_replyp++ = c; 161629088Smarkm } 161729181Smarkm if ((ep = vp)) { 1618144231Snectar if (opt_replyp + (1 + 2 + 2) > opt_replyend) 1619144231Snectar return; 162029088Smarkm#ifdef OLD_ENVIRON 162129088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 162229088Smarkm *opt_replyp++ = old_env_value; 162329088Smarkm else 162429088Smarkm#endif 162529088Smarkm *opt_replyp++ = NEW_ENV_VALUE; 162629088Smarkm vp = NULL; 162729088Smarkm } else 162829088Smarkm break; 162929088Smarkm } 163029088Smarkm} 163129088Smarkm 163287139Smarkmint 163387139Smarkmopt_welldefined(const char *ep) 163429088Smarkm{ 163529088Smarkm if ((strcmp(ep, "USER") == 0) || 163629088Smarkm (strcmp(ep, "DISPLAY") == 0) || 163729088Smarkm (strcmp(ep, "PRINTER") == 0) || 163829088Smarkm (strcmp(ep, "SYSTEMTYPE") == 0) || 163929088Smarkm (strcmp(ep, "JOB") == 0) || 164029088Smarkm (strcmp(ep, "ACCT") == 0)) 164129088Smarkm return(1); 164229088Smarkm return(0); 164329088Smarkm} 164487139Smarkm 164587139Smarkmvoid 164687139Smarkmenv_opt_end(int emptyok) 164729088Smarkm{ 164887139Smarkm int len; 164929088Smarkm 1650144231Snectar if (opt_replyp + 2 > opt_replyend) 1651144231Snectar return; 1652144231Snectar len = opt_replyp + 2 - opt_reply; 165329088Smarkm if (emptyok || len > 6) { 165429088Smarkm *opt_replyp++ = IAC; 165529088Smarkm *opt_replyp++ = SE; 165629088Smarkm if (NETROOM() > len) { 165729088Smarkm ring_supply_data(&netoring, opt_reply, len); 165829088Smarkm printsub('>', &opt_reply[2], len - 2); 165929088Smarkm } 166029088Smarkm/*@*/ else printf("slc_end_reply: not enough room\n"); 166129088Smarkm } 166229088Smarkm if (opt_reply) { 166329088Smarkm free(opt_reply); 166429088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 166529088Smarkm } 166629088Smarkm} 166729088Smarkm 166829088Smarkm 1669275508Sngie 167087139Smarkmint 167187139Smarkmtelrcv(void) 167229088Smarkm{ 167387139Smarkm int c; 167487139Smarkm int scc; 167587139Smarkm unsigned char *sbp; 167629088Smarkm int count; 167729088Smarkm int returnValue = 0; 167829088Smarkm 167929088Smarkm scc = 0; 168029088Smarkm count = 0; 168129088Smarkm while (TTYROOM() > 2) { 168229088Smarkm if (scc == 0) { 168329088Smarkm if (count) { 168429088Smarkm ring_consumed(&netiring, count); 168529088Smarkm returnValue = 1; 168629088Smarkm count = 0; 168729088Smarkm } 168829088Smarkm sbp = netiring.consume; 168929088Smarkm scc = ring_full_consecutive(&netiring); 169029088Smarkm if (scc == 0) { 169129088Smarkm /* No more data coming in */ 169229088Smarkm break; 169329088Smarkm } 169429088Smarkm } 169529088Smarkm 169629088Smarkm c = *sbp++ & 0xff, scc--; count++; 169729088Smarkm#ifdef ENCRYPTION 169829088Smarkm if (decrypt_input) 169929088Smarkm c = (*decrypt_input)(c); 170029088Smarkm#endif /* ENCRYPTION */ 170129088Smarkm 170229088Smarkm switch (telrcv_state) { 170329088Smarkm 170429088Smarkm case TS_CR: 170529088Smarkm telrcv_state = TS_DATA; 170629088Smarkm if (c == '\0') { 170729088Smarkm break; /* Ignore \0 after CR */ 170829088Smarkm } 170929088Smarkm else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 171029088Smarkm TTYADD(c); 171129088Smarkm break; 171229088Smarkm } 1713103955Smarkm /* FALLTHROUGH */ 171429088Smarkm 171529088Smarkm case TS_DATA: 1716142790Stobez if (c == IAC && telnetport >= 0) { 171729088Smarkm telrcv_state = TS_IAC; 171829088Smarkm break; 171929088Smarkm } 172029088Smarkm /* 172129088Smarkm * The 'crmod' hack (see following) is needed 172229088Smarkm * since we can't * set CRMOD on output only. 172329088Smarkm * Machines like MULTICS like to send \r without 172429088Smarkm * \n; since we must turn off CRMOD to get proper 172529088Smarkm * input, the mapping is done here (sigh). 172629088Smarkm */ 172729088Smarkm if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 172829088Smarkm if (scc > 0) { 172929088Smarkm c = *sbp&0xff; 173029088Smarkm#ifdef ENCRYPTION 173129088Smarkm if (decrypt_input) 173229088Smarkm c = (*decrypt_input)(c); 173329088Smarkm#endif /* ENCRYPTION */ 173429088Smarkm if (c == 0) { 173529088Smarkm sbp++, scc--; count++; 173629088Smarkm /* a "true" CR */ 173729088Smarkm TTYADD('\r'); 173829088Smarkm } else if (my_want_state_is_dont(TELOPT_ECHO) && 173929088Smarkm (c == '\n')) { 174029088Smarkm sbp++, scc--; count++; 174129088Smarkm TTYADD('\n'); 174229088Smarkm } else { 174329088Smarkm#ifdef ENCRYPTION 174429088Smarkm if (decrypt_input) 174529088Smarkm (*decrypt_input)(-1); 174629088Smarkm#endif /* ENCRYPTION */ 174729088Smarkm 174829088Smarkm TTYADD('\r'); 174929088Smarkm if (crmod) { 175029088Smarkm TTYADD('\n'); 175129088Smarkm } 175229088Smarkm } 175329088Smarkm } else { 175429088Smarkm telrcv_state = TS_CR; 175529088Smarkm TTYADD('\r'); 175629088Smarkm if (crmod) { 175729088Smarkm TTYADD('\n'); 175829088Smarkm } 175929088Smarkm } 176029088Smarkm } else { 176129088Smarkm TTYADD(c); 176229088Smarkm } 176329088Smarkm continue; 176429088Smarkm 176529088Smarkm case TS_IAC: 176629088Smarkmprocess_iac: 176729088Smarkm switch (c) { 176829088Smarkm 176929088Smarkm case WILL: 177029088Smarkm telrcv_state = TS_WILL; 177129088Smarkm continue; 177229088Smarkm 177329088Smarkm case WONT: 177429088Smarkm telrcv_state = TS_WONT; 177529088Smarkm continue; 177629088Smarkm 177729088Smarkm case DO: 177829088Smarkm telrcv_state = TS_DO; 177929088Smarkm continue; 178029088Smarkm 178129088Smarkm case DONT: 178229088Smarkm telrcv_state = TS_DONT; 178329088Smarkm continue; 178429088Smarkm 178529088Smarkm case DM: 178629088Smarkm /* 178729088Smarkm * We may have missed an urgent notification, 178829088Smarkm * so make sure we flush whatever is in the 178929088Smarkm * buffer currently. 179029088Smarkm */ 179129088Smarkm printoption("RCVD", IAC, DM); 179229088Smarkm SYNCHing = 1; 179329088Smarkm (void) ttyflush(1); 179429088Smarkm SYNCHing = stilloob(); 179529088Smarkm settimer(gotDM); 179629088Smarkm break; 179729088Smarkm 179829088Smarkm case SB: 179929088Smarkm SB_CLEAR(); 180029088Smarkm telrcv_state = TS_SB; 180129088Smarkm continue; 180229088Smarkm 180329088Smarkm case IAC: 180429088Smarkm TTYADD(IAC); 180529088Smarkm break; 180629088Smarkm 180729088Smarkm case NOP: 180829088Smarkm case GA: 180929088Smarkm default: 181029088Smarkm printoption("RCVD", IAC, c); 181129088Smarkm break; 181229088Smarkm } 181329088Smarkm telrcv_state = TS_DATA; 181429088Smarkm continue; 181529088Smarkm 181629088Smarkm case TS_WILL: 181729088Smarkm printoption("RCVD", WILL, c); 181829088Smarkm willoption(c); 181929088Smarkm telrcv_state = TS_DATA; 182029088Smarkm continue; 182129088Smarkm 182229088Smarkm case TS_WONT: 182329088Smarkm printoption("RCVD", WONT, c); 182429088Smarkm wontoption(c); 182529088Smarkm telrcv_state = TS_DATA; 182629088Smarkm continue; 182729088Smarkm 182829088Smarkm case TS_DO: 182929088Smarkm printoption("RCVD", DO, c); 183029088Smarkm dooption(c); 183129088Smarkm if (c == TELOPT_NAWS) { 183229088Smarkm sendnaws(); 183329088Smarkm } else if (c == TELOPT_LFLOW) { 183429088Smarkm localflow = 1; 183529088Smarkm setcommandmode(); 183629088Smarkm setconnmode(0); 183729088Smarkm } 183829088Smarkm telrcv_state = TS_DATA; 183929088Smarkm continue; 184029088Smarkm 184129088Smarkm case TS_DONT: 184229088Smarkm printoption("RCVD", DONT, c); 184329088Smarkm dontoption(c); 184429088Smarkm flushline = 1; 184529088Smarkm setconnmode(0); /* set new tty mode (maybe) */ 184629088Smarkm telrcv_state = TS_DATA; 184729088Smarkm continue; 184829088Smarkm 184929088Smarkm case TS_SB: 185029088Smarkm if (c == IAC) { 185129088Smarkm telrcv_state = TS_SE; 185229088Smarkm } else { 185329088Smarkm SB_ACCUM(c); 185429088Smarkm } 185529088Smarkm continue; 185629088Smarkm 185729088Smarkm case TS_SE: 185829088Smarkm if (c != SE) { 185929088Smarkm if (c != IAC) { 186029088Smarkm /* 186129088Smarkm * This is an error. We only expect to get 186229088Smarkm * "IAC IAC" or "IAC SE". Several things may 186329088Smarkm * have happend. An IAC was not doubled, the 186429088Smarkm * IAC SE was left off, or another option got 186529088Smarkm * inserted into the suboption are all possibilities. 186629088Smarkm * If we assume that the IAC was not doubled, 186729088Smarkm * and really the IAC SE was left off, we could 186829088Smarkm * get into an infinate loop here. So, instead, 186929088Smarkm * we terminate the suboption, and process the 187029088Smarkm * partial suboption if we can. 187129088Smarkm */ 187229088Smarkm SB_ACCUM(IAC); 187329088Smarkm SB_ACCUM(c); 187429088Smarkm subpointer -= 2; 187529088Smarkm SB_TERM(); 187629088Smarkm 187729088Smarkm printoption("In SUBOPTION processing, RCVD", IAC, c); 187829088Smarkm suboption(); /* handle sub-option */ 187929088Smarkm telrcv_state = TS_IAC; 188029088Smarkm goto process_iac; 188129088Smarkm } 188229088Smarkm SB_ACCUM(c); 188329088Smarkm telrcv_state = TS_SB; 188429088Smarkm } else { 188529088Smarkm SB_ACCUM(IAC); 188629088Smarkm SB_ACCUM(SE); 188729088Smarkm subpointer -= 2; 188829088Smarkm SB_TERM(); 188929088Smarkm suboption(); /* handle sub-option */ 189029088Smarkm telrcv_state = TS_DATA; 189129088Smarkm } 189229088Smarkm } 189329088Smarkm } 189429088Smarkm if (count) 189529088Smarkm ring_consumed(&netiring, count); 189629088Smarkm return returnValue||count; 189729088Smarkm} 189829088Smarkm 189929088Smarkmstatic int bol = 1, local = 0; 190029088Smarkm 190187139Smarkmint 190287139Smarkmrlogin_susp(void) 190329088Smarkm{ 190429088Smarkm if (local) { 190529088Smarkm local = 0; 190629088Smarkm bol = 1; 190729088Smarkm command(0, "z\n", 2); 190829088Smarkm return(1); 190929088Smarkm } 191029088Smarkm return(0); 191129088Smarkm} 191229088Smarkm 191387139Smarkmstatic int 191487139Smarkmtelsnd(void) 191529088Smarkm{ 191629088Smarkm int tcc; 191729088Smarkm int count; 191829088Smarkm int returnValue = 0; 191929088Smarkm unsigned char *tbp; 192029088Smarkm 192129088Smarkm tcc = 0; 192229088Smarkm count = 0; 192329088Smarkm while (NETROOM() > 2) { 192487139Smarkm int sc; 192587139Smarkm int c; 192629088Smarkm 192729088Smarkm if (tcc == 0) { 192829088Smarkm if (count) { 192929088Smarkm ring_consumed(&ttyiring, count); 193029088Smarkm returnValue = 1; 193129088Smarkm count = 0; 193229088Smarkm } 193329088Smarkm tbp = ttyiring.consume; 193429088Smarkm tcc = ring_full_consecutive(&ttyiring); 193529088Smarkm if (tcc == 0) { 193629088Smarkm break; 193729088Smarkm } 193829088Smarkm } 193929088Smarkm c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 194029088Smarkm if (rlogin != _POSIX_VDISABLE) { 194129088Smarkm if (bol) { 194229088Smarkm bol = 0; 194329088Smarkm if (sc == rlogin) { 194429088Smarkm local = 1; 194529088Smarkm continue; 194629088Smarkm } 194729088Smarkm } else if (local) { 194829088Smarkm local = 0; 194929088Smarkm if (sc == '.' || c == termEofChar) { 195029088Smarkm bol = 1; 195129088Smarkm command(0, "close\n", 6); 195229088Smarkm continue; 195329088Smarkm } 195429088Smarkm if (sc == termSuspChar) { 195529088Smarkm bol = 1; 195629088Smarkm command(0, "z\n", 2); 195729088Smarkm continue; 195829088Smarkm } 195929088Smarkm if (sc == escape) { 196087139Smarkm command(0, tbp, tcc); 196129088Smarkm bol = 1; 196229088Smarkm count += tcc; 196329088Smarkm tcc = 0; 196429088Smarkm flushline = 1; 196529088Smarkm break; 196629088Smarkm } 196729088Smarkm if (sc != rlogin) { 196829088Smarkm ++tcc; 196929088Smarkm --tbp; 197029088Smarkm --count; 197129088Smarkm c = sc = rlogin; 197229088Smarkm } 197329088Smarkm } 197429088Smarkm if ((sc == '\n') || (sc == '\r')) 197529088Smarkm bol = 1; 197647973Sru } else if (escape != _POSIX_VDISABLE && sc == escape) { 197729088Smarkm /* 197829088Smarkm * Double escape is a pass through of a single escape character. 197929088Smarkm */ 198029088Smarkm if (tcc && strip(*tbp) == escape) { 198129088Smarkm tbp++; 198229088Smarkm tcc--; 198329088Smarkm count++; 198429088Smarkm bol = 0; 198529088Smarkm } else { 198629088Smarkm command(0, (char *)tbp, tcc); 198729088Smarkm bol = 1; 198829088Smarkm count += tcc; 198929088Smarkm tcc = 0; 199029088Smarkm flushline = 1; 199129088Smarkm break; 199229088Smarkm } 199329088Smarkm } else 199429088Smarkm bol = 0; 199529088Smarkm#ifdef KLUDGELINEMODE 199629088Smarkm if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 199729088Smarkm if (tcc > 0 && strip(*tbp) == echoc) { 199829088Smarkm tcc--; tbp++; count++; 199929088Smarkm } else { 200029088Smarkm dontlecho = !dontlecho; 200129088Smarkm settimer(echotoggle); 200229088Smarkm setconnmode(0); 200329088Smarkm flushline = 1; 200429088Smarkm break; 200529088Smarkm } 200629088Smarkm } 200729088Smarkm#endif 200829088Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 200929088Smarkm if (TerminalSpecialChars(sc) == 0) { 201029088Smarkm bol = 1; 201129088Smarkm break; 201229088Smarkm } 201329088Smarkm } 201429088Smarkm if (my_want_state_is_wont(TELOPT_BINARY)) { 201529088Smarkm switch (c) { 201629088Smarkm case '\n': 201729088Smarkm /* 201829088Smarkm * If we are in CRMOD mode (\r ==> \n) 201929088Smarkm * on our local machine, then probably 202029088Smarkm * a newline (unix) is CRLF (TELNET). 202129088Smarkm */ 202229088Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 202329088Smarkm NETADD('\r'); 202429088Smarkm } 202529088Smarkm NETADD('\n'); 202629088Smarkm bol = flushline = 1; 202729088Smarkm break; 202829088Smarkm case '\r': 202929088Smarkm if (!crlf) { 203029088Smarkm NET2ADD('\r', '\0'); 203129088Smarkm } else { 203229088Smarkm NET2ADD('\r', '\n'); 203329088Smarkm } 203429088Smarkm bol = flushline = 1; 203529088Smarkm break; 203629088Smarkm case IAC: 203729088Smarkm NET2ADD(IAC, IAC); 203829088Smarkm break; 203929088Smarkm default: 204029088Smarkm NETADD(c); 204129088Smarkm break; 204229088Smarkm } 204329088Smarkm } else if (c == IAC) { 204429088Smarkm NET2ADD(IAC, IAC); 204529088Smarkm } else { 204629088Smarkm NETADD(c); 204729088Smarkm } 204829088Smarkm } 204929088Smarkm if (count) 205029088Smarkm ring_consumed(&ttyiring, count); 205129088Smarkm return returnValue||count; /* Non-zero if we did anything */ 205229088Smarkm} 2053275508Sngie 205429088Smarkm/* 205529088Smarkm * Scheduler() 205629088Smarkm * 205729088Smarkm * Try to do something. 205829088Smarkm * 205929088Smarkm * If we do something useful, return 1; else return 0. 206029088Smarkm * 206129088Smarkm */ 206229088Smarkm 206387139Smarkmstatic int 206487139SmarkmScheduler(int block) 206529088Smarkm{ 206629088Smarkm /* One wants to be a bit careful about setting returnValue 206729088Smarkm * to one, since a one implies we did some useful work, 206829088Smarkm * and therefore probably won't be called to block next 206929088Smarkm */ 207029088Smarkm int returnValue; 207129088Smarkm int netin, netout, netex, ttyin, ttyout; 207229088Smarkm 207329088Smarkm /* Decide which rings should be processed */ 207429088Smarkm 207529088Smarkm netout = ring_full_count(&netoring) && 207629088Smarkm (flushline || 207729088Smarkm (my_want_state_is_wont(TELOPT_LINEMODE) 207829088Smarkm#ifdef KLUDGELINEMODE 207929088Smarkm && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 208029088Smarkm#endif 208129088Smarkm ) || 208229088Smarkm my_want_state_is_will(TELOPT_BINARY)); 208329088Smarkm ttyout = ring_full_count(&ttyoring); 208429088Smarkm 208529181Smarkm ttyin = ring_empty_count(&ttyiring) && (clienteof == 0); 208629088Smarkm 208729088Smarkm netin = !ISend && ring_empty_count(&netiring); 208829088Smarkm 208929088Smarkm netex = !SYNCHing; 209029088Smarkm 209129088Smarkm /* Call to system code to process rings */ 209229088Smarkm 209329088Smarkm returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 209429088Smarkm 209529088Smarkm /* Now, look at the input rings, looking for work to do. */ 209629088Smarkm 209729088Smarkm if (ring_full_count(&ttyiring)) { 209829088Smarkm returnValue |= telsnd(); 209929088Smarkm } 210029088Smarkm 210129088Smarkm if (ring_full_count(&netiring)) { 210229088Smarkm returnValue |= telrcv(); 210329088Smarkm } 210429088Smarkm return returnValue; 210529088Smarkm} 210629088Smarkm 210787139Smarkm#ifdef AUTHENTICATION 210887139Smarkm#define __unusedhere 210987139Smarkm#else 211087139Smarkm#define __unusedhere __unused 211187139Smarkm#endif 211229088Smarkm/* 211329088Smarkm * Select from tty and network... 211429088Smarkm */ 211587139Smarkmvoid 211687139Smarkmtelnet(char *user __unusedhere) 211729088Smarkm{ 211829088Smarkm sys_telnet_init(); 211929088Smarkm 212087139Smarkm#ifdef AUTHENTICATION 212187139Smarkm#ifdef ENCRYPTION 212229088Smarkm { 212329088Smarkm static char local_host[256] = { 0 }; 212429088Smarkm 212529088Smarkm if (!local_host[0]) { 212629088Smarkm gethostname(local_host, sizeof(local_host)); 212729088Smarkm local_host[sizeof(local_host)-1] = 0; 212829088Smarkm } 212929088Smarkm auth_encrypt_init(local_host, hostname, "TELNET", 0); 213029088Smarkm auth_encrypt_user(user); 213129088Smarkm } 213287139Smarkm#endif 213387139Smarkm#endif 2134142790Stobez if (telnetport > 0) { 213587139Smarkm#ifdef AUTHENTICATION 213629088Smarkm if (autologin) 213729088Smarkm send_will(TELOPT_AUTHENTICATION, 1); 213829088Smarkm#endif 213929088Smarkm#ifdef ENCRYPTION 214029088Smarkm send_do(TELOPT_ENCRYPT, 1); 214129088Smarkm send_will(TELOPT_ENCRYPT, 1); 214229088Smarkm#endif /* ENCRYPTION */ 214329088Smarkm send_do(TELOPT_SGA, 1); 214429088Smarkm send_will(TELOPT_TTYPE, 1); 214529088Smarkm send_will(TELOPT_NAWS, 1); 214629088Smarkm send_will(TELOPT_TSPEED, 1); 214729088Smarkm send_will(TELOPT_LFLOW, 1); 214829088Smarkm send_will(TELOPT_LINEMODE, 1); 214929088Smarkm send_will(TELOPT_NEW_ENVIRON, 1); 215029088Smarkm send_do(TELOPT_STATUS, 1); 215187139Smarkm if (env_getvalue("DISPLAY")) 215229088Smarkm send_will(TELOPT_XDISPLOC, 1); 215329088Smarkm if (eight) 215429088Smarkm tel_enter_binary(eight); 215529088Smarkm } 215629088Smarkm 215729088Smarkm for (;;) { 215829088Smarkm int schedValue; 215929088Smarkm 216029088Smarkm while ((schedValue = Scheduler(0)) != 0) { 216129088Smarkm if (schedValue == -1) { 216229088Smarkm setcommandmode(); 216329088Smarkm return; 216429088Smarkm } 216529088Smarkm } 216629088Smarkm 216729088Smarkm if (Scheduler(1) == -1) { 216829088Smarkm setcommandmode(); 216929088Smarkm return; 217029088Smarkm } 217129088Smarkm } 217229088Smarkm} 217329088Smarkm 217429088Smarkm#if 0 /* XXX - this not being in is a bug */ 217529088Smarkm/* 217629088Smarkm * nextitem() 217729088Smarkm * 217829088Smarkm * Return the address of the next "item" in the TELNET data 217929088Smarkm * stream. This will be the address of the next character if 218029088Smarkm * the current address is a user data character, or it will 218129088Smarkm * be the address of the character following the TELNET command 218229088Smarkm * if the current address is a TELNET IAC ("I Am a Command") 218329088Smarkm * character. 218429088Smarkm */ 218529088Smarkm 218687139Smarkmstatic char * 218787139Smarkmnextitem(char *current) 218829088Smarkm{ 218929088Smarkm if ((*current&0xff) != IAC) { 219029088Smarkm return current+1; 219129088Smarkm } 219229088Smarkm switch (*(current+1)&0xff) { 219329088Smarkm case DO: 219429088Smarkm case DONT: 219529088Smarkm case WILL: 219629088Smarkm case WONT: 219729088Smarkm return current+3; 219829088Smarkm case SB: /* loop forever looking for the SE */ 219929088Smarkm { 220087139Smarkm char *look = current+2; 220129088Smarkm 220229088Smarkm for (;;) { 220329088Smarkm if ((*look++&0xff) == IAC) { 220429088Smarkm if ((*look++&0xff) == SE) { 220529088Smarkm return look; 220629088Smarkm } 220729088Smarkm } 220829088Smarkm } 220929088Smarkm } 221029088Smarkm default: 221129088Smarkm return current+2; 221229088Smarkm } 221329088Smarkm} 221429088Smarkm#endif /* 0 */ 221529088Smarkm 221629088Smarkm/* 221729088Smarkm * netclear() 221829088Smarkm * 221929088Smarkm * We are about to do a TELNET SYNCH operation. Clear 222029088Smarkm * the path to the network. 222129088Smarkm * 222229088Smarkm * Things are a bit tricky since we may have sent the first 222329088Smarkm * byte or so of a previous TELNET command into the network. 222429088Smarkm * So, we have to scan the network buffer from the beginning 222529088Smarkm * until we are up to where we want to be. 222629088Smarkm * 222729088Smarkm * A side effect of what we do, just to keep things 222829088Smarkm * simple, is to clear the urgent data pointer. The principal 222929088Smarkm * caller should be setting the urgent data pointer AFTER calling 223029088Smarkm * us in any case. 223129088Smarkm */ 223229088Smarkm 223387139Smarkmstatic void 223487139Smarkmnetclear(void) 223529088Smarkm{ 223687139Smarkm /* Deleted */ 223729088Smarkm} 223829088Smarkm 223929088Smarkm/* 224029088Smarkm * These routines add various telnet commands to the data stream. 224129088Smarkm */ 224229088Smarkm 224387139Smarkmstatic void 224487139Smarkmdoflush(void) 224529088Smarkm{ 224629088Smarkm NET2ADD(IAC, DO); 224729088Smarkm NETADD(TELOPT_TM); 224829088Smarkm flushline = 1; 224929088Smarkm flushout = 1; 225029088Smarkm (void) ttyflush(1); /* Flush/drop output */ 225129088Smarkm /* do printoption AFTER flush, otherwise the output gets tossed... */ 225229088Smarkm printoption("SENT", DO, TELOPT_TM); 225329088Smarkm} 225429088Smarkm 225587139Smarkmvoid 225687139SmarkmxmitAO(void) 225729088Smarkm{ 225829088Smarkm NET2ADD(IAC, AO); 225929088Smarkm printoption("SENT", IAC, AO); 226029088Smarkm if (autoflush) { 226129088Smarkm doflush(); 226229088Smarkm } 226329088Smarkm} 226429088Smarkm 226587139Smarkmvoid 226687139SmarkmxmitEL(void) 226729088Smarkm{ 226829088Smarkm NET2ADD(IAC, EL); 226929088Smarkm printoption("SENT", IAC, EL); 227029088Smarkm} 227129088Smarkm 227287139Smarkmvoid 227387139SmarkmxmitEC(void) 227429088Smarkm{ 227529088Smarkm NET2ADD(IAC, EC); 227629088Smarkm printoption("SENT", IAC, EC); 227729088Smarkm} 227829088Smarkm 227987139Smarkmint 228087139Smarkmdosynch(char *ch __unused) 228129088Smarkm{ 228229088Smarkm netclear(); /* clear the path to the network */ 228329088Smarkm NETADD(IAC); 228429088Smarkm setneturg(); 228529088Smarkm NETADD(DM); 228629088Smarkm printoption("SENT", IAC, DM); 228729088Smarkm return 1; 228829088Smarkm} 228929088Smarkm 229029088Smarkmint want_status_response = 0; 229129088Smarkm 229287139Smarkmint 229387139Smarkmget_status(char *ch __unused) 229429088Smarkm{ 229529088Smarkm unsigned char tmp[16]; 229687139Smarkm unsigned char *cp; 229729088Smarkm 229829088Smarkm if (my_want_state_is_dont(TELOPT_STATUS)) { 229929088Smarkm printf("Remote side does not support STATUS option\n"); 230029088Smarkm return 0; 230129088Smarkm } 230229088Smarkm cp = tmp; 230329088Smarkm 230429088Smarkm *cp++ = IAC; 230529088Smarkm *cp++ = SB; 230629088Smarkm *cp++ = TELOPT_STATUS; 230729088Smarkm *cp++ = TELQUAL_SEND; 230829088Smarkm *cp++ = IAC; 230929088Smarkm *cp++ = SE; 231029088Smarkm if (NETROOM() >= cp - tmp) { 231129088Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 231229088Smarkm printsub('>', tmp+2, cp - tmp - 2); 231329088Smarkm } 231429088Smarkm ++want_status_response; 231529088Smarkm return 1; 231629088Smarkm} 231729088Smarkm 231887139Smarkmvoid 231987139Smarkmintp(void) 232029088Smarkm{ 232129088Smarkm NET2ADD(IAC, IP); 232229088Smarkm printoption("SENT", IAC, IP); 232329088Smarkm flushline = 1; 232429088Smarkm if (autoflush) { 232529088Smarkm doflush(); 232629088Smarkm } 232729088Smarkm if (autosynch) { 232887139Smarkm dosynch(NULL); 232929088Smarkm } 233029088Smarkm} 233129088Smarkm 233287139Smarkmvoid 233387139Smarkmsendbrk(void) 233429088Smarkm{ 233529088Smarkm NET2ADD(IAC, BREAK); 233629088Smarkm printoption("SENT", IAC, BREAK); 233729088Smarkm flushline = 1; 233829088Smarkm if (autoflush) { 233929088Smarkm doflush(); 234029088Smarkm } 234129088Smarkm if (autosynch) { 234287139Smarkm dosynch(NULL); 234329088Smarkm } 234429088Smarkm} 234529088Smarkm 234687139Smarkmvoid 234787139Smarkmsendabort(void) 234829088Smarkm{ 234929088Smarkm NET2ADD(IAC, ABORT); 235029088Smarkm printoption("SENT", IAC, ABORT); 235129088Smarkm flushline = 1; 235229088Smarkm if (autoflush) { 235329088Smarkm doflush(); 235429088Smarkm } 235529088Smarkm if (autosynch) { 235687139Smarkm dosynch(NULL); 235729088Smarkm } 235829088Smarkm} 235929088Smarkm 236087139Smarkmvoid 236187139Smarkmsendsusp(void) 236229088Smarkm{ 236329088Smarkm NET2ADD(IAC, SUSP); 236429088Smarkm printoption("SENT", IAC, SUSP); 236529088Smarkm flushline = 1; 236629088Smarkm if (autoflush) { 236729088Smarkm doflush(); 236829088Smarkm } 236929088Smarkm if (autosynch) { 237087139Smarkm dosynch(NULL); 237129088Smarkm } 237229088Smarkm} 237329088Smarkm 237487139Smarkmvoid 237587139Smarkmsendeof(void) 237629088Smarkm{ 237729088Smarkm NET2ADD(IAC, xEOF); 237829088Smarkm printoption("SENT", IAC, xEOF); 237929088Smarkm} 238029088Smarkm 238187139Smarkmvoid 238287139Smarkmsendayt(void) 238329088Smarkm{ 238429088Smarkm NET2ADD(IAC, AYT); 238529088Smarkm printoption("SENT", IAC, AYT); 238629088Smarkm} 238729088Smarkm 238829088Smarkm/* 238929088Smarkm * Send a window size update to the remote system. 239029088Smarkm */ 239129088Smarkm 239287139Smarkmvoid 239387139Smarkmsendnaws(void) 239429088Smarkm{ 239529088Smarkm long rows, cols; 239629088Smarkm unsigned char tmp[16]; 239787139Smarkm unsigned char *cp; 239829088Smarkm 239929088Smarkm if (my_state_is_wont(TELOPT_NAWS)) 240029088Smarkm return; 240129088Smarkm 240229088Smarkm#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 240329088Smarkm if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 240429088Smarkm 240529088Smarkm if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 240629088Smarkm return; 240729088Smarkm } 240829088Smarkm 240929088Smarkm cp = tmp; 241029088Smarkm 241129088Smarkm *cp++ = IAC; 241229088Smarkm *cp++ = SB; 241329088Smarkm *cp++ = TELOPT_NAWS; 241429088Smarkm PUTSHORT(cp, cols); 241529088Smarkm PUTSHORT(cp, rows); 241629088Smarkm *cp++ = IAC; 241729088Smarkm *cp++ = SE; 241829088Smarkm if (NETROOM() >= cp - tmp) { 241929088Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 242029088Smarkm printsub('>', tmp+2, cp - tmp - 2); 242129088Smarkm } 242229088Smarkm} 242329088Smarkm 242487139Smarkmvoid 242587139Smarkmtel_enter_binary(int rw) 242629088Smarkm{ 242729088Smarkm if (rw&1) 242829088Smarkm send_do(TELOPT_BINARY, 1); 242929088Smarkm if (rw&2) 243029088Smarkm send_will(TELOPT_BINARY, 1); 243129088Smarkm} 243229088Smarkm 243387139Smarkmvoid 243487139Smarkmtel_leave_binary(int rw) 243529088Smarkm{ 243629088Smarkm if (rw&1) 243729088Smarkm send_dont(TELOPT_BINARY, 1); 243829088Smarkm if (rw&2) 243929088Smarkm send_wont(TELOPT_BINARY, 1); 244029088Smarkm} 2441