Merge branch 'master' into lua-scripting
[screen-lua.git] / src / teln.c
bloba18f003a25dbac9ffb91f67e9f683310e0f0c0b6
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)
9 * any later version.
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>
26 #include <fcntl.h>
27 #include <netdb.h>
29 #include "config.h"
31 #ifdef BUILTIN_TELNET
33 #include "screen.h"
34 #include "extern.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)
48 #define TC_IAC 255
49 #define TC_DONT 254
50 #define TC_DO 253
51 #define TC_WONT 252
52 #define TC_WILL 251
53 #define TC_SB 250
54 #define TC_BREAK 243
55 #define TC_SE 240
57 #define TC_S "S b swWdDc"
59 #define TO_BINARY 0
60 #define TO_ECHO 1
61 #define TO_SGA 3
62 #define TO_TM 6
63 #define TO_TTYPE 24
64 #define TO_NAWS 31
65 #define TO_TSPEED 32
66 #define TO_LFLOW 33
67 #define TO_LINEMODE 34
68 #define TO_XDISPLOC 35
69 #define TO_NEWENV 39
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,
81 static void
82 tel_connev_fn(ev, data)
83 struct event *ev;
84 char *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)
89 char buf[1024];
90 buf[0] = ' ';
91 strncpy(buf + 1, strerror(errno), sizeof(buf) - 2);
92 buf[sizeof(buf) - 1] = 0;
93 WriteString(p, buf, strlen(buf));
94 WindowDied(p, 0, 0);
95 return;
97 WriteString(p, "connected.\r\n", 12);
98 evdeq(&p->w_telconnev);
99 p->w_telstate = 0;
103 TelOpen(args)
104 char **args;
106 int fd;
107 int on = 1;
109 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
111 Msg(errno, "TelOpen: socket");
112 return -1;
114 if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)))
115 Msg(errno, "TelOpen: setsockopt SO_OOBINLINE");
116 return fd;
120 TelConnect(p)
121 struct win *p;
123 int port = TEL_DEFPORT;
124 struct hostent *hp;
125 char **args;
126 char buf[256];
128 args = p->w_cmdargs + 1;
130 if (!*args)
132 Msg(0, "Usage: screen //telnet host [port]");
133 return -1;
135 if (args[1])
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);
143 return -1;
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);
148 return -1;
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);
156 else
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);
172 else
174 Msg(errno, "TelOpen: connect");
175 return -1;
178 else
179 WriteString(p, "connected.\r\n", 12);
180 if (port == TEL_DEFPORT)
181 TelReply(p, (char *)tn_init, sizeof(tn_init));
182 return 0;
186 TelIsline(p)
187 struct win *p;
189 return !fore->w_telropts[TO_SGA];
192 void
193 TelProcessLine(bufpp, lenp)
194 char **bufpp;
195 int *lenp;
197 int echo = !fore->w_telropts[TO_ECHO];
198 unsigned char c;
199 char *tb;
200 int tl;
202 char *buf = *bufpp;
203 int l = *lenp;
204 while (l--)
206 c = *(unsigned char *)buf++;
207 if (fore->w_telbufl + 2 >= IOSIZE)
209 WBell(fore, visual_bell);
210 continue;
212 if (c == '\r')
214 if (echo)
215 WriteString(fore, "\r\n", 2);
216 fore->w_telbuf[fore->w_telbufl++] = '\r';
217 fore->w_telbuf[fore->w_telbufl++] = '\n';
218 tb = fore->w_telbuf;
219 tl = fore->w_telbufl;
220 LayProcess(&tb, &tl);
221 fore->w_telbufl = 0;
222 continue;
224 if (c == '\b' && fore->w_telbufl > 0)
226 if (echo)
228 WriteString(fore, (char *)&c, 1);
229 WriteString(fore, " ", 1);
230 WriteString(fore, (char *)&c, 1);
232 fore->w_telbufl--;
234 if ((c >= 0x20 && c <= 0x7e) || c >= 0xa0)
236 if (echo)
237 WriteString(fore, (char *)&c, 1);
238 fore->w_telbuf[fore->w_telbufl++] = c;
241 *lenp = 0;
245 DoTelnet(buf, lenp, f)
246 char *buf;
247 int *lenp;
248 int 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;
254 int trunc = 0;
255 int c;
256 int l = *lenp;
258 sbuf = p;
259 while (l-- > 0)
261 c = *(unsigned char *)p++;
262 if (c == TC_IAC || (c == '\r' && (l ==0 || *p != '\n') && cmode && !bin))
264 if (cmode && echo)
266 WriteString(fore, sbuf, p - sbuf);
267 sbuf = p;
269 if (f-- <= 0)
271 trunc++;
272 l--;
274 if (l < 0)
276 p--; /* drop char */
277 break;
279 if (l)
280 bcopy(p, p + 1, l);
281 if (c == TC_IAC)
282 *p++ = c;
283 else if (c == '\r')
284 *p++ = 0;
285 else if (c == '\n')
287 p[-1] = '\r';
288 *p++ = '\n';
292 *lenp = p - buf;
293 return trunc;
296 /* modifies data in-place, returns new length */
298 TelIn(p, buf, len, free)
299 struct win *p;
300 char *buf;
301 int len;
302 int free;
304 char *rp, *wp;
305 int c;
307 rp = wp = buf;
308 while (len-- > 0)
310 c = *(unsigned char *)rp++;
312 if (p->w_telstate >= TC_WILL && p->w_telstate <= TC_DONT)
314 TelDocmd(p, p->w_telstate, c);
315 p->w_telstate = 0;
316 continue;
318 if (p->w_telstate == TC_SB || p->w_telstate == TC_SE)
320 if (p->w_telstate == TC_SE && c == TC_IAC)
321 p->w_telsubidx--;
322 if (p->w_telstate == TC_SE && c == TC_SE)
324 p->w_telsubidx--;
325 TelDosub(p);
326 p->w_telstate = 0;
327 continue;
329 if (p->w_telstate == TC_SB && c == TC_IAC)
330 p->w_telstate = TC_SE;
331 else
332 p->w_telstate = TC_SB;
333 p->w_telsubbuf[p->w_telsubidx] = c;
334 if (p->w_telsubidx < sizeof(p->w_telsubbuf) - 1)
335 p->w_telsubidx++;
336 continue;
338 if (p->w_telstate == TC_IAC)
340 if ((c >= TC_WILL && c <= TC_DONT) || c == TC_SB)
342 p->w_telsubidx = 0;
343 p->w_telstate = c;
344 continue;
346 p->w_telstate = 0;
347 if (c != TC_IAC)
348 continue;
350 else if (c == TC_IAC)
352 p->w_telstate = c;
353 continue;
355 if (p->w_telstate == '\r')
357 p->w_telstate = 0;
358 if (c == 0)
359 continue; /* suppress trailing \0 */
361 else if (c == '\n' && !p->w_telropts[TO_SGA])
363 /* oops... simulate terminal line mode: insert \r */
364 if (wp + 1 == rp)
366 if (free-- > 0)
368 if (len)
369 bcopy(rp, rp + 1, len);
370 rp++;
371 *wp++ = '\r';
374 else
375 *wp++ = '\r';
377 if (c == '\r')
378 p->w_telstate = c;
379 *wp++ = c;
381 return wp - buf;
384 static void
385 TelReply(p, str, len)
386 struct win *p;
387 char *str;
388 int len;
390 if (len <= 0)
391 return;
392 if (p->w_inlen + len > IOSIZE)
394 Msg(0, "Warning: telnet protocol overrun!");
395 return;
397 bcopy(str, p->w_inbuf + p->w_inlen, len);
398 p->w_inlen += len;
401 static void
402 TelDocmd(p, cmd, opt)
403 struct win *p;
404 int cmd, opt;
406 unsigned char b[3];
407 int repl = 0;
409 if (cmd == TC_WONT)
410 debug2("[<-WONT %c %d]\n", TO_S[opt], opt);
411 if (cmd == TC_WILL)
412 debug2("[<-WILL %c %d]\n", TO_S[opt], opt);
413 if (cmd == TC_DONT)
414 debug2("[<-DONT %c %d]\n", TO_S[opt], opt);
415 if (cmd == TC_DO)
416 debug2("[<-DO %c %d]\n", TO_S[opt], opt);
418 switch(cmd)
420 case TC_WILL:
421 if (p->w_telropts[opt] || opt == TO_TM)
422 return;
423 repl = TC_DONT;
424 if (opt == TO_ECHO || opt == TO_SGA || opt == TO_BINARY)
426 p->w_telropts[opt] = 1;
427 /* setcon(); */
428 repl = TC_DO;
430 break;
431 case TC_WONT:
432 if (!p->w_telropts[opt] || opt == TO_TM)
433 return;
434 repl = TC_DONT;
435 #if 0
436 if (opt == TO_ECHO || opt == TO_SGA)
437 setcon();
438 #endif
439 p->w_telropts[opt] = 0;
440 break;
441 case TC_DO:
442 if (p->w_telmopts[opt])
443 return;
444 repl = TC_WONT;
445 if (opt == TO_TTYPE || opt == TO_SGA || opt == TO_BINARY || opt == TO_NAWS || opt == TO_TM || opt == TO_LFLOW)
447 repl = TC_WILL;
448 p->w_telmopts[opt] = 1;
450 p->w_telmopts[TO_TM] = 0;
451 break;
452 case TC_DONT:
453 if (!p->w_telmopts[opt])
454 return;
455 repl = TC_WONT;
456 p->w_telmopts[opt] = 0;
457 break;
459 b[0] = TC_IAC;
460 b[1] = repl;
461 b[2] = opt;
463 if (repl == TC_WONT)
464 debug2("[->WONT %c %d]\n", TO_S[opt], opt);
465 if (repl == TC_WILL)
466 debug2("[->WILL %c %d]\n", TO_S[opt], opt);
467 if (repl == TC_DONT)
468 debug2("[->DONT %c %d]\n", TO_S[opt], opt);
469 if (repl == TC_DO)
470 debug2("[->DO %c %d]\n", TO_S[opt], opt);
472 TelReply(p, (char *)b, 3);
473 if (cmd == TC_DO && opt == TO_NAWS)
474 TelWindowSize(p);
478 static void
479 TelDosub(p)
480 struct win *p;
482 char trepl[20 + 6 + 1];
483 int l;
485 switch(p->w_telsubbuf[0])
487 case TO_TTYPE:
488 if (p->w_telsubidx != 2 || p->w_telsubbuf[1] != 1)
489 return;
490 l = strlen(screenterm);
491 if (l >= 20)
492 break;
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);
495 break;
496 case TO_LFLOW:
497 if (p->w_telsubidx != 2)
498 return;
499 debug1("[FLOW %d]\r\n", p->w_telsubbuf[1]);
500 break;
501 default:
502 break;
506 void
507 TelBreak(p)
508 struct win *p;
510 static unsigned char tel_break[] = { TC_IAC, TC_BREAK };
511 TelReply(p, (char *)tel_break, 2);
514 void
515 TelWindowSize(p)
516 struct win *p;
518 char s[20], trepl[20], *t;
519 int i;
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])
523 return;
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);
525 t = trepl;
526 for (i = 0; i < 9; i++)
527 if ((unsigned char)(*t++ = s[i]) == TC_IAC)
528 *t++ = TC_IAC;
529 trepl[0] = TC_IAC;
530 t[-2] = TC_IAC;
531 debug(" - sending");
532 for (i = 0; trepl + i < t; i++)
533 debug1(" %02x", (unsigned char)trepl[i]);
534 debug("\n");
535 TelReply(p, trepl, t - trepl);
538 static char tc_s[] = TC_S;
539 static char to_s[] = TO_S;
541 void
542 TelStatus(p, buf, l)
543 struct win *p;
544 char *buf;
545 int l;
547 int i;
549 *buf++ = '[';
550 for (i = 0; to_s[i]; i++)
552 if (to_s[i] == ' ' || p->w_telmopts[i] == 0)
553 continue;
554 *buf++ = to_s[i];
556 *buf++ = ':';
557 for (i = 0; to_s[i]; i++)
559 if (to_s[i] == ' ' || p->w_telropts[i] == 0)
560 continue;
561 *buf++ = to_s[i];
563 if (p->w_telstate == TEL_CONNECTING)
564 buf[-1] = 'C';
565 else if (p->w_telstate && p->w_telstate != '\r')
567 *buf++ = ':';
568 *buf++ = tc_s[p->w_telstate - TC_SE];
570 *buf++ = ']';
571 *buf = 0;
572 return;
575 #endif /* BUILTIN_TELNET */