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