telnet.c revision 57416
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#ifdef HAVE_TERMCAP_H 3657416Smarkm#include <termcap.h> 3757416Smarkm#endif 3857416Smarkm 3957416SmarkmRCSID("$Id: telnet.c,v 1.27 2000/01/01 11:53:24 assar Exp $"); 4057416Smarkm 4157416Smarkm#define strip(x) (eight ? (x) : ((x) & 0x7f)) 4257416Smarkm 4357416Smarkmstatic unsigned char subbuffer[SUBBUFSIZE], 4457416Smarkm *subpointer, *subend; /* buffer for sub-options */ 4557416Smarkm#define SB_CLEAR() subpointer = subbuffer; 4657416Smarkm#define SB_TERM() { subend = subpointer; SB_CLEAR(); } 4757416Smarkm#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 4857416Smarkm *subpointer++ = (c); \ 4957416Smarkm } 5057416Smarkm 5157416Smarkm#define SB_GET() ((*subpointer++)&0xff) 5257416Smarkm#define SB_PEEK() ((*subpointer)&0xff) 5357416Smarkm#define SB_EOF() (subpointer >= subend) 5457416Smarkm#define SB_LEN() (subend - subpointer) 5557416Smarkm 5657416Smarkmchar options[256]; /* The combined options */ 5757416Smarkmchar do_dont_resp[256]; 5857416Smarkmchar will_wont_resp[256]; 5957416Smarkm 6057416Smarkmint 6157416Smarkm eight = 3, 6257416Smarkm binary = 0, 6357416Smarkm autologin = 0, /* Autologin anyone? */ 6457416Smarkm skiprc = 0, 6557416Smarkm connected, 6657416Smarkm showoptions, 6757416Smarkm ISend, /* trying to send network data in */ 6857416Smarkm debug = 0, 6957416Smarkm crmod, 7057416Smarkm netdata, /* Print out network data flow */ 7157416Smarkm crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 7257416Smarkm telnetport, 7357416Smarkm SYNCHing, /* we are in TELNET SYNCH mode */ 7457416Smarkm flushout, /* flush output */ 7557416Smarkm autoflush = 0, /* flush output when interrupting? */ 7657416Smarkm autosynch, /* send interrupt characters with SYNCH? */ 7757416Smarkm localflow, /* we handle flow control locally */ 7857416Smarkm restartany, /* if flow control enabled, restart on any character */ 7957416Smarkm localchars, /* we recognize interrupt/quit */ 8057416Smarkm donelclchars, /* the user has set "localchars" */ 8157416Smarkm donebinarytoggle, /* the user has put us in binary */ 8257416Smarkm dontlecho, /* do we suppress local echoing right now? */ 8357416Smarkm globalmode; 8457416Smarkm 8557416Smarkmchar *prompt = 0; 8657416Smarkm 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 50357416Smarkm * the pipe seperated 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 */ 57957416Smarkm#define ISASCII(c) (!((c)&0x80)) 58057416Smarkm if ((c == ' ') || !ISASCII(c)) 58157416Smarkm n = 1; 58257416Smarkm else if (islower(c)) 58357416Smarkm *cp = toupper(c); 58457416Smarkm } 58557416Smarkm 58657416Smarkm /* 58757416Smarkm * Check for an old V6 2 character name. If the second 58857416Smarkm * name points to the beginning of the buffer, and is 58957416Smarkm * only 2 characters long, move it to the end of the array. 59057416Smarkm */ 59157416Smarkm if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 59257416Smarkm --argvp; 59357416Smarkm for (avt = &argv[1]; avt < argvp; avt++) 59457416Smarkm *avt = *(avt+1); 59557416Smarkm *argvp++ = buf; 59657416Smarkm } 59757416Smarkm 59857416Smarkm /* 59957416Smarkm * Duplicate last name, for TTYPE option, and null 60057416Smarkm * terminate the array. If we didn't find a match on 60157416Smarkm * our terminal name, put that name at the beginning. 60257416Smarkm */ 60357416Smarkm cp = *(argvp-1); 60457416Smarkm *argvp++ = cp; 60557416Smarkm *argvp = 0; 60657416Smarkm 60757416Smarkm if (*argv == 0) { 60857416Smarkm if (name) 60957416Smarkm *argv = name; 61057416Smarkm else { 61157416Smarkm --argvp; 61257416Smarkm for (avt = argv; avt < argvp; avt++) 61357416Smarkm *avt = *(avt+1); 61457416Smarkm } 61557416Smarkm } 61657416Smarkm if (*argv) 61757416Smarkm return(argv); 61857416Smarkm else 61957416Smarkm return(unknown); 62057416Smarkm} 62157416Smarkm 62257416Smarkmstatic int 62357416Smarkmis_unique(char *name, char **as, char **ae) 62457416Smarkm{ 62557416Smarkm char **ap; 62657416Smarkm int n; 62757416Smarkm 62857416Smarkm n = strlen(name) + 1; 62957416Smarkm for (ap = as; ap < ae; ap++) 63057416Smarkm if (strncasecmp(*ap, name, n) == 0) 63157416Smarkm return(0); 63257416Smarkm return (1); 63357416Smarkm} 63457416Smarkm 63557416Smarkmstatic char termbuf[1024]; 63657416Smarkm 63757416Smarkmstatic int 63857416Smarkmtelnet_setupterm(const char *tname, int fd, int *errp) 63957416Smarkm{ 64057416Smarkm if (tgetent(termbuf, tname) == 1) { 64157416Smarkm termbuf[1023] = '\0'; 64257416Smarkm if (errp) 64357416Smarkm *errp = 1; 64457416Smarkm return(0); 64557416Smarkm } 64657416Smarkm if (errp) 64757416Smarkm *errp = 0; 64857416Smarkm return(-1); 64957416Smarkm} 65057416Smarkm 65157416Smarkmint resettermname = 1; 65257416Smarkm 65357416Smarkmstatic char * 65457416Smarkmgettermname() 65557416Smarkm{ 65657416Smarkm char *tname; 65757416Smarkm static char **tnamep = 0; 65857416Smarkm static char **next; 65957416Smarkm int err; 66057416Smarkm 66157416Smarkm if (resettermname) { 66257416Smarkm resettermname = 0; 66357416Smarkm if (tnamep && tnamep != unknown) 66457416Smarkm free(tnamep); 66557416Smarkm if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && 66657416Smarkm telnet_setupterm(tname, 1, &err) == 0) { 66757416Smarkm tnamep = mklist(termbuf, tname); 66857416Smarkm } else { 66957416Smarkm if (tname && ((int)strlen(tname) <= 40)) { 67057416Smarkm unknown[0] = tname; 67157416Smarkm strupr(tname); 67257416Smarkm } else 67357416Smarkm unknown[0] = name_unknown; 67457416Smarkm tnamep = unknown; 67557416Smarkm } 67657416Smarkm next = tnamep; 67757416Smarkm } 67857416Smarkm if (*next == 0) 67957416Smarkm next = tnamep; 68057416Smarkm return(*next++); 68157416Smarkm} 68257416Smarkm/* 68357416Smarkm * suboption() 68457416Smarkm * 68557416Smarkm * Look at the sub-option buffer, and try to be helpful to the other 68657416Smarkm * side. 68757416Smarkm * 68857416Smarkm * Currently we recognize: 68957416Smarkm * 69057416Smarkm * Terminal type, send request. 69157416Smarkm * Terminal speed (send request). 69257416Smarkm * Local flow control (is request). 69357416Smarkm * Linemode 69457416Smarkm */ 69557416Smarkm 69657416Smarkmstatic void 69757416Smarkmsuboption() 69857416Smarkm{ 69957416Smarkm unsigned char subchar; 70057416Smarkm 70157416Smarkm printsub('<', subbuffer, SB_LEN()+2); 70257416Smarkm switch (subchar = SB_GET()) { 70357416Smarkm case TELOPT_TTYPE: 70457416Smarkm if (my_want_state_is_wont(TELOPT_TTYPE)) 70557416Smarkm return; 70657416Smarkm if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 70757416Smarkm return; 70857416Smarkm } else { 70957416Smarkm char *name; 71057416Smarkm unsigned char temp[50]; 71157416Smarkm int len; 71257416Smarkm 71357416Smarkm name = gettermname(); 71457416Smarkm len = strlen(name) + 4 + 2; 71557416Smarkm if (len < NETROOM()) { 71657416Smarkm snprintf((char *)temp, sizeof(temp), 71757416Smarkm "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 71857416Smarkm TELQUAL_IS, name, IAC, SE); 71957416Smarkm ring_supply_data(&netoring, temp, len); 72057416Smarkm printsub('>', &temp[2], len-2); 72157416Smarkm } else { 72257416Smarkm ExitString("No room in buffer for terminal type.\n", 1); 72357416Smarkm /*NOTREACHED*/ 72457416Smarkm } 72557416Smarkm } 72657416Smarkm break; 72757416Smarkm case TELOPT_TSPEED: 72857416Smarkm if (my_want_state_is_wont(TELOPT_TSPEED)) 72957416Smarkm return; 73057416Smarkm if (SB_EOF()) 73157416Smarkm return; 73257416Smarkm if (SB_GET() == TELQUAL_SEND) { 73357416Smarkm long output_speed, input_speed; 73457416Smarkm unsigned char temp[50]; 73557416Smarkm int len; 73657416Smarkm 73757416Smarkm TerminalSpeeds(&input_speed, &output_speed); 73857416Smarkm 73957416Smarkm snprintf((char *)temp, sizeof(temp), 74057416Smarkm "%c%c%c%c%u,%u%c%c", IAC, SB, TELOPT_TSPEED, 74157416Smarkm TELQUAL_IS, 74257416Smarkm (unsigned)output_speed, 74357416Smarkm (unsigned)input_speed, IAC, SE); 74457416Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 74557416Smarkm 74657416Smarkm if (len < NETROOM()) { 74757416Smarkm ring_supply_data(&netoring, temp, len); 74857416Smarkm printsub('>', temp+2, len - 2); 74957416Smarkm } 75057416Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 75157416Smarkm } 75257416Smarkm break; 75357416Smarkm case TELOPT_LFLOW: 75457416Smarkm if (my_want_state_is_wont(TELOPT_LFLOW)) 75557416Smarkm return; 75657416Smarkm if (SB_EOF()) 75757416Smarkm return; 75857416Smarkm switch(SB_GET()) { 75957416Smarkm case LFLOW_RESTART_ANY: 76057416Smarkm restartany = 1; 76157416Smarkm break; 76257416Smarkm case LFLOW_RESTART_XON: 76357416Smarkm restartany = 0; 76457416Smarkm break; 76557416Smarkm case LFLOW_ON: 76657416Smarkm localflow = 1; 76757416Smarkm break; 76857416Smarkm case LFLOW_OFF: 76957416Smarkm localflow = 0; 77057416Smarkm break; 77157416Smarkm default: 77257416Smarkm return; 77357416Smarkm } 77457416Smarkm setcommandmode(); 77557416Smarkm setconnmode(0); 77657416Smarkm break; 77757416Smarkm 77857416Smarkm case TELOPT_LINEMODE: 77957416Smarkm if (my_want_state_is_wont(TELOPT_LINEMODE)) 78057416Smarkm return; 78157416Smarkm if (SB_EOF()) 78257416Smarkm return; 78357416Smarkm switch (SB_GET()) { 78457416Smarkm case WILL: 78557416Smarkm lm_will(subpointer, SB_LEN()); 78657416Smarkm break; 78757416Smarkm case WONT: 78857416Smarkm lm_wont(subpointer, SB_LEN()); 78957416Smarkm break; 79057416Smarkm case DO: 79157416Smarkm lm_do(subpointer, SB_LEN()); 79257416Smarkm break; 79357416Smarkm case DONT: 79457416Smarkm lm_dont(subpointer, SB_LEN()); 79557416Smarkm break; 79657416Smarkm case LM_SLC: 79757416Smarkm slc(subpointer, SB_LEN()); 79857416Smarkm break; 79957416Smarkm case LM_MODE: 80057416Smarkm lm_mode(subpointer, SB_LEN(), 0); 80157416Smarkm break; 80257416Smarkm default: 80357416Smarkm break; 80457416Smarkm } 80557416Smarkm break; 80657416Smarkm 80757416Smarkm#ifdef OLD_ENVIRON 80857416Smarkm case TELOPT_OLD_ENVIRON: 80957416Smarkm#endif 81057416Smarkm case TELOPT_NEW_ENVIRON: 81157416Smarkm if (SB_EOF()) 81257416Smarkm return; 81357416Smarkm switch(SB_PEEK()) { 81457416Smarkm case TELQUAL_IS: 81557416Smarkm case TELQUAL_INFO: 81657416Smarkm if (my_want_state_is_dont(subchar)) 81757416Smarkm return; 81857416Smarkm break; 81957416Smarkm case TELQUAL_SEND: 82057416Smarkm if (my_want_state_is_wont(subchar)) { 82157416Smarkm return; 82257416Smarkm } 82357416Smarkm break; 82457416Smarkm default: 82557416Smarkm return; 82657416Smarkm } 82757416Smarkm env_opt(subpointer, SB_LEN()); 82857416Smarkm break; 82957416Smarkm 83057416Smarkm case TELOPT_XDISPLOC: 83157416Smarkm if (my_want_state_is_wont(TELOPT_XDISPLOC)) 83257416Smarkm return; 83357416Smarkm if (SB_EOF()) 83457416Smarkm return; 83557416Smarkm if (SB_GET() == TELQUAL_SEND) { 83657416Smarkm unsigned char temp[50], *dp; 83757416Smarkm int len; 83857416Smarkm 83957416Smarkm if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { 84057416Smarkm /* 84157416Smarkm * Something happened, we no longer have a DISPLAY 84257416Smarkm * variable. So, turn off the option. 84357416Smarkm */ 84457416Smarkm send_wont(TELOPT_XDISPLOC, 1); 84557416Smarkm break; 84657416Smarkm } 84757416Smarkm snprintf((char *)temp, sizeof(temp), 84857416Smarkm "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, 84957416Smarkm TELQUAL_IS, dp, IAC, SE); 85057416Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 85157416Smarkm 85257416Smarkm if (len < NETROOM()) { 85357416Smarkm ring_supply_data(&netoring, temp, len); 85457416Smarkm printsub('>', temp+2, len - 2); 85557416Smarkm } 85657416Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 85757416Smarkm } 85857416Smarkm break; 85957416Smarkm 86057416Smarkm#if defined(AUTHENTICATION) 86157416Smarkm case TELOPT_AUTHENTICATION: { 86257416Smarkm if (!autologin) 86357416Smarkm break; 86457416Smarkm if (SB_EOF()) 86557416Smarkm return; 86657416Smarkm switch(SB_GET()) { 86757416Smarkm case TELQUAL_IS: 86857416Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 86957416Smarkm return; 87057416Smarkm auth_is(subpointer, SB_LEN()); 87157416Smarkm break; 87257416Smarkm case TELQUAL_SEND: 87357416Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 87457416Smarkm return; 87557416Smarkm auth_send(subpointer, SB_LEN()); 87657416Smarkm break; 87757416Smarkm case TELQUAL_REPLY: 87857416Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 87957416Smarkm return; 88057416Smarkm auth_reply(subpointer, SB_LEN()); 88157416Smarkm break; 88257416Smarkm case TELQUAL_NAME: 88357416Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 88457416Smarkm return; 88557416Smarkm auth_name(subpointer, SB_LEN()); 88657416Smarkm break; 88757416Smarkm } 88857416Smarkm } 88957416Smarkm break; 89057416Smarkm#endif 89157416Smarkm#if defined(ENCRYPTION) 89257416Smarkm case TELOPT_ENCRYPT: 89357416Smarkm if (SB_EOF()) 89457416Smarkm return; 89557416Smarkm switch(SB_GET()) { 89657416Smarkm case ENCRYPT_START: 89757416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 89857416Smarkm return; 89957416Smarkm encrypt_start(subpointer, SB_LEN()); 90057416Smarkm break; 90157416Smarkm case ENCRYPT_END: 90257416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 90357416Smarkm return; 90457416Smarkm encrypt_end(); 90557416Smarkm break; 90657416Smarkm case ENCRYPT_SUPPORT: 90757416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 90857416Smarkm return; 90957416Smarkm encrypt_support(subpointer, SB_LEN()); 91057416Smarkm break; 91157416Smarkm case ENCRYPT_REQSTART: 91257416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 91357416Smarkm return; 91457416Smarkm encrypt_request_start(subpointer, SB_LEN()); 91557416Smarkm break; 91657416Smarkm case ENCRYPT_REQEND: 91757416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 91857416Smarkm return; 91957416Smarkm /* 92057416Smarkm * We can always send an REQEND so that we cannot 92157416Smarkm * get stuck encrypting. We should only get this 92257416Smarkm * if we have been able to get in the correct mode 92357416Smarkm * anyhow. 92457416Smarkm */ 92557416Smarkm encrypt_request_end(); 92657416Smarkm break; 92757416Smarkm case ENCRYPT_IS: 92857416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 92957416Smarkm return; 93057416Smarkm encrypt_is(subpointer, SB_LEN()); 93157416Smarkm break; 93257416Smarkm case ENCRYPT_REPLY: 93357416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 93457416Smarkm return; 93557416Smarkm encrypt_reply(subpointer, SB_LEN()); 93657416Smarkm break; 93757416Smarkm case ENCRYPT_ENC_KEYID: 93857416Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 93957416Smarkm return; 94057416Smarkm encrypt_enc_keyid(subpointer, SB_LEN()); 94157416Smarkm break; 94257416Smarkm case ENCRYPT_DEC_KEYID: 94357416Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 94457416Smarkm return; 94557416Smarkm encrypt_dec_keyid(subpointer, SB_LEN()); 94657416Smarkm break; 94757416Smarkm default: 94857416Smarkm break; 94957416Smarkm } 95057416Smarkm break; 95157416Smarkm#endif 95257416Smarkm default: 95357416Smarkm break; 95457416Smarkm } 95557416Smarkm} 95657416Smarkm 95757416Smarkmstatic unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 95857416Smarkm 95957416Smarkmvoid 96057416Smarkmlm_will(unsigned char *cmd, int len) 96157416Smarkm{ 96257416Smarkm if (len < 1) { 96357416Smarkm/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 96457416Smarkm return; 96557416Smarkm } 96657416Smarkm switch(cmd[0]) { 96757416Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 96857416Smarkm default: 96957416Smarkm str_lm[3] = DONT; 97057416Smarkm str_lm[4] = cmd[0]; 97157416Smarkm if (NETROOM() > sizeof(str_lm)) { 97257416Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 97357416Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 97457416Smarkm } 97557416Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 97657416Smarkm break; 97757416Smarkm } 97857416Smarkm} 97957416Smarkm 98057416Smarkmvoid 98157416Smarkmlm_wont(unsigned char *cmd, int len) 98257416Smarkm{ 98357416Smarkm if (len < 1) { 98457416Smarkm/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 98557416Smarkm return; 98657416Smarkm } 98757416Smarkm switch(cmd[0]) { 98857416Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 98957416Smarkm default: 99057416Smarkm /* We are always DONT, so don't respond */ 99157416Smarkm return; 99257416Smarkm } 99357416Smarkm} 99457416Smarkm 99557416Smarkmvoid 99657416Smarkmlm_do(unsigned char *cmd, int len) 99757416Smarkm{ 99857416Smarkm if (len < 1) { 99957416Smarkm/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 100057416Smarkm return; 100157416Smarkm } 100257416Smarkm switch(cmd[0]) { 100357416Smarkm case LM_FORWARDMASK: 100457416Smarkm default: 100557416Smarkm str_lm[3] = WONT; 100657416Smarkm str_lm[4] = cmd[0]; 100757416Smarkm if (NETROOM() > sizeof(str_lm)) { 100857416Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 100957416Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 101057416Smarkm } 101157416Smarkm/*@*/ else printf("lm_do: not enough room in buffer\n"); 101257416Smarkm break; 101357416Smarkm } 101457416Smarkm} 101557416Smarkm 101657416Smarkmvoid 101757416Smarkmlm_dont(unsigned char *cmd, int len) 101857416Smarkm{ 101957416Smarkm if (len < 1) { 102057416Smarkm/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 102157416Smarkm return; 102257416Smarkm } 102357416Smarkm switch(cmd[0]) { 102457416Smarkm case LM_FORWARDMASK: 102557416Smarkm default: 102657416Smarkm /* we are always WONT, so don't respond */ 102757416Smarkm break; 102857416Smarkm } 102957416Smarkm} 103057416Smarkm 103157416Smarkmstatic unsigned char str_lm_mode[] = { 103257416Smarkm IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 103357416Smarkm}; 103457416Smarkm 103557416Smarkmvoid 103657416Smarkmlm_mode(unsigned char *cmd, int len, int init) 103757416Smarkm{ 103857416Smarkm if (len != 1) 103957416Smarkm return; 104057416Smarkm if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 104157416Smarkm return; 104257416Smarkm if (*cmd&MODE_ACK) 104357416Smarkm return; 104457416Smarkm linemode = *cmd&(MODE_MASK&~MODE_ACK); 104557416Smarkm str_lm_mode[4] = linemode; 104657416Smarkm if (!init) 104757416Smarkm str_lm_mode[4] |= MODE_ACK; 104857416Smarkm if (NETROOM() > sizeof(str_lm_mode)) { 104957416Smarkm ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 105057416Smarkm printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 105157416Smarkm } 105257416Smarkm/*@*/ else printf("lm_mode: not enough room in buffer\n"); 105357416Smarkm setconnmode(0); /* set changed mode */ 105457416Smarkm} 105557416Smarkm 105657416Smarkm 105757416Smarkm 105857416Smarkm/* 105957416Smarkm * slc() 106057416Smarkm * Handle special character suboption of LINEMODE. 106157416Smarkm */ 106257416Smarkm 106357416Smarkmstruct spc { 106457416Smarkm cc_t val; 106557416Smarkm cc_t *valp; 106657416Smarkm char flags; /* Current flags & level */ 106757416Smarkm char mylevel; /* Maximum level & flags */ 106857416Smarkm} spc_data[NSLC+1]; 106957416Smarkm 107057416Smarkm#define SLC_IMPORT 0 107157416Smarkm#define SLC_EXPORT 1 107257416Smarkm#define SLC_RVALUE 2 107357416Smarkmstatic int slc_mode = SLC_EXPORT; 107457416Smarkm 107557416Smarkmvoid 107657416Smarkmslc_init() 107757416Smarkm{ 107857416Smarkm struct spc *spcp; 107957416Smarkm 108057416Smarkm localchars = 1; 108157416Smarkm for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 108257416Smarkm spcp->val = 0; 108357416Smarkm spcp->valp = 0; 108457416Smarkm spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 108557416Smarkm } 108657416Smarkm 108757416Smarkm#define initfunc(func, flags) { \ 108857416Smarkm spcp = &spc_data[func]; \ 108957416Smarkm if ((spcp->valp = tcval(func))) { \ 109057416Smarkm spcp->val = *spcp->valp; \ 109157416Smarkm spcp->mylevel = SLC_VARIABLE|flags; \ 109257416Smarkm } else { \ 109357416Smarkm spcp->val = 0; \ 109457416Smarkm spcp->mylevel = SLC_DEFAULT; \ 109557416Smarkm } \ 109657416Smarkm } 109757416Smarkm 109857416Smarkm initfunc(SLC_SYNCH, 0); 109957416Smarkm /* No BRK */ 110057416Smarkm initfunc(SLC_AO, 0); 110157416Smarkm initfunc(SLC_AYT, 0); 110257416Smarkm /* No EOR */ 110357416Smarkm initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 110457416Smarkm initfunc(SLC_EOF, 0); 110557416Smarkm initfunc(SLC_SUSP, SLC_FLUSHIN); 110657416Smarkm initfunc(SLC_EC, 0); 110757416Smarkm initfunc(SLC_EL, 0); 110857416Smarkm initfunc(SLC_EW, 0); 110957416Smarkm initfunc(SLC_RP, 0); 111057416Smarkm initfunc(SLC_LNEXT, 0); 111157416Smarkm initfunc(SLC_XON, 0); 111257416Smarkm initfunc(SLC_XOFF, 0); 111357416Smarkm initfunc(SLC_FORW1, 0); 111457416Smarkm initfunc(SLC_FORW2, 0); 111557416Smarkm /* No FORW2 */ 111657416Smarkm 111757416Smarkm initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 111857416Smarkm#undef initfunc 111957416Smarkm 112057416Smarkm if (slc_mode == SLC_EXPORT) 112157416Smarkm slc_export(); 112257416Smarkm else 112357416Smarkm slc_import(1); 112457416Smarkm 112557416Smarkm} 112657416Smarkm 112757416Smarkmvoid 112857416Smarkmslcstate() 112957416Smarkm{ 113057416Smarkm printf("Special characters are %s values\n", 113157416Smarkm slc_mode == SLC_IMPORT ? "remote default" : 113257416Smarkm slc_mode == SLC_EXPORT ? "local" : 113357416Smarkm "remote"); 113457416Smarkm} 113557416Smarkm 113657416Smarkmvoid 113757416Smarkmslc_mode_export() 113857416Smarkm{ 113957416Smarkm slc_mode = SLC_EXPORT; 114057416Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 114157416Smarkm slc_export(); 114257416Smarkm} 114357416Smarkm 114457416Smarkmvoid 114557416Smarkmslc_mode_import(int def) 114657416Smarkm{ 114757416Smarkm slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 114857416Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 114957416Smarkm slc_import(def); 115057416Smarkm} 115157416Smarkm 115257416Smarkmunsigned char slc_import_val[] = { 115357416Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 115457416Smarkm}; 115557416Smarkmunsigned char slc_import_def[] = { 115657416Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 115757416Smarkm}; 115857416Smarkm 115957416Smarkmvoid 116057416Smarkmslc_import(int def) 116157416Smarkm{ 116257416Smarkm if (NETROOM() > sizeof(slc_import_val)) { 116357416Smarkm if (def) { 116457416Smarkm ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 116557416Smarkm printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 116657416Smarkm } else { 116757416Smarkm ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 116857416Smarkm printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 116957416Smarkm } 117057416Smarkm } 117157416Smarkm/*@*/ else printf("slc_import: not enough room\n"); 117257416Smarkm} 117357416Smarkm 117457416Smarkmvoid 117557416Smarkmslc_export() 117657416Smarkm{ 117757416Smarkm struct spc *spcp; 117857416Smarkm 117957416Smarkm TerminalDefaultChars(); 118057416Smarkm 118157416Smarkm slc_start_reply(); 118257416Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 118357416Smarkm if (spcp->mylevel != SLC_NOSUPPORT) { 118457416Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 118557416Smarkm spcp->flags = SLC_NOSUPPORT; 118657416Smarkm else 118757416Smarkm spcp->flags = spcp->mylevel; 118857416Smarkm if (spcp->valp) 118957416Smarkm spcp->val = *spcp->valp; 119057416Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 119157416Smarkm } 119257416Smarkm } 119357416Smarkm slc_end_reply(); 119457416Smarkm slc_update(); 119557416Smarkm setconnmode(1); /* Make sure the character values are set */ 119657416Smarkm} 119757416Smarkm 119857416Smarkmvoid 119957416Smarkmslc(unsigned char *cp, int len) 120057416Smarkm{ 120157416Smarkm struct spc *spcp; 120257416Smarkm int func,level; 120357416Smarkm 120457416Smarkm slc_start_reply(); 120557416Smarkm 120657416Smarkm for (; len >= 3; len -=3, cp +=3) { 120757416Smarkm 120857416Smarkm func = cp[SLC_FUNC]; 120957416Smarkm 121057416Smarkm if (func == 0) { 121157416Smarkm /* 121257416Smarkm * Client side: always ignore 0 function. 121357416Smarkm */ 121457416Smarkm continue; 121557416Smarkm } 121657416Smarkm if (func > NSLC) { 121757416Smarkm if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 121857416Smarkm slc_add_reply(func, SLC_NOSUPPORT, 0); 121957416Smarkm continue; 122057416Smarkm } 122157416Smarkm 122257416Smarkm spcp = &spc_data[func]; 122357416Smarkm 122457416Smarkm level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 122557416Smarkm 122657416Smarkm if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 122757416Smarkm ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 122857416Smarkm continue; 122957416Smarkm } 123057416Smarkm 123157416Smarkm if (level == (SLC_DEFAULT|SLC_ACK)) { 123257416Smarkm /* 123357416Smarkm * This is an error condition, the SLC_ACK 123457416Smarkm * bit should never be set for the SLC_DEFAULT 123557416Smarkm * level. Our best guess to recover is to 123657416Smarkm * ignore the SLC_ACK bit. 123757416Smarkm */ 123857416Smarkm cp[SLC_FLAGS] &= ~SLC_ACK; 123957416Smarkm } 124057416Smarkm 124157416Smarkm if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 124257416Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 124357416Smarkm spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 124457416Smarkm continue; 124557416Smarkm } 124657416Smarkm 124757416Smarkm level &= ~SLC_ACK; 124857416Smarkm 124957416Smarkm if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 125057416Smarkm spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 125157416Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 125257416Smarkm } 125357416Smarkm if (level == SLC_DEFAULT) { 125457416Smarkm if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 125557416Smarkm spcp->flags = spcp->mylevel; 125657416Smarkm else 125757416Smarkm spcp->flags = SLC_NOSUPPORT; 125857416Smarkm } 125957416Smarkm slc_add_reply(func, spcp->flags, spcp->val); 126057416Smarkm } 126157416Smarkm slc_end_reply(); 126257416Smarkm if (slc_update()) 126357416Smarkm setconnmode(1); /* set the new character values */ 126457416Smarkm} 126557416Smarkm 126657416Smarkmvoid 126757416Smarkmslc_check() 126857416Smarkm{ 126957416Smarkm struct spc *spcp; 127057416Smarkm 127157416Smarkm slc_start_reply(); 127257416Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 127357416Smarkm if (spcp->valp && spcp->val != *spcp->valp) { 127457416Smarkm spcp->val = *spcp->valp; 127557416Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 127657416Smarkm spcp->flags = SLC_NOSUPPORT; 127757416Smarkm else 127857416Smarkm spcp->flags = spcp->mylevel; 127957416Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 128057416Smarkm } 128157416Smarkm } 128257416Smarkm slc_end_reply(); 128357416Smarkm setconnmode(1); 128457416Smarkm} 128557416Smarkm 128657416Smarkm 128757416Smarkmunsigned char slc_reply[128]; 128857416Smarkmunsigned char *slc_replyp; 128957416Smarkm 129057416Smarkmvoid 129157416Smarkmslc_start_reply() 129257416Smarkm{ 129357416Smarkm slc_replyp = slc_reply; 129457416Smarkm *slc_replyp++ = IAC; 129557416Smarkm *slc_replyp++ = SB; 129657416Smarkm *slc_replyp++ = TELOPT_LINEMODE; 129757416Smarkm *slc_replyp++ = LM_SLC; 129857416Smarkm} 129957416Smarkm 130057416Smarkmvoid 130157416Smarkmslc_add_reply(unsigned char func, unsigned char flags, cc_t value) 130257416Smarkm{ 130357416Smarkm if ((*slc_replyp++ = func) == IAC) 130457416Smarkm *slc_replyp++ = IAC; 130557416Smarkm if ((*slc_replyp++ = flags) == IAC) 130657416Smarkm *slc_replyp++ = IAC; 130757416Smarkm if ((*slc_replyp++ = (unsigned char)value) == IAC) 130857416Smarkm *slc_replyp++ = IAC; 130957416Smarkm} 131057416Smarkm 131157416Smarkmvoid 131257416Smarkmslc_end_reply() 131357416Smarkm{ 131457416Smarkm int len; 131557416Smarkm 131657416Smarkm *slc_replyp++ = IAC; 131757416Smarkm *slc_replyp++ = SE; 131857416Smarkm len = slc_replyp - slc_reply; 131957416Smarkm if (len <= 6) 132057416Smarkm return; 132157416Smarkm if (NETROOM() > len) { 132257416Smarkm ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 132357416Smarkm printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 132457416Smarkm } 132557416Smarkm/*@*/else printf("slc_end_reply: not enough room\n"); 132657416Smarkm} 132757416Smarkm 132857416Smarkmint 132957416Smarkmslc_update() 133057416Smarkm{ 133157416Smarkm struct spc *spcp; 133257416Smarkm int need_update = 0; 133357416Smarkm 133457416Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 133557416Smarkm if (!(spcp->flags&SLC_ACK)) 133657416Smarkm continue; 133757416Smarkm spcp->flags &= ~SLC_ACK; 133857416Smarkm if (spcp->valp && (*spcp->valp != spcp->val)) { 133957416Smarkm *spcp->valp = spcp->val; 134057416Smarkm need_update = 1; 134157416Smarkm } 134257416Smarkm } 134357416Smarkm return(need_update); 134457416Smarkm} 134557416Smarkm 134657416Smarkm#ifdef OLD_ENVIRON 134757416Smarkm# define old_env_var OLD_ENV_VAR 134857416Smarkm# define old_env_value OLD_ENV_VALUE 134957416Smarkm#endif 135057416Smarkm 135157416Smarkmvoid 135257416Smarkmenv_opt(unsigned char *buf, int len) 135357416Smarkm{ 135457416Smarkm unsigned char *ep = 0, *epc = 0; 135557416Smarkm int i; 135657416Smarkm 135757416Smarkm switch(buf[0]&0xff) { 135857416Smarkm case TELQUAL_SEND: 135957416Smarkm env_opt_start(); 136057416Smarkm if (len == 1) { 136157416Smarkm env_opt_add(NULL); 136257416Smarkm } else for (i = 1; i < len; i++) { 136357416Smarkm switch (buf[i]&0xff) { 136457416Smarkm#ifdef OLD_ENVIRON 136557416Smarkm case OLD_ENV_VAR: 136657416Smarkm case OLD_ENV_VALUE: 136757416Smarkm /* 136857416Smarkm * Although OLD_ENV_VALUE is not legal, we will 136957416Smarkm * still recognize it, just in case it is an 137057416Smarkm * old server that has VAR & VALUE mixed up... 137157416Smarkm */ 137257416Smarkm /* FALL THROUGH */ 137357416Smarkm#else 137457416Smarkm case NEW_ENV_VAR: 137557416Smarkm#endif 137657416Smarkm case ENV_USERVAR: 137757416Smarkm if (ep) { 137857416Smarkm *epc = 0; 137957416Smarkm env_opt_add(ep); 138057416Smarkm } 138157416Smarkm ep = epc = &buf[i+1]; 138257416Smarkm break; 138357416Smarkm case ENV_ESC: 138457416Smarkm i++; 138557416Smarkm /*FALL THROUGH*/ 138657416Smarkm default: 138757416Smarkm if (epc) 138857416Smarkm *epc++ = buf[i]; 138957416Smarkm break; 139057416Smarkm } 139157416Smarkm } 139257416Smarkm if (ep) { 139357416Smarkm *epc = 0; 139457416Smarkm env_opt_add(ep); 139557416Smarkm } 139657416Smarkm env_opt_end(1); 139757416Smarkm break; 139857416Smarkm 139957416Smarkm case TELQUAL_IS: 140057416Smarkm case TELQUAL_INFO: 140157416Smarkm /* Ignore for now. We shouldn't get it anyway. */ 140257416Smarkm break; 140357416Smarkm 140457416Smarkm default: 140557416Smarkm break; 140657416Smarkm } 140757416Smarkm} 140857416Smarkm 140957416Smarkm#define OPT_REPLY_SIZE 256 141057416Smarkmunsigned char *opt_reply; 141157416Smarkmunsigned char *opt_replyp; 141257416Smarkmunsigned char *opt_replyend; 141357416Smarkm 141457416Smarkmvoid 141557416Smarkmenv_opt_start() 141657416Smarkm{ 141757416Smarkm if (opt_reply) { 141857416Smarkm void *tmp = realloc (opt_reply, OPT_REPLY_SIZE); 141957416Smarkm if (tmp != NULL) { 142057416Smarkm opt_reply = tmp; 142157416Smarkm } else { 142257416Smarkm free (opt_reply); 142357416Smarkm opt_reply = NULL; 142457416Smarkm } 142557416Smarkm } else 142657416Smarkm opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 142757416Smarkm if (opt_reply == NULL) { 142857416Smarkm/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 142957416Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 143057416Smarkm return; 143157416Smarkm } 143257416Smarkm opt_replyp = opt_reply; 143357416Smarkm opt_replyend = opt_reply + OPT_REPLY_SIZE; 143457416Smarkm *opt_replyp++ = IAC; 143557416Smarkm *opt_replyp++ = SB; 143657416Smarkm *opt_replyp++ = telopt_environ; 143757416Smarkm *opt_replyp++ = TELQUAL_IS; 143857416Smarkm} 143957416Smarkm 144057416Smarkmvoid 144157416Smarkmenv_opt_start_info() 144257416Smarkm{ 144357416Smarkm env_opt_start(); 144457416Smarkm if (opt_replyp) 144557416Smarkm opt_replyp[-1] = TELQUAL_INFO; 144657416Smarkm} 144757416Smarkm 144857416Smarkmvoid 144957416Smarkmenv_opt_add(unsigned char *ep) 145057416Smarkm{ 145157416Smarkm unsigned char *vp, c; 145257416Smarkm 145357416Smarkm if (opt_reply == NULL) /*XXX*/ 145457416Smarkm return; /*XXX*/ 145557416Smarkm 145657416Smarkm if (ep == NULL || *ep == '\0') { 145757416Smarkm /* Send user defined variables first. */ 145857416Smarkm env_default(1, 0); 145957416Smarkm while ((ep = env_default(0, 0))) 146057416Smarkm env_opt_add(ep); 146157416Smarkm 146257416Smarkm /* Now add the list of well know variables. */ 146357416Smarkm env_default(1, 1); 146457416Smarkm while ((ep = env_default(0, 1))) 146557416Smarkm env_opt_add(ep); 146657416Smarkm return; 146757416Smarkm } 146857416Smarkm vp = env_getvalue(ep); 146957416Smarkm if (opt_replyp + (vp ? strlen((char *)vp) : 0) + 147057416Smarkm strlen((char *)ep) + 6 > opt_replyend) 147157416Smarkm { 147257416Smarkm int len; 147357416Smarkm void *tmp; 147457416Smarkm opt_replyend += OPT_REPLY_SIZE; 147557416Smarkm len = opt_replyend - opt_reply; 147657416Smarkm tmp = realloc(opt_reply, len); 147757416Smarkm if (tmp == NULL) { 147857416Smarkm/*@*/ printf("env_opt_add: realloc() failed!!!\n"); 147957416Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 148057416Smarkm return; 148157416Smarkm } 148257416Smarkm opt_reply = tmp; 148357416Smarkm opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 148457416Smarkm opt_replyend = opt_reply + len; 148557416Smarkm } 148657416Smarkm if (opt_welldefined((char *)ep)) { 148757416Smarkm#ifdef OLD_ENVIRON 148857416Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 148957416Smarkm *opt_replyp++ = old_env_var; 149057416Smarkm else 149157416Smarkm#endif 149257416Smarkm *opt_replyp++ = NEW_ENV_VAR; 149357416Smarkm } else 149457416Smarkm *opt_replyp++ = ENV_USERVAR; 149557416Smarkm for (;;) { 149657416Smarkm while ((c = *ep++)) { 149757416Smarkm switch(c&0xff) { 149857416Smarkm case IAC: 149957416Smarkm *opt_replyp++ = IAC; 150057416Smarkm break; 150157416Smarkm case NEW_ENV_VAR: 150257416Smarkm case NEW_ENV_VALUE: 150357416Smarkm case ENV_ESC: 150457416Smarkm case ENV_USERVAR: 150557416Smarkm *opt_replyp++ = ENV_ESC; 150657416Smarkm break; 150757416Smarkm } 150857416Smarkm *opt_replyp++ = c; 150957416Smarkm } 151057416Smarkm if ((ep = vp)) { 151157416Smarkm#ifdef OLD_ENVIRON 151257416Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 151357416Smarkm *opt_replyp++ = old_env_value; 151457416Smarkm else 151557416Smarkm#endif 151657416Smarkm *opt_replyp++ = NEW_ENV_VALUE; 151757416Smarkm vp = NULL; 151857416Smarkm } else 151957416Smarkm break; 152057416Smarkm } 152157416Smarkm} 152257416Smarkm 152357416Smarkmint 152457416Smarkmopt_welldefined(char *ep) 152557416Smarkm{ 152657416Smarkm if ((strcmp(ep, "USER") == 0) || 152757416Smarkm (strcmp(ep, "DISPLAY") == 0) || 152857416Smarkm (strcmp(ep, "PRINTER") == 0) || 152957416Smarkm (strcmp(ep, "SYSTEMTYPE") == 0) || 153057416Smarkm (strcmp(ep, "JOB") == 0) || 153157416Smarkm (strcmp(ep, "ACCT") == 0)) 153257416Smarkm return(1); 153357416Smarkm return(0); 153457416Smarkm} 153557416Smarkm 153657416Smarkmvoid 153757416Smarkmenv_opt_end(int emptyok) 153857416Smarkm{ 153957416Smarkm int len; 154057416Smarkm 154157416Smarkm len = opt_replyp - opt_reply + 2; 154257416Smarkm if (emptyok || len > 6) { 154357416Smarkm *opt_replyp++ = IAC; 154457416Smarkm *opt_replyp++ = SE; 154557416Smarkm if (NETROOM() > len) { 154657416Smarkm ring_supply_data(&netoring, opt_reply, len); 154757416Smarkm printsub('>', &opt_reply[2], len - 2); 154857416Smarkm } 154957416Smarkm/*@*/ else printf("slc_end_reply: not enough room\n"); 155057416Smarkm } 155157416Smarkm if (opt_reply) { 155257416Smarkm free(opt_reply); 155357416Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 155457416Smarkm } 155557416Smarkm} 155657416Smarkm 155757416Smarkm 155857416Smarkm 155957416Smarkmint 156057416Smarkmtelrcv(void) 156157416Smarkm{ 156257416Smarkm int c; 156357416Smarkm int scc; 156457416Smarkm unsigned char *sbp = NULL; 156557416Smarkm int count; 156657416Smarkm int returnValue = 0; 156757416Smarkm 156857416Smarkm scc = 0; 156957416Smarkm count = 0; 157057416Smarkm while (TTYROOM() > 2) { 157157416Smarkm if (scc == 0) { 157257416Smarkm if (count) { 157357416Smarkm ring_consumed(&netiring, count); 157457416Smarkm returnValue = 1; 157557416Smarkm count = 0; 157657416Smarkm } 157757416Smarkm sbp = netiring.consume; 157857416Smarkm scc = ring_full_consecutive(&netiring); 157957416Smarkm if (scc == 0) { 158057416Smarkm /* No more data coming in */ 158157416Smarkm break; 158257416Smarkm } 158357416Smarkm } 158457416Smarkm 158557416Smarkm c = *sbp++ & 0xff, scc--; count++; 158657416Smarkm#if defined(ENCRYPTION) 158757416Smarkm if (decrypt_input) 158857416Smarkm c = (*decrypt_input)(c); 158957416Smarkm#endif 159057416Smarkm 159157416Smarkm switch (telrcv_state) { 159257416Smarkm 159357416Smarkm case TS_CR: 159457416Smarkm telrcv_state = TS_DATA; 159557416Smarkm if (c == '\0') { 159657416Smarkm break; /* Ignore \0 after CR */ 159757416Smarkm } 159857416Smarkm else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 159957416Smarkm TTYADD(c); 160057416Smarkm break; 160157416Smarkm } 160257416Smarkm /* Else, fall through */ 160357416Smarkm 160457416Smarkm case TS_DATA: 160557416Smarkm if (c == IAC) { 160657416Smarkm telrcv_state = TS_IAC; 160757416Smarkm break; 160857416Smarkm } 160957416Smarkm /* 161057416Smarkm * The 'crmod' hack (see following) is needed 161157416Smarkm * since we can't set CRMOD on output only. 161257416Smarkm * Machines like MULTICS like to send \r without 161357416Smarkm * \n; since we must turn off CRMOD to get proper 161457416Smarkm * input, the mapping is done here (sigh). 161557416Smarkm */ 161657416Smarkm if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 161757416Smarkm if (scc > 0) { 161857416Smarkm c = *sbp&0xff; 161957416Smarkm#if defined(ENCRYPTION) 162057416Smarkm if (decrypt_input) 162157416Smarkm c = (*decrypt_input)(c); 162257416Smarkm#endif 162357416Smarkm if (c == 0) { 162457416Smarkm sbp++, scc--; count++; 162557416Smarkm /* a "true" CR */ 162657416Smarkm TTYADD('\r'); 162757416Smarkm } else if (my_want_state_is_dont(TELOPT_ECHO) && 162857416Smarkm (c == '\n')) { 162957416Smarkm sbp++, scc--; count++; 163057416Smarkm TTYADD('\n'); 163157416Smarkm } else { 163257416Smarkm#if defined(ENCRYPTION) 163357416Smarkm if (decrypt_input) 163457416Smarkm (*decrypt_input)(-1); 163557416Smarkm#endif 163657416Smarkm 163757416Smarkm TTYADD('\r'); 163857416Smarkm if (crmod) { 163957416Smarkm TTYADD('\n'); 164057416Smarkm } 164157416Smarkm } 164257416Smarkm } else { 164357416Smarkm telrcv_state = TS_CR; 164457416Smarkm TTYADD('\r'); 164557416Smarkm if (crmod) { 164657416Smarkm TTYADD('\n'); 164757416Smarkm } 164857416Smarkm } 164957416Smarkm } else { 165057416Smarkm TTYADD(c); 165157416Smarkm } 165257416Smarkm continue; 165357416Smarkm 165457416Smarkm case TS_IAC: 165557416Smarkmprocess_iac: 165657416Smarkm switch (c) { 165757416Smarkm 165857416Smarkm case WILL: 165957416Smarkm telrcv_state = TS_WILL; 166057416Smarkm continue; 166157416Smarkm 166257416Smarkm case WONT: 166357416Smarkm telrcv_state = TS_WONT; 166457416Smarkm continue; 166557416Smarkm 166657416Smarkm case DO: 166757416Smarkm telrcv_state = TS_DO; 166857416Smarkm continue; 166957416Smarkm 167057416Smarkm case DONT: 167157416Smarkm telrcv_state = TS_DONT; 167257416Smarkm continue; 167357416Smarkm 167457416Smarkm case DM: 167557416Smarkm /* 167657416Smarkm * We may have missed an urgent notification, 167757416Smarkm * so make sure we flush whatever is in the 167857416Smarkm * buffer currently. 167957416Smarkm */ 168057416Smarkm printoption("RCVD", IAC, DM); 168157416Smarkm SYNCHing = 1; 168257416Smarkm ttyflush(1); 168357416Smarkm SYNCHing = stilloob(); 168457416Smarkm settimer(gotDM); 168557416Smarkm break; 168657416Smarkm 168757416Smarkm case SB: 168857416Smarkm SB_CLEAR(); 168957416Smarkm telrcv_state = TS_SB; 169057416Smarkm continue; 169157416Smarkm 169257416Smarkm 169357416Smarkm case IAC: 169457416Smarkm TTYADD(IAC); 169557416Smarkm break; 169657416Smarkm 169757416Smarkm case NOP: 169857416Smarkm case GA: 169957416Smarkm default: 170057416Smarkm printoption("RCVD", IAC, c); 170157416Smarkm break; 170257416Smarkm } 170357416Smarkm telrcv_state = TS_DATA; 170457416Smarkm continue; 170557416Smarkm 170657416Smarkm case TS_WILL: 170757416Smarkm printoption("RCVD", WILL, c); 170857416Smarkm willoption(c); 170957416Smarkm telrcv_state = TS_DATA; 171057416Smarkm continue; 171157416Smarkm 171257416Smarkm case TS_WONT: 171357416Smarkm printoption("RCVD", WONT, c); 171457416Smarkm wontoption(c); 171557416Smarkm telrcv_state = TS_DATA; 171657416Smarkm continue; 171757416Smarkm 171857416Smarkm case TS_DO: 171957416Smarkm printoption("RCVD", DO, c); 172057416Smarkm dooption(c); 172157416Smarkm if (c == TELOPT_NAWS) { 172257416Smarkm sendnaws(); 172357416Smarkm } else if (c == TELOPT_LFLOW) { 172457416Smarkm localflow = 1; 172557416Smarkm setcommandmode(); 172657416Smarkm setconnmode(0); 172757416Smarkm } 172857416Smarkm telrcv_state = TS_DATA; 172957416Smarkm continue; 173057416Smarkm 173157416Smarkm case TS_DONT: 173257416Smarkm printoption("RCVD", DONT, c); 173357416Smarkm dontoption(c); 173457416Smarkm flushline = 1; 173557416Smarkm setconnmode(0); /* set new tty mode (maybe) */ 173657416Smarkm telrcv_state = TS_DATA; 173757416Smarkm continue; 173857416Smarkm 173957416Smarkm case TS_SB: 174057416Smarkm if (c == IAC) { 174157416Smarkm telrcv_state = TS_SE; 174257416Smarkm } else { 174357416Smarkm SB_ACCUM(c); 174457416Smarkm } 174557416Smarkm continue; 174657416Smarkm 174757416Smarkm case TS_SE: 174857416Smarkm if (c != SE) { 174957416Smarkm if (c != IAC) { 175057416Smarkm /* 175157416Smarkm * This is an error. We only expect to get 175257416Smarkm * "IAC IAC" or "IAC SE". Several things may 175357416Smarkm * have happend. An IAC was not doubled, the 175457416Smarkm * IAC SE was left off, or another option got 175557416Smarkm * inserted into the suboption are all possibilities. 175657416Smarkm * If we assume that the IAC was not doubled, 175757416Smarkm * and really the IAC SE was left off, we could 175857416Smarkm * get into an infinate loop here. So, instead, 175957416Smarkm * we terminate the suboption, and process the 176057416Smarkm * partial suboption if we can. 176157416Smarkm */ 176257416Smarkm SB_ACCUM(IAC); 176357416Smarkm SB_ACCUM(c); 176457416Smarkm subpointer -= 2; 176557416Smarkm SB_TERM(); 176657416Smarkm 176757416Smarkm printoption("In SUBOPTION processing, RCVD", IAC, c); 176857416Smarkm suboption(); /* handle sub-option */ 176957416Smarkm telrcv_state = TS_IAC; 177057416Smarkm goto process_iac; 177157416Smarkm } 177257416Smarkm SB_ACCUM(c); 177357416Smarkm telrcv_state = TS_SB; 177457416Smarkm } else { 177557416Smarkm SB_ACCUM(IAC); 177657416Smarkm SB_ACCUM(SE); 177757416Smarkm subpointer -= 2; 177857416Smarkm SB_TERM(); 177957416Smarkm suboption(); /* handle sub-option */ 178057416Smarkm telrcv_state = TS_DATA; 178157416Smarkm } 178257416Smarkm } 178357416Smarkm } 178457416Smarkm if (count) 178557416Smarkm ring_consumed(&netiring, count); 178657416Smarkm return returnValue||count; 178757416Smarkm} 178857416Smarkm 178957416Smarkmstatic int bol = 1, local = 0; 179057416Smarkm 179157416Smarkmint 179257416Smarkmrlogin_susp(void) 179357416Smarkm{ 179457416Smarkm if (local) { 179557416Smarkm local = 0; 179657416Smarkm bol = 1; 179757416Smarkm command(0, "z\n", 2); 179857416Smarkm return(1); 179957416Smarkm } 180057416Smarkm return(0); 180157416Smarkm} 180257416Smarkm 180357416Smarkmstatic int 180457416Smarkmtelsnd() 180557416Smarkm{ 180657416Smarkm int tcc; 180757416Smarkm int count; 180857416Smarkm int returnValue = 0; 180957416Smarkm unsigned char *tbp = NULL; 181057416Smarkm 181157416Smarkm tcc = 0; 181257416Smarkm count = 0; 181357416Smarkm while (NETROOM() > 2) { 181457416Smarkm int sc; 181557416Smarkm int c; 181657416Smarkm 181757416Smarkm if (tcc == 0) { 181857416Smarkm if (count) { 181957416Smarkm ring_consumed(&ttyiring, count); 182057416Smarkm returnValue = 1; 182157416Smarkm count = 0; 182257416Smarkm } 182357416Smarkm tbp = ttyiring.consume; 182457416Smarkm tcc = ring_full_consecutive(&ttyiring); 182557416Smarkm if (tcc == 0) { 182657416Smarkm break; 182757416Smarkm } 182857416Smarkm } 182957416Smarkm c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 183057416Smarkm if (rlogin != _POSIX_VDISABLE) { 183157416Smarkm if (bol) { 183257416Smarkm bol = 0; 183357416Smarkm if (sc == rlogin) { 183457416Smarkm local = 1; 183557416Smarkm continue; 183657416Smarkm } 183757416Smarkm } else if (local) { 183857416Smarkm local = 0; 183957416Smarkm if (sc == '.' || c == termEofChar) { 184057416Smarkm bol = 1; 184157416Smarkm command(0, "close\n", 6); 184257416Smarkm continue; 184357416Smarkm } 184457416Smarkm if (sc == termSuspChar) { 184557416Smarkm bol = 1; 184657416Smarkm command(0, "z\n", 2); 184757416Smarkm continue; 184857416Smarkm } 184957416Smarkm if (sc == escape) { 185057416Smarkm command(0, (char *)tbp, tcc); 185157416Smarkm bol = 1; 185257416Smarkm count += tcc; 185357416Smarkm tcc = 0; 185457416Smarkm flushline = 1; 185557416Smarkm break; 185657416Smarkm } 185757416Smarkm if (sc != rlogin) { 185857416Smarkm ++tcc; 185957416Smarkm --tbp; 186057416Smarkm --count; 186157416Smarkm c = sc = rlogin; 186257416Smarkm } 186357416Smarkm } 186457416Smarkm if ((sc == '\n') || (sc == '\r')) 186557416Smarkm bol = 1; 186657416Smarkm } else if (sc == escape) { 186757416Smarkm /* 186857416Smarkm * Double escape is a pass through of a single escape character. 186957416Smarkm */ 187057416Smarkm if (tcc && strip(*tbp) == escape) { 187157416Smarkm tbp++; 187257416Smarkm tcc--; 187357416Smarkm count++; 187457416Smarkm bol = 0; 187557416Smarkm } else { 187657416Smarkm command(0, (char *)tbp, tcc); 187757416Smarkm bol = 1; 187857416Smarkm count += tcc; 187957416Smarkm tcc = 0; 188057416Smarkm flushline = 1; 188157416Smarkm break; 188257416Smarkm } 188357416Smarkm } else 188457416Smarkm bol = 0; 188557416Smarkm#ifdef KLUDGELINEMODE 188657416Smarkm if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 188757416Smarkm if (tcc > 0 && strip(*tbp) == echoc) { 188857416Smarkm tcc--; tbp++; count++; 188957416Smarkm } else { 189057416Smarkm dontlecho = !dontlecho; 189157416Smarkm settimer(echotoggle); 189257416Smarkm setconnmode(0); 189357416Smarkm flushline = 1; 189457416Smarkm break; 189557416Smarkm } 189657416Smarkm } 189757416Smarkm#endif 189857416Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 189957416Smarkm if (TerminalSpecialChars(sc) == 0) { 190057416Smarkm bol = 1; 190157416Smarkm break; 190257416Smarkm } 190357416Smarkm } 190457416Smarkm if (my_want_state_is_wont(TELOPT_BINARY)) { 190557416Smarkm switch (c) { 190657416Smarkm case '\n': 190757416Smarkm /* 190857416Smarkm * If we are in CRMOD mode (\r ==> \n) 190957416Smarkm * on our local machine, then probably 191057416Smarkm * a newline (unix) is CRLF (TELNET). 191157416Smarkm */ 191257416Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 191357416Smarkm NETADD('\r'); 191457416Smarkm } 191557416Smarkm NETADD('\n'); 191657416Smarkm bol = flushline = 1; 191757416Smarkm break; 191857416Smarkm case '\r': 191957416Smarkm if (!crlf) { 192057416Smarkm NET2ADD('\r', '\0'); 192157416Smarkm } else { 192257416Smarkm NET2ADD('\r', '\n'); 192357416Smarkm } 192457416Smarkm bol = flushline = 1; 192557416Smarkm break; 192657416Smarkm case IAC: 192757416Smarkm NET2ADD(IAC, IAC); 192857416Smarkm break; 192957416Smarkm default: 193057416Smarkm NETADD(c); 193157416Smarkm break; 193257416Smarkm } 193357416Smarkm } else if (c == IAC) { 193457416Smarkm NET2ADD(IAC, IAC); 193557416Smarkm } else { 193657416Smarkm NETADD(c); 193757416Smarkm } 193857416Smarkm } 193957416Smarkm if (count) 194057416Smarkm ring_consumed(&ttyiring, count); 194157416Smarkm return returnValue||count; /* Non-zero if we did anything */ 194257416Smarkm} 194357416Smarkm 194457416Smarkm/* 194557416Smarkm * Scheduler() 194657416Smarkm * 194757416Smarkm * Try to do something. 194857416Smarkm * 194957416Smarkm * If we do something useful, return 1; else return 0. 195057416Smarkm * 195157416Smarkm */ 195257416Smarkm 195357416Smarkm 195457416Smarkmstatic int 195557416SmarkmScheduler(int block) /* should we block in the select ? */ 195657416Smarkm{ 195757416Smarkm /* One wants to be a bit careful about setting returnValue 195857416Smarkm * to one, since a one implies we did some useful work, 195957416Smarkm * and therefore probably won't be called to block next 196057416Smarkm * time (TN3270 mode only). 196157416Smarkm */ 196257416Smarkm int returnValue; 196357416Smarkm int netin, netout, netex, ttyin, ttyout; 196457416Smarkm 196557416Smarkm /* Decide which rings should be processed */ 196657416Smarkm 196757416Smarkm netout = ring_full_count(&netoring) && 196857416Smarkm (flushline || 196957416Smarkm (my_want_state_is_wont(TELOPT_LINEMODE) 197057416Smarkm#ifdef KLUDGELINEMODE 197157416Smarkm && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 197257416Smarkm#endif 197357416Smarkm ) || 197457416Smarkm my_want_state_is_will(TELOPT_BINARY)); 197557416Smarkm ttyout = ring_full_count(&ttyoring); 197657416Smarkm 197757416Smarkm ttyin = ring_empty_count(&ttyiring); 197857416Smarkm 197957416Smarkm netin = !ISend && ring_empty_count(&netiring); 198057416Smarkm 198157416Smarkm netex = !SYNCHing; 198257416Smarkm 198357416Smarkm /* If we have seen a signal recently, reset things */ 198457416Smarkm 198557416Smarkm /* Call to system code to process rings */ 198657416Smarkm 198757416Smarkm returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 198857416Smarkm 198957416Smarkm /* Now, look at the input rings, looking for work to do. */ 199057416Smarkm 199157416Smarkm if (ring_full_count(&ttyiring)) { 199257416Smarkm returnValue |= telsnd(); 199357416Smarkm } 199457416Smarkm 199557416Smarkm if (ring_full_count(&netiring)) { 199657416Smarkm returnValue |= telrcv(); 199757416Smarkm } 199857416Smarkm return returnValue; 199957416Smarkm} 200057416Smarkm 200157416Smarkm/* 200257416Smarkm * Select from tty and network... 200357416Smarkm */ 200457416Smarkmvoid 200557416Smarkmmy_telnet(char *user) 200657416Smarkm{ 200757416Smarkm sys_telnet_init(); 200857416Smarkm 200957416Smarkm#if defined(AUTHENTICATION) || defined(ENCRYPTION) 201057416Smarkm { 201157416Smarkm static char local_host[256] = { 0 }; 201257416Smarkm 201357416Smarkm if (!local_host[0]) { 201457416Smarkm /* XXX - should be k_gethostname? */ 201557416Smarkm gethostname(local_host, sizeof(local_host)); 201657416Smarkm local_host[sizeof(local_host)-1] = 0; 201757416Smarkm } 201857416Smarkm auth_encrypt_init(local_host, hostname, "TELNET", 0); 201957416Smarkm auth_encrypt_user(user); 202057416Smarkm } 202157416Smarkm#endif 202257416Smarkm if (telnetport) { 202357416Smarkm#if defined(AUTHENTICATION) 202457416Smarkm if (autologin) 202557416Smarkm send_will(TELOPT_AUTHENTICATION, 1); 202657416Smarkm#endif 202757416Smarkm#if defined(ENCRYPTION) 202857416Smarkm send_do(TELOPT_ENCRYPT, 1); 202957416Smarkm send_will(TELOPT_ENCRYPT, 1); 203057416Smarkm#endif 203157416Smarkm send_do(TELOPT_SGA, 1); 203257416Smarkm send_will(TELOPT_TTYPE, 1); 203357416Smarkm send_will(TELOPT_NAWS, 1); 203457416Smarkm send_will(TELOPT_TSPEED, 1); 203557416Smarkm send_will(TELOPT_LFLOW, 1); 203657416Smarkm send_will(TELOPT_LINEMODE, 1); 203757416Smarkm send_will(TELOPT_NEW_ENVIRON, 1); 203857416Smarkm send_do(TELOPT_STATUS, 1); 203957416Smarkm if (env_getvalue((unsigned char *)"DISPLAY")) 204057416Smarkm send_will(TELOPT_XDISPLOC, 1); 204157416Smarkm if (binary) 204257416Smarkm tel_enter_binary(binary); 204357416Smarkm } 204457416Smarkm 204557416Smarkm for (;;) { 204657416Smarkm int schedValue; 204757416Smarkm 204857416Smarkm while ((schedValue = Scheduler(0)) != 0) { 204957416Smarkm if (schedValue == -1) { 205057416Smarkm setcommandmode(); 205157416Smarkm return; 205257416Smarkm } 205357416Smarkm } 205457416Smarkm 205557416Smarkm if (Scheduler(1) == -1) { 205657416Smarkm setcommandmode(); 205757416Smarkm return; 205857416Smarkm } 205957416Smarkm } 206057416Smarkm} 206157416Smarkm 206257416Smarkm/* 206357416Smarkm * netclear() 206457416Smarkm * 206557416Smarkm * We are about to do a TELNET SYNCH operation. Clear 206657416Smarkm * the path to the network. 206757416Smarkm * 206857416Smarkm * Things are a bit tricky since we may have sent the first 206957416Smarkm * byte or so of a previous TELNET command into the network. 207057416Smarkm * So, we have to scan the network buffer from the beginning 207157416Smarkm * until we are up to where we want to be. 207257416Smarkm * 207357416Smarkm * A side effect of what we do, just to keep things 207457416Smarkm * simple, is to clear the urgent data pointer. The principal 207557416Smarkm * caller should be setting the urgent data pointer AFTER calling 207657416Smarkm * us in any case. 207757416Smarkm */ 207857416Smarkm 207957416Smarkmstatic void 208057416Smarkmnetclear() 208157416Smarkm{ 208257416Smarkm#if 0 /* XXX */ 208357416Smarkm char *thisitem, *next; 208457416Smarkm char *good; 208557416Smarkm#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 208657416Smarkm ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 208757416Smarkm 208857416Smarkm thisitem = netobuf; 208957416Smarkm 209057416Smarkm while ((next = nextitem(thisitem)) <= netobuf.send) { 209157416Smarkm thisitem = next; 209257416Smarkm } 209357416Smarkm 209457416Smarkm /* Now, thisitem is first before/at boundary. */ 209557416Smarkm 209657416Smarkm good = netobuf; /* where the good bytes go */ 209757416Smarkm 209857416Smarkm while (netoring.add > thisitem) { 209957416Smarkm if (wewant(thisitem)) { 210057416Smarkm int length; 210157416Smarkm 210257416Smarkm next = thisitem; 210357416Smarkm do { 210457416Smarkm next = nextitem(next); 210557416Smarkm } while (wewant(next) && (nfrontp > next)); 210657416Smarkm length = next-thisitem; 210757416Smarkm memmove(good, thisitem, length); 210857416Smarkm good += length; 210957416Smarkm thisitem = next; 211057416Smarkm } else { 211157416Smarkm thisitem = nextitem(thisitem); 211257416Smarkm } 211357416Smarkm } 211457416Smarkm 211557416Smarkm#endif /* 0 */ 211657416Smarkm} 211757416Smarkm 211857416Smarkm/* 211957416Smarkm * These routines add various telnet commands to the data stream. 212057416Smarkm */ 212157416Smarkm 212257416Smarkmstatic void 212357416Smarkmdoflush() 212457416Smarkm{ 212557416Smarkm NET2ADD(IAC, DO); 212657416Smarkm NETADD(TELOPT_TM); 212757416Smarkm flushline = 1; 212857416Smarkm flushout = 1; 212957416Smarkm ttyflush(1); /* Flush/drop output */ 213057416Smarkm /* do printoption AFTER flush, otherwise the output gets tossed... */ 213157416Smarkm printoption("SENT", DO, TELOPT_TM); 213257416Smarkm} 213357416Smarkm 213457416Smarkmvoid 213557416SmarkmxmitAO(void) 213657416Smarkm{ 213757416Smarkm NET2ADD(IAC, AO); 213857416Smarkm printoption("SENT", IAC, AO); 213957416Smarkm if (autoflush) { 214057416Smarkm doflush(); 214157416Smarkm } 214257416Smarkm} 214357416Smarkm 214457416Smarkm 214557416Smarkmvoid 214657416SmarkmxmitEL(void) 214757416Smarkm{ 214857416Smarkm NET2ADD(IAC, EL); 214957416Smarkm printoption("SENT", IAC, EL); 215057416Smarkm} 215157416Smarkm 215257416Smarkmvoid 215357416SmarkmxmitEC(void) 215457416Smarkm{ 215557416Smarkm NET2ADD(IAC, EC); 215657416Smarkm printoption("SENT", IAC, EC); 215757416Smarkm} 215857416Smarkm 215957416Smarkm 216057416Smarkmint 216157416Smarkmdosynch() 216257416Smarkm{ 216357416Smarkm netclear(); /* clear the path to the network */ 216457416Smarkm NETADD(IAC); 216557416Smarkm setneturg(); 216657416Smarkm NETADD(DM); 216757416Smarkm printoption("SENT", IAC, DM); 216857416Smarkm return 1; 216957416Smarkm} 217057416Smarkm 217157416Smarkmint want_status_response = 0; 217257416Smarkm 217357416Smarkmint 217457416Smarkmget_status() 217557416Smarkm{ 217657416Smarkm unsigned char tmp[16]; 217757416Smarkm unsigned char *cp; 217857416Smarkm 217957416Smarkm if (my_want_state_is_dont(TELOPT_STATUS)) { 218057416Smarkm printf("Remote side does not support STATUS option\n"); 218157416Smarkm return 0; 218257416Smarkm } 218357416Smarkm cp = tmp; 218457416Smarkm 218557416Smarkm *cp++ = IAC; 218657416Smarkm *cp++ = SB; 218757416Smarkm *cp++ = TELOPT_STATUS; 218857416Smarkm *cp++ = TELQUAL_SEND; 218957416Smarkm *cp++ = IAC; 219057416Smarkm *cp++ = SE; 219157416Smarkm if (NETROOM() >= cp - tmp) { 219257416Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 219357416Smarkm printsub('>', tmp+2, cp - tmp - 2); 219457416Smarkm } 219557416Smarkm ++want_status_response; 219657416Smarkm return 1; 219757416Smarkm} 219857416Smarkm 219957416Smarkmvoid 220057416Smarkmintp(void) 220157416Smarkm{ 220257416Smarkm NET2ADD(IAC, IP); 220357416Smarkm printoption("SENT", IAC, IP); 220457416Smarkm flushline = 1; 220557416Smarkm if (autoflush) { 220657416Smarkm doflush(); 220757416Smarkm } 220857416Smarkm if (autosynch) { 220957416Smarkm dosynch(); 221057416Smarkm } 221157416Smarkm} 221257416Smarkm 221357416Smarkmvoid 221457416Smarkmsendbrk(void) 221557416Smarkm{ 221657416Smarkm NET2ADD(IAC, BREAK); 221757416Smarkm printoption("SENT", IAC, BREAK); 221857416Smarkm flushline = 1; 221957416Smarkm if (autoflush) { 222057416Smarkm doflush(); 222157416Smarkm } 222257416Smarkm if (autosynch) { 222357416Smarkm dosynch(); 222457416Smarkm } 222557416Smarkm} 222657416Smarkm 222757416Smarkmvoid 222857416Smarkmsendabort(void) 222957416Smarkm{ 223057416Smarkm NET2ADD(IAC, ABORT); 223157416Smarkm printoption("SENT", IAC, ABORT); 223257416Smarkm flushline = 1; 223357416Smarkm if (autoflush) { 223457416Smarkm doflush(); 223557416Smarkm } 223657416Smarkm if (autosynch) { 223757416Smarkm dosynch(); 223857416Smarkm } 223957416Smarkm} 224057416Smarkm 224157416Smarkmvoid 224257416Smarkmsendsusp(void) 224357416Smarkm{ 224457416Smarkm NET2ADD(IAC, SUSP); 224557416Smarkm printoption("SENT", IAC, SUSP); 224657416Smarkm flushline = 1; 224757416Smarkm if (autoflush) { 224857416Smarkm doflush(); 224957416Smarkm } 225057416Smarkm if (autosynch) { 225157416Smarkm dosynch(); 225257416Smarkm } 225357416Smarkm} 225457416Smarkm 225557416Smarkmvoid 225657416Smarkmsendeof(void) 225757416Smarkm{ 225857416Smarkm NET2ADD(IAC, xEOF); 225957416Smarkm printoption("SENT", IAC, xEOF); 226057416Smarkm} 226157416Smarkm 226257416Smarkmvoid 226357416Smarkmsendayt(void) 226457416Smarkm{ 226557416Smarkm NET2ADD(IAC, AYT); 226657416Smarkm printoption("SENT", IAC, AYT); 226757416Smarkm} 226857416Smarkm 226957416Smarkm/* 227057416Smarkm * Send a window size update to the remote system. 227157416Smarkm */ 227257416Smarkm 227357416Smarkmvoid 227457416Smarkmsendnaws() 227557416Smarkm{ 227657416Smarkm long rows, cols; 227757416Smarkm unsigned char tmp[16]; 227857416Smarkm unsigned char *cp; 227957416Smarkm 228057416Smarkm if (my_state_is_wont(TELOPT_NAWS)) 228157416Smarkm return; 228257416Smarkm 228357416Smarkm#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 228457416Smarkm if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 228557416Smarkm 228657416Smarkm if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 228757416Smarkm return; 228857416Smarkm } 228957416Smarkm 229057416Smarkm cp = tmp; 229157416Smarkm 229257416Smarkm *cp++ = IAC; 229357416Smarkm *cp++ = SB; 229457416Smarkm *cp++ = TELOPT_NAWS; 229557416Smarkm PUTSHORT(cp, cols); 229657416Smarkm PUTSHORT(cp, rows); 229757416Smarkm *cp++ = IAC; 229857416Smarkm *cp++ = SE; 229957416Smarkm if (NETROOM() >= cp - tmp) { 230057416Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 230157416Smarkm printsub('>', tmp+2, cp - tmp - 2); 230257416Smarkm } 230357416Smarkm} 230457416Smarkm 230557416Smarkmvoid 230657416Smarkmtel_enter_binary(int rw) 230757416Smarkm{ 230857416Smarkm if (rw&1) 230957416Smarkm send_do(TELOPT_BINARY, 1); 231057416Smarkm if (rw&2) 231157416Smarkm send_will(TELOPT_BINARY, 1); 231257416Smarkm} 231357416Smarkm 231457416Smarkmvoid 231557416Smarkmtel_leave_binary(int rw) 231657416Smarkm{ 231757416Smarkm if (rw&1) 231857416Smarkm send_dont(TELOPT_BINARY, 1); 231957416Smarkm if (rw&2) 232057416Smarkm send_wont(TELOPT_BINARY, 1); 232157416Smarkm} 2322