-/*
- * Copyright (c) 1988, 1990 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
+#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(); break;
+ case TELOPT_SGA: to_sga(); break;
+#ifdef CONFIG_FEATURE_TELNET_TTYPE
+ case TELOPT_TTYPE: to_ttype();break;
+#endif
+#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
+ case TELOPT_NEW_ENVIRON: to_new_environ(); 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;
+ }
+}
+
+
+/* ******************************* */
+
+/* subnegotiation -- ignore all (except TTYPE,NAWS) */
+
+static int subneg(byte c)
+{
+ switch (G.telstate)
+ {
+ case TS_SUB1:
+ if (c == IAC)
+ G.telstate = TS_SUB2;
+#ifdef CONFIG_FEATURE_TELNET_TTYPE
+ else
+ if (c == TELOPT_TTYPE)
+ putiac_subopt(TELOPT_TTYPE,ttype);
+#endif
+#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
+ else
+ if (c == TELOPT_NEW_ENVIRON)
+ putiac_subopt_autologin();
+#endif
+ break;
+ case TS_SUB2:
+ if (c == SE)
+ return TRUE;
+ G.telstate = TS_SUB1;
+ /* break; */
+ }
+ return FALSE;
+}
+
+/* ******************************* */
+
+static void fgotsig(int sig)
+{
+ G.gotsig = sig;
+}
+
+
+static void rawmode(void)
+{
+ if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_raw);
+}
+
+static void cookmode(void)
+{
+ if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_def);
+}
+
+int telnet_main(int argc, char** argv)
+{
+ int len;
+ struct sockaddr_in s_in;
+#ifdef USE_POLL
+ struct pollfd ufds[2];
+#else
+ fd_set readfds;
+ int maxfd;
+#endif
+
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+ get_terminal_width_height(0, &win_width, &win_height);
+#endif
+
+#ifdef CONFIG_FEATURE_TELNET_TTYPE
+ ttype = getenv("TERM");
+#endif
+
+ memset(&G, 0, sizeof G);
+
+ if (tcgetattr(0, &G.termios_def) >= 0) {
+ G.do_termios = 1;
+
+ G.termios_raw = G.termios_def;
+ cfmakeraw(&G.termios_raw);
+ }
+
+ if (argc < 2)
+ bb_show_usage();
+
+#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
+ if (1 & bb_getopt_ulflags(argc, argv, "al:", &autologin))
+ autologin = getenv("USER");
+
+ if (optind < argc) {
+ bb_lookup_host(&s_in, argv[optind++]);
+ s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] :
+ "telnet", "tcp", 23);
+ if (optind < argc)
+ bb_show_usage();
+ } else
+ bb_show_usage();
+#else
+ bb_lookup_host(&s_in, argv[1]);
+ s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23);
+#endif
+
+ G.netfd = xconnect(&s_in);
+
+ setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
+
+ signal(SIGINT, fgotsig);
+
+#ifdef USE_POLL
+ ufds[0].fd = 0; ufds[1].fd = G.netfd;
+ ufds[0].events = ufds[1].events = POLLIN;
+#else
+ FD_ZERO(&readfds);
+ FD_SET(0, &readfds);
+ FD_SET(G.netfd, &readfds);
+ maxfd = G.netfd + 1;
+#endif
+
+ while (1)
+ {
+#ifndef USE_POLL
+ fd_set rfds = readfds;
+
+ switch (select(maxfd, &rfds, NULL, NULL, NULL))
+#else
+ switch (poll(ufds, 2, -1))
+#endif
+ {
+ case 0:
+ /* timeout */
+ case -1:
+ /* error, ignore and/or log something, bay go to loop */
+ if (G.gotsig)
+ conescape();
+ else
+ sleep(1);
+ break;
+ default:
+
+#ifdef USE_POLL
+ if (ufds[0].revents) /* well, should check POLLIN, but ... */
+#else
+ if (FD_ISSET(0, &rfds))
+#endif
+ {
+ len = read(0, G.buf, DATABUFSIZE);
+
+ if (len <= 0)
+ doexit(0);
+
+ TRACE(0, ("Read con: %d\n", len));
+
+ handlenetoutput(len);
+ }
+
+#ifdef USE_POLL
+ if (ufds[1].revents) /* well, should check POLLIN, but ... */
+#else
+ if (FD_ISSET(G.netfd, &rfds))
+#endif
+ {
+ len = read(G.netfd, G.buf, DATABUFSIZE);
+
+ if (len <= 0)
+ {
+ WriteCS(1, "Connection closed by foreign host.\r\n");
+ doexit(1);
+ }
+ TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
+
+ handlenetinput(len);
+ }
+ }
+ }
+}