157416Smarkm/* 257416Smarkm * Copyright (c) 1988, 1990, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm#include "telnet_locl.h" 3557416Smarkm 36233294SstasRCSID("$Id$"); 3757416Smarkm 3857416Smarkm#define strip(x) (eight ? (x) : ((x) & 0x7f)) 3957416Smarkm 4057416Smarkmstatic unsigned char subbuffer[SUBBUFSIZE], 4157416Smarkm *subpointer, *subend; /* buffer for sub-options */ 4257416Smarkm#define SB_CLEAR() subpointer = subbuffer; 4357416Smarkm#define SB_TERM() { subend = subpointer; SB_CLEAR(); } 4457416Smarkm#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 4557416Smarkm *subpointer++ = (c); \ 4657416Smarkm } 4757416Smarkm 4857416Smarkm#define SB_GET() ((*subpointer++)&0xff) 4957416Smarkm#define SB_PEEK() ((*subpointer)&0xff) 5057416Smarkm#define SB_EOF() (subpointer >= subend) 5157416Smarkm#define SB_LEN() (subend - subpointer) 5257416Smarkm 5357416Smarkmchar options[256]; /* The combined options */ 5457416Smarkmchar do_dont_resp[256]; 5557416Smarkmchar will_wont_resp[256]; 5657416Smarkm 5757416Smarkmint 5857416Smarkm eight = 3, 5957416Smarkm binary = 0, 6057416Smarkm autologin = 0, /* Autologin anyone? */ 6157416Smarkm skiprc = 0, 6257416Smarkm connected, 6357416Smarkm showoptions, 6457416Smarkm ISend, /* trying to send network data in */ 6557416Smarkm debug = 0, 6657416Smarkm crmod, 6757416Smarkm netdata, /* Print out network data flow */ 6857416Smarkm crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 6957416Smarkm telnetport, 7090926Snectar wantencryption = 0, 7157416Smarkm SYNCHing, /* we are in TELNET SYNCH mode */ 7257416Smarkm flushout, /* flush output */ 7357416Smarkm autoflush = 0, /* flush output when interrupting? */ 7457416Smarkm autosynch, /* send interrupt characters with SYNCH? */ 7557416Smarkm localflow, /* we handle flow control locally */ 7657416Smarkm restartany, /* if flow control enabled, restart on any character */ 7757416Smarkm localchars, /* we recognize interrupt/quit */ 7857416Smarkm donelclchars, /* the user has set "localchars" */ 7957416Smarkm donebinarytoggle, /* the user has put us in binary */ 8057416Smarkm dontlecho, /* do we suppress local echoing right now? */ 8157416Smarkm globalmode; 8257416Smarkm 8357416Smarkmchar *prompt = 0; 8457416Smarkm 8590926Snectarint scheduler_lockout_tty = 0; 8690926Snectar 8757416Smarkmcc_t escape; 8857416Smarkmcc_t rlogin; 8957416Smarkm#ifdef KLUDGELINEMODE 9057416Smarkmcc_t echoc; 9157416Smarkm#endif 9257416Smarkm 9357416Smarkm/* 9457416Smarkm * Telnet receiver states for fsm 9557416Smarkm */ 9657416Smarkm#define TS_DATA 0 9757416Smarkm#define TS_IAC 1 9857416Smarkm#define TS_WILL 2 9957416Smarkm#define TS_WONT 3 10057416Smarkm#define TS_DO 4 10157416Smarkm#define TS_DONT 5 10257416Smarkm#define TS_CR 6 10357416Smarkm#define TS_SB 7 /* sub-option collection */ 10457416Smarkm#define TS_SE 8 /* looking for sub-option end */ 10557416Smarkm 10657416Smarkmstatic int telrcv_state; 10757416Smarkm#ifdef OLD_ENVIRON 10857416Smarkmunsigned char telopt_environ = TELOPT_NEW_ENVIRON; 10957416Smarkm#else 11057416Smarkm# define telopt_environ TELOPT_NEW_ENVIRON 11157416Smarkm#endif 11257416Smarkm 11357416Smarkmjmp_buf toplevel; 11457416Smarkmjmp_buf peerdied; 11557416Smarkm 11657416Smarkmint flushline; 11757416Smarkmint linemode; 11857416Smarkm 11957416Smarkm#ifdef KLUDGELINEMODE 12057416Smarkmint kludgelinemode = 1; 12157416Smarkm#endif 12257416Smarkm 12357416Smarkm/* 12457416Smarkm * The following are some clocks used to decide how to interpret 12557416Smarkm * the relationship between various variables. 12657416Smarkm */ 12757416Smarkm 12857416SmarkmClocks clocks; 12957416Smarkm 13057416Smarkmstatic int is_unique(char *name, char **as, char **ae); 13157416Smarkm 13257416Smarkm 13357416Smarkm/* 13457416Smarkm * Initialize telnet environment. 13557416Smarkm */ 13657416Smarkm 13757416Smarkmvoid 13857416Smarkminit_telnet(void) 13957416Smarkm{ 14057416Smarkm env_init(); 14157416Smarkm 14257416Smarkm SB_CLEAR(); 14357416Smarkm memset(options, 0, sizeof options); 14457416Smarkm 14557416Smarkm connected = ISend = localflow = donebinarytoggle = 0; 14657416Smarkm#if defined(AUTHENTICATION) || defined(ENCRYPTION) 14757416Smarkm auth_encrypt_connect(connected); 14857416Smarkm#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ 14957416Smarkm restartany = -1; 15057416Smarkm 15157416Smarkm SYNCHing = 0; 15257416Smarkm 15357416Smarkm /* Don't change NetTrace */ 15457416Smarkm 15557416Smarkm escape = CONTROL(']'); 15657416Smarkm rlogin = _POSIX_VDISABLE; 15757416Smarkm#ifdef KLUDGELINEMODE 15857416Smarkm echoc = CONTROL('E'); 15957416Smarkm#endif 16057416Smarkm 16157416Smarkm flushline = 1; 16257416Smarkm telrcv_state = TS_DATA; 16357416Smarkm} 16457416Smarkm 16557416Smarkm 16657416Smarkm/* 16757416Smarkm * These routines are in charge of sending option negotiations 16857416Smarkm * to the other side. 16957416Smarkm * 17057416Smarkm * The basic idea is that we send the negotiation if either side 17157416Smarkm * is in disagreement as to what the current state should be. 17257416Smarkm */ 17357416Smarkm 17457416Smarkmvoid 17557416Smarkmsend_do(int c, int init) 17657416Smarkm{ 17757416Smarkm if (init) { 17857416Smarkm if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 17957416Smarkm my_want_state_is_do(c)) 18057416Smarkm return; 18157416Smarkm set_my_want_state_do(c); 18257416Smarkm do_dont_resp[c]++; 18357416Smarkm } 18457416Smarkm NET2ADD(IAC, DO); 18557416Smarkm NETADD(c); 18657416Smarkm printoption("SENT", DO, c); 18757416Smarkm} 18857416Smarkm 18957416Smarkmvoid 19057416Smarkmsend_dont(int c, int init) 19157416Smarkm{ 19257416Smarkm if (init) { 19357416Smarkm if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 19457416Smarkm my_want_state_is_dont(c)) 19557416Smarkm return; 19657416Smarkm set_my_want_state_dont(c); 19757416Smarkm do_dont_resp[c]++; 19857416Smarkm } 19957416Smarkm NET2ADD(IAC, DONT); 20057416Smarkm NETADD(c); 20157416Smarkm printoption("SENT", DONT, c); 20257416Smarkm} 20357416Smarkm 20457416Smarkmvoid 20557416Smarkmsend_will(int c, int init) 20657416Smarkm{ 20757416Smarkm if (init) { 20857416Smarkm if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 20957416Smarkm my_want_state_is_will(c)) 21057416Smarkm return; 21157416Smarkm set_my_want_state_will(c); 21257416Smarkm will_wont_resp[c]++; 21357416Smarkm } 21457416Smarkm NET2ADD(IAC, WILL); 21557416Smarkm NETADD(c); 21657416Smarkm printoption("SENT", WILL, c); 21757416Smarkm} 21857416Smarkm 21957416Smarkmvoid 22057416Smarkmsend_wont(int c, int init) 22157416Smarkm{ 22257416Smarkm if (init) { 22357416Smarkm if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 22457416Smarkm my_want_state_is_wont(c)) 22557416Smarkm return; 22657416Smarkm set_my_want_state_wont(c); 22757416Smarkm will_wont_resp[c]++; 22857416Smarkm } 22957416Smarkm NET2ADD(IAC, WONT); 23057416Smarkm NETADD(c); 23157416Smarkm printoption("SENT", WONT, c); 23257416Smarkm} 23357416Smarkm 23457416Smarkm 23557416Smarkmvoid 23657416Smarkmwilloption(int option) 23757416Smarkm{ 23857416Smarkm int new_state_ok = 0; 23957416Smarkm 24057416Smarkm if (do_dont_resp[option]) { 24157416Smarkm --do_dont_resp[option]; 24257416Smarkm if (do_dont_resp[option] && my_state_is_do(option)) 24357416Smarkm --do_dont_resp[option]; 24457416Smarkm } 24557416Smarkm 24657416Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 24757416Smarkm 24857416Smarkm switch (option) { 24957416Smarkm 25057416Smarkm case TELOPT_ECHO: 25157416Smarkm case TELOPT_BINARY: 25257416Smarkm case TELOPT_SGA: 25357416Smarkm settimer(modenegotiated); 25457416Smarkm /* FALL THROUGH */ 25557416Smarkm case TELOPT_STATUS: 25657416Smarkm#if defined(AUTHENTICATION) 25757416Smarkm case TELOPT_AUTHENTICATION: 25857416Smarkm#endif 25957416Smarkm#if defined(ENCRYPTION) 26057416Smarkm case TELOPT_ENCRYPT: 26157416Smarkm#endif 26257416Smarkm new_state_ok = 1; 26357416Smarkm break; 26457416Smarkm 26557416Smarkm case TELOPT_TM: 26657416Smarkm if (flushout) 26757416Smarkm flushout = 0; 26857416Smarkm /* 26957416Smarkm * Special case for TM. If we get back a WILL, 27057416Smarkm * pretend we got back a WONT. 27157416Smarkm */ 27257416Smarkm set_my_want_state_dont(option); 27357416Smarkm set_my_state_dont(option); 27457416Smarkm return; /* Never reply to TM will's/wont's */ 27557416Smarkm 27657416Smarkm case TELOPT_LINEMODE: 27757416Smarkm default: 27857416Smarkm break; 27957416Smarkm } 28057416Smarkm 28157416Smarkm if (new_state_ok) { 28257416Smarkm set_my_want_state_do(option); 28357416Smarkm send_do(option, 0); 28457416Smarkm setconnmode(0); /* possibly set new tty mode */ 28557416Smarkm } else { 28657416Smarkm do_dont_resp[option]++; 28757416Smarkm send_dont(option, 0); 28857416Smarkm } 28957416Smarkm } 29057416Smarkm set_my_state_do(option); 29157416Smarkm#if defined(ENCRYPTION) 29257416Smarkm if (option == TELOPT_ENCRYPT) 29357416Smarkm encrypt_send_support(); 29457416Smarkm#endif 29557416Smarkm} 29657416Smarkm 29757416Smarkmvoid 29857416Smarkmwontoption(int option) 29957416Smarkm{ 30057416Smarkm if (do_dont_resp[option]) { 30157416Smarkm --do_dont_resp[option]; 30257416Smarkm if (do_dont_resp[option] && my_state_is_dont(option)) 30357416Smarkm --do_dont_resp[option]; 30457416Smarkm } 30557416Smarkm 30657416Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 30757416Smarkm 30857416Smarkm switch (option) { 30957416Smarkm 31057416Smarkm#ifdef KLUDGELINEMODE 31157416Smarkm case TELOPT_SGA: 31257416Smarkm if (!kludgelinemode) 31357416Smarkm break; 31457416Smarkm /* FALL THROUGH */ 31557416Smarkm#endif 31657416Smarkm case TELOPT_ECHO: 31757416Smarkm settimer(modenegotiated); 31857416Smarkm break; 31957416Smarkm 32057416Smarkm case TELOPT_TM: 32157416Smarkm if (flushout) 32257416Smarkm flushout = 0; 32357416Smarkm set_my_want_state_dont(option); 32457416Smarkm set_my_state_dont(option); 32557416Smarkm return; /* Never reply to TM will's/wont's */ 32657416Smarkm 32757416Smarkm#ifdef ENCRYPTION 32857416Smarkm case TELOPT_ENCRYPT: 32957416Smarkm encrypt_not(); 33057416Smarkm break; 33157416Smarkm#endif 33257416Smarkm default: 33357416Smarkm break; 33457416Smarkm } 33557416Smarkm set_my_want_state_dont(option); 33657416Smarkm if (my_state_is_do(option)) 33757416Smarkm send_dont(option, 0); 33857416Smarkm setconnmode(0); /* Set new tty mode */ 33957416Smarkm } else if (option == TELOPT_TM) { 34057416Smarkm /* 34157416Smarkm * Special case for TM. 34257416Smarkm */ 34357416Smarkm if (flushout) 34457416Smarkm flushout = 0; 34557416Smarkm set_my_want_state_dont(option); 34657416Smarkm } 34757416Smarkm set_my_state_dont(option); 34857416Smarkm} 34957416Smarkm 35057416Smarkmstatic void 35157416Smarkmdooption(int option) 35257416Smarkm{ 35357416Smarkm int new_state_ok = 0; 35457416Smarkm 35557416Smarkm if (will_wont_resp[option]) { 35657416Smarkm --will_wont_resp[option]; 35757416Smarkm if (will_wont_resp[option] && my_state_is_will(option)) 35857416Smarkm --will_wont_resp[option]; 35957416Smarkm } 36057416Smarkm 36157416Smarkm if (will_wont_resp[option] == 0) { 36257416Smarkm if (my_want_state_is_wont(option)) { 36357416Smarkm 36457416Smarkm switch (option) { 36557416Smarkm 36657416Smarkm case TELOPT_TM: 36757416Smarkm /* 36857416Smarkm * Special case for TM. We send a WILL, but pretend 36957416Smarkm * we sent WONT. 37057416Smarkm */ 37157416Smarkm send_will(option, 0); 37257416Smarkm set_my_want_state_wont(TELOPT_TM); 37357416Smarkm set_my_state_wont(TELOPT_TM); 37457416Smarkm return; 37557416Smarkm 37657416Smarkm case TELOPT_BINARY: /* binary mode */ 37757416Smarkm case TELOPT_NAWS: /* window size */ 37857416Smarkm case TELOPT_TSPEED: /* terminal speed */ 37957416Smarkm case TELOPT_LFLOW: /* local flow control */ 38057416Smarkm case TELOPT_TTYPE: /* terminal type option */ 38157416Smarkm case TELOPT_SGA: /* no big deal */ 38257416Smarkm#if defined(ENCRYPTION) 38357416Smarkm case TELOPT_ENCRYPT: /* encryption variable option */ 38457416Smarkm#endif 38557416Smarkm new_state_ok = 1; 38657416Smarkm break; 38757416Smarkm 38857416Smarkm case TELOPT_NEW_ENVIRON: /* New environment variable option */ 38957416Smarkm#ifdef OLD_ENVIRON 39057416Smarkm if (my_state_is_will(TELOPT_OLD_ENVIRON)) 39157416Smarkm send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ 39257416Smarkm goto env_common; 39357416Smarkm case TELOPT_OLD_ENVIRON: /* Old environment variable option */ 39457416Smarkm if (my_state_is_will(TELOPT_NEW_ENVIRON)) 39557416Smarkm break; /* Don't enable if new one is in use! */ 39657416Smarkm env_common: 39757416Smarkm telopt_environ = option; 39857416Smarkm#endif 39957416Smarkm new_state_ok = 1; 40057416Smarkm break; 40157416Smarkm 40257416Smarkm#if defined(AUTHENTICATION) 40357416Smarkm case TELOPT_AUTHENTICATION: 40457416Smarkm if (autologin) 40557416Smarkm new_state_ok = 1; 40657416Smarkm break; 40757416Smarkm#endif 40857416Smarkm 40957416Smarkm case TELOPT_XDISPLOC: /* X Display location */ 41057416Smarkm if (env_getvalue((unsigned char *)"DISPLAY")) 41157416Smarkm new_state_ok = 1; 41257416Smarkm break; 41357416Smarkm 41457416Smarkm case TELOPT_LINEMODE: 41557416Smarkm#ifdef KLUDGELINEMODE 41657416Smarkm kludgelinemode = 0; 41757416Smarkm send_do(TELOPT_SGA, 1); 41857416Smarkm#endif 41957416Smarkm set_my_want_state_will(TELOPT_LINEMODE); 42057416Smarkm send_will(option, 0); 42157416Smarkm set_my_state_will(TELOPT_LINEMODE); 42257416Smarkm slc_init(); 42357416Smarkm return; 42457416Smarkm 42557416Smarkm case TELOPT_ECHO: /* We're never going to echo... */ 42657416Smarkm default: 42757416Smarkm break; 42857416Smarkm } 42957416Smarkm 43057416Smarkm if (new_state_ok) { 43157416Smarkm set_my_want_state_will(option); 43257416Smarkm send_will(option, 0); 43357416Smarkm setconnmode(0); /* Set new tty mode */ 43457416Smarkm } else { 43557416Smarkm will_wont_resp[option]++; 43657416Smarkm send_wont(option, 0); 43757416Smarkm } 43857416Smarkm } else { 43957416Smarkm /* 44057416Smarkm * Handle options that need more things done after the 44157416Smarkm * other side has acknowledged the option. 44257416Smarkm */ 44357416Smarkm switch (option) { 44457416Smarkm case TELOPT_LINEMODE: 44557416Smarkm#ifdef KLUDGELINEMODE 44657416Smarkm kludgelinemode = 0; 44757416Smarkm send_do(TELOPT_SGA, 1); 44857416Smarkm#endif 44957416Smarkm set_my_state_will(option); 45057416Smarkm slc_init(); 45157416Smarkm send_do(TELOPT_SGA, 0); 45257416Smarkm return; 45357416Smarkm } 45457416Smarkm } 45557416Smarkm } 45657416Smarkm set_my_state_will(option); 45757416Smarkm} 45857416Smarkm 45957416Smarkmstatic void 46057416Smarkmdontoption(int option) 46157416Smarkm{ 46257416Smarkm 46357416Smarkm if (will_wont_resp[option]) { 46457416Smarkm --will_wont_resp[option]; 46557416Smarkm if (will_wont_resp[option] && my_state_is_wont(option)) 46657416Smarkm --will_wont_resp[option]; 46757416Smarkm } 46857416Smarkm 46957416Smarkm if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 47057416Smarkm switch (option) { 47157416Smarkm case TELOPT_LINEMODE: 47257416Smarkm linemode = 0; /* put us back to the default state */ 47357416Smarkm break; 47457416Smarkm#ifdef OLD_ENVIRON 47557416Smarkm case TELOPT_NEW_ENVIRON: 47657416Smarkm /* 47757416Smarkm * The new environ option wasn't recognized, try 47857416Smarkm * the old one. 47957416Smarkm */ 48057416Smarkm send_will(TELOPT_OLD_ENVIRON, 1); 48157416Smarkm telopt_environ = TELOPT_OLD_ENVIRON; 48257416Smarkm break; 48357416Smarkm#endif 48457416Smarkm#if 0 48557416Smarkm#ifdef ENCRYPTION 48657416Smarkm case TELOPT_ENCRYPT: 48757416Smarkm encrypt_not(); 48857416Smarkm break; 48957416Smarkm#endif 49057416Smarkm#endif 49157416Smarkm } 49257416Smarkm /* we always accept a DONT */ 49357416Smarkm set_my_want_state_wont(option); 49457416Smarkm if (my_state_is_will(option)) 49557416Smarkm send_wont(option, 0); 49657416Smarkm setconnmode(0); /* Set new tty mode */ 49757416Smarkm } 49857416Smarkm set_my_state_wont(option); 49957416Smarkm} 50057416Smarkm 50157416Smarkm/* 50257416Smarkm * Given a buffer returned by tgetent(), this routine will turn 503178825Sdfr * the pipe separated list of names in the buffer into an array 50457416Smarkm * of pointers to null terminated names. We toss out any bad, 50557416Smarkm * duplicate, or verbose names (names with spaces). 50657416Smarkm */ 50757416Smarkm 50857416Smarkmstatic char *name_unknown = "UNKNOWN"; 50957416Smarkmstatic char *unknown[] = { 0, 0 }; 51057416Smarkm 51157416Smarkmstatic char ** 51257416Smarkmmklist(char *buf, char *name) 51357416Smarkm{ 51457416Smarkm int n; 51557416Smarkm char c, *cp, **argvp, *cp2, **argv, **avt; 51657416Smarkm 51757416Smarkm if (name) { 51857416Smarkm if ((int)strlen(name) > 40) { 51957416Smarkm name = 0; 52057416Smarkm unknown[0] = name_unknown; 52157416Smarkm } else { 52257416Smarkm unknown[0] = name; 52357416Smarkm strupr(name); 52457416Smarkm } 52557416Smarkm } else 52657416Smarkm unknown[0] = name_unknown; 52757416Smarkm /* 52857416Smarkm * Count up the number of names. 52957416Smarkm */ 53057416Smarkm for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 53157416Smarkm if (*cp == '|') 53257416Smarkm n++; 53357416Smarkm } 53457416Smarkm /* 53557416Smarkm * Allocate an array to put the name pointers into 53657416Smarkm */ 53757416Smarkm argv = (char **)malloc((n+3)*sizeof(char *)); 53857416Smarkm if (argv == 0) 53957416Smarkm return(unknown); 54057416Smarkm 54157416Smarkm /* 54257416Smarkm * Fill up the array of pointers to names. 54357416Smarkm */ 54457416Smarkm *argv = 0; 54557416Smarkm argvp = argv+1; 54657416Smarkm n = 0; 54757416Smarkm for (cp = cp2 = buf; (c = *cp); cp++) { 54857416Smarkm if (c == '|' || c == ':') { 54957416Smarkm *cp++ = '\0'; 55057416Smarkm /* 55157416Smarkm * Skip entries that have spaces or are over 40 55257416Smarkm * characters long. If this is our environment 55357416Smarkm * name, then put it up front. Otherwise, as 55457416Smarkm * long as this is not a duplicate name (case 55557416Smarkm * insensitive) add it to the list. 55657416Smarkm */ 55757416Smarkm if (n || (cp - cp2 > 41)) 55857416Smarkm ; 55957416Smarkm else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 56057416Smarkm *argv = cp2; 56157416Smarkm else if (is_unique(cp2, argv+1, argvp)) 56257416Smarkm *argvp++ = cp2; 56357416Smarkm if (c == ':') 56457416Smarkm break; 56557416Smarkm /* 56657416Smarkm * Skip multiple delimiters. Reset cp2 to 56757416Smarkm * the beginning of the next name. Reset n, 56857416Smarkm * the flag for names with spaces. 56957416Smarkm */ 57057416Smarkm while ((c = *cp) == '|') 57157416Smarkm cp++; 57257416Smarkm cp2 = cp; 57357416Smarkm n = 0; 57457416Smarkm } 57557416Smarkm /* 57657416Smarkm * Skip entries with spaces or non-ascii values. 57757416Smarkm * Convert lower case letters to upper case. 57857416Smarkm */ 579178825Sdfr#undef ISASCII 58057416Smarkm#define ISASCII(c) (!((c)&0x80)) 58157416Smarkm if ((c == ' ') || !ISASCII(c)) 58257416Smarkm n = 1; 58390926Snectar else if (islower((unsigned char)c)) 584178825Sdfr *cp = toupper((unsigned char)c); 58557416Smarkm } 58657416Smarkm 58757416Smarkm /* 58857416Smarkm * Check for an old V6 2 character name. If the second 58957416Smarkm * name points to the beginning of the buffer, and is 59057416Smarkm * only 2 characters long, move it to the end of the array. 59157416Smarkm */ 59257416Smarkm if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 59357416Smarkm --argvp; 59457416Smarkm for (avt = &argv[1]; avt < argvp; avt++) 59557416Smarkm *avt = *(avt+1); 59657416Smarkm *argvp++ = buf; 59757416Smarkm } 59857416Smarkm 59957416Smarkm /* 60057416Smarkm * Duplicate last name, for TTYPE option, and null 60157416Smarkm * terminate the array. If we didn't find a match on 60257416Smarkm * our terminal name, put that name at the beginning. 60357416Smarkm */ 60457416Smarkm cp = *(argvp-1); 60557416Smarkm *argvp++ = cp; 60657416Smarkm *argvp = 0; 60757416Smarkm 60857416Smarkm if (*argv == 0) { 60957416Smarkm if (name) 61057416Smarkm *argv = name; 61157416Smarkm else { 61257416Smarkm --argvp; 61357416Smarkm for (avt = argv; avt < argvp; avt++) 61457416Smarkm *avt = *(avt+1); 61557416Smarkm } 61657416Smarkm } 61757416Smarkm if (*argv) 61857416Smarkm return(argv); 61957416Smarkm else 62057416Smarkm return(unknown); 62157416Smarkm} 62257416Smarkm 62357416Smarkmstatic int 62457416Smarkmis_unique(char *name, char **as, char **ae) 62557416Smarkm{ 62657416Smarkm char **ap; 62757416Smarkm int n; 62857416Smarkm 62957416Smarkm n = strlen(name) + 1; 63057416Smarkm for (ap = as; ap < ae; ap++) 63157416Smarkm if (strncasecmp(*ap, name, n) == 0) 63257416Smarkm return(0); 63357416Smarkm return (1); 63457416Smarkm} 63557416Smarkm 63657416Smarkmstatic char termbuf[1024]; 63757416Smarkm 63857416Smarkmstatic int 63957416Smarkmtelnet_setupterm(const char *tname, int fd, int *errp) 64057416Smarkm{ 64172445Sassar#ifdef HAVE_TGETENT 64272445Sassar if (tgetent(termbuf, tname) == 1) { 64372445Sassar termbuf[1023] = '\0'; 64457416Smarkm if (errp) 64572445Sassar *errp = 1; 64672445Sassar return(0); 64772445Sassar } 64872445Sassar if (errp) 64972445Sassar *errp = 0; 65072445Sassar return(-1); 65172445Sassar#else 65272445Sassar strlcpy(termbuf, tname, sizeof(termbuf)); 65372445Sassar if(errp) *errp = 1; 65472445Sassar return 0; 65572445Sassar#endif 65657416Smarkm} 65757416Smarkm 65857416Smarkmint resettermname = 1; 65957416Smarkm 66057416Smarkmstatic char * 66157416Smarkmgettermname() 66257416Smarkm{ 66357416Smarkm char *tname; 66457416Smarkm static char **tnamep = 0; 66557416Smarkm static char **next; 66657416Smarkm int err; 66757416Smarkm 66857416Smarkm if (resettermname) { 66957416Smarkm resettermname = 0; 67057416Smarkm if (tnamep && tnamep != unknown) 67157416Smarkm free(tnamep); 67257416Smarkm if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && 67357416Smarkm telnet_setupterm(tname, 1, &err) == 0) { 67457416Smarkm tnamep = mklist(termbuf, tname); 67557416Smarkm } else { 67657416Smarkm if (tname && ((int)strlen(tname) <= 40)) { 67757416Smarkm unknown[0] = tname; 67857416Smarkm strupr(tname); 67957416Smarkm } else 68057416Smarkm unknown[0] = name_unknown; 68157416Smarkm tnamep = unknown; 68257416Smarkm } 68357416Smarkm next = tnamep; 68457416Smarkm } 68557416Smarkm if (*next == 0) 68657416Smarkm next = tnamep; 68757416Smarkm return(*next++); 68857416Smarkm} 68957416Smarkm/* 69057416Smarkm * suboption() 69157416Smarkm * 69257416Smarkm * Look at the sub-option buffer, and try to be helpful to the other 69357416Smarkm * side. 69457416Smarkm * 69557416Smarkm * Currently we recognize: 69657416Smarkm * 69757416Smarkm * Terminal type, send request. 69857416Smarkm * Terminal speed (send request). 69957416Smarkm * Local flow control (is request). 70057416Smarkm * Linemode 70157416Smarkm */ 70257416Smarkm 70357416Smarkmstatic void 70457416Smarkmsuboption() 70557416Smarkm{ 70657416Smarkm unsigned char subchar; 70757416Smarkm 70857416Smarkm printsub('<', subbuffer, SB_LEN()+2); 70957416Smarkm switch (subchar = SB_GET()) { 71057416Smarkm case TELOPT_TTYPE: 71157416Smarkm if (my_want_state_is_wont(TELOPT_TTYPE)) 71257416Smarkm return; 71357416Smarkm if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 71457416Smarkm return; 71557416Smarkm } else { 71657416Smarkm char *name; 71757416Smarkm unsigned char temp[50]; 71857416Smarkm int len; 71957416Smarkm 72057416Smarkm name = gettermname(); 72157416Smarkm len = strlen(name) + 4 + 2; 72257416Smarkm if (len < NETROOM()) { 72357416Smarkm snprintf((char *)temp, sizeof(temp), 72457416Smarkm "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 72557416Smarkm TELQUAL_IS, name, IAC, SE); 72657416Smarkm ring_supply_data(&netoring, temp, len); 72757416Smarkm printsub('>', &temp[2], len-2); 72857416Smarkm } else { 72957416Smarkm ExitString("No room in buffer for terminal type.\n", 1); 73057416Smarkm /*NOTREACHED*/ 73157416Smarkm } 73257416Smarkm } 73357416Smarkm break; 73457416Smarkm case TELOPT_TSPEED: 73557416Smarkm if (my_want_state_is_wont(TELOPT_TSPEED)) 73657416Smarkm return; 73757416Smarkm if (SB_EOF()) 73857416Smarkm return; 73957416Smarkm if (SB_GET() == TELQUAL_SEND) { 74057416Smarkm long output_speed, input_speed; 74157416Smarkm unsigned char temp[50]; 74257416Smarkm int len; 74357416Smarkm 74457416Smarkm TerminalSpeeds(&input_speed, &output_speed); 74557416Smarkm 74657416Smarkm snprintf((char *)temp, sizeof(temp), 74757416Smarkm "%c%c%c%c%u,%u%c%c", IAC, SB, TELOPT_TSPEED, 74857416Smarkm TELQUAL_IS, 74957416Smarkm (unsigned)output_speed, 75057416Smarkm (unsigned)input_speed, IAC, SE); 75157416Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 75257416Smarkm 75357416Smarkm if (len < NETROOM()) { 75457416Smarkm ring_supply_data(&netoring, temp, len); 75557416Smarkm printsub('>', temp+2, len - 2); 75657416Smarkm } 75757416Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 75857416Smarkm } 75957416Smarkm break; 76057416Smarkm case TELOPT_LFLOW: 76157416Smarkm if (my_want_state_is_wont(TELOPT_LFLOW)) 76257416Smarkm return; 76357416Smarkm if (SB_EOF()) 76457416Smarkm return; 76557416Smarkm switch(SB_GET()) { 76657416Smarkm case LFLOW_RESTART_ANY: 76757416Smarkm restartany = 1; 76857416Smarkm break; 76957416Smarkm case LFLOW_RESTART_XON: 77057416Smarkm restartany = 0; 77157416Smarkm break; 77257416Smarkm case LFLOW_ON: 77357416Smarkm localflow = 1; 77457416Smarkm break; 77557416Smarkm case LFLOW_OFF: 77657416Smarkm localflow = 0; 77757416Smarkm break; 77857416Smarkm default: 77957416Smarkm return; 78057416Smarkm } 78157416Smarkm setcommandmode(); 78257416Smarkm setconnmode(0); 78357416Smarkm break; 78457416Smarkm 78557416Smarkm case TELOPT_LINEMODE: 78657416Smarkm if (my_want_state_is_wont(TELOPT_LINEMODE)) 78757416Smarkm return; 78857416Smarkm if (SB_EOF()) 78957416Smarkm return; 79057416Smarkm switch (SB_GET()) { 79157416Smarkm case WILL: 79257416Smarkm lm_will(subpointer, SB_LEN()); 79357416Smarkm break; 79457416Smarkm case WONT: 79557416Smarkm lm_wont(subpointer, SB_LEN()); 79657416Smarkm break; 79757416Smarkm case DO: 79857416Smarkm lm_do(subpointer, SB_LEN()); 79957416Smarkm break; 80057416Smarkm case DONT: 80157416Smarkm lm_dont(subpointer, SB_LEN()); 80257416Smarkm break; 80357416Smarkm case LM_SLC: 80457416Smarkm slc(subpointer, SB_LEN()); 80557416Smarkm break; 80657416Smarkm case LM_MODE: 80757416Smarkm lm_mode(subpointer, SB_LEN(), 0); 80857416Smarkm break; 80957416Smarkm default: 81057416Smarkm break; 81157416Smarkm } 81257416Smarkm break; 81357416Smarkm 81457416Smarkm#ifdef OLD_ENVIRON 81557416Smarkm case TELOPT_OLD_ENVIRON: 81657416Smarkm#endif 81757416Smarkm case TELOPT_NEW_ENVIRON: 81857416Smarkm if (SB_EOF()) 81957416Smarkm return; 82057416Smarkm switch(SB_PEEK()) { 82157416Smarkm case TELQUAL_IS: 82257416Smarkm case TELQUAL_INFO: 82357416Smarkm if (my_want_state_is_dont(subchar)) 82457416Smarkm return; 82557416Smarkm break; 82657416Smarkm case TELQUAL_SEND: 82757416Smarkm if (my_want_state_is_wont(subchar)) { 82857416Smarkm return; 82957416Smarkm } 83057416Smarkm break; 83157416Smarkm default: 83257416Smarkm return; 83357416Smarkm } 83457416Smarkm env_opt(subpointer, SB_LEN()); 83557416Smarkm break; 83657416Smarkm 83757416Smarkm case TELOPT_XDISPLOC: 83857416Smarkm if (my_want_state_is_wont(TELOPT_XDISPLOC)) 83957416Smarkm return; 84057416Smarkm if (SB_EOF()) 84157416Smarkm return; 84257416Smarkm if (SB_GET() == TELQUAL_SEND) { 84357416Smarkm unsigned char temp[50], *dp; 84457416Smarkm int len; 84557416Smarkm 84657416Smarkm if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { 84757416Smarkm /* 84857416Smarkm * Something happened, we no longer have a DISPLAY 84957416Smarkm * variable. So, turn off the option. 85057416Smarkm */ 85157416Smarkm send_wont(TELOPT_XDISPLOC, 1); 85257416Smarkm break; 85357416Smarkm } 85457416Smarkm snprintf((char *)temp, sizeof(temp), 85557416Smarkm "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, 85657416Smarkm TELQUAL_IS, dp, IAC, SE); 85757416Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 85857416Smarkm 85957416Smarkm if (len < NETROOM()) { 86057416Smarkm ring_supply_data(&netoring, temp, len); 86157416Smarkm printsub('>', temp+2, len - 2); 86257416Smarkm } 86357416Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 86457416Smarkm } 86557416Smarkm break; 86657416Smarkm 86757416Smarkm#if defined(AUTHENTICATION) 86857416Smarkm case TELOPT_AUTHENTICATION: { 86957416Smarkm if (!autologin) 87057416Smarkm break; 87157416Smarkm if (SB_EOF()) 87257416Smarkm return; 87357416Smarkm switch(SB_GET()) { 87457416Smarkm case TELQUAL_IS: 87557416Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 87657416Smarkm return; 87757416Smarkm auth_is(subpointer, SB_LEN()); 87857416Smarkm break; 87957416Smarkm case TELQUAL_SEND: 88057416Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 88157416Smarkm return; 88257416Smarkm auth_send(subpointer, SB_LEN()); 88357416Smarkm break; 88457416Smarkm case TELQUAL_REPLY: 88557416Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 88657416Smarkm return; 88757416Smarkm auth_reply(subpointer, SB_LEN()); 88857416Smarkm break; 88957416Smarkm case TELQUAL_NAME: 89057416Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 89157416Smarkm return; 89257416Smarkm auth_name(subpointer, SB_LEN()); 89357416Smarkm break; 89457416Smarkm } 89557416Smarkm } 89657416Smarkm break; 89757416Smarkm#endif 89857416Smarkm#if defined(ENCRYPTION) 89957416Smarkm case TELOPT_ENCRYPT: 90057416Smarkm if (SB_EOF()) 90157416Smarkm return; 90257416Smarkm switch(SB_GET()) { 90357416Smarkm case ENCRYPT_START: 90457416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 90557416Smarkm return; 90657416Smarkm encrypt_start(subpointer, SB_LEN()); 90757416Smarkm break; 90857416Smarkm case ENCRYPT_END: 90957416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 91057416Smarkm return; 91157416Smarkm encrypt_end(); 91257416Smarkm break; 91357416Smarkm case ENCRYPT_SUPPORT: 91457416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 91557416Smarkm return; 91657416Smarkm encrypt_support(subpointer, SB_LEN()); 91757416Smarkm break; 91857416Smarkm case ENCRYPT_REQSTART: 91957416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 92057416Smarkm return; 92157416Smarkm encrypt_request_start(subpointer, SB_LEN()); 92257416Smarkm break; 92357416Smarkm case ENCRYPT_REQEND: 92457416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 92557416Smarkm return; 92657416Smarkm /* 92757416Smarkm * We can always send an REQEND so that we cannot 92857416Smarkm * get stuck encrypting. We should only get this 92957416Smarkm * if we have been able to get in the correct mode 93057416Smarkm * anyhow. 93157416Smarkm */ 93257416Smarkm encrypt_request_end(); 93357416Smarkm break; 93457416Smarkm case ENCRYPT_IS: 93557416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 93657416Smarkm return; 93757416Smarkm encrypt_is(subpointer, SB_LEN()); 93857416Smarkm break; 93957416Smarkm case ENCRYPT_REPLY: 94057416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 94157416Smarkm return; 94257416Smarkm encrypt_reply(subpointer, SB_LEN()); 94357416Smarkm break; 94457416Smarkm case ENCRYPT_ENC_KEYID: 94557416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 94657416Smarkm return; 94757416Smarkm encrypt_enc_keyid(subpointer, SB_LEN()); 94857416Smarkm break; 94957416Smarkm case ENCRYPT_DEC_KEYID: 95057416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 95157416Smarkm return; 95257416Smarkm encrypt_dec_keyid(subpointer, SB_LEN()); 95357416Smarkm break; 95457416Smarkm default: 95557416Smarkm break; 95657416Smarkm } 95757416Smarkm break; 95857416Smarkm#endif 95957416Smarkm default: 96057416Smarkm break; 96157416Smarkm } 96257416Smarkm} 96357416Smarkm 96457416Smarkmstatic unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 96557416Smarkm 96657416Smarkmvoid 96757416Smarkmlm_will(unsigned char *cmd, int len) 96857416Smarkm{ 96957416Smarkm if (len < 1) { 97057416Smarkm/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 97157416Smarkm return; 97257416Smarkm } 97357416Smarkm switch(cmd[0]) { 97457416Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 97557416Smarkm default: 97657416Smarkm str_lm[3] = DONT; 97757416Smarkm str_lm[4] = cmd[0]; 97857416Smarkm if (NETROOM() > sizeof(str_lm)) { 97957416Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 98057416Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 98157416Smarkm } 98257416Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 98357416Smarkm break; 98457416Smarkm } 98557416Smarkm} 98657416Smarkm 98757416Smarkmvoid 98857416Smarkmlm_wont(unsigned char *cmd, int len) 98957416Smarkm{ 99057416Smarkm if (len < 1) { 99157416Smarkm/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 99257416Smarkm return; 99357416Smarkm } 99457416Smarkm switch(cmd[0]) { 99557416Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 99657416Smarkm default: 99757416Smarkm /* We are always DONT, so don't respond */ 99857416Smarkm return; 99957416Smarkm } 100057416Smarkm} 100157416Smarkm 100257416Smarkmvoid 100357416Smarkmlm_do(unsigned char *cmd, int len) 100457416Smarkm{ 100557416Smarkm if (len < 1) { 100657416Smarkm/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 100757416Smarkm return; 100857416Smarkm } 100957416Smarkm switch(cmd[0]) { 101057416Smarkm case LM_FORWARDMASK: 101157416Smarkm default: 101257416Smarkm str_lm[3] = WONT; 101357416Smarkm str_lm[4] = cmd[0]; 101457416Smarkm if (NETROOM() > sizeof(str_lm)) { 101557416Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 101657416Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 101757416Smarkm } 101857416Smarkm/*@*/ else printf("lm_do: not enough room in buffer\n"); 101957416Smarkm break; 102057416Smarkm } 102157416Smarkm} 102257416Smarkm 102357416Smarkmvoid 102457416Smarkmlm_dont(unsigned char *cmd, int len) 102557416Smarkm{ 102657416Smarkm if (len < 1) { 102757416Smarkm/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 102857416Smarkm return; 102957416Smarkm } 103057416Smarkm switch(cmd[0]) { 103157416Smarkm case LM_FORWARDMASK: 103257416Smarkm default: 103357416Smarkm /* we are always WONT, so don't respond */ 103457416Smarkm break; 103557416Smarkm } 103657416Smarkm} 103757416Smarkm 103857416Smarkmstatic unsigned char str_lm_mode[] = { 103957416Smarkm IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 104057416Smarkm}; 104157416Smarkm 104257416Smarkmvoid 104357416Smarkmlm_mode(unsigned char *cmd, int len, int init) 104457416Smarkm{ 104557416Smarkm if (len != 1) 104657416Smarkm return; 104757416Smarkm if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 104857416Smarkm return; 104957416Smarkm if (*cmd&MODE_ACK) 105057416Smarkm return; 105157416Smarkm linemode = *cmd&(MODE_MASK&~MODE_ACK); 105257416Smarkm str_lm_mode[4] = linemode; 105357416Smarkm if (!init) 105457416Smarkm str_lm_mode[4] |= MODE_ACK; 105557416Smarkm if (NETROOM() > sizeof(str_lm_mode)) { 105657416Smarkm ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 105757416Smarkm printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 105857416Smarkm } 105957416Smarkm/*@*/ else printf("lm_mode: not enough room in buffer\n"); 106057416Smarkm setconnmode(0); /* set changed mode */ 106157416Smarkm} 106257416Smarkm 106357416Smarkm 106457416Smarkm 106557416Smarkm/* 106657416Smarkm * slc() 106757416Smarkm * Handle special character suboption of LINEMODE. 106857416Smarkm */ 106957416Smarkm 107057416Smarkmstruct spc { 107157416Smarkm cc_t val; 107257416Smarkm cc_t *valp; 107357416Smarkm char flags; /* Current flags & level */ 107457416Smarkm char mylevel; /* Maximum level & flags */ 107557416Smarkm} spc_data[NSLC+1]; 107657416Smarkm 107757416Smarkm#define SLC_IMPORT 0 107857416Smarkm#define SLC_EXPORT 1 107957416Smarkm#define SLC_RVALUE 2 108057416Smarkmstatic int slc_mode = SLC_EXPORT; 108157416Smarkm 108257416Smarkmvoid 108357416Smarkmslc_init() 108457416Smarkm{ 108557416Smarkm struct spc *spcp; 108657416Smarkm 108757416Smarkm localchars = 1; 108857416Smarkm for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 108957416Smarkm spcp->val = 0; 109057416Smarkm spcp->valp = 0; 109157416Smarkm spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 109257416Smarkm } 109357416Smarkm 109457416Smarkm#define initfunc(func, flags) { \ 109557416Smarkm spcp = &spc_data[func]; \ 109657416Smarkm if ((spcp->valp = tcval(func))) { \ 109757416Smarkm spcp->val = *spcp->valp; \ 109857416Smarkm spcp->mylevel = SLC_VARIABLE|flags; \ 109957416Smarkm } else { \ 110057416Smarkm spcp->val = 0; \ 110157416Smarkm spcp->mylevel = SLC_DEFAULT; \ 110257416Smarkm } \ 110357416Smarkm } 110457416Smarkm 110557416Smarkm initfunc(SLC_SYNCH, 0); 110657416Smarkm /* No BRK */ 110757416Smarkm initfunc(SLC_AO, 0); 110857416Smarkm initfunc(SLC_AYT, 0); 110957416Smarkm /* No EOR */ 111057416Smarkm initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 111157416Smarkm initfunc(SLC_EOF, 0); 111257416Smarkm initfunc(SLC_SUSP, SLC_FLUSHIN); 111357416Smarkm initfunc(SLC_EC, 0); 111457416Smarkm initfunc(SLC_EL, 0); 111557416Smarkm initfunc(SLC_EW, 0); 111657416Smarkm initfunc(SLC_RP, 0); 111757416Smarkm initfunc(SLC_LNEXT, 0); 111857416Smarkm initfunc(SLC_XON, 0); 111957416Smarkm initfunc(SLC_XOFF, 0); 112057416Smarkm initfunc(SLC_FORW1, 0); 112157416Smarkm initfunc(SLC_FORW2, 0); 112257416Smarkm /* No FORW2 */ 112357416Smarkm 112457416Smarkm initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 112557416Smarkm#undef initfunc 112657416Smarkm 112757416Smarkm if (slc_mode == SLC_EXPORT) 112857416Smarkm slc_export(); 112957416Smarkm else 113057416Smarkm slc_import(1); 113157416Smarkm 113257416Smarkm} 113357416Smarkm 113457416Smarkmvoid 113557416Smarkmslcstate() 113657416Smarkm{ 113757416Smarkm printf("Special characters are %s values\n", 113857416Smarkm slc_mode == SLC_IMPORT ? "remote default" : 113957416Smarkm slc_mode == SLC_EXPORT ? "local" : 114057416Smarkm "remote"); 114157416Smarkm} 114257416Smarkm 114357416Smarkmvoid 114457416Smarkmslc_mode_export() 114557416Smarkm{ 114657416Smarkm slc_mode = SLC_EXPORT; 114757416Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 114857416Smarkm slc_export(); 114957416Smarkm} 115057416Smarkm 115157416Smarkmvoid 115257416Smarkmslc_mode_import(int def) 115357416Smarkm{ 115457416Smarkm slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 115557416Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 115657416Smarkm slc_import(def); 115757416Smarkm} 115857416Smarkm 115957416Smarkmunsigned char slc_import_val[] = { 116057416Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 116157416Smarkm}; 116257416Smarkmunsigned char slc_import_def[] = { 116357416Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 116457416Smarkm}; 116557416Smarkm 116657416Smarkmvoid 116757416Smarkmslc_import(int def) 116857416Smarkm{ 116957416Smarkm if (NETROOM() > sizeof(slc_import_val)) { 117057416Smarkm if (def) { 117157416Smarkm ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 117257416Smarkm printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 117357416Smarkm } else { 117457416Smarkm ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 117557416Smarkm printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 117657416Smarkm } 117757416Smarkm } 117857416Smarkm/*@*/ else printf("slc_import: not enough room\n"); 117957416Smarkm} 118057416Smarkm 118157416Smarkmvoid 118257416Smarkmslc_export() 118357416Smarkm{ 118457416Smarkm struct spc *spcp; 118557416Smarkm 118657416Smarkm TerminalDefaultChars(); 118757416Smarkm 118857416Smarkm slc_start_reply(); 118957416Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 119057416Smarkm if (spcp->mylevel != SLC_NOSUPPORT) { 119157416Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 119257416Smarkm spcp->flags = SLC_NOSUPPORT; 119357416Smarkm else 119457416Smarkm spcp->flags = spcp->mylevel; 119557416Smarkm if (spcp->valp) 119657416Smarkm spcp->val = *spcp->valp; 119757416Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 119857416Smarkm } 119957416Smarkm } 120057416Smarkm slc_end_reply(); 120157416Smarkm slc_update(); 120257416Smarkm setconnmode(1); /* Make sure the character values are set */ 120357416Smarkm} 120457416Smarkm 120557416Smarkmvoid 120657416Smarkmslc(unsigned char *cp, int len) 120757416Smarkm{ 120857416Smarkm struct spc *spcp; 120957416Smarkm int func,level; 121057416Smarkm 121157416Smarkm slc_start_reply(); 121257416Smarkm 121357416Smarkm for (; len >= 3; len -=3, cp +=3) { 121457416Smarkm 121557416Smarkm func = cp[SLC_FUNC]; 121657416Smarkm 121757416Smarkm if (func == 0) { 121857416Smarkm /* 121957416Smarkm * Client side: always ignore 0 function. 122057416Smarkm */ 122157416Smarkm continue; 122257416Smarkm } 122357416Smarkm if (func > NSLC) { 122457416Smarkm if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 122557416Smarkm slc_add_reply(func, SLC_NOSUPPORT, 0); 122657416Smarkm continue; 122757416Smarkm } 122857416Smarkm 122957416Smarkm spcp = &spc_data[func]; 123057416Smarkm 123157416Smarkm level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 123257416Smarkm 123357416Smarkm if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 123457416Smarkm ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 123557416Smarkm continue; 123657416Smarkm } 123757416Smarkm 123857416Smarkm if (level == (SLC_DEFAULT|SLC_ACK)) { 123957416Smarkm /* 124057416Smarkm * This is an error condition, the SLC_ACK 124157416Smarkm * bit should never be set for the SLC_DEFAULT 124257416Smarkm * level. Our best guess to recover is to 124357416Smarkm * ignore the SLC_ACK bit. 124457416Smarkm */ 124557416Smarkm cp[SLC_FLAGS] &= ~SLC_ACK; 124657416Smarkm } 124757416Smarkm 124857416Smarkm if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 124957416Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 125057416Smarkm spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 125157416Smarkm continue; 125257416Smarkm } 125357416Smarkm 125457416Smarkm level &= ~SLC_ACK; 125557416Smarkm 125657416Smarkm if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 125757416Smarkm spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 125857416Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 125957416Smarkm } 126057416Smarkm if (level == SLC_DEFAULT) { 126157416Smarkm if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 126257416Smarkm spcp->flags = spcp->mylevel; 126357416Smarkm else 126457416Smarkm spcp->flags = SLC_NOSUPPORT; 126557416Smarkm } 126657416Smarkm slc_add_reply(func, spcp->flags, spcp->val); 126757416Smarkm } 126857416Smarkm slc_end_reply(); 126957416Smarkm if (slc_update()) 127057416Smarkm setconnmode(1); /* set the new character values */ 127157416Smarkm} 127257416Smarkm 127357416Smarkmvoid 127457416Smarkmslc_check() 127557416Smarkm{ 127657416Smarkm struct spc *spcp; 127757416Smarkm 127857416Smarkm slc_start_reply(); 127957416Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 128057416Smarkm if (spcp->valp && spcp->val != *spcp->valp) { 128157416Smarkm spcp->val = *spcp->valp; 128257416Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 128357416Smarkm spcp->flags = SLC_NOSUPPORT; 128457416Smarkm else 128557416Smarkm spcp->flags = spcp->mylevel; 128657416Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 128757416Smarkm } 128857416Smarkm } 128957416Smarkm slc_end_reply(); 129057416Smarkm setconnmode(1); 129157416Smarkm} 129257416Smarkm 129357416Smarkm 129457416Smarkmunsigned char slc_reply[128]; 1295178825Sdfrunsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)]; 129657416Smarkmunsigned char *slc_replyp; 129757416Smarkm 129857416Smarkmvoid 129957416Smarkmslc_start_reply() 130057416Smarkm{ 130157416Smarkm slc_replyp = slc_reply; 130257416Smarkm *slc_replyp++ = IAC; 130357416Smarkm *slc_replyp++ = SB; 130457416Smarkm *slc_replyp++ = TELOPT_LINEMODE; 130557416Smarkm *slc_replyp++ = LM_SLC; 130657416Smarkm} 130757416Smarkm 130857416Smarkmvoid 130957416Smarkmslc_add_reply(unsigned char func, unsigned char flags, cc_t value) 131057416Smarkm{ 1311178825Sdfr /* A sequence of up to 6 bytes my be written for this member of the SLC 1312178825Sdfr * suboption list by this function. The end of negotiation command, 1313178825Sdfr * which is written by slc_end_reply(), will require 2 additional 1314178825Sdfr * bytes. Do not proceed unless there is sufficient space for these 1315178825Sdfr * items. 1316178825Sdfr */ 1317178825Sdfr if (&slc_replyp[6+2] > slc_reply_eom) 1318178825Sdfr return; 131957416Smarkm if ((*slc_replyp++ = func) == IAC) 132057416Smarkm *slc_replyp++ = IAC; 132157416Smarkm if ((*slc_replyp++ = flags) == IAC) 132257416Smarkm *slc_replyp++ = IAC; 132357416Smarkm if ((*slc_replyp++ = (unsigned char)value) == IAC) 132457416Smarkm *slc_replyp++ = IAC; 132557416Smarkm} 132657416Smarkm 132757416Smarkmvoid 132857416Smarkmslc_end_reply() 132957416Smarkm{ 133057416Smarkm int len; 133157416Smarkm 1332178825Sdfr /* The end of negotiation command requires 2 bytes. */ 1333178825Sdfr if (&slc_replyp[2] > slc_reply_eom) 1334178825Sdfr return; 133557416Smarkm *slc_replyp++ = IAC; 133657416Smarkm *slc_replyp++ = SE; 133757416Smarkm len = slc_replyp - slc_reply; 133857416Smarkm if (len <= 6) 133957416Smarkm return; 134057416Smarkm if (NETROOM() > len) { 134157416Smarkm ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 134257416Smarkm printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 134357416Smarkm } 134457416Smarkm/*@*/else printf("slc_end_reply: not enough room\n"); 134557416Smarkm} 134657416Smarkm 134757416Smarkmint 134857416Smarkmslc_update() 134957416Smarkm{ 135057416Smarkm struct spc *spcp; 135157416Smarkm int need_update = 0; 135257416Smarkm 135357416Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 135457416Smarkm if (!(spcp->flags&SLC_ACK)) 135557416Smarkm continue; 135657416Smarkm spcp->flags &= ~SLC_ACK; 135757416Smarkm if (spcp->valp && (*spcp->valp != spcp->val)) { 135857416Smarkm *spcp->valp = spcp->val; 135957416Smarkm need_update = 1; 136057416Smarkm } 136157416Smarkm } 136257416Smarkm return(need_update); 136357416Smarkm} 136457416Smarkm 136557416Smarkm#ifdef OLD_ENVIRON 136657416Smarkm# define old_env_var OLD_ENV_VAR 136757416Smarkm# define old_env_value OLD_ENV_VALUE 136857416Smarkm#endif 136957416Smarkm 137057416Smarkmvoid 137157416Smarkmenv_opt(unsigned char *buf, int len) 137257416Smarkm{ 137357416Smarkm unsigned char *ep = 0, *epc = 0; 137457416Smarkm int i; 137557416Smarkm 137657416Smarkm switch(buf[0]&0xff) { 137757416Smarkm case TELQUAL_SEND: 137857416Smarkm env_opt_start(); 137957416Smarkm if (len == 1) { 138057416Smarkm env_opt_add(NULL); 138157416Smarkm } else for (i = 1; i < len; i++) { 138257416Smarkm switch (buf[i]&0xff) { 138357416Smarkm#ifdef OLD_ENVIRON 138457416Smarkm case OLD_ENV_VAR: 138557416Smarkm case OLD_ENV_VALUE: 138657416Smarkm /* 138757416Smarkm * Although OLD_ENV_VALUE is not legal, we will 138857416Smarkm * still recognize it, just in case it is an 138957416Smarkm * old server that has VAR & VALUE mixed up... 139057416Smarkm */ 139157416Smarkm /* FALL THROUGH */ 139257416Smarkm#else 139357416Smarkm case NEW_ENV_VAR: 139457416Smarkm#endif 139557416Smarkm case ENV_USERVAR: 139657416Smarkm if (ep) { 139757416Smarkm *epc = 0; 139857416Smarkm env_opt_add(ep); 139957416Smarkm } 140057416Smarkm ep = epc = &buf[i+1]; 140157416Smarkm break; 140257416Smarkm case ENV_ESC: 140357416Smarkm i++; 140457416Smarkm /*FALL THROUGH*/ 140557416Smarkm default: 140657416Smarkm if (epc) 140757416Smarkm *epc++ = buf[i]; 140857416Smarkm break; 140957416Smarkm } 141057416Smarkm } 141157416Smarkm if (ep) { 141257416Smarkm *epc = 0; 141357416Smarkm env_opt_add(ep); 141457416Smarkm } 141557416Smarkm env_opt_end(1); 141657416Smarkm break; 141757416Smarkm 141857416Smarkm case TELQUAL_IS: 141957416Smarkm case TELQUAL_INFO: 142057416Smarkm /* Ignore for now. We shouldn't get it anyway. */ 142157416Smarkm break; 142257416Smarkm 142357416Smarkm default: 142457416Smarkm break; 142557416Smarkm } 142657416Smarkm} 142757416Smarkm 1428178825Sdfr#define OPT_REPLY_SIZE (2 * SUBBUFSIZE) 142957416Smarkmunsigned char *opt_reply; 143057416Smarkmunsigned char *opt_replyp; 143157416Smarkmunsigned char *opt_replyend; 143257416Smarkm 143357416Smarkmvoid 143457416Smarkmenv_opt_start() 143557416Smarkm{ 143657416Smarkm if (opt_reply) { 143757416Smarkm void *tmp = realloc (opt_reply, OPT_REPLY_SIZE); 143857416Smarkm if (tmp != NULL) { 143957416Smarkm opt_reply = tmp; 144057416Smarkm } else { 144157416Smarkm free (opt_reply); 144257416Smarkm opt_reply = NULL; 144357416Smarkm } 144457416Smarkm } else 144557416Smarkm opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 144657416Smarkm if (opt_reply == NULL) { 144757416Smarkm/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 144857416Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 144957416Smarkm return; 145057416Smarkm } 145157416Smarkm opt_replyp = opt_reply; 145257416Smarkm opt_replyend = opt_reply + OPT_REPLY_SIZE; 145357416Smarkm *opt_replyp++ = IAC; 145457416Smarkm *opt_replyp++ = SB; 145557416Smarkm *opt_replyp++ = telopt_environ; 145657416Smarkm *opt_replyp++ = TELQUAL_IS; 145757416Smarkm} 145857416Smarkm 145957416Smarkmvoid 146057416Smarkmenv_opt_start_info() 146157416Smarkm{ 146257416Smarkm env_opt_start(); 146357416Smarkm if (opt_replyp) 146457416Smarkm opt_replyp[-1] = TELQUAL_INFO; 146557416Smarkm} 146657416Smarkm 146757416Smarkmvoid 146857416Smarkmenv_opt_add(unsigned char *ep) 146957416Smarkm{ 147057416Smarkm unsigned char *vp, c; 147157416Smarkm 147257416Smarkm if (opt_reply == NULL) /*XXX*/ 147357416Smarkm return; /*XXX*/ 147457416Smarkm 147557416Smarkm if (ep == NULL || *ep == '\0') { 147657416Smarkm /* Send user defined variables first. */ 147757416Smarkm env_default(1, 0); 147857416Smarkm while ((ep = env_default(0, 0))) 147957416Smarkm env_opt_add(ep); 148057416Smarkm 148157416Smarkm /* Now add the list of well know variables. */ 148257416Smarkm env_default(1, 1); 148357416Smarkm while ((ep = env_default(0, 1))) 148457416Smarkm env_opt_add(ep); 148557416Smarkm return; 148657416Smarkm } 148757416Smarkm vp = env_getvalue(ep); 1488178825Sdfr if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) + 1489178825Sdfr 2 * strlen((char *)ep) + 6 > opt_replyend) 1490178825Sdfr { 149157416Smarkm int len; 149257416Smarkm void *tmp; 149357416Smarkm opt_replyend += OPT_REPLY_SIZE; 149457416Smarkm len = opt_replyend - opt_reply; 149557416Smarkm tmp = realloc(opt_reply, len); 149657416Smarkm if (tmp == NULL) { 149757416Smarkm/*@*/ printf("env_opt_add: realloc() failed!!!\n"); 149857416Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 149957416Smarkm return; 150057416Smarkm } 150157416Smarkm opt_reply = tmp; 150257416Smarkm opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 150357416Smarkm opt_replyend = opt_reply + len; 150457416Smarkm } 150557416Smarkm if (opt_welldefined((char *)ep)) { 150657416Smarkm#ifdef OLD_ENVIRON 150757416Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 150857416Smarkm *opt_replyp++ = old_env_var; 150957416Smarkm else 151057416Smarkm#endif 151157416Smarkm *opt_replyp++ = NEW_ENV_VAR; 151257416Smarkm } else 151357416Smarkm *opt_replyp++ = ENV_USERVAR; 151457416Smarkm for (;;) { 151557416Smarkm while ((c = *ep++)) { 1516178825Sdfr if (opt_replyp + (2 + 2) > opt_replyend) 1517178825Sdfr return; 151857416Smarkm switch(c&0xff) { 151957416Smarkm case IAC: 152057416Smarkm *opt_replyp++ = IAC; 152157416Smarkm break; 152257416Smarkm case NEW_ENV_VAR: 152357416Smarkm case NEW_ENV_VALUE: 152457416Smarkm case ENV_ESC: 152557416Smarkm case ENV_USERVAR: 152657416Smarkm *opt_replyp++ = ENV_ESC; 152757416Smarkm break; 152857416Smarkm } 152957416Smarkm *opt_replyp++ = c; 153057416Smarkm } 153157416Smarkm if ((ep = vp)) { 1532178825Sdfr if (opt_replyp + (1 + 2 + 2) > opt_replyend) 1533178825Sdfr return; 153457416Smarkm#ifdef OLD_ENVIRON 153557416Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 153657416Smarkm *opt_replyp++ = old_env_value; 153757416Smarkm else 153857416Smarkm#endif 153957416Smarkm *opt_replyp++ = NEW_ENV_VALUE; 154057416Smarkm vp = NULL; 154157416Smarkm } else 154257416Smarkm break; 154357416Smarkm } 154457416Smarkm} 154557416Smarkm 154657416Smarkmint 154757416Smarkmopt_welldefined(char *ep) 154857416Smarkm{ 154957416Smarkm if ((strcmp(ep, "USER") == 0) || 155057416Smarkm (strcmp(ep, "DISPLAY") == 0) || 155157416Smarkm (strcmp(ep, "PRINTER") == 0) || 155257416Smarkm (strcmp(ep, "SYSTEMTYPE") == 0) || 155357416Smarkm (strcmp(ep, "JOB") == 0) || 155457416Smarkm (strcmp(ep, "ACCT") == 0)) 155557416Smarkm return(1); 155657416Smarkm return(0); 155757416Smarkm} 155857416Smarkm 155957416Smarkmvoid 156057416Smarkmenv_opt_end(int emptyok) 156157416Smarkm{ 156257416Smarkm int len; 156357416Smarkm 1564178825Sdfr if (opt_replyp + 2 > opt_replyend) 1565178825Sdfr return; 1566178825Sdfr len = opt_replyp + 2 - opt_reply; 156757416Smarkm if (emptyok || len > 6) { 156857416Smarkm *opt_replyp++ = IAC; 156957416Smarkm *opt_replyp++ = SE; 157057416Smarkm if (NETROOM() > len) { 157157416Smarkm ring_supply_data(&netoring, opt_reply, len); 157257416Smarkm printsub('>', &opt_reply[2], len - 2); 157357416Smarkm } 157457416Smarkm/*@*/ else printf("slc_end_reply: not enough room\n"); 157557416Smarkm } 157657416Smarkm if (opt_reply) { 157757416Smarkm free(opt_reply); 157857416Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 157957416Smarkm } 158057416Smarkm} 158157416Smarkm 158257416Smarkm 158357416Smarkm 158457416Smarkmint 158557416Smarkmtelrcv(void) 158657416Smarkm{ 158757416Smarkm int c; 158857416Smarkm int scc; 158957416Smarkm unsigned char *sbp = NULL; 159057416Smarkm int count; 159157416Smarkm int returnValue = 0; 159257416Smarkm 159357416Smarkm scc = 0; 159457416Smarkm count = 0; 159557416Smarkm while (TTYROOM() > 2) { 159657416Smarkm if (scc == 0) { 159757416Smarkm if (count) { 159857416Smarkm ring_consumed(&netiring, count); 159957416Smarkm returnValue = 1; 160057416Smarkm count = 0; 160157416Smarkm } 160257416Smarkm sbp = netiring.consume; 160357416Smarkm scc = ring_full_consecutive(&netiring); 160457416Smarkm if (scc == 0) { 160557416Smarkm /* No more data coming in */ 160657416Smarkm break; 160757416Smarkm } 160857416Smarkm } 160957416Smarkm 161057416Smarkm c = *sbp++ & 0xff, scc--; count++; 161157416Smarkm#if defined(ENCRYPTION) 161257416Smarkm if (decrypt_input) 161357416Smarkm c = (*decrypt_input)(c); 161457416Smarkm#endif 161557416Smarkm 161657416Smarkm switch (telrcv_state) { 161757416Smarkm 161857416Smarkm case TS_CR: 161957416Smarkm telrcv_state = TS_DATA; 162057416Smarkm if (c == '\0') { 162157416Smarkm break; /* Ignore \0 after CR */ 162257416Smarkm } 162357416Smarkm else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 162457416Smarkm TTYADD(c); 162557416Smarkm break; 162657416Smarkm } 162757416Smarkm /* Else, fall through */ 162857416Smarkm 162957416Smarkm case TS_DATA: 163057416Smarkm if (c == IAC) { 163157416Smarkm telrcv_state = TS_IAC; 163257416Smarkm break; 163357416Smarkm } 1634233294Sstas /* 163557416Smarkm * The 'crmod' hack (see following) is needed 163657416Smarkm * since we can't set CRMOD on output only. 163757416Smarkm * Machines like MULTICS like to send \r without 163857416Smarkm * \n; since we must turn off CRMOD to get proper 163957416Smarkm * input, the mapping is done here (sigh). 164057416Smarkm */ 164157416Smarkm if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 164257416Smarkm if (scc > 0) { 164357416Smarkm c = *sbp&0xff; 164457416Smarkm#if defined(ENCRYPTION) 164557416Smarkm if (decrypt_input) 164657416Smarkm c = (*decrypt_input)(c); 164757416Smarkm#endif 164857416Smarkm if (c == 0) { 164957416Smarkm sbp++, scc--; count++; 165057416Smarkm /* a "true" CR */ 165157416Smarkm TTYADD('\r'); 165257416Smarkm } else if (my_want_state_is_dont(TELOPT_ECHO) && 165357416Smarkm (c == '\n')) { 165457416Smarkm sbp++, scc--; count++; 165557416Smarkm TTYADD('\n'); 165657416Smarkm } else { 165757416Smarkm#if defined(ENCRYPTION) 165857416Smarkm if (decrypt_input) 165957416Smarkm (*decrypt_input)(-1); 166057416Smarkm#endif 166157416Smarkm 166257416Smarkm TTYADD('\r'); 166357416Smarkm if (crmod) { 166457416Smarkm TTYADD('\n'); 166557416Smarkm } 166657416Smarkm } 166757416Smarkm } else { 166857416Smarkm telrcv_state = TS_CR; 166957416Smarkm TTYADD('\r'); 167057416Smarkm if (crmod) { 167157416Smarkm TTYADD('\n'); 167257416Smarkm } 167357416Smarkm } 167457416Smarkm } else { 167557416Smarkm TTYADD(c); 167657416Smarkm } 167757416Smarkm continue; 167857416Smarkm 167957416Smarkm case TS_IAC: 168057416Smarkmprocess_iac: 168157416Smarkm switch (c) { 168257416Smarkm 168357416Smarkm case WILL: 168457416Smarkm telrcv_state = TS_WILL; 168557416Smarkm continue; 168657416Smarkm 168757416Smarkm case WONT: 168857416Smarkm telrcv_state = TS_WONT; 168957416Smarkm continue; 169057416Smarkm 169157416Smarkm case DO: 169257416Smarkm telrcv_state = TS_DO; 169357416Smarkm continue; 169457416Smarkm 169557416Smarkm case DONT: 169657416Smarkm telrcv_state = TS_DONT; 169757416Smarkm continue; 169857416Smarkm 169957416Smarkm case DM: 170057416Smarkm /* 170157416Smarkm * We may have missed an urgent notification, 170257416Smarkm * so make sure we flush whatever is in the 170357416Smarkm * buffer currently. 170457416Smarkm */ 170557416Smarkm printoption("RCVD", IAC, DM); 170657416Smarkm SYNCHing = 1; 170757416Smarkm ttyflush(1); 170857416Smarkm SYNCHing = stilloob(); 170957416Smarkm settimer(gotDM); 171057416Smarkm break; 171157416Smarkm 171257416Smarkm case SB: 171357416Smarkm SB_CLEAR(); 171457416Smarkm telrcv_state = TS_SB; 171557416Smarkm continue; 171657416Smarkm 171757416Smarkm 171857416Smarkm case IAC: 171957416Smarkm TTYADD(IAC); 172057416Smarkm break; 172157416Smarkm 172257416Smarkm case NOP: 172357416Smarkm case GA: 172457416Smarkm default: 172557416Smarkm printoption("RCVD", IAC, c); 172657416Smarkm break; 172757416Smarkm } 172857416Smarkm telrcv_state = TS_DATA; 172957416Smarkm continue; 173057416Smarkm 173157416Smarkm case TS_WILL: 173257416Smarkm printoption("RCVD", WILL, c); 173357416Smarkm willoption(c); 173457416Smarkm telrcv_state = TS_DATA; 173557416Smarkm continue; 173657416Smarkm 173757416Smarkm case TS_WONT: 173857416Smarkm printoption("RCVD", WONT, c); 173957416Smarkm wontoption(c); 174057416Smarkm telrcv_state = TS_DATA; 174157416Smarkm continue; 174257416Smarkm 174357416Smarkm case TS_DO: 174457416Smarkm printoption("RCVD", DO, c); 174557416Smarkm dooption(c); 174657416Smarkm if (c == TELOPT_NAWS) { 174757416Smarkm sendnaws(); 174857416Smarkm } else if (c == TELOPT_LFLOW) { 174957416Smarkm localflow = 1; 175057416Smarkm setcommandmode(); 175157416Smarkm setconnmode(0); 175257416Smarkm } 175357416Smarkm telrcv_state = TS_DATA; 175457416Smarkm continue; 175557416Smarkm 175657416Smarkm case TS_DONT: 175757416Smarkm printoption("RCVD", DONT, c); 175857416Smarkm dontoption(c); 175957416Smarkm flushline = 1; 176057416Smarkm setconnmode(0); /* set new tty mode (maybe) */ 176157416Smarkm telrcv_state = TS_DATA; 176257416Smarkm continue; 176357416Smarkm 176457416Smarkm case TS_SB: 176557416Smarkm if (c == IAC) { 176657416Smarkm telrcv_state = TS_SE; 176757416Smarkm } else { 176857416Smarkm SB_ACCUM(c); 176957416Smarkm } 177057416Smarkm continue; 177157416Smarkm 177257416Smarkm case TS_SE: 177357416Smarkm if (c != SE) { 177457416Smarkm if (c != IAC) { 177557416Smarkm /* 177657416Smarkm * This is an error. We only expect to get 177757416Smarkm * "IAC IAC" or "IAC SE". Several things may 1778178825Sdfr * have happened. An IAC was not doubled, the 177957416Smarkm * IAC SE was left off, or another option got 178057416Smarkm * inserted into the suboption are all possibilities. 178157416Smarkm * If we assume that the IAC was not doubled, 178257416Smarkm * and really the IAC SE was left off, we could 1783178825Sdfr * get into an infinite loop here. So, instead, 178457416Smarkm * we terminate the suboption, and process the 178557416Smarkm * partial suboption if we can. 178657416Smarkm */ 178757416Smarkm SB_ACCUM(IAC); 178857416Smarkm SB_ACCUM(c); 178957416Smarkm subpointer -= 2; 179057416Smarkm SB_TERM(); 179157416Smarkm 179257416Smarkm printoption("In SUBOPTION processing, RCVD", IAC, c); 179357416Smarkm suboption(); /* handle sub-option */ 179457416Smarkm telrcv_state = TS_IAC; 179557416Smarkm goto process_iac; 179657416Smarkm } 179757416Smarkm SB_ACCUM(c); 179857416Smarkm telrcv_state = TS_SB; 179957416Smarkm } else { 180057416Smarkm SB_ACCUM(IAC); 180157416Smarkm SB_ACCUM(SE); 180257416Smarkm subpointer -= 2; 180357416Smarkm SB_TERM(); 180457416Smarkm suboption(); /* handle sub-option */ 180557416Smarkm telrcv_state = TS_DATA; 180657416Smarkm } 180757416Smarkm } 180857416Smarkm } 180957416Smarkm if (count) 181057416Smarkm ring_consumed(&netiring, count); 181157416Smarkm return returnValue||count; 181257416Smarkm} 181357416Smarkm 181457416Smarkmstatic int bol = 1, local = 0; 181557416Smarkm 181657416Smarkmint 181757416Smarkmrlogin_susp(void) 181857416Smarkm{ 181957416Smarkm if (local) { 182057416Smarkm local = 0; 182157416Smarkm bol = 1; 182257416Smarkm command(0, "z\n", 2); 182357416Smarkm return(1); 182457416Smarkm } 182557416Smarkm return(0); 182657416Smarkm} 182757416Smarkm 182857416Smarkmstatic int 182957416Smarkmtelsnd() 183057416Smarkm{ 183157416Smarkm int tcc; 183257416Smarkm int count; 183357416Smarkm int returnValue = 0; 183457416Smarkm unsigned char *tbp = NULL; 183557416Smarkm 183657416Smarkm tcc = 0; 183757416Smarkm count = 0; 183857416Smarkm while (NETROOM() > 2) { 183957416Smarkm int sc; 184057416Smarkm int c; 184157416Smarkm 184257416Smarkm if (tcc == 0) { 184357416Smarkm if (count) { 184457416Smarkm ring_consumed(&ttyiring, count); 184557416Smarkm returnValue = 1; 184657416Smarkm count = 0; 184757416Smarkm } 184857416Smarkm tbp = ttyiring.consume; 184957416Smarkm tcc = ring_full_consecutive(&ttyiring); 185057416Smarkm if (tcc == 0) { 185157416Smarkm break; 185257416Smarkm } 185357416Smarkm } 185457416Smarkm c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 185557416Smarkm if (rlogin != _POSIX_VDISABLE) { 185657416Smarkm if (bol) { 185757416Smarkm bol = 0; 185857416Smarkm if (sc == rlogin) { 185957416Smarkm local = 1; 186057416Smarkm continue; 186157416Smarkm } 186257416Smarkm } else if (local) { 186357416Smarkm local = 0; 186457416Smarkm if (sc == '.' || c == termEofChar) { 186557416Smarkm bol = 1; 186657416Smarkm command(0, "close\n", 6); 186757416Smarkm continue; 186857416Smarkm } 186957416Smarkm if (sc == termSuspChar) { 187057416Smarkm bol = 1; 187157416Smarkm command(0, "z\n", 2); 187257416Smarkm continue; 187357416Smarkm } 187457416Smarkm if (sc == escape) { 187557416Smarkm command(0, (char *)tbp, tcc); 187657416Smarkm bol = 1; 187757416Smarkm count += tcc; 187857416Smarkm tcc = 0; 187957416Smarkm flushline = 1; 188057416Smarkm break; 188157416Smarkm } 188257416Smarkm if (sc != rlogin) { 188357416Smarkm ++tcc; 188457416Smarkm --tbp; 188557416Smarkm --count; 188657416Smarkm c = sc = rlogin; 188757416Smarkm } 188857416Smarkm } 188957416Smarkm if ((sc == '\n') || (sc == '\r')) 189057416Smarkm bol = 1; 189157416Smarkm } else if (sc == escape) { 189257416Smarkm /* 189357416Smarkm * Double escape is a pass through of a single escape character. 189457416Smarkm */ 189557416Smarkm if (tcc && strip(*tbp) == escape) { 189657416Smarkm tbp++; 189757416Smarkm tcc--; 189857416Smarkm count++; 189957416Smarkm bol = 0; 190057416Smarkm } else { 190157416Smarkm command(0, (char *)tbp, tcc); 190257416Smarkm bol = 1; 190357416Smarkm count += tcc; 190457416Smarkm tcc = 0; 190557416Smarkm flushline = 1; 190657416Smarkm break; 190757416Smarkm } 190857416Smarkm } else 190957416Smarkm bol = 0; 191057416Smarkm#ifdef KLUDGELINEMODE 191157416Smarkm if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 191257416Smarkm if (tcc > 0 && strip(*tbp) == echoc) { 191357416Smarkm tcc--; tbp++; count++; 191457416Smarkm } else { 191557416Smarkm dontlecho = !dontlecho; 191657416Smarkm settimer(echotoggle); 191757416Smarkm setconnmode(0); 191857416Smarkm flushline = 1; 191957416Smarkm break; 192057416Smarkm } 192157416Smarkm } 192257416Smarkm#endif 192357416Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 192457416Smarkm if (TerminalSpecialChars(sc) == 0) { 192557416Smarkm bol = 1; 192657416Smarkm break; 192757416Smarkm } 192857416Smarkm } 192957416Smarkm if (my_want_state_is_wont(TELOPT_BINARY)) { 193057416Smarkm switch (c) { 193157416Smarkm case '\n': 193257416Smarkm /* 193357416Smarkm * If we are in CRMOD mode (\r ==> \n) 193457416Smarkm * on our local machine, then probably 193557416Smarkm * a newline (unix) is CRLF (TELNET). 193657416Smarkm */ 193757416Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 193857416Smarkm NETADD('\r'); 193957416Smarkm } 194057416Smarkm NETADD('\n'); 194157416Smarkm bol = flushline = 1; 194257416Smarkm break; 194357416Smarkm case '\r': 194457416Smarkm if (!crlf) { 194557416Smarkm NET2ADD('\r', '\0'); 194657416Smarkm } else { 194757416Smarkm NET2ADD('\r', '\n'); 194857416Smarkm } 194957416Smarkm bol = flushline = 1; 195057416Smarkm break; 195157416Smarkm case IAC: 195257416Smarkm NET2ADD(IAC, IAC); 195357416Smarkm break; 195457416Smarkm default: 195557416Smarkm NETADD(c); 195657416Smarkm break; 195757416Smarkm } 195857416Smarkm } else if (c == IAC) { 195957416Smarkm NET2ADD(IAC, IAC); 196057416Smarkm } else { 196157416Smarkm NETADD(c); 196257416Smarkm } 196357416Smarkm } 196457416Smarkm if (count) 196557416Smarkm ring_consumed(&ttyiring, count); 196657416Smarkm return returnValue||count; /* Non-zero if we did anything */ 196757416Smarkm} 196857416Smarkm 196957416Smarkm/* 197057416Smarkm * Scheduler() 197157416Smarkm * 197257416Smarkm * Try to do something. 197357416Smarkm * 197457416Smarkm * If we do something useful, return 1; else return 0. 197557416Smarkm * 197657416Smarkm */ 197757416Smarkm 197857416Smarkm 197990926Snectar int 198057416SmarkmScheduler(int block) /* should we block in the select ? */ 198157416Smarkm{ 198257416Smarkm /* One wants to be a bit careful about setting returnValue 198357416Smarkm * to one, since a one implies we did some useful work, 198457416Smarkm * and therefore probably won't be called to block next 198557416Smarkm * time (TN3270 mode only). 198657416Smarkm */ 198757416Smarkm int returnValue; 198857416Smarkm int netin, netout, netex, ttyin, ttyout; 198957416Smarkm 199057416Smarkm /* Decide which rings should be processed */ 199157416Smarkm 199257416Smarkm netout = ring_full_count(&netoring) && 199357416Smarkm (flushline || 199457416Smarkm (my_want_state_is_wont(TELOPT_LINEMODE) 199557416Smarkm#ifdef KLUDGELINEMODE 199657416Smarkm && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 199757416Smarkm#endif 199857416Smarkm ) || 199957416Smarkm my_want_state_is_will(TELOPT_BINARY)); 200057416Smarkm ttyout = ring_full_count(&ttyoring); 200157416Smarkm 200257416Smarkm ttyin = ring_empty_count(&ttyiring); 200357416Smarkm 200457416Smarkm netin = !ISend && ring_empty_count(&netiring); 200557416Smarkm 200657416Smarkm netex = !SYNCHing; 200757416Smarkm 200857416Smarkm /* If we have seen a signal recently, reset things */ 200957416Smarkm 201090926Snectar if (scheduler_lockout_tty) { 201190926Snectar ttyin = ttyout = 0; 201290926Snectar } 201390926Snectar 201457416Smarkm /* Call to system code to process rings */ 201557416Smarkm 201657416Smarkm returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 201757416Smarkm 201857416Smarkm /* Now, look at the input rings, looking for work to do. */ 201957416Smarkm 202057416Smarkm if (ring_full_count(&ttyiring)) { 202157416Smarkm returnValue |= telsnd(); 202257416Smarkm } 202357416Smarkm 202457416Smarkm if (ring_full_count(&netiring)) { 202557416Smarkm returnValue |= telrcv(); 202657416Smarkm } 202757416Smarkm return returnValue; 202857416Smarkm} 202957416Smarkm 2030178825Sdfrextern int auth_has_failed; /* XXX should be somewhere else */ 2031178825Sdfr 203257416Smarkm/* 203357416Smarkm * Select from tty and network... 203457416Smarkm */ 203557416Smarkmvoid 203657416Smarkmmy_telnet(char *user) 203757416Smarkm{ 203890926Snectar int printed_encrypt = 0; 2039233294Sstas 204057416Smarkm sys_telnet_init(); 204157416Smarkm 204257416Smarkm#if defined(AUTHENTICATION) || defined(ENCRYPTION) 204357416Smarkm { 204457416Smarkm static char local_host[256] = { 0 }; 204557416Smarkm 204657416Smarkm if (!local_host[0]) { 204757416Smarkm /* XXX - should be k_gethostname? */ 204857416Smarkm gethostname(local_host, sizeof(local_host)); 204957416Smarkm local_host[sizeof(local_host)-1] = 0; 205057416Smarkm } 205157416Smarkm auth_encrypt_init(local_host, hostname, "TELNET", 0); 205257416Smarkm auth_encrypt_user(user); 205357416Smarkm } 205457416Smarkm#endif 205557416Smarkm if (telnetport) { 205657416Smarkm#if defined(AUTHENTICATION) 205757416Smarkm if (autologin) 205857416Smarkm send_will(TELOPT_AUTHENTICATION, 1); 205957416Smarkm#endif 206057416Smarkm#if defined(ENCRYPTION) 206157416Smarkm send_do(TELOPT_ENCRYPT, 1); 206257416Smarkm send_will(TELOPT_ENCRYPT, 1); 206357416Smarkm#endif 206457416Smarkm send_do(TELOPT_SGA, 1); 206557416Smarkm send_will(TELOPT_TTYPE, 1); 206657416Smarkm send_will(TELOPT_NAWS, 1); 206757416Smarkm send_will(TELOPT_TSPEED, 1); 206857416Smarkm send_will(TELOPT_LFLOW, 1); 206957416Smarkm send_will(TELOPT_LINEMODE, 1); 207057416Smarkm send_will(TELOPT_NEW_ENVIRON, 1); 207157416Smarkm send_do(TELOPT_STATUS, 1); 207257416Smarkm if (env_getvalue((unsigned char *)"DISPLAY")) 207357416Smarkm send_will(TELOPT_XDISPLOC, 1); 207457416Smarkm if (binary) 207557416Smarkm tel_enter_binary(binary); 207657416Smarkm } 207757416Smarkm 207890926Snectar#ifdef ENCRYPTION 207990926Snectar /* 208090926Snectar * Note: we assume a tie to the authentication option here. This 208190926Snectar * is necessary so that authentication fails, we don't spin 2082233294Sstas * forever. 208390926Snectar */ 2084102644Snectar if (telnetport && wantencryption) { 208590926Snectar time_t timeout = time(0) + 60; 208690926Snectar 208790926Snectar send_do(TELOPT_ENCRYPT, 1); 208890926Snectar send_will(TELOPT_ENCRYPT, 1); 208990926Snectar while (1) { 209090926Snectar if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) { 2091102644Snectar if (wantencryption == -1) { 2092102644Snectar break; 2093102644Snectar } else { 2094102644Snectar printf("\nServer refused to negotiate authentication,\n"); 2095102644Snectar printf("which is required for encryption.\n"); 2096102644Snectar Exit(1); 2097102644Snectar } 209890926Snectar } 209990926Snectar if (auth_has_failed) { 2100178825Sdfr printf("\nAuthentication negotiation has failed,\n"); 210190926Snectar printf("which is required for encryption.\n"); 210290926Snectar Exit(1); 210390926Snectar } 210490926Snectar if (my_want_state_is_dont(TELOPT_ENCRYPT) || 210590926Snectar my_want_state_is_wont(TELOPT_ENCRYPT)) { 210690926Snectar printf("\nServer refused to negotiate encryption.\n"); 210790926Snectar Exit(1); 210890926Snectar } 210990926Snectar if (encrypt_is_encrypting()) 211090926Snectar break; 211190926Snectar if (time(0) > timeout) { 211290926Snectar printf("\nEncryption could not be enabled.\n"); 211390926Snectar Exit(1); 211490926Snectar } 211590926Snectar if (printed_encrypt == 0) { 211690926Snectar printed_encrypt = 1; 211790926Snectar printf("Waiting for encryption to be negotiated...\n"); 211890926Snectar /* 2119233294Sstas * Turn on MODE_TRAPSIG and then turn off localchars 212090926Snectar * so that ^C will cause telnet to exit. 212190926Snectar */ 212290926Snectar TerminalNewMode(getconnmode()|MODE_TRAPSIG); 212390926Snectar intr_waiting = 1; 212490926Snectar } 212590926Snectar if (intr_happened) { 212690926Snectar printf("\nUser interrupt.\n"); 212790926Snectar Exit(1); 212890926Snectar } 2129178825Sdfr if (telnet_spin()) { 2130178825Sdfr printf("\nServer disconnected.\n"); 2131178825Sdfr Exit(1); 2132178825Sdfr } 2133233294Sstas 213490926Snectar } 213590926Snectar if (printed_encrypt) { 2136102644Snectar printf("Encryption negotiated.\n"); 213790926Snectar intr_waiting = 0; 213890926Snectar setconnmode(0); 213990926Snectar } 214090926Snectar } 214190926Snectar#endif 214290926Snectar 214357416Smarkm for (;;) { 214457416Smarkm int schedValue; 214557416Smarkm 214657416Smarkm while ((schedValue = Scheduler(0)) != 0) { 214757416Smarkm if (schedValue == -1) { 214857416Smarkm setcommandmode(); 214957416Smarkm return; 215057416Smarkm } 215157416Smarkm } 215257416Smarkm 215357416Smarkm if (Scheduler(1) == -1) { 215457416Smarkm setcommandmode(); 215557416Smarkm return; 215657416Smarkm } 215757416Smarkm } 215857416Smarkm} 215957416Smarkm 216057416Smarkm/* 216157416Smarkm * netclear() 216257416Smarkm * 216357416Smarkm * We are about to do a TELNET SYNCH operation. Clear 216457416Smarkm * the path to the network. 216557416Smarkm * 216657416Smarkm * Things are a bit tricky since we may have sent the first 216757416Smarkm * byte or so of a previous TELNET command into the network. 216857416Smarkm * So, we have to scan the network buffer from the beginning 216957416Smarkm * until we are up to where we want to be. 217057416Smarkm * 217157416Smarkm * A side effect of what we do, just to keep things 217257416Smarkm * simple, is to clear the urgent data pointer. The principal 217357416Smarkm * caller should be setting the urgent data pointer AFTER calling 217457416Smarkm * us in any case. 217557416Smarkm */ 217657416Smarkm 217757416Smarkmstatic void 217857416Smarkmnetclear() 217957416Smarkm{ 218057416Smarkm#if 0 /* XXX */ 218157416Smarkm char *thisitem, *next; 218257416Smarkm char *good; 218357416Smarkm#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 218457416Smarkm ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 218557416Smarkm 218657416Smarkm thisitem = netobuf; 218757416Smarkm 218857416Smarkm while ((next = nextitem(thisitem)) <= netobuf.send) { 218957416Smarkm thisitem = next; 219057416Smarkm } 219157416Smarkm 219257416Smarkm /* Now, thisitem is first before/at boundary. */ 219357416Smarkm 219457416Smarkm good = netobuf; /* where the good bytes go */ 219557416Smarkm 219657416Smarkm while (netoring.add > thisitem) { 219757416Smarkm if (wewant(thisitem)) { 219857416Smarkm int length; 219957416Smarkm 220057416Smarkm next = thisitem; 220157416Smarkm do { 220257416Smarkm next = nextitem(next); 220357416Smarkm } while (wewant(next) && (nfrontp > next)); 220457416Smarkm length = next-thisitem; 220557416Smarkm memmove(good, thisitem, length); 220657416Smarkm good += length; 220757416Smarkm thisitem = next; 220857416Smarkm } else { 220957416Smarkm thisitem = nextitem(thisitem); 221057416Smarkm } 221157416Smarkm } 221257416Smarkm 221357416Smarkm#endif /* 0 */ 221457416Smarkm} 221557416Smarkm 221657416Smarkm/* 221757416Smarkm * These routines add various telnet commands to the data stream. 221857416Smarkm */ 221957416Smarkm 222057416Smarkmstatic void 222157416Smarkmdoflush() 222257416Smarkm{ 222357416Smarkm NET2ADD(IAC, DO); 222457416Smarkm NETADD(TELOPT_TM); 222557416Smarkm flushline = 1; 222657416Smarkm flushout = 1; 222757416Smarkm ttyflush(1); /* Flush/drop output */ 222857416Smarkm /* do printoption AFTER flush, otherwise the output gets tossed... */ 222957416Smarkm printoption("SENT", DO, TELOPT_TM); 223057416Smarkm} 223157416Smarkm 223257416Smarkmvoid 223357416SmarkmxmitAO(void) 223457416Smarkm{ 223557416Smarkm NET2ADD(IAC, AO); 223657416Smarkm printoption("SENT", IAC, AO); 223757416Smarkm if (autoflush) { 223857416Smarkm doflush(); 223957416Smarkm } 224057416Smarkm} 224157416Smarkm 224257416Smarkm 224357416Smarkmvoid 224457416SmarkmxmitEL(void) 224557416Smarkm{ 224657416Smarkm NET2ADD(IAC, EL); 224757416Smarkm printoption("SENT", IAC, EL); 224857416Smarkm} 224957416Smarkm 225057416Smarkmvoid 225157416SmarkmxmitEC(void) 225257416Smarkm{ 225357416Smarkm NET2ADD(IAC, EC); 225457416Smarkm printoption("SENT", IAC, EC); 225557416Smarkm} 225657416Smarkm 225757416Smarkm 225857416Smarkmint 225957416Smarkmdosynch() 226057416Smarkm{ 226157416Smarkm netclear(); /* clear the path to the network */ 226257416Smarkm NETADD(IAC); 226357416Smarkm setneturg(); 226457416Smarkm NETADD(DM); 226557416Smarkm printoption("SENT", IAC, DM); 226657416Smarkm return 1; 226757416Smarkm} 226857416Smarkm 226957416Smarkmint want_status_response = 0; 227057416Smarkm 227157416Smarkmint 227257416Smarkmget_status() 227357416Smarkm{ 227457416Smarkm unsigned char tmp[16]; 227557416Smarkm unsigned char *cp; 227657416Smarkm 227757416Smarkm if (my_want_state_is_dont(TELOPT_STATUS)) { 227857416Smarkm printf("Remote side does not support STATUS option\n"); 227957416Smarkm return 0; 228057416Smarkm } 228157416Smarkm cp = tmp; 228257416Smarkm 228357416Smarkm *cp++ = IAC; 228457416Smarkm *cp++ = SB; 228557416Smarkm *cp++ = TELOPT_STATUS; 228657416Smarkm *cp++ = TELQUAL_SEND; 228757416Smarkm *cp++ = IAC; 228857416Smarkm *cp++ = SE; 228957416Smarkm if (NETROOM() >= cp - tmp) { 229057416Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 229157416Smarkm printsub('>', tmp+2, cp - tmp - 2); 229257416Smarkm } 229357416Smarkm ++want_status_response; 229457416Smarkm return 1; 229557416Smarkm} 229657416Smarkm 229757416Smarkmvoid 229857416Smarkmintp(void) 229957416Smarkm{ 230057416Smarkm NET2ADD(IAC, IP); 230157416Smarkm printoption("SENT", IAC, IP); 230257416Smarkm flushline = 1; 230357416Smarkm if (autoflush) { 230457416Smarkm doflush(); 230557416Smarkm } 230657416Smarkm if (autosynch) { 230757416Smarkm dosynch(); 230857416Smarkm } 230957416Smarkm} 231057416Smarkm 231157416Smarkmvoid 231257416Smarkmsendbrk(void) 231357416Smarkm{ 231457416Smarkm NET2ADD(IAC, BREAK); 231557416Smarkm printoption("SENT", IAC, BREAK); 231657416Smarkm flushline = 1; 231757416Smarkm if (autoflush) { 231857416Smarkm doflush(); 231957416Smarkm } 232057416Smarkm if (autosynch) { 232157416Smarkm dosynch(); 232257416Smarkm } 232357416Smarkm} 232457416Smarkm 232557416Smarkmvoid 232657416Smarkmsendabort(void) 232757416Smarkm{ 232857416Smarkm NET2ADD(IAC, ABORT); 232957416Smarkm printoption("SENT", IAC, ABORT); 233057416Smarkm flushline = 1; 233157416Smarkm if (autoflush) { 233257416Smarkm doflush(); 233357416Smarkm } 233457416Smarkm if (autosynch) { 233557416Smarkm dosynch(); 233657416Smarkm } 233757416Smarkm} 233857416Smarkm 233957416Smarkmvoid 234057416Smarkmsendsusp(void) 234157416Smarkm{ 234257416Smarkm NET2ADD(IAC, SUSP); 234357416Smarkm printoption("SENT", IAC, SUSP); 234457416Smarkm flushline = 1; 234557416Smarkm if (autoflush) { 234657416Smarkm doflush(); 234757416Smarkm } 234857416Smarkm if (autosynch) { 234957416Smarkm dosynch(); 235057416Smarkm } 235157416Smarkm} 235257416Smarkm 235357416Smarkmvoid 235457416Smarkmsendeof(void) 235557416Smarkm{ 235657416Smarkm NET2ADD(IAC, xEOF); 235757416Smarkm printoption("SENT", IAC, xEOF); 235857416Smarkm} 235957416Smarkm 236057416Smarkmvoid 236157416Smarkmsendayt(void) 236257416Smarkm{ 236357416Smarkm NET2ADD(IAC, AYT); 236457416Smarkm printoption("SENT", IAC, AYT); 236557416Smarkm} 236657416Smarkm 236757416Smarkm/* 236857416Smarkm * Send a window size update to the remote system. 236957416Smarkm */ 237057416Smarkm 237157416Smarkmvoid 237257416Smarkmsendnaws() 237357416Smarkm{ 237457416Smarkm long rows, cols; 237557416Smarkm unsigned char tmp[16]; 237657416Smarkm unsigned char *cp; 237757416Smarkm 237857416Smarkm if (my_state_is_wont(TELOPT_NAWS)) 237957416Smarkm return; 238057416Smarkm 238190926Snectar#undef PUTSHORT 238257416Smarkm#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 238357416Smarkm if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 238457416Smarkm 238557416Smarkm if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 238657416Smarkm return; 238757416Smarkm } 238857416Smarkm 238957416Smarkm cp = tmp; 239057416Smarkm 239157416Smarkm *cp++ = IAC; 239257416Smarkm *cp++ = SB; 239357416Smarkm *cp++ = TELOPT_NAWS; 239457416Smarkm PUTSHORT(cp, cols); 239557416Smarkm PUTSHORT(cp, rows); 239657416Smarkm *cp++ = IAC; 239757416Smarkm *cp++ = SE; 239857416Smarkm if (NETROOM() >= cp - tmp) { 239957416Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 240057416Smarkm printsub('>', tmp+2, cp - tmp - 2); 240157416Smarkm } 240257416Smarkm} 240357416Smarkm 240457416Smarkmvoid 240557416Smarkmtel_enter_binary(int rw) 240657416Smarkm{ 240757416Smarkm if (rw&1) 240857416Smarkm send_do(TELOPT_BINARY, 1); 240957416Smarkm if (rw&2) 241057416Smarkm send_will(TELOPT_BINARY, 1); 241157416Smarkm} 241257416Smarkm 241357416Smarkmvoid 241457416Smarkmtel_leave_binary(int rw) 241557416Smarkm{ 241657416Smarkm if (rw&1) 241757416Smarkm send_dont(TELOPT_BINARY, 1); 241857416Smarkm if (rw&2) 241957416Smarkm send_wont(TELOPT_BINARY, 1); 242057416Smarkm} 2421