* initial revision
* Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen
* <andersen@lineo.com>
+ * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
+ * <jam@ltsp.org>
*
*/
-#warning This applet has moved to netkit-tiny. After BusyBox 0.49, this
-#warning applet will be removed from BusyBox. All maintenance efforts
-#warning should be done in the netkit-tiny source tree.
-
-
-#include "busybox.h"
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
+#include "busybox.h"
#if 0
static const int DOTRACE = 1;
#include <sys/time.h>
#endif
-static const int DATABUFSIZE = 128;
-static const int IACBUFSIZE = 128;
+#define DATABUFSIZE 128
+#define IACBUFSIZE 128
static const int CHM_TRY = 0;
static const int CHM_ON = 1;
typedef unsigned char byte;
/* use globals to reduce size ??? */ /* test this hypothesis later */
-struct Globalvars {
+static struct Globalvars {
int netfd; /* console fd:s are 0 and 1 (and 2) */
/* same buffer used both for network and console read/write */
- char * buf; /* allocating so static size is smaller */
- short len;
+ char buf[DATABUFSIZE]; /* allocating so static size is smaller */
byte telstate; /* telnet negotiation state from network input */
byte telwish; /* DO, DONT, WILL, WONT */
byte charmode;
byte telflags;
byte gotsig;
/* buffer to handle telnet negotiations */
- char * iacbuf;
+ char iacbuf[IACBUFSIZE];
short iaclen; /* could even use byte */
struct termios termios_def;
struct termios termios_raw;
struct Globalvars * Gptr;
#define G (*Gptr)
#else
-struct Globalvars G;
+static struct Globalvars G;
#endif
static inline void iacflush()
/* Some globals */
static int one = 1;
+#ifdef BB_FEATURE_TELNET_TTYPE
+static char *ttype;
+#endif
+
static void doexit(int ev)
{
cookmode();
G.gotsig = 0;
}
-static void handlenetoutput()
+static void handlenetoutput(int len)
{
/* here we could do smart tricks how to handle 0xFF:s in output
* stream like writing twice every sequence of FF:s (thus doing
int i;
byte * p = G.buf;
- for (i = G.len; i > 0; i--, p++)
+ for (i = len; i > 0; i--, p++)
{
if (*p == 0x1d)
{
if (*p == 0xff)
*p = 0x7f;
}
- write(G.netfd, G.buf, G.len);
+ write(G.netfd, G.buf, len);
}
-static void handlenetinput()
+static void handlenetinput(int len)
{
int i;
int cstart = 0;
- for (i = 0; i < G.len; i++)
+ for (i = 0; i < len; i++)
{
byte c = G.buf[i];
if (G.iaclen) iacflush();
if (G.telstate == TS_0) G.telstate = 0;
- G.len = cstart;
+ len = cstart;
}
- if (G.len)
- write(1, G.buf, G.len);
+ if (len)
+ write(1, G.buf, len);
}
}
#endif
+#ifdef BB_FEATURE_TELNET_TTYPE
+static void putiac_subopt(byte c, char *str)
+{
+ int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 )
+
+ if (G.iaclen + len > IACBUFSIZE)
+ iacflush();
+
+ putiac(IAC);
+ putiac(SB);
+ putiac(c);
+ putiac(0);
+
+ while(*str)
+ putiac(*str++);
+
+ putiac(IAC);
+ putiac(SE);
+}
+#endif
+
/* void putiacstring (subneg strings) */
/* ******************************* */
-char const escapecharis[] = "\r\nEscape character is ";
+static char const escapecharis[] = "\r\nEscape character is ";
static void setConMode()
{
return;
}
+#ifdef BB_FEATURE_TELNET_TTYPE
+static inline void to_ttype()
+{
+ /* Tell server we will (or won't) do TTYPE */
+
+ if(ttype)
+ putiac2(WILL, TELOPT_TTYPE);
+ else
+ putiac2(WONT, TELOPT_TTYPE);
+
+ return;
+}
+#endif
+
static void telopt(byte c)
{
switch (c)
{
case TELOPT_ECHO: to_echo(c); break;
case TELOPT_SGA: to_sga(c); break;
+#ifdef BB_FEATURE_TELNET_TTYPE
+ case TELOPT_TTYPE: to_ttype(c); break;
+#endif
default: to_notsup(c); break;
}
}
/* ******************************* */
-/* subnegotiation -- ignore all */
+/* subnegotiation -- ignore all (except TTYPE) */
static int subneg(byte c)
{
case TS_SUB1:
if (c == IAC)
G.telstate = TS_SUB2;
+#ifdef BB_FEATURE_TELNET_TTYPE
+ else
+ if (c == TELOPT_TTYPE)
+ putiac_subopt(TELOPT_TTYPE,ttype);
+#endif
break;
case TS_SUB2:
if (c == SE)
{
struct in_addr host;
int port;
+ int len;
#ifdef USE_POLL
struct pollfd ufds[2];
#else
int maxfd;
#endif
+#ifdef BB_FEATURE_TELNET_TTYPE
+ ttype = getenv("TERM");
+#endif
memset(&G, 0, sizeof G);
exit(1);
G.termios_raw = G.termios_def;
-
cfmakeraw(&G.termios_raw);
- if (argc < 2) usage(telnet_usage);
+ if (argc < 2) show_usage();
port = (argc > 2)? getport(argv[2]): 23;
- G.buf = xmalloc(DATABUFSIZE);
- G.iacbuf = xmalloc(IACBUFSIZE);
-
host = getserver(argv[1]);
G.netfd = remote_connect(host, port);
if (FD_ISSET(0, &rfds))
#endif
{
- G.len = read(0, G.buf, DATABUFSIZE);
+ len = read(0, G.buf, DATABUFSIZE);
- if (G.len <= 0)
+ if (len <= 0)
doexit(0);
- TRACE(0, ("Read con: %d\n", G.len));
+ TRACE(0, ("Read con: %d\n", len));
- handlenetoutput();
+ handlenetoutput(len);
}
#ifdef USE_POLL
if (FD_ISSET(G.netfd, &rfds))
#endif
{
- G.len = read(G.netfd, G.buf, DATABUFSIZE);
+ len = read(G.netfd, G.buf, DATABUFSIZE);
- if (G.len <= 0)
+ if (len <= 0)
{
WriteCS(1, "Connection closed by foreign host.\r\n");
doexit(1);
}
- TRACE(0, ("Read netfd (%d): %d\n", G.netfd, G.len));
+ TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
- handlenetinput();
+ handlenetinput(len);
}
}
}
if ((unsigned)(port - 1 ) > 65534)
{
- error_msg_and_die("%s: bad port number\n", p);
+ error_msg_and_die("%s: bad port number", p);
}
return port;
}
static struct in_addr getserver(char * host)
{
struct in_addr addr;
-
+
struct hostent * he;
- if ((he = gethostbyname(host)) == NULL)
- {
- error_msg_and_die("%s: Unknown host\n", host);
- }
+ he = xgethostbyname(host);
memcpy(&addr, he->h_addr, sizeof addr);
TRACE(1, ("addr: %s\n", inet_ntoa(addr)));
-
+
return addr;
-}
+}
static int create_socket()
{
static void setup_sockaddr_in(struct sockaddr_in * addr, int port)
{
- memset(addr, 0, sizeof addr);
+ memset(addr, 0, sizeof(struct sockaddr_in));
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
}