blob: 8f2573c2768943783a209b4c871d32ceacfe3b6f [file] [log] [blame]
Eric Andersen28c70b32000-06-14 20:42:57 +00001/* vi: set sw=4 ts=4: */
Erik Andersenf7c49ef2000-02-22 17:17:45 +00002/*
Eric Andersen28c70b32000-06-14 20:42:57 +00003 * telnet implementation for busybox
Erik Andersenf7c49ef2000-02-22 17:17:45 +00004 *
Eric Andersen28c70b32000-06-14 20:42:57 +00005 * Author: Tomi Ollila <too@iki.fi>
6 * Copyright (C) 1994-2000 by Tomi Ollila
7 *
8 * Created: Thu Apr 7 13:29:41 1994 too
9 * Last modified: Fri Jun 9 14:34:24 2000 too
Erik Andersenf7c49ef2000-02-22 17:17:45 +000010 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
Eric Andersen28c70b32000-06-14 20:42:57 +000025 * HISTORY
26 * Revision 3.1 1994/04/17 11:31:54 too
27 * initial revision
Eric Andersen27d37662002-06-06 12:59:13 +000028 * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen <andersee@debian.org>
Eric Andersen7e1273e2001-05-07 17:57:45 +000029 * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
30 * <jam@ltsp.org>
Erik Andersenf7c49ef2000-02-22 17:17:45 +000031 *
Erik Andersenf7c49ef2000-02-22 17:17:45 +000032 */
33
Erik Andersenf7c49ef2000-02-22 17:17:45 +000034#include <termios.h>
Eric Andersen28c70b32000-06-14 20:42:57 +000035#include <unistd.h>
36#include <errno.h>
37#include <stdlib.h>
38#include <stdarg.h>
Eric Andersen2276d832002-07-11 11:11:56 +000039#include <string.h>
Eric Andersen28c70b32000-06-14 20:42:57 +000040#include <signal.h>
41#include <arpa/telnet.h>
Erik Andersenf7c49ef2000-02-22 17:17:45 +000042#include <sys/types.h>
43#include <sys/socket.h>
Eric Andersen28c70b32000-06-14 20:42:57 +000044#include <netinet/in.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000045#include "busybox.h"
Erik Andersenf7c49ef2000-02-22 17:17:45 +000046
Eric Andersen0e28e1f2002-04-26 07:20:47 +000047#ifdef CONFIG_FEATURE_AUTOWIDTH
48# include <sys/ioctl.h>
49#endif
50
Eric Andersen28c70b32000-06-14 20:42:57 +000051#if 0
Mark Whitley59ab0252001-01-23 22:30:04 +000052static const int DOTRACE = 1;
Eric Andersen28c70b32000-06-14 20:42:57 +000053#endif
54
Pavel Roskin616d13b2000-07-28 19:38:27 +000055#ifdef DOTRACE
Eric Andersen28c70b32000-06-14 20:42:57 +000056#include <arpa/inet.h> /* for inet_ntoa()... */
57#define TRACE(x, y) do { if (x) printf y; } while (0)
58#else
59#define TRACE(x, y)
60#endif
61
62#if 0
63#define USE_POLL
64#include <sys/poll.h>
65#else
66#include <sys/time.h>
67#endif
68
Glenn L McGrath78b0e372001-06-26 02:06:08 +000069#define DATABUFSIZE 128
70#define IACBUFSIZE 128
Eric Andersen28c70b32000-06-14 20:42:57 +000071
Mark Whitley59ab0252001-01-23 22:30:04 +000072static const int CHM_TRY = 0;
73static const int CHM_ON = 1;
74static const int CHM_OFF = 2;
Eric Andersen28c70b32000-06-14 20:42:57 +000075
Mark Whitley59ab0252001-01-23 22:30:04 +000076static const int UF_ECHO = 0x01;
77static const int UF_SGA = 0x02;
Eric Andersen28c70b32000-06-14 20:42:57 +000078
Mark Whitley59ab0252001-01-23 22:30:04 +000079enum {
80 TS_0 = 1,
81 TS_IAC = 2,
82 TS_OPT = 3,
83 TS_SUB1 = 4,
84 TS_SUB2 = 5,
85};
Eric Andersen28c70b32000-06-14 20:42:57 +000086
87#define WriteCS(fd, str) write(fd, str, sizeof str -1)
88
89typedef unsigned char byte;
90
91/* use globals to reduce size ??? */ /* test this hypothesis later */
Eric Andersen92d23242001-03-19 23:49:41 +000092static struct Globalvars {
Eric Andersen28c70b32000-06-14 20:42:57 +000093 int netfd; /* console fd:s are 0 and 1 (and 2) */
94 /* same buffer used both for network and console read/write */
Glenn L McGrath78b0e372001-06-26 02:06:08 +000095 char buf[DATABUFSIZE]; /* allocating so static size is smaller */
Eric Andersen28c70b32000-06-14 20:42:57 +000096 byte telstate; /* telnet negotiation state from network input */
97 byte telwish; /* DO, DONT, WILL, WONT */
98 byte charmode;
99 byte telflags;
100 byte gotsig;
101 /* buffer to handle telnet negotiations */
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000102 char iacbuf[IACBUFSIZE];
Eric Andersen28c70b32000-06-14 20:42:57 +0000103 short iaclen; /* could even use byte */
104 struct termios termios_def;
105 struct termios termios_raw;
106} G;
107
108#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */
109
110#ifdef USE_GLOBALVAR_PTR
111struct Globalvars * Gptr;
112#define G (*Gptr)
Eric Andersen28c70b32000-06-14 20:42:57 +0000113#endif
114
Eric Andersencd8c4362001-11-10 11:22:46 +0000115static inline void iacflush(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000116{
117 write(G.netfd, G.iacbuf, G.iaclen);
118 G.iaclen = 0;
119}
120
121/* Function prototypes */
Eric Andersencd8c4362001-11-10 11:22:46 +0000122static void rawmode(void);
123static void cookmode(void);
124static void do_linemode(void);
125static void will_charmode(void);
Eric Andersen28c70b32000-06-14 20:42:57 +0000126static void telopt(byte c);
127static int subneg(byte c);
Eric Andersen28c70b32000-06-14 20:42:57 +0000128
129/* Some globals */
130static int one = 1;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000131
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000132#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000133static char *ttype;
134#endif
135
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000136#ifdef CONFIG_FEATURE_AUTOWIDTH
137static int win_width, win_height;
138#endif
139
Eric Andersen28c70b32000-06-14 20:42:57 +0000140static void doexit(int ev)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000141{
Eric Andersen28c70b32000-06-14 20:42:57 +0000142 cookmode();
143 exit(ev);
144}
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000145
Eric Andersencd8c4362001-11-10 11:22:46 +0000146static void conescape(void)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000147{
Eric Andersen28c70b32000-06-14 20:42:57 +0000148 char b;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000149
Eric Andersen28c70b32000-06-14 20:42:57 +0000150 if (G.gotsig) /* came from line mode... go raw */
151 rawmode();
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000152
Eric Andersen28c70b32000-06-14 20:42:57 +0000153 WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
154 " l go to line mode\r\n"
155 " c go to character mode\r\n"
156 " z suspend telnet\r\n"
157 " e exit telnet\r\n");
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000158
Eric Andersen28c70b32000-06-14 20:42:57 +0000159 if (read(0, &b, 1) <= 0)
160 doexit(1);
161
162 switch (b)
163 {
164 case 'l':
165 if (!G.gotsig)
166 {
167 do_linemode();
168 goto rrturn;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000169 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000170 break;
171 case 'c':
172 if (G.gotsig)
173 {
174 will_charmode();
175 goto rrturn;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000176 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000177 break;
178 case 'z':
179 cookmode();
180 kill(0, SIGTSTP);
181 rawmode();
182 break;
183 case 'e':
184 doexit(0);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000185 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000186
187 WriteCS(1, "continuing...\r\n");
188
189 if (G.gotsig)
190 cookmode();
191
192 rrturn:
193 G.gotsig = 0;
194
195}
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000196static void handlenetoutput(int len)
Eric Andersen28c70b32000-06-14 20:42:57 +0000197{
198 /* here we could do smart tricks how to handle 0xFF:s in output
199 * stream like writing twice every sequence of FF:s (thus doing
200 * many write()s. But I think interactive telnet application does
201 * not need to be 100% 8-bit clean, so changing every 0xff:s to
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000202 * 0x7f:s
203 *
204 * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com)
205 * I don't agree.
206 * first - I cannot use programs like sz/rz
207 * second - the 0x0D is sent as one character and if the next
208 * char is 0x0A then it's eaten by a server side.
209 * third - whay doy you have to make 'many write()s'?
210 * I don't understand.
211 * So I implemented it. It's realy useful for me. I hope that
212 * others people will find it interesting to.
213 */
Eric Andersen28c70b32000-06-14 20:42:57 +0000214
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000215 int i, j;
Eric Andersen28c70b32000-06-14 20:42:57 +0000216 byte * p = G.buf;
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000217 byte outbuf[4*DATABUFSIZE];
Eric Andersen28c70b32000-06-14 20:42:57 +0000218
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000219 for (i = len, j = 0; i > 0; i--, p++)
Eric Andersen28c70b32000-06-14 20:42:57 +0000220 {
221 if (*p == 0x1d)
222 {
223 conescape();
224 return;
225 }
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000226 outbuf[j++] = *p;
Eric Andersen28c70b32000-06-14 20:42:57 +0000227 if (*p == 0xff)
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000228 outbuf[j++] = 0xff;
229 else if (*p == 0x0d)
230 outbuf[j++] = 0x00;
Eric Andersen28c70b32000-06-14 20:42:57 +0000231 }
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000232 if (j > 0 )
233 write(G.netfd, outbuf, j);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000234}
235
Eric Andersen28c70b32000-06-14 20:42:57 +0000236
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000237static void handlenetinput(int len)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000238{
Eric Andersen28c70b32000-06-14 20:42:57 +0000239 int i;
240 int cstart = 0;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000241
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000242 for (i = 0; i < len; i++)
Eric Andersen28c70b32000-06-14 20:42:57 +0000243 {
244 byte c = G.buf[i];
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000245
Eric Andersen28c70b32000-06-14 20:42:57 +0000246 if (G.telstate == 0) /* most of the time state == 0 */
247 {
248 if (c == IAC)
249 {
250 cstart = i;
251 G.telstate = TS_IAC;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000252 }
253 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000254 else
255 switch (G.telstate)
256 {
257 case TS_0:
258 if (c == IAC)
259 G.telstate = TS_IAC;
260 else
261 G.buf[cstart++] = c;
262 break;
263
264 case TS_IAC:
265 if (c == IAC) /* IAC IAC -> 0xFF */
266 {
267 G.buf[cstart++] = c;
268 G.telstate = TS_0;
269 break;
270 }
271 /* else */
272 switch (c)
273 {
274 case SB:
275 G.telstate = TS_SUB1;
276 break;
277 case DO:
278 case DONT:
279 case WILL:
280 case WONT:
281 G.telwish = c;
282 G.telstate = TS_OPT;
283 break;
284 default:
285 G.telstate = TS_0; /* DATA MARK must be added later */
286 }
287 break;
288 case TS_OPT: /* WILL, WONT, DO, DONT */
289 telopt(c);
290 G.telstate = TS_0;
291 break;
292 case TS_SUB1: /* Subnegotiation */
293 case TS_SUB2: /* Subnegotiation */
Matt Kraai1f0c4362001-12-20 23:13:26 +0000294 if (subneg(c))
Eric Andersen28c70b32000-06-14 20:42:57 +0000295 G.telstate = TS_0;
296 break;
297 }
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000298 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000299 if (G.telstate)
300 {
301 if (G.iaclen) iacflush();
302 if (G.telstate == TS_0) G.telstate = 0;
303
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000304 len = cstart;
Eric Andersen28c70b32000-06-14 20:42:57 +0000305 }
306
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000307 if (len)
308 write(1, G.buf, len);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000309}
310
Eric Andersen28c70b32000-06-14 20:42:57 +0000311
312/* ******************************* */
313
314static inline void putiac(int c)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000315{
Eric Andersen28c70b32000-06-14 20:42:57 +0000316 G.iacbuf[G.iaclen++] = c;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000317}
318
Eric Andersen28c70b32000-06-14 20:42:57 +0000319
320static void putiac2(byte wwdd, byte c)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000321{
Eric Andersen28c70b32000-06-14 20:42:57 +0000322 if (G.iaclen + 3 > IACBUFSIZE)
323 iacflush();
324
325 putiac(IAC);
326 putiac(wwdd);
327 putiac(c);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000328}
329
Eric Andersen28c70b32000-06-14 20:42:57 +0000330#if 0
331static void putiac1(byte c)
332{
333 if (G.iaclen + 2 > IACBUFSIZE)
334 iacflush();
335
336 putiac(IAC);
337 putiac(c);
338}
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000339#endif
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000340
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000341#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000342static void putiac_subopt(byte c, char *str)
343{
344 int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 )
345
346 if (G.iaclen + len > IACBUFSIZE)
347 iacflush();
348
349 putiac(IAC);
350 putiac(SB);
351 putiac(c);
352 putiac(0);
353
354 while(*str)
355 putiac(*str++);
356
357 putiac(IAC);
358 putiac(SE);
359}
360#endif
361
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000362#ifdef CONFIG_FEATURE_AUTOWIDTH
363static void putiac_naws(byte c, int x, int y)
364{
365 if (G.iaclen + 9 > IACBUFSIZE)
366 iacflush();
367
368 putiac(IAC);
369 putiac(SB);
370 putiac(c);
371
372 putiac((x >> 8) & 0xff);
373 putiac(x & 0xff);
374 putiac((y >> 8) & 0xff);
375 putiac(y & 0xff);
376
377 putiac(IAC);
378 putiac(SE);
379}
380#endif
381
Eric Andersen28c70b32000-06-14 20:42:57 +0000382/* void putiacstring (subneg strings) */
383
384/* ******************************* */
385
Eric Andersen3e6ff902001-03-09 21:24:12 +0000386static char const escapecharis[] = "\r\nEscape character is ";
Eric Andersen28c70b32000-06-14 20:42:57 +0000387
Eric Andersencd8c4362001-11-10 11:22:46 +0000388static void setConMode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000389{
390 if (G.telflags & UF_ECHO)
391 {
392 if (G.charmode == CHM_TRY) {
393 G.charmode = CHM_ON;
Matt Kraai12f417e2001-01-18 02:57:08 +0000394 printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis);
Eric Andersen28c70b32000-06-14 20:42:57 +0000395 rawmode();
396 }
397 }
398 else
399 {
400 if (G.charmode != CHM_OFF) {
401 G.charmode = CHM_OFF;
Matt Kraai12f417e2001-01-18 02:57:08 +0000402 printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis);
Eric Andersen28c70b32000-06-14 20:42:57 +0000403 cookmode();
404 }
405 }
406}
407
408/* ******************************* */
409
Eric Andersencd8c4362001-11-10 11:22:46 +0000410static void will_charmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000411{
412 G.charmode = CHM_TRY;
413 G.telflags |= (UF_ECHO | UF_SGA);
414 setConMode();
415
416 putiac2(DO, TELOPT_ECHO);
417 putiac2(DO, TELOPT_SGA);
418 iacflush();
419}
420
Eric Andersencd8c4362001-11-10 11:22:46 +0000421static void do_linemode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000422{
423 G.charmode = CHM_TRY;
424 G.telflags &= ~(UF_ECHO | UF_SGA);
425 setConMode();
426
427 putiac2(DONT, TELOPT_ECHO);
428 putiac2(DONT, TELOPT_SGA);
429 iacflush();
430}
431
432/* ******************************* */
433
434static inline void to_notsup(char c)
435{
436 if (G.telwish == WILL) putiac2(DONT, c);
437 else if (G.telwish == DO) putiac2(WONT, c);
438}
439
Eric Andersencd8c4362001-11-10 11:22:46 +0000440static inline void to_echo(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000441{
442 /* if server requests ECHO, don't agree */
443 if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; }
444 else if (G.telwish == DONT) return;
445
446 if (G.telflags & UF_ECHO)
447 {
448 if (G.telwish == WILL)
449 return;
450 }
451 else
452 if (G.telwish == WONT)
453 return;
454
455 if (G.charmode != CHM_OFF)
456 G.telflags ^= UF_ECHO;
457
458 if (G.telflags & UF_ECHO)
459 putiac2(DO, TELOPT_ECHO);
460 else
461 putiac2(DONT, TELOPT_ECHO);
462
463 setConMode();
464 WriteCS(1, "\r\n"); /* sudden modec */
465}
466
Eric Andersencd8c4362001-11-10 11:22:46 +0000467static inline void to_sga(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000468{
469 /* daemon always sends will/wont, client do/dont */
470
471 if (G.telflags & UF_SGA)
472 {
473 if (G.telwish == WILL)
474 return;
475 }
476 else
477 if (G.telwish == WONT)
478 return;
479
480 if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
481 putiac2(DO, TELOPT_SGA);
482 else
483 putiac2(DONT, TELOPT_SGA);
484
485 return;
486}
487
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000488#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersencd8c4362001-11-10 11:22:46 +0000489static inline void to_ttype(void)
Eric Andersen7e1273e2001-05-07 17:57:45 +0000490{
491 /* Tell server we will (or won't) do TTYPE */
492
493 if(ttype)
494 putiac2(WILL, TELOPT_TTYPE);
495 else
496 putiac2(WONT, TELOPT_TTYPE);
497
498 return;
499}
500#endif
501
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000502#ifdef CONFIG_FEATURE_AUTOWIDTH
Tim Rikered8e0362002-04-26 07:53:39 +0000503static inline void to_naws(void)
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000504{
505 /* Tell server we will do NAWS */
506 putiac2(WILL, TELOPT_NAWS);
507 return;
508}
509#endif
510
Eric Andersen28c70b32000-06-14 20:42:57 +0000511static void telopt(byte c)
512{
513 switch (c)
514 {
Eric Andersen41634062002-04-26 08:44:17 +0000515 case TELOPT_ECHO: to_echo(); break;
516 case TELOPT_SGA: to_sga(); break;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000517#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen41634062002-04-26 08:44:17 +0000518 case TELOPT_TTYPE: to_ttype();break;
Eric Andersen7e1273e2001-05-07 17:57:45 +0000519#endif
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000520#ifdef CONFIG_FEATURE_AUTOWIDTH
Eric Andersen41634062002-04-26 08:44:17 +0000521 case TELOPT_NAWS: to_naws();
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000522 putiac_naws(c, win_width, win_height);
523 break;
524#endif
Eric Andersen8db361b2002-04-26 08:00:33 +0000525 default: to_notsup(c);
526 break;
Eric Andersen28c70b32000-06-14 20:42:57 +0000527 }
528}
529
530
531/* ******************************* */
532
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000533/* subnegotiation -- ignore all (except TTYPE,NAWS) */
Eric Andersen28c70b32000-06-14 20:42:57 +0000534
535static int subneg(byte c)
536{
537 switch (G.telstate)
538 {
539 case TS_SUB1:
540 if (c == IAC)
541 G.telstate = TS_SUB2;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000542#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000543 else
544 if (c == TELOPT_TTYPE)
545 putiac_subopt(TELOPT_TTYPE,ttype);
546#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000547 break;
548 case TS_SUB2:
549 if (c == SE)
550 return TRUE;
551 G.telstate = TS_SUB1;
552 /* break; */
553 }
554 return FALSE;
555}
556
557/* ******************************* */
558
559static void fgotsig(int sig)
560{
561 G.gotsig = sig;
562}
563
564
Eric Andersencd8c4362001-11-10 11:22:46 +0000565static void rawmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000566{
567 tcsetattr(0, TCSADRAIN, &G.termios_raw);
568}
569
Eric Andersencd8c4362001-11-10 11:22:46 +0000570static void cookmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000571{
572 tcsetattr(0, TCSADRAIN, &G.termios_def);
573}
574
575extern int telnet_main(int argc, char** argv)
576{
Eric Andersen0b315862002-07-03 11:51:44 +0000577 char *host;
578 char *port;
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000579 int len;
Eric Andersen28c70b32000-06-14 20:42:57 +0000580#ifdef USE_POLL
581 struct pollfd ufds[2];
582#else
583 fd_set readfds;
584 int maxfd;
585#endif
586
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000587#ifdef CONFIG_FEATURE_AUTOWIDTH
588 struct winsize winp;
589 if( ioctl(0, TIOCGWINSZ, &winp) == 0 ) {
590 win_width = winp.ws_col;
591 win_height = winp.ws_row;
592 }
593#endif
594
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000595#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000596 ttype = getenv("TERM");
597#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000598
599 memset(&G, 0, sizeof G);
600
601 if (tcgetattr(0, &G.termios_def) < 0)
602 exit(1);
603
604 G.termios_raw = G.termios_def;
Eric Andersen28c70b32000-06-14 20:42:57 +0000605 cfmakeraw(&G.termios_raw);
606
Manuel Novoa III cad53642003-03-19 09:13:01 +0000607 if (argc < 2) bb_show_usage();
Eric Andersen0b315862002-07-03 11:51:44 +0000608 port = (argc > 2)? argv[2] : "23";
Eric Andersen28c70b32000-06-14 20:42:57 +0000609
Eric Andersen0b315862002-07-03 11:51:44 +0000610 host = argv[1];
611
612 G.netfd = xconnect(host, port);
Eric Andersen28c70b32000-06-14 20:42:57 +0000613
Eric Andersen0b315862002-07-03 11:51:44 +0000614 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
Eric Andersen28c70b32000-06-14 20:42:57 +0000615
616 signal(SIGINT, fgotsig);
617
618#ifdef USE_POLL
619 ufds[0].fd = 0; ufds[1].fd = G.netfd;
620 ufds[0].events = ufds[1].events = POLLIN;
621#else
622 FD_ZERO(&readfds);
623 FD_SET(0, &readfds);
624 FD_SET(G.netfd, &readfds);
625 maxfd = G.netfd + 1;
626#endif
627
628 while (1)
629 {
630#ifndef USE_POLL
631 fd_set rfds = readfds;
632
633 switch (select(maxfd, &rfds, NULL, NULL, NULL))
634#else
635 switch (poll(ufds, 2, -1))
636#endif
637 {
638 case 0:
639 /* timeout */
640 case -1:
641 /* error, ignore and/or log something, bay go to loop */
642 if (G.gotsig)
643 conescape();
644 else
645 sleep(1);
646 break;
647 default:
648
649#ifdef USE_POLL
650 if (ufds[0].revents) /* well, should check POLLIN, but ... */
651#else
652 if (FD_ISSET(0, &rfds))
653#endif
654 {
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000655 len = read(0, G.buf, DATABUFSIZE);
Eric Andersen28c70b32000-06-14 20:42:57 +0000656
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000657 if (len <= 0)
Eric Andersen28c70b32000-06-14 20:42:57 +0000658 doexit(0);
659
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000660 TRACE(0, ("Read con: %d\n", len));
Eric Andersen28c70b32000-06-14 20:42:57 +0000661
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000662 handlenetoutput(len);
Eric Andersen28c70b32000-06-14 20:42:57 +0000663 }
664
665#ifdef USE_POLL
666 if (ufds[1].revents) /* well, should check POLLIN, but ... */
667#else
668 if (FD_ISSET(G.netfd, &rfds))
669#endif
670 {
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000671 len = read(G.netfd, G.buf, DATABUFSIZE);
Eric Andersen28c70b32000-06-14 20:42:57 +0000672
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000673 if (len <= 0)
Eric Andersen28c70b32000-06-14 20:42:57 +0000674 {
675 WriteCS(1, "Connection closed by foreign host.\r\n");
676 doexit(1);
677 }
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000678 TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
Eric Andersen28c70b32000-06-14 20:42:57 +0000679
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000680 handlenetinput(len);
Eric Andersen28c70b32000-06-14 20:42:57 +0000681 }
682 }
683 }
684}
685
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000686/*
Eric Andersen28c70b32000-06-14 20:42:57 +0000687Local Variables:
688c-file-style: "linux"
689c-basic-offset: 4
690tab-width: 4
691End:
692*/