⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 telnet.c

📁 经典的unix下telnet的c代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*	$OpenBSD: telnet.c,v 1.18 2003/11/08 19:17:29 jmc Exp $	*//*	$NetBSD: telnet.c,v 1.7 1996/02/28 21:04:15 thorpej Exp $	*//* * Copyright (c) 1988, 1990, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "telnet_locl.h"#include <curses.h>#include <term.h>#define        strip(x) (eight ? (x) : ((x) & 0x7f))static unsigned char	subbuffer[SUBBUFSIZE],			*subpointer, *subend;	 /* buffer for sub-options */#define	SB_CLEAR()	subpointer = subbuffer;#define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }#define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \				*subpointer++ = (c); \			}#define	SB_GET()	((*subpointer++)&0xff)#define	SB_PEEK()	((*subpointer)&0xff)#define	SB_EOF()	(subpointer >= subend)#define	SB_LEN()	(subend - subpointer)char	options[256];		/* The combined options */char	do_dont_resp[256];char	will_wont_resp[256];int	eight = 3,	binary = 0,	autologin = 0,	/* Autologin anyone? */	skiprc = 0,	connected,	showoptions,	In3270,		/* Are we in 3270 mode? */	ISend,		/* trying to send network data in */	debug = 0,	crmod,	netdata,	/* Print out network data flow */	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */#if	defined(TN3270)	noasynchtty = 0,/* User specified "-noasynch" on command line */	noasynchnet = 0,/* User specified "-noasynch" on command line */	askedSGA = 0,	/* We have talked about suppress go ahead */#endif	/* defined(TN3270) */	telnetport,	wantencryption = 0,	SYNCHing,	/* we are in TELNET SYNCH mode */	flushout,	/* flush output */	autoflush = 0,	/* flush output when interrupting? */	autosynch,	/* send interrupt characters with SYNCH? */	localflow,	/* we handle flow control locally */	restartany,	/* if flow control enabled, restart on any character */	localchars,	/* we recognize interrupt/quit */	donelclchars,	/* the user has set "localchars" */	donebinarytoggle,	/* the user has put us in binary */	dontlecho,	/* do we suppress local echoing right now? */	globalmode,	clienteof = 0;char *prompt = 0;int scheduler_lockout_tty = 0;cc_t escape;cc_t rlogin;#ifdef	KLUDGELINEMODEcc_t echoc;#endif/* * Telnet receiver states for fsm */#define	TS_DATA		0#define	TS_IAC		1#define	TS_WILL		2#define	TS_WONT		3#define	TS_DO		4#define	TS_DONT		5#define	TS_CR		6#define	TS_SB		7		/* sub-option collection */#define	TS_SE		8		/* looking for sub-option end */static int	telrcv_state;#ifdef	OLD_ENVIRONunsigned char telopt_environ = TELOPT_NEW_ENVIRON;#else# define telopt_environ TELOPT_NEW_ENVIRON#endifjmp_buf	toplevel = { 0 };jmp_buf	peerdied;int	flushline;int	linemode;#ifdef	KLUDGELINEMODEint	kludgelinemode = 1;#endif/* * The following are some clocks used to decide how to interpret * the relationship between various variables. */Clocks clocks;/* * Initialize telnet environment. */    voidinit_telnet(){    env_init();    SB_CLEAR();    memset((char *)options, 0, sizeof options);    connected = In3270 = ISend = localflow = donebinarytoggle = 0;#if	defined(AUTHENTICATION) || defined(ENCRYPTION)    auth_encrypt_connect(connected);#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */    restartany = -1;    SYNCHing = 0;    /* Don't change NetTrace */    escape = CONTROL(']');    rlogin = _POSIX_VDISABLE;#ifdef	KLUDGELINEMODE    echoc = CONTROL('E');#endif    flushline = 1;    telrcv_state = TS_DATA;}/* * These routines are in charge of sending option negotiations * to the other side. * * The basic idea is that we send the negotiation if either side * is in disagreement as to what the current state should be. */    voidsend_do(c, init)    int c, init;{    if (init) {	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||				my_want_state_is_do(c))	    return;	set_my_want_state_do(c);	do_dont_resp[c]++;    }    NET2ADD(IAC, DO);    NETADD(c);    printoption("SENT",DO, c);}    voidsend_dont(c, init)    int c, init;{    if (init) {	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||				my_want_state_is_dont(c))	    return;	set_my_want_state_dont(c);	do_dont_resp[c]++;    }    NET2ADD(IAC, DONT);    NETADD(c);    printoption("SENT", DONT, c);}    voidsend_will(c, init)    int c, init;{    if (init) {	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||				my_want_state_is_will(c))	    return;	set_my_want_state_will(c);	will_wont_resp[c]++;    }    NET2ADD(IAC, WILL);    NETADD(c);    printoption("SENT", WILL, c);}    voidsend_wont(c, init)    int c, init;{    if (init) {	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||				my_want_state_is_wont(c))	    return;	set_my_want_state_wont(c);	will_wont_resp[c]++;    }    NET2ADD(IAC, WONT);    NETADD(c);    printoption("SENT", WONT, c);}	voidwilloption(option)	int option;{	int new_state_ok = 0;	if (do_dont_resp[option]) {	    --do_dont_resp[option];	    if (do_dont_resp[option] && my_state_is_do(option))		--do_dont_resp[option];	}	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {	    switch (option) {	    case TELOPT_ECHO:#	    if defined(TN3270)		/*		 * The following is a pain in the rear-end.		 * Various IBM servers (some versions of Wiscnet,		 * possibly Fibronics/Spartacus, and who knows who		 * else) will NOT allow us to send "DO SGA" too early		 * in the setup proceedings.  On the other hand,		 * 4.2 servers (telnetd) won't set SGA correctly.		 * So, we are stuck.  Empirically (but, based on		 * a VERY small sample), the IBM servers don't send		 * out anything about ECHO, so we postpone our sending		 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers		 * DO send).		  */		{		    if (askedSGA == 0) {			askedSGA = 1;			if (my_want_state_is_dont(TELOPT_SGA))			    send_do(TELOPT_SGA, 1);		    }		}		    /* Fall through */	    case TELOPT_EOR:#endif	    /* defined(TN3270) */	    case TELOPT_BINARY:	    case TELOPT_SGA:		settimer(modenegotiated);		/* FALL THROUGH */	    case TELOPT_STATUS:#if	defined(AUTHENTICATION)	    case TELOPT_AUTHENTICATION:#endif#if    defined(ENCRYPTION)	    case TELOPT_ENCRYPT:#endif		new_state_ok = 1;		break;	    case TELOPT_TM:		if (flushout)		    flushout = 0;		/*		 * Special case for TM.  If we get back a WILL,		 * pretend we got back a WONT.		 */		set_my_want_state_dont(option);		set_my_state_dont(option);		return;			/* Never reply to TM will's/wont's */	    case TELOPT_LINEMODE:	    default:		break;	    }	    if (new_state_ok) {		set_my_want_state_do(option);		send_do(option, 0);		setconnmode(0);		/* possibly set new tty mode */	    } else {		do_dont_resp[option]++;		send_dont(option, 0);	    }	}	set_my_state_do(option);#if    defined(ENCRYPTION)	if (option == TELOPT_ENCRYPT)		encrypt_send_support();#endif}	voidwontoption(option)	int option;{	if (do_dont_resp[option]) {	    --do_dont_resp[option];	    if (do_dont_resp[option] && my_state_is_dont(option))		--do_dont_resp[option];	}	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {	    switch (option) {#ifdef	KLUDGELINEMODE	    case TELOPT_SGA:		if (!kludgelinemode)		    break;		/* FALL THROUGH */#endif	    case TELOPT_ECHO:		settimer(modenegotiated);		break;	    case TELOPT_TM:		if (flushout)		    flushout = 0;		set_my_want_state_dont(option);		set_my_state_dont(option);		return;		/* Never reply to TM will's/wont's */#ifdef ENCRYPTION	    case TELOPT_ENCRYPT:		encrypt_not();		break;#endif	    default:		break;	    }	    set_my_want_state_dont(option);	    if (my_state_is_do(option))		send_dont(option, 0);	    setconnmode(0);			/* Set new tty mode */	} else if (option == TELOPT_TM) {	    /*	     * Special case for TM.	     */	    if (flushout)		flushout = 0;	    set_my_want_state_dont(option);	}	set_my_state_dont(option);}	static voiddooption(option)	int option;{	int new_state_ok = 0;	if (will_wont_resp[option]) {	    --will_wont_resp[option];	    if (will_wont_resp[option] && my_state_is_will(option))		--will_wont_resp[option];	}	if (will_wont_resp[option] == 0) {	  if (my_want_state_is_wont(option)) {	    switch (option) {	    case TELOPT_TM:		/*		 * Special case for TM.  We send a WILL, but pretend		 * we sent WONT.		 */		send_will(option, 0);		set_my_want_state_wont(TELOPT_TM);		set_my_state_wont(TELOPT_TM);		return;#	if defined(TN3270)	    case TELOPT_EOR:		/* end of record */#	endif	/* defined(TN3270) */	    case TELOPT_BINARY:		/* binary mode */	    case TELOPT_NAWS:		/* window size */	    case TELOPT_TSPEED:		/* terminal speed */	    case TELOPT_LFLOW:		/* local flow control */	    case TELOPT_TTYPE:		/* terminal type option */	    case TELOPT_SGA:		/* no big deal */#if    defined(ENCRYPTION)	    case TELOPT_ENCRYPT:        /* encryption variable option */#endif		new_state_ok = 1;		break;	    case TELOPT_NEW_ENVIRON:	/* New environment variable option */#ifdef	OLD_ENVIRON		if (my_state_is_will(TELOPT_OLD_ENVIRON))			send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */		goto env_common;	    case TELOPT_OLD_ENVIRON:	/* Old environment variable option */		if (my_state_is_will(TELOPT_NEW_ENVIRON))			break;		/* Don't enable if new one is in use! */	    env_common:		telopt_environ = option;#endif		new_state_ok = 1;		break;#if	defined(AUTHENTICATION)	    case TELOPT_AUTHENTICATION:		if (autologin)			new_state_ok = 1;		break;#endif	    case TELOPT_XDISPLOC:	/* X Display location */		if (env_getvalue((unsigned char *)"DISPLAY"))		    new_state_ok = 1;		break;	    case TELOPT_LINEMODE:#ifdef	KLUDGELINEMODE		kludgelinemode = 0;		send_do(TELOPT_SGA, 1);#endif		set_my_want_state_will(TELOPT_LINEMODE);		send_will(option, 0);		set_my_state_will(TELOPT_LINEMODE);		slc_init();		return;	    case TELOPT_ECHO:		/* We're never going to echo... */	    default:		break;	    }	    if (new_state_ok) {		set_my_want_state_will(option);		send_will(option, 0);		setconnmode(0);			/* Set new tty mode */	    } else {		will_wont_resp[option]++;		send_wont(option, 0);	    }	  } else {	    /*	     * Handle options that need more things done after the	     * other side has acknowledged the option.	     */	    switch (option) {	    case TELOPT_LINEMODE:#ifdef	KLUDGELINEMODE		kludgelinemode = 0;		send_do(TELOPT_SGA, 1);#endif		set_my_state_will(option);		slc_init();		send_do(TELOPT_SGA, 0);		return;	    }	  }	}	set_my_state_will(option);}	static voiddontoption(option)	int option;{	if (will_wont_resp[option]) {	    --will_wont_resp[option];	    if (will_wont_resp[option] && my_state_is_wont(option))		--will_wont_resp[option];	}	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {	    switch (option) {	    case TELOPT_LINEMODE:		linemode = 0;	/* put us back to the default state */		break;#ifdef	OLD_ENVIRON	    case TELOPT_NEW_ENVIRON:		/*		 * The new environ option wasn't recognized, try		 * the old one.		 */		send_will(TELOPT_OLD_ENVIRON, 1);		telopt_environ = TELOPT_OLD_ENVIRON;		break;#endif	    }	    /* we always accept a DONT */	    set_my_want_state_wont(option);	    if (my_state_is_will(option))		send_wont(option, 0);	    setconnmode(0);			/* Set new tty mode */	}	set_my_state_wont(option);}/* * This routine will turn a pipe separated list of names in the buffer * into an array of pointers to NUL terminated names.  We toss out any * bad, duplicate, or verbose names (names with spaces). */int is_unique(char *, char **, char **);static char *name_unknown = "UNKNOWN";static char *unknown[] = { 0, 0 };	char **mklist(buf, name)	char *buf, *name;{	int n;	char c, *cp, **argvp, *cp2, **argv, **avt;	if (name) {		if ((int)strlen(name) > 40) {			name = 0;			unknown[0] = name_unknown;		} else {			unknown[0] = name;			upcase(name);		}	} else		unknown[0] = name_unknown;	/*	 * Count up the number of names.	 */	for (n = 1, cp = buf; *cp; cp++) {		if (*cp == '|')			n++;	}	/*	 * Allocate an array to put the name pointers into	 */	argv = (char **)malloc((n+3)*sizeof(char *));	if (argv == 0)		return(unknown);	/*	 * Fill up the array of pointers to names.	 */	*argv = 0;	argvp = argv+1;	n = 0;	for (cp = cp2 = buf; (c = *cp);  cp++) {		if (c == '|' || c == ':') {			*cp++ = '\0';			/*			 * Skip entries that have spaces or are over 40			 * characters long.  If this is our environment			 * name, then put it up front.  Otherwise, as			 * long as this is not a duplicate name (case			 * insensitive) add it to the list.			 */			if (n || (cp - cp2 > 41))				;			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))				*argv = cp2;			else if (is_unique(cp2, argv+1, argvp))				*argvp++ = cp2;			if (c == ':')				break;			/*			 * Skip multiple delimiters. Reset cp2 to			 * the beginning of the next name. Reset n,			 * the flag for names with spaces.			 */			while ((c = *cp) == '|')				cp++;			cp2 = cp;			n = 0;		}		/*		 * Skip entries with spaces or non-ascii values.		 * Convert lower case letters to upper case.		 */#define ISASCII(c) (!((c)&0x80))		if ((c == ' ') || !ISASCII(c))			n = 1;		else if (islower(c))			*cp = toupper(c);	}	/*	 * Check for an old V6 2 character name.  If the second	 * name points to the beginning of the buffer, and is	 * only 2 characters long, move it to the end of the array.	 */	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {		--argvp;		for (avt = &argv[1]; avt < argvp; avt++)			*avt = *(avt+1);		*argvp++ = buf;	}	/*	 * Duplicate last name, for TTYPE option, and null	 * terminate the array.  If we didn't find a match on	 * our terminal name, put that name at the beginning.	 */	cp = *(argvp-1);	*argvp++ = cp;	*argvp = 0;	if (*argv == 0) {		if (name)			*argv = name;		else {			--argvp;			for (avt = argv; avt < argvp; avt++)				*avt = *(avt+1);		}	}	if (*argv)		return(argv);	else		return(unknown);}	intis_unique(name, as, ae)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -