1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
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 3, or (at your option)
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
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include <sys/socket.h>
41 extern struct win
*fore
;
42 extern struct layer
*flayer
;
43 extern int visual_bell
;
44 extern char screenterm
[];
46 static void TelReply
__P((struct win
*, char *, int));
47 static void TelDocmd
__P((struct win
*, int, int));
48 static void TelDosub
__P((struct win
*));
50 #define TEL_DEFPORT 23
51 #define TEL_CONNECTING (-2)
62 #define TC_S "S b swWdDc"
72 #define TO_LINEMODE 34
73 #define TO_XDISPLOC 35
76 #define TO_S "be c t wsf xE E"
79 static unsigned char tn_init
[] = {
80 TC_IAC
, TC_DO
, TO_SGA
,
81 TC_IAC
, TC_WILL
, TO_TTYPE
,
82 TC_IAC
, TC_WILL
, TO_NAWS
,
83 TC_IAC
, TC_WILL
, TO_LFLOW
,
87 tel_connev_fn(ev
, data
)
91 struct win
*p
= (struct win
*)data
;
92 if (connect(p
->w_ptyfd
, (struct sockaddr
*)&p
->w_telsa
, sizeof(p
->w_telsa
)) && errno
!= EISCONN
)
96 strncpy(buf
+ 1, strerror(errno
), sizeof(buf
) - 2);
97 buf
[sizeof(buf
) - 1] = 0;
98 WriteString(p
, buf
, strlen(buf
));
102 WriteString(p
, "connected.\r\n", 12);
103 evdeq(&p
->w_telconnev
);
114 if ((fd
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) == -1)
116 Msg(errno
, "TelOpen: socket");
119 if (setsockopt(fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *)&on
, sizeof(on
)))
120 Msg(errno
, "TelOpen: setsockopt SO_OOBINLINE");
128 int port
= TEL_DEFPORT
;
133 args
= p
->w_cmdargs
+ 1;
137 Msg(0, "Usage: screen //telnet host [port]");
141 port
= atoi(args
[1]);
142 p
->w_telsa
.sin_family
= AF_INET
;
143 if((p
->w_telsa
.sin_addr
.s_addr
= inet_addr(*args
)) == -1)
145 if ((hp
= gethostbyname(*args
)) == NULL
)
147 Msg(0, "unknown host: %s", *args
);
150 if (hp
->h_length
!= sizeof(p
->w_telsa
.sin_addr
.s_addr
) || hp
->h_addrtype
!= AF_INET
)
152 Msg(0, "Bad address type for %s", hp
->h_name
);
155 bcopy((char *)hp
->h_addr
,(char *)&p
->w_telsa
.sin_addr
.s_addr
, hp
->h_length
);
156 p
->w_telsa
.sin_family
= hp
->h_addrtype
;
158 p
->w_telsa
.sin_port
= htons(port
);
159 if (port
!= TEL_DEFPORT
)
160 sprintf(buf
, "Trying %s %d...", inet_ntoa(p
->w_telsa
.sin_addr
), port
);
162 sprintf(buf
, "Trying %s...", inet_ntoa(p
->w_telsa
.sin_addr
));
163 WriteString(p
, buf
, strlen(buf
));
164 if (connect(p
->w_ptyfd
, (struct sockaddr
*)&p
->w_telsa
, sizeof(p
->w_telsa
)))
166 if (errno
== EINPROGRESS
)
168 p
->w_telstate
= TEL_CONNECTING
;
169 p
->w_telconnev
.fd
= p
->w_ptyfd
;
170 p
->w_telconnev
.handler
= tel_connev_fn
;
171 p
->w_telconnev
.data
= (char *)p
;
172 p
->w_telconnev
.type
= EV_WRITE
;
173 p
->w_telconnev
.pri
= 1;
174 debug("telnet connect in progress...\n");
175 evenq(&p
->w_telconnev
);
179 Msg(errno
, "TelOpen: connect");
184 WriteString(p
, "connected.\r\n", 12);
185 if (port
== TEL_DEFPORT
)
186 TelReply(p
, (char *)tn_init
, sizeof(tn_init
));
194 return !fore
->w_telropts
[TO_SGA
];
198 TelProcessLine(bufpp
, lenp
)
202 int echo
= !fore
->w_telropts
[TO_ECHO
];
211 c
= *(unsigned char *)buf
++;
212 if (fore
->w_telbufl
+ 2 >= IOSIZE
)
214 WBell(fore
, visual_bell
);
220 WriteString(fore
, "\r\n", 2);
221 fore
->w_telbuf
[fore
->w_telbufl
++] = '\r';
222 fore
->w_telbuf
[fore
->w_telbufl
++] = '\n';
224 tl
= fore
->w_telbufl
;
225 LayProcess(&tb
, &tl
);
229 if (c
== '\b' && fore
->w_telbufl
> 0)
233 WriteString(fore
, (char *)&c
, 1);
234 WriteString(fore
, " ", 1);
235 WriteString(fore
, (char *)&c
, 1);
239 if ((c
>= 0x20 && c
<= 0x7e) || c
>= 0xa0)
242 WriteString(fore
, (char *)&c
, 1);
243 fore
->w_telbuf
[fore
->w_telbufl
++] = c
;
250 DoTelnet(buf
, lenp
, f
)
255 int echo
= !fore
->w_telropts
[TO_ECHO
];
256 int cmode
= fore
->w_telropts
[TO_SGA
];
257 int bin
= fore
->w_telropts
[TO_BINARY
];
258 char *p
= buf
, *sbuf
;
266 c
= *(unsigned char *)p
++;
267 if (c
== TC_IAC
|| (c
== '\r' && (l
==0 || *p
!= '\n') && cmode
&& !bin
))
271 WriteString(fore
, sbuf
, p
- sbuf
);
301 /* modifies data in-place, returns new length */
303 TelIn(p
, buf
, len
, free
)
315 c
= *(unsigned char *)rp
++;
317 if (p
->w_telstate
>= TC_WILL
&& p
->w_telstate
<= TC_DONT
)
319 TelDocmd(p
, p
->w_telstate
, c
);
323 if (p
->w_telstate
== TC_SB
|| p
->w_telstate
== TC_SE
)
325 if (p
->w_telstate
== TC_SE
&& c
== TC_IAC
)
327 if (p
->w_telstate
== TC_SE
&& c
== TC_SE
)
334 if (p
->w_telstate
== TC_SB
&& c
== TC_IAC
)
335 p
->w_telstate
= TC_SE
;
337 p
->w_telstate
= TC_SB
;
338 p
->w_telsubbuf
[p
->w_telsubidx
] = c
;
339 if (p
->w_telsubidx
< sizeof(p
->w_telsubbuf
) - 1)
343 if (p
->w_telstate
== TC_IAC
)
345 if ((c
>= TC_WILL
&& c
<= TC_DONT
) || c
== TC_SB
)
355 else if (c
== TC_IAC
)
360 if (p
->w_telstate
== '\r')
364 continue; /* suppress trailing \0 */
366 else if (c
== '\n' && !p
->w_telropts
[TO_SGA
])
368 /* oops... simulate terminal line mode: insert \r */
374 bcopy(rp
, rp
+ 1, len
);
390 TelReply(p
, str
, len
)
397 if (p
->w_inlen
+ len
> IOSIZE
)
399 Msg(0, "Warning: telnet protocol overrun!");
402 bcopy(str
, p
->w_inbuf
+ p
->w_inlen
, len
);
407 TelDocmd(p
, cmd
, opt
)
415 debug2("[<-WONT %c %d]\n", TO_S
[opt
], opt
);
417 debug2("[<-WILL %c %d]\n", TO_S
[opt
], opt
);
419 debug2("[<-DONT %c %d]\n", TO_S
[opt
], opt
);
421 debug2("[<-DO %c %d]\n", TO_S
[opt
], opt
);
426 if (p
->w_telropts
[opt
] || opt
== TO_TM
)
429 if (opt
== TO_ECHO
|| opt
== TO_SGA
|| opt
== TO_BINARY
)
431 p
->w_telropts
[opt
] = 1;
437 if (!p
->w_telropts
[opt
] || opt
== TO_TM
)
441 if (opt
== TO_ECHO
|| opt
== TO_SGA
)
444 p
->w_telropts
[opt
] = 0;
447 if (p
->w_telmopts
[opt
])
450 if (opt
== TO_TTYPE
|| opt
== TO_SGA
|| opt
== TO_BINARY
|| opt
== TO_NAWS
|| opt
== TO_TM
|| opt
== TO_LFLOW
)
453 p
->w_telmopts
[opt
] = 1;
455 p
->w_telmopts
[TO_TM
] = 0;
458 if (!p
->w_telmopts
[opt
])
461 p
->w_telmopts
[opt
] = 0;
469 debug2("[->WONT %c %d]\n", TO_S
[opt
], opt
);
471 debug2("[->WILL %c %d]\n", TO_S
[opt
], opt
);
473 debug2("[->DONT %c %d]\n", TO_S
[opt
], opt
);
475 debug2("[->DO %c %d]\n", TO_S
[opt
], opt
);
477 TelReply(p
, (char *)b
, 3);
478 if (cmd
== TC_DO
&& opt
== TO_NAWS
)
487 char trepl
[20 + 6 + 1];
490 switch(p
->w_telsubbuf
[0])
493 if (p
->w_telsubidx
!= 2 || p
->w_telsubbuf
[1] != 1)
495 l
= strlen(screenterm
);
498 sprintf(trepl
, "%c%c%c%c%s%c%c", TC_IAC
, TC_SB
, TO_TTYPE
, 0, screenterm
, TC_IAC
, TC_SE
);
499 TelReply(p
, trepl
, l
+ 6);
502 if (p
->w_telsubidx
!= 2)
504 debug1("[FLOW %d]\r\n", p
->w_telsubbuf
[1]);
515 static unsigned char tel_break
[] = { TC_IAC
, TC_BREAK
};
516 TelReply(p
, (char *)tel_break
, 2);
523 char s
[20], trepl
[20], *t
;
526 debug2("TelWindowSize %d %d\n", p
->w_width
, p
->w_height
);
527 if (p
->w_width
== 0 || p
->w_height
== 0 || !p
->w_telmopts
[TO_NAWS
])
529 sprintf(s
, "%c%c%c%c%c%c%c%c%c", TC_SB
, TC_SB
, TO_NAWS
, p
->w_width
/ 256, p
->w_width
& 255, p
->w_height
/ 256, p
->w_height
& 255, TC_SE
, TC_SE
);
531 for (i
= 0; i
< 9; i
++)
532 if ((unsigned char)(*t
++ = s
[i
]) == TC_IAC
)
537 for (i
= 0; trepl
+ i
< t
; i
++)
538 debug1(" %02x", (unsigned char)trepl
[i
]);
540 TelReply(p
, trepl
, t
- trepl
);
543 static char tc_s
[] = TC_S
;
544 static char to_s
[] = TO_S
;
555 for (i
= 0; to_s
[i
]; i
++)
557 if (to_s
[i
] == ' ' || p
->w_telmopts
[i
] == 0)
562 for (i
= 0; to_s
[i
]; i
++)
564 if (to_s
[i
] == ' ' || p
->w_telropts
[i
] == 0)
568 if (p
->w_telstate
== TEL_CONNECTING
)
570 else if (p
->w_telstate
&& p
->w_telstate
!= '\r')
573 *buf
++ = tc_s
[p
->w_telstate
- TC_SE
];
580 #endif /* BUILTIN_TELNET */