blob: 14b71c85da8045763370b39074a7d203b1b23920 [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)
113#else
Eric Andersen92d23242001-03-19 23:49:41 +0000114static struct Globalvars G;
Eric Andersen28c70b32000-06-14 20:42:57 +0000115#endif
116
Eric Andersencd8c4362001-11-10 11:22:46 +0000117static inline void iacflush(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000118{
119 write(G.netfd, G.iacbuf, G.iaclen);
120 G.iaclen = 0;
121}
122
123/* Function prototypes */
Eric Andersencd8c4362001-11-10 11:22:46 +0000124static void rawmode(void);
125static void cookmode(void);
126static void do_linemode(void);
127static void will_charmode(void);
Eric Andersen28c70b32000-06-14 20:42:57 +0000128static void telopt(byte c);
129static int subneg(byte c);
Eric Andersen28c70b32000-06-14 20:42:57 +0000130
131/* Some globals */
132static int one = 1;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000133
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000134#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000135static char *ttype;
136#endif
137
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000138#ifdef CONFIG_FEATURE_AUTOWIDTH
139static int win_width, win_height;
140#endif
141
Eric Andersen28c70b32000-06-14 20:42:57 +0000142static void doexit(int ev)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000143{
Eric Andersen28c70b32000-06-14 20:42:57 +0000144 cookmode();
145 exit(ev);
146}
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000147
Eric Andersencd8c4362001-11-10 11:22:46 +0000148static void conescape(void)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000149{
Eric Andersen28c70b32000-06-14 20:42:57 +0000150 char b;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000151
Eric Andersen28c70b32000-06-14 20:42:57 +0000152 if (G.gotsig) /* came from line mode... go raw */
153 rawmode();
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000154
Eric Andersen28c70b32000-06-14 20:42:57 +0000155 WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
156 " l go to line mode\r\n"
157 " c go to character mode\r\n"
158 " z suspend telnet\r\n"
159 " e exit telnet\r\n");
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000160
Eric Andersen28c70b32000-06-14 20:42:57 +0000161 if (read(0, &b, 1) <= 0)
162 doexit(1);
163
164 switch (b)
165 {
166 case 'l':
167 if (!G.gotsig)
168 {
169 do_linemode();
170 goto rrturn;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000171 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000172 break;
173 case 'c':
174 if (G.gotsig)
175 {
176 will_charmode();
177 goto rrturn;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000178 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000179 break;
180 case 'z':
181 cookmode();
182 kill(0, SIGTSTP);
183 rawmode();
184 break;
185 case 'e':
186 doexit(0);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000187 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000188
189 WriteCS(1, "continuing...\r\n");
190
191 if (G.gotsig)
192 cookmode();
193
194 rrturn:
195 G.gotsig = 0;
196
197}
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000198static void handlenetoutput(int len)
Eric Andersen28c70b32000-06-14 20:42:57 +0000199{
200 /* here we could do smart tricks how to handle 0xFF:s in output
201 * stream like writing twice every sequence of FF:s (thus doing
202 * many write()s. But I think interactive telnet application does
203 * not need to be 100% 8-bit clean, so changing every 0xff:s to
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000204 * 0x7f:s
205 *
206 * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com)
207 * I don't agree.
208 * first - I cannot use programs like sz/rz
209 * second - the 0x0D is sent as one character and if the next
210 * char is 0x0A then it's eaten by a server side.
211 * third - whay doy you have to make 'many write()s'?
212 * I don't understand.
213 * So I implemented it. It's realy useful for me. I hope that
214 * others people will find it interesting to.
215 */
Eric Andersen28c70b32000-06-14 20:42:57 +0000216
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000217 int i, j;
Eric Andersen28c70b32000-06-14 20:42:57 +0000218 byte * p = G.buf;
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000219 byte outbuf[4*DATABUFSIZE];
Eric Andersen28c70b32000-06-14 20:42:57 +0000220
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000221 for (i = len, j = 0; i > 0; i--, p++)
Eric Andersen28c70b32000-06-14 20:42:57 +0000222 {
223 if (*p == 0x1d)
224 {
225 conescape();
226 return;
227 }
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000228 outbuf[j++] = *p;
Eric Andersen28c70b32000-06-14 20:42:57 +0000229 if (*p == 0xff)
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000230 outbuf[j++] = 0xff;
231 else if (*p == 0x0d)
232 outbuf[j++] = 0x00;
Eric Andersen28c70b32000-06-14 20:42:57 +0000233 }
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000234 if (j > 0 )
235 write(G.netfd, outbuf, j);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000236}
237
Eric Andersen28c70b32000-06-14 20:42:57 +0000238
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000239static void handlenetinput(int len)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000240{
Eric Andersen28c70b32000-06-14 20:42:57 +0000241 int i;
242 int cstart = 0;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000243
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000244 for (i = 0; i < len; i++)
Eric Andersen28c70b32000-06-14 20:42:57 +0000245 {
246 byte c = G.buf[i];
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000247
Eric Andersen28c70b32000-06-14 20:42:57 +0000248 if (G.telstate == 0) /* most of the time state == 0 */
249 {
250 if (c == IAC)
251 {
252 cstart = i;
253 G.telstate = TS_IAC;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000254 }
255 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000256 else
257 switch (G.telstate)
258 {
259 case TS_0:
260 if (c == IAC)
261 G.telstate = TS_IAC;
262 else
263 G.buf[cstart++] = c;
264 break;
265
266 case TS_IAC:
267 if (c == IAC) /* IAC IAC -> 0xFF */
268 {
269 G.buf[cstart++] = c;
270 G.telstate = TS_0;
271 break;
272 }
273 /* else */
274 switch (c)
275 {
276 case SB:
277 G.telstate = TS_SUB1;
278 break;
279 case DO:
280 case DONT:
281 case WILL:
282 case WONT:
283 G.telwish = c;
284 G.telstate = TS_OPT;
285 break;
286 default:
287 G.telstate = TS_0; /* DATA MARK must be added later */
288 }
289 break;
290 case TS_OPT: /* WILL, WONT, DO, DONT */
291 telopt(c);
292 G.telstate = TS_0;
293 break;
294 case TS_SUB1: /* Subnegotiation */
295 case TS_SUB2: /* Subnegotiation */
Matt Kraai1f0c4362001-12-20 23:13:26 +0000296 if (subneg(c))
Eric Andersen28c70b32000-06-14 20:42:57 +0000297 G.telstate = TS_0;
298 break;
299 }
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000300 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000301 if (G.telstate)
302 {
303 if (G.iaclen) iacflush();
304 if (G.telstate == TS_0) G.telstate = 0;
305
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000306 len = cstart;
Eric Andersen28c70b32000-06-14 20:42:57 +0000307 }
308
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000309 if (len)
310 write(1, G.buf, len);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000311}
312
Eric Andersen28c70b32000-06-14 20:42:57 +0000313
314/* ******************************* */
315
316static inline void putiac(int c)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000317{
Eric Andersen28c70b32000-06-14 20:42:57 +0000318 G.iacbuf[G.iaclen++] = c;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000319}
320
Eric Andersen28c70b32000-06-14 20:42:57 +0000321
322static void putiac2(byte wwdd, byte c)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000323{
Eric Andersen28c70b32000-06-14 20:42:57 +0000324 if (G.iaclen + 3 > IACBUFSIZE)
325 iacflush();
326
327 putiac(IAC);
328 putiac(wwdd);
329 putiac(c);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000330}
331
Eric Andersen28c70b32000-06-14 20:42:57 +0000332#if 0
333static void putiac1(byte c)
334{
335 if (G.iaclen + 2 > IACBUFSIZE)
336 iacflush();
337
338 putiac(IAC);
339 putiac(c);
340}
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000341#endif
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000342
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000343#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000344static void putiac_subopt(byte c, char *str)
345{
346 int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 )
347
348 if (G.iaclen + len > IACBUFSIZE)
349 iacflush();
350
351 putiac(IAC);
352 putiac(SB);
353 putiac(c);
354 putiac(0);
355
356 while(*str)
357 putiac(*str++);
358
359 putiac(IAC);
360 putiac(SE);
361}
362#endif
363
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000364#ifdef CONFIG_FEATURE_AUTOWIDTH
365static void putiac_naws(byte c, int x, int y)
366{
367 if (G.iaclen + 9 > IACBUFSIZE)
368 iacflush();
369
370 putiac(IAC);
371 putiac(SB);
372 putiac(c);
373
374 putiac((x >> 8) & 0xff);
375 putiac(x & 0xff);
376 putiac((y >> 8) & 0xff);
377 putiac(y & 0xff);
378
379 putiac(IAC);
380 putiac(SE);
381}
382#endif
383
Eric Andersen28c70b32000-06-14 20:42:57 +0000384/* void putiacstring (subneg strings) */
385
386/* ******************************* */
387
Eric Andersen3e6ff902001-03-09 21:24:12 +0000388static char const escapecharis[] = "\r\nEscape character is ";
Eric Andersen28c70b32000-06-14 20:42:57 +0000389
Eric Andersencd8c4362001-11-10 11:22:46 +0000390static void setConMode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000391{
392 if (G.telflags & UF_ECHO)
393 {
394 if (G.charmode == CHM_TRY) {
395 G.charmode = CHM_ON;
Matt Kraai12f417e2001-01-18 02:57:08 +0000396 printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis);
Eric Andersen28c70b32000-06-14 20:42:57 +0000397 rawmode();
398 }
399 }
400 else
401 {
402 if (G.charmode != CHM_OFF) {
403 G.charmode = CHM_OFF;
Matt Kraai12f417e2001-01-18 02:57:08 +0000404 printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis);
Eric Andersen28c70b32000-06-14 20:42:57 +0000405 cookmode();
406 }
407 }
408}
409
410/* ******************************* */
411
Eric Andersencd8c4362001-11-10 11:22:46 +0000412static void will_charmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000413{
414 G.charmode = CHM_TRY;
415 G.telflags |= (UF_ECHO | UF_SGA);
416 setConMode();
417
418 putiac2(DO, TELOPT_ECHO);
419 putiac2(DO, TELOPT_SGA);
420 iacflush();
421}
422
Eric Andersencd8c4362001-11-10 11:22:46 +0000423static void do_linemode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000424{
425 G.charmode = CHM_TRY;
426 G.telflags &= ~(UF_ECHO | UF_SGA);
427 setConMode();
428
429 putiac2(DONT, TELOPT_ECHO);
430 putiac2(DONT, TELOPT_SGA);
431 iacflush();
432}
433
434/* ******************************* */
435
436static inline void to_notsup(char c)
437{
438 if (G.telwish == WILL) putiac2(DONT, c);
439 else if (G.telwish == DO) putiac2(WONT, c);
440}
441
Eric Andersencd8c4362001-11-10 11:22:46 +0000442static inline void to_echo(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000443{
444 /* if server requests ECHO, don't agree */
445 if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; }
446 else if (G.telwish == DONT) return;
447
448 if (G.telflags & UF_ECHO)
449 {
450 if (G.telwish == WILL)
451 return;
452 }
453 else
454 if (G.telwish == WONT)
455 return;
456
457 if (G.charmode != CHM_OFF)
458 G.telflags ^= UF_ECHO;
459
460 if (G.telflags & UF_ECHO)
461 putiac2(DO, TELOPT_ECHO);
462 else
463 putiac2(DONT, TELOPT_ECHO);
464
465 setConMode();
466 WriteCS(1, "\r\n"); /* sudden modec */
467}
468
Eric Andersencd8c4362001-11-10 11:22:46 +0000469static inline void to_sga(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000470{
471 /* daemon always sends will/wont, client do/dont */
472
473 if (G.telflags & UF_SGA)
474 {
475 if (G.telwish == WILL)
476 return;
477 }
478 else
479 if (G.telwish == WONT)
480 return;
481
482 if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
483 putiac2(DO, TELOPT_SGA);
484 else
485 putiac2(DONT, TELOPT_SGA);
486
487 return;
488}
489
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000490#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersencd8c4362001-11-10 11:22:46 +0000491static inline void to_ttype(void)
Eric Andersen7e1273e2001-05-07 17:57:45 +0000492{
493 /* Tell server we will (or won't) do TTYPE */
494
495 if(ttype)
496 putiac2(WILL, TELOPT_TTYPE);
497 else
498 putiac2(WONT, TELOPT_TTYPE);
499
500 return;
501}
502#endif
503
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000504#ifdef CONFIG_FEATURE_AUTOWIDTH
Tim Rikered8e0362002-04-26 07:53:39 +0000505static inline void to_naws(void)
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000506{
507 /* Tell server we will do NAWS */
508 putiac2(WILL, TELOPT_NAWS);
509 return;
510}
511#endif
512
Eric Andersen28c70b32000-06-14 20:42:57 +0000513static void telopt(byte c)
514{
515 switch (c)
516 {
Eric Andersen41634062002-04-26 08:44:17 +0000517 case TELOPT_ECHO: to_echo(); break;
518 case TELOPT_SGA: to_sga(); break;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000519#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen41634062002-04-26 08:44:17 +0000520 case TELOPT_TTYPE: to_ttype();break;
Eric Andersen7e1273e2001-05-07 17:57:45 +0000521#endif
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000522#ifdef CONFIG_FEATURE_AUTOWIDTH
Eric Andersen41634062002-04-26 08:44:17 +0000523 case TELOPT_NAWS: to_naws();
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000524 putiac_naws(c, win_width, win_height);
525 break;
526#endif
Eric Andersen8db361b2002-04-26 08:00:33 +0000527 default: to_notsup(c);
528 break;
Eric Andersen28c70b32000-06-14 20:42:57 +0000529 }
530}
531
532
533/* ******************************* */
534
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000535/* subnegotiation -- ignore all (except TTYPE,NAWS) */
Eric Andersen28c70b32000-06-14 20:42:57 +0000536
537static int subneg(byte c)
538{
539 switch (G.telstate)
540 {
541 case TS_SUB1:
542 if (c == IAC)
543 G.telstate = TS_SUB2;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000544#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000545 else
546 if (c == TELOPT_TTYPE)
547 putiac_subopt(TELOPT_TTYPE,ttype);
548#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000549 break;
550 case TS_SUB2:
551 if (c == SE)
552 return TRUE;
553 G.telstate = TS_SUB1;
554 /* break; */
555 }
556 return FALSE;
557}
558
559/* ******************************* */
560
561static void fgotsig(int sig)
562{
563 G.gotsig = sig;
564}
565
566
Eric Andersencd8c4362001-11-10 11:22:46 +0000567static void rawmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000568{
569 tcsetattr(0, TCSADRAIN, &G.termios_raw);
570}
571
Eric Andersencd8c4362001-11-10 11:22:46 +0000572static void cookmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000573{
574 tcsetattr(0, TCSADRAIN, &G.termios_def);
575}
576
577extern int telnet_main(int argc, char** argv)
578{
Eric Andersen0b315862002-07-03 11:51:44 +0000579 char *host;
580 char *port;
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000581 int len;
Eric Andersen28c70b32000-06-14 20:42:57 +0000582#ifdef USE_POLL
583 struct pollfd ufds[2];
584#else
585 fd_set readfds;
586 int maxfd;
587#endif
588
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000589#ifdef CONFIG_FEATURE_AUTOWIDTH
590 struct winsize winp;
591 if( ioctl(0, TIOCGWINSZ, &winp) == 0 ) {
592 win_width = winp.ws_col;
593 win_height = winp.ws_row;
594 }
595#endif
596
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000597#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000598 ttype = getenv("TERM");
599#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000600
601 memset(&G, 0, sizeof G);
602
603 if (tcgetattr(0, &G.termios_def) < 0)
604 exit(1);
605
606 G.termios_raw = G.termios_def;
Eric Andersen28c70b32000-06-14 20:42:57 +0000607 cfmakeraw(&G.termios_raw);
608
Eric Andersen67991cf2001-02-14 21:23:06 +0000609 if (argc < 2) show_usage();
Eric Andersen0b315862002-07-03 11:51:44 +0000610 port = (argc > 2)? argv[2] : "23";
Eric Andersen28c70b32000-06-14 20:42:57 +0000611
Eric Andersen0b315862002-07-03 11:51:44 +0000612 host = argv[1];
613
614 G.netfd = xconnect(host, port);
Eric Andersen28c70b32000-06-14 20:42:57 +0000615
Eric Andersen0b315862002-07-03 11:51:44 +0000616 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
Eric Andersen28c70b32000-06-14 20:42:57 +0000617
618 signal(SIGINT, fgotsig);
619
620#ifdef USE_POLL
621 ufds[0].fd = 0; ufds[1].fd = G.netfd;
622 ufds[0].events = ufds[1].events = POLLIN;
623#else
624 FD_ZERO(&readfds);
625 FD_SET(0, &readfds);
626 FD_SET(G.netfd, &readfds);
627 maxfd = G.netfd + 1;
628#endif
629
630 while (1)
631 {
632#ifndef USE_POLL
633 fd_set rfds = readfds;
634
635 switch (select(maxfd, &rfds, NULL, NULL, NULL))
636#else
637 switch (poll(ufds, 2, -1))
638#endif
639 {
640 case 0:
641 /* timeout */
642 case -1:
643 /* error, ignore and/or log something, bay go to loop */
644 if (G.gotsig)
645 conescape();
646 else
647 sleep(1);
648 break;
649 default:
650
651#ifdef USE_POLL
652 if (ufds[0].revents) /* well, should check POLLIN, but ... */
653#else
654 if (FD_ISSET(0, &rfds))
655#endif
656 {
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000657 len = read(0, G.buf, DATABUFSIZE);
Eric Andersen28c70b32000-06-14 20:42:57 +0000658
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000659 if (len <= 0)
Eric Andersen28c70b32000-06-14 20:42:57 +0000660 doexit(0);
661
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000662 TRACE(0, ("Read con: %d\n", len));
Eric Andersen28c70b32000-06-14 20:42:57 +0000663
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000664 handlenetoutput(len);
Eric Andersen28c70b32000-06-14 20:42:57 +0000665 }
666
667#ifdef USE_POLL
668 if (ufds[1].revents) /* well, should check POLLIN, but ... */
669#else
670 if (FD_ISSET(G.netfd, &rfds))
671#endif
672 {
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000673 len = read(G.netfd, G.buf, DATABUFSIZE);
Eric Andersen28c70b32000-06-14 20:42:57 +0000674
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000675 if (len <= 0)
Eric Andersen28c70b32000-06-14 20:42:57 +0000676 {
677 WriteCS(1, "Connection closed by foreign host.\r\n");
678 doexit(1);
679 }
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000680 TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
Eric Andersen28c70b32000-06-14 20:42:57 +0000681
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000682 handlenetinput(len);
Eric Andersen28c70b32000-06-14 20:42:57 +0000683 }
684 }
685 }
686}
687
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000688/*
Eric Andersen28c70b32000-06-14 20:42:57 +0000689Local Variables:
690c-file-style: "linux"
691c-basic-offset: 4
692tab-width: 4
693End:
694*/