1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include <sys/socket.h>
36 extern struct win
*fore
;
37 extern struct layer
*flayer
;
38 extern int visual_bell
;
39 extern char screenterm
[];
41 static void TelReply
__P((struct win
*, char *, int));
42 static void TelDocmd
__P((struct win
*, int, int));
43 static void TelDosub
__P((struct win
*));
45 #define TEL_DEFPORT 23
46 #define TEL_CONNECTING (-2)
57 #define TC_S "S b swWdDc"
67 #define TO_LINEMODE 34
68 #define TO_XDISPLOC 35
71 #define TO_S "be c t wsf xE E"
74 static unsigned char tn_init
[] = {
75 TC_IAC
, TC_DO
, TO_SGA
,
76 TC_IAC
, TC_WILL
, TO_TTYPE
,
77 TC_IAC
, TC_WILL
, TO_NAWS
,
78 TC_IAC
, TC_WILL
, TO_LFLOW
,
82 tel_connev_fn(ev
, data
)
86 struct win
*p
= (struct win
*)data
;
87 if (connect(p
->w_ptyfd
, (struct sockaddr
*)&p
->w_telsa
, sizeof(p
->w_telsa
)) && errno
!= EISCONN
)
91 strncpy(buf
+ 1, strerror(errno
), sizeof(buf
) - 2);
92 buf
[sizeof(buf
) - 1] = 0;
93 WriteString(p
, buf
, strlen(buf
));
97 WriteString(p
, "connected.\r\n", 12);
98 evdeq(&p
->w_telconnev
);
109 if ((fd
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) == -1)
111 Msg(errno
, "TelOpen: socket");
114 if (setsockopt(fd
, SOL_SOCKET
, SO_OOBINLINE
, (char *)&on
, sizeof(on
)))
115 Msg(errno
, "TelOpen: setsockopt SO_OOBINLINE");
123 int port
= TEL_DEFPORT
;
128 args
= p
->w_cmdargs
+ 1;
132 Msg(0, "Usage: screen //telnet host [port]");
136 port
= atoi(args
[1]);
137 p
->w_telsa
.sin_family
= AF_INET
;
138 if((p
->w_telsa
.sin_addr
.s_addr
= inet_addr(*args
)) == -1)
140 if ((hp
= gethostbyname(*args
)) == NULL
)
142 Msg(0, "unknown host: %s", *args
);
145 if (hp
->h_length
!= sizeof(p
->w_telsa
.sin_addr
.s_addr
) || hp
->h_addrtype
!= AF_INET
)
147 Msg(0, "Bad address type for %s", hp
->h_name
);
150 bcopy((char *)hp
->h_addr
,(char *)&p
->w_telsa
.sin_addr
.s_addr
, hp
->h_length
);
151 p
->w_telsa
.sin_family
= hp
->h_addrtype
;
153 p
->w_telsa
.sin_port
= htons(port
);
154 if (port
!= TEL_DEFPORT
)
155 sprintf(buf
, "Trying %s %d...", inet_ntoa(p
->w_telsa
.sin_addr
), port
);
157 sprintf(buf
, "Trying %s...", inet_ntoa(p
->w_telsa
.sin_addr
));
158 WriteString(p
, buf
, strlen(buf
));
159 if (connect(p
->w_ptyfd
, (struct sockaddr
*)&p
->w_telsa
, sizeof(p
->w_telsa
)))
161 if (errno
== EINPROGRESS
)
163 p
->w_telstate
= TEL_CONNECTING
;
164 p
->w_telconnev
.fd
= p
->w_ptyfd
;
165 p
->w_telconnev
.handler
= tel_connev_fn
;
166 p
->w_telconnev
.data
= (char *)p
;
167 p
->w_telconnev
.type
= EV_WRITE
;
168 p
->w_telconnev
.pri
= 1;
169 debug("telnet connect in progress...\n");
170 evenq(&p
->w_telconnev
);
174 Msg(errno
, "TelOpen: connect");
179 WriteString(p
, "connected.\r\n", 12);
180 if (port
== TEL_DEFPORT
)
181 TelReply(p
, (char *)tn_init
, sizeof(tn_init
));
189 return !fore
->w_telropts
[TO_SGA
];
193 TelProcessLine(bufpp
, lenp
)
197 int echo
= !fore
->w_telropts
[TO_ECHO
];
206 c
= *(unsigned char *)buf
++;
207 if (fore
->w_telbufl
+ 2 >= IOSIZE
)
209 WBell(fore
, visual_bell
);
215 WriteString(fore
, "\r\n", 2);
216 fore
->w_telbuf
[fore
->w_telbufl
++] = '\r';
217 fore
->w_telbuf
[fore
->w_telbufl
++] = '\n';
219 tl
= fore
->w_telbufl
;
220 LayProcess(&tb
, &tl
);
224 if (c
== '\b' && fore
->w_telbufl
> 0)
228 WriteString(fore
, (char *)&c
, 1);
229 WriteString(fore
, " ", 1);
230 WriteString(fore
, (char *)&c
, 1);
234 if ((c
>= 0x20 && c
<= 0x7e) || c
>= 0xa0)
237 WriteString(fore
, (char *)&c
, 1);
238 fore
->w_telbuf
[fore
->w_telbufl
++] = c
;
245 DoTelnet(buf
, lenp
, f
)
250 int echo
= !fore
->w_telropts
[TO_ECHO
];
251 int cmode
= fore
->w_telropts
[TO_SGA
];
252 int bin
= fore
->w_telropts
[TO_BINARY
];
253 char *p
= buf
, *sbuf
;
261 c
= *(unsigned char *)p
++;
262 if (c
== TC_IAC
|| (c
== '\r' && (l
==0 || *p
!= '\n') && cmode
&& !bin
))
266 WriteString(fore
, sbuf
, p
- sbuf
);
296 /* modifies data in-place, returns new length */
298 TelIn(p
, buf
, len
, free
)
310 c
= *(unsigned char *)rp
++;
312 if (p
->w_telstate
>= TC_WILL
&& p
->w_telstate
<= TC_DONT
)
314 TelDocmd(p
, p
->w_telstate
, c
);
318 if (p
->w_telstate
== TC_SB
|| p
->w_telstate
== TC_SE
)
320 if (p
->w_telstate
== TC_SE
&& c
== TC_IAC
)
322 if (p
->w_telstate
== TC_SE
&& c
== TC_SE
)
329 if (p
->w_telstate
== TC_SB
&& c
== TC_IAC
)
330 p
->w_telstate
= TC_SE
;
332 p
->w_telstate
= TC_SB
;
333 p
->w_telsubbuf
[p
->w_telsubidx
] = c
;
334 if (p
->w_telsubidx
< sizeof(p
->w_telsubbuf
) - 1)
338 if (p
->w_telstate
== TC_IAC
)
340 if ((c
>= TC_WILL
&& c
<= TC_DONT
) || c
== TC_SB
)
350 else if (c
== TC_IAC
)
355 if (p
->w_telstate
== '\r')
359 continue; /* suppress trailing \0 */
361 else if (c
== '\n' && !p
->w_telropts
[TO_SGA
])
363 /* oops... simulate terminal line mode: insert \r */
369 bcopy(rp
, rp
+ 1, len
);
385 TelReply(p
, str
, len
)
392 if (p
->w_inlen
+ len
> IOSIZE
)
394 Msg(0, "Warning: telnet protocol overrun!");
397 bcopy(str
, p
->w_inbuf
+ p
->w_inlen
, len
);
402 TelDocmd(p
, cmd
, opt
)
410 debug2("[<-WONT %c %d]\n", TO_S
[opt
], opt
);
412 debug2("[<-WILL %c %d]\n", TO_S
[opt
], opt
);
414 debug2("[<-DONT %c %d]\n", TO_S
[opt
], opt
);
416 debug2("[<-DO %c %d]\n", TO_S
[opt
], opt
);
421 if (p
->w_telropts
[opt
] || opt
== TO_TM
)
424 if (opt
== TO_ECHO
|| opt
== TO_SGA
|| opt
== TO_BINARY
)
426 p
->w_telropts
[opt
] = 1;
432 if (!p
->w_telropts
[opt
] || opt
== TO_TM
)
436 if (opt
== TO_ECHO
|| opt
== TO_SGA
)
439 p
->w_telropts
[opt
] = 0;
442 if (p
->w_telmopts
[opt
])
445 if (opt
== TO_TTYPE
|| opt
== TO_SGA
|| opt
== TO_BINARY
|| opt
== TO_NAWS
|| opt
== TO_TM
|| opt
== TO_LFLOW
)
448 p
->w_telmopts
[opt
] = 1;
450 p
->w_telmopts
[TO_TM
] = 0;
453 if (!p
->w_telmopts
[opt
])
456 p
->w_telmopts
[opt
] = 0;
464 debug2("[->WONT %c %d]\n", TO_S
[opt
], opt
);
466 debug2("[->WILL %c %d]\n", TO_S
[opt
], opt
);
468 debug2("[->DONT %c %d]\n", TO_S
[opt
], opt
);
470 debug2("[->DO %c %d]\n", TO_S
[opt
], opt
);
472 TelReply(p
, (char *)b
, 3);
473 if (cmd
== TC_DO
&& opt
== TO_NAWS
)
482 char trepl
[20 + 6 + 1];
485 switch(p
->w_telsubbuf
[0])
488 if (p
->w_telsubidx
!= 2 || p
->w_telsubbuf
[1] != 1)
490 l
= strlen(screenterm
);
493 sprintf(trepl
, "%c%c%c%c%s%c%c", TC_IAC
, TC_SB
, TO_TTYPE
, 0, screenterm
, TC_IAC
, TC_SE
);
494 TelReply(p
, trepl
, l
+ 6);
497 if (p
->w_telsubidx
!= 2)
499 debug1("[FLOW %d]\r\n", p
->w_telsubbuf
[1]);
510 static unsigned char tel_break
[] = { TC_IAC
, TC_BREAK
};
511 TelReply(p
, (char *)tel_break
, 2);
518 char s
[20], trepl
[20], *t
;
521 debug2("TelWindowSize %d %d\n", p
->w_width
, p
->w_height
);
522 if (p
->w_width
== 0 || p
->w_height
== 0 || !p
->w_telmopts
[TO_NAWS
])
524 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
);
526 for (i
= 0; i
< 9; i
++)
527 if ((unsigned char)(*t
++ = s
[i
]) == TC_IAC
)
532 for (i
= 0; trepl
+ i
< t
; i
++)
533 debug1(" %02x", (unsigned char)trepl
[i
]);
535 TelReply(p
, trepl
, t
- trepl
);
538 static char tc_s
[] = TC_S
;
539 static char to_s
[] = TO_S
;
550 for (i
= 0; to_s
[i
]; i
++)
552 if (to_s
[i
] == ' ' || p
->w_telmopts
[i
] == 0)
557 for (i
= 0; to_s
[i
]; i
++)
559 if (to_s
[i
] == ' ' || p
->w_telropts
[i
] == 0)
563 if (p
->w_telstate
== TEL_CONNECTING
)
565 else if (p
->w_telstate
&& p
->w_telstate
!= '\r')
568 *buf
++ = tc_s
[p
->w_telstate
- TC_SE
];
575 #endif /* BUILTIN_TELNET */