* HISTORY
* Revision 3.1 1994/04/17 11:31:54 too
* initial revision
- * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen
- * <andersen@lineo.com>
+ * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen <andersen@codepoet.org>
* Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
* <jam@ltsp.org>
*
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <netdb.h>
#include "busybox.h"
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+# include <sys/ioctl.h>
+#endif
+
#if 0
static const int DOTRACE = 1;
#endif
#ifdef USE_GLOBALVAR_PTR
struct Globalvars * Gptr;
#define G (*Gptr)
-#else
-static struct Globalvars G;
#endif
-static inline void iacflush()
+static inline void iacflush(void)
{
write(G.netfd, G.iacbuf, G.iaclen);
G.iaclen = 0;
}
/* Function prototypes */
-static int getport(char * p);
-static struct in_addr getserver(char * p);
-static int create_socket();
-static void setup_sockaddr_in(struct sockaddr_in * addr, int port);
-static int remote_connect(struct in_addr addr, int port);
-static void rawmode();
-static void cookmode();
-static void do_linemode();
-static void will_charmode();
+static void rawmode(void);
+static void cookmode(void);
+static void do_linemode(void);
+static void will_charmode(void);
static void telopt(byte c);
static int subneg(byte c);
-#if 0
-static int local_bind(int port);
-#endif
/* Some globals */
static int one = 1;
static char *ttype;
#endif
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+static int win_width, win_height;
+#endif
+
static void doexit(int ev)
{
cookmode();
exit(ev);
}
-static void conescape()
+static void conescape(void)
{
char b;
* stream like writing twice every sequence of FF:s (thus doing
* many write()s. But I think interactive telnet application does
* not need to be 100% 8-bit clean, so changing every 0xff:s to
- * 0x7f:s */
-
- int i;
+ * 0x7f:s
+ *
+ * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com)
+ * I don't agree.
+ * first - I cannot use programs like sz/rz
+ * second - the 0x0D is sent as one character and if the next
+ * char is 0x0A then it's eaten by a server side.
+ * third - whay doy you have to make 'many write()s'?
+ * I don't understand.
+ * So I implemented it. It's realy useful for me. I hope that
+ * others people will find it interesting to.
+ */
+
+ int i, j;
byte * p = G.buf;
+ byte outbuf[4*DATABUFSIZE];
- for (i = len; i > 0; i--, p++)
+ for (i = len, j = 0; i > 0; i--, p++)
{
if (*p == 0x1d)
{
conescape();
return;
}
+ outbuf[j++] = *p;
if (*p == 0xff)
- *p = 0x7f;
+ outbuf[j++] = 0xff;
+ else if (*p == 0x0d)
+ outbuf[j++] = 0x00;
}
- write(G.netfd, G.buf, len);
+ if (j > 0 )
+ write(G.netfd, outbuf, j);
}
break;
case TS_SUB1: /* Subnegotiation */
case TS_SUB2: /* Subnegotiation */
- if (subneg(c) == TRUE)
+ if (subneg(c))
G.telstate = TS_0;
break;
}
}
#endif
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+static void putiac_naws(byte c, int x, int y)
+{
+ if (G.iaclen + 9 > IACBUFSIZE)
+ iacflush();
+
+ putiac(IAC);
+ putiac(SB);
+ putiac(c);
+
+ putiac((x >> 8) & 0xff);
+ putiac(x & 0xff);
+ putiac((y >> 8) & 0xff);
+ putiac(y & 0xff);
+
+ putiac(IAC);
+ putiac(SE);
+}
+#endif
+
/* void putiacstring (subneg strings) */
/* ******************************* */
static char const escapecharis[] = "\r\nEscape character is ";
-static void setConMode()
+static void setConMode(void)
{
if (G.telflags & UF_ECHO)
{
/* ******************************* */
-static void will_charmode()
+static void will_charmode(void)
{
G.charmode = CHM_TRY;
G.telflags |= (UF_ECHO | UF_SGA);
iacflush();
}
-static void do_linemode()
+static void do_linemode(void)
{
G.charmode = CHM_TRY;
G.telflags &= ~(UF_ECHO | UF_SGA);
else if (G.telwish == DO) putiac2(WONT, c);
}
-static inline void to_echo()
+static inline void to_echo(void)
{
/* if server requests ECHO, don't agree */
if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; }
WriteCS(1, "\r\n"); /* sudden modec */
}
-static inline void to_sga()
+static inline void to_sga(void)
{
/* daemon always sends will/wont, client do/dont */
}
#ifdef CONFIG_FEATURE_TELNET_TTYPE
-static inline void to_ttype()
+static inline void to_ttype(void)
{
/* Tell server we will (or won't) do TTYPE */
}
#endif
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+static inline void to_naws(void)
+{
+ /* Tell server we will do NAWS */
+ putiac2(WILL, TELOPT_NAWS);
+ return;
+}
+#endif
+
static void telopt(byte c)
{
switch (c)
{
- case TELOPT_ECHO: to_echo(c); break;
- case TELOPT_SGA: to_sga(c); break;
+ case TELOPT_ECHO: to_echo(); break;
+ case TELOPT_SGA: to_sga(); break;
#ifdef CONFIG_FEATURE_TELNET_TTYPE
- case TELOPT_TTYPE: to_ttype(c); break;
+ case TELOPT_TTYPE: to_ttype();break;
+#endif
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+ case TELOPT_NAWS: to_naws();
+ putiac_naws(c, win_width, win_height);
+ break;
#endif
- default: to_notsup(c); break;
+ default: to_notsup(c);
+ break;
}
}
/* ******************************* */
-/* subnegotiation -- ignore all (except TTYPE) */
+/* subnegotiation -- ignore all (except TTYPE,NAWS) */
static int subneg(byte c)
{
}
-static void rawmode()
+static void rawmode(void)
{
tcsetattr(0, TCSADRAIN, &G.termios_raw);
}
-static void cookmode()
+static void cookmode(void)
{
tcsetattr(0, TCSADRAIN, &G.termios_def);
}
extern int telnet_main(int argc, char** argv)
{
- struct in_addr host;
- int port;
+ char *host;
+ char *port;
int len;
#ifdef USE_POLL
struct pollfd ufds[2];
int maxfd;
#endif
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+ struct winsize winp;
+ if( ioctl(0, TIOCGWINSZ, &winp) == 0 ) {
+ win_width = winp.ws_col;
+ win_height = winp.ws_row;
+ }
+#endif
+
#ifdef CONFIG_FEATURE_TELNET_TTYPE
ttype = getenv("TERM");
#endif
G.termios_raw = G.termios_def;
cfmakeraw(&G.termios_raw);
- if (argc < 2) show_usage();
- port = (argc > 2)? getport(argv[2]): 23;
+ if (argc < 2) bb_show_usage();
+ port = (argc > 2)? argv[2] : "23";
- host = getserver(argv[1]);
+ host = argv[1];
+
+ G.netfd = xconnect(host, port);
- G.netfd = remote_connect(host, port);
+ setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
signal(SIGINT, fgotsig);
}
}
-static int getport(char * p)
-{
- unsigned int port = atoi(p);
-
- if ((unsigned)(port - 1 ) > 65534)
- {
- 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;
- he = xgethostbyname(host);
- memcpy(&addr, he->h_addr, sizeof addr);
-
- TRACE(1, ("addr: %s\n", inet_ntoa(addr)));
-
- return addr;
-}
-
-static int create_socket()
-{
- return socket(AF_INET, SOCK_STREAM, 0);
-}
-
-static void setup_sockaddr_in(struct sockaddr_in * addr, int port)
-{
- memset(addr, 0, sizeof(struct sockaddr_in));
- addr->sin_family = AF_INET;
- addr->sin_port = htons(port);
-}
-
-#if 0
-static int local_bind(int port)
-{
- struct sockaddr_in s_addr;
- int s = create_socket();
-
- setup_sockaddr_in(&s_addr, port);
-
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
-
- if (bind(s, &s_addr, sizeof s_addr) < 0)
- {
- char * e = sys_errlist[errno];
- syserrorexit("bind");
- exit(1);
- }
- listen(s, 1);
-
- return s;
-}
-#endif
-
-static int remote_connect(struct in_addr addr, int port)
-{
- struct sockaddr_in s_addr;
- int s = create_socket();
-
- setup_sockaddr_in(&s_addr, port);
- s_addr.sin_addr = addr;
-
- setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
-
- if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0)
- {
- perror_msg_and_die("Unable to connect to remote host");
- }
- return s;
-}
-
/*
Local Variables:
c-file-style: "linux"
tab-width: 4
End:
*/
-