make source match the man page, handle -number/+number more cleanly
[unix-history] / usr / src / usr.bin / telnet / sys_bsd.c
CommitLineData
897ce52e 1/*
7a26b73d 2 * Copyright (c) 1988, 1990 Regents of the University of California.
897ce52e
KB
3 * All rights reserved.
4 *
cb956e54 5 * %sccs.include.redist.c%
897ce52e
KB
6 */
7
8#ifndef lint
15d31b7e 9static char sccsid[] = "@(#)sys_bsd.c 5.2 (Berkeley) %G%";
897ce52e
KB
10#endif /* not lint */
11
e767b7ab
GM
12/*
13 * The following routines try to encapsulate what is system dependent
14 * (at least between 4.x and dos) which is used in telnet.c.
15 */
16
e767b7ab 17
344def17 18#include <fcntl.h>
115a5494 19#include <sys/types.h>
e767b7ab 20#include <sys/time.h>
b307f09e 21#include <sys/socket.h>
e767b7ab 22#include <signal.h>
b307f09e 23#include <errno.h>
6055a9f6 24#include <arpa/telnet.h>
e767b7ab 25
115a5494
GM
26#include "ring.h"
27
807a3a7d
GM
28#include "fdset.h"
29
e767b7ab
GM
30#include "defines.h"
31#include "externs.h"
32#include "types.h"
33
7a26b73d 34#if defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO))
87b60187
PB
35#define SIG_FUNC_RET void
36#else
37#define SIG_FUNC_RET int
38#endif
39
e767b7ab 40int
b307f09e
GM
41 tout, /* Output file descriptor */
42 tin, /* Input file descriptor */
4ad36dea 43 net;
e767b7ab 44
6055a9f6
PB
45#ifndef USE_TERMIO
46struct tchars otc = { 0 }, ntc = { 0 };
47struct ltchars oltc = { 0 }, nltc = { 0 };
48struct sgttyb ottyb = { 0 }, nttyb = { 0 };
6570c863 49int olmode = 0;
7a26b73d
PB
50# define cfgetispeed(ptr) (ptr)->sg_ispeed
51# define cfgetospeed(ptr) (ptr)->sg_ospeed
52# define old_tc ottyb
6055a9f6 53
6055a9f6
PB
54#else /* USE_TERMIO */
55struct termio old_tc = { 0 };
56extern struct termio new_tc;
57
7a26b73d
PB
58# ifndef TCSANOW
59# ifdef TCSETS
60# define TCSANOW TCSETS
61# define TCSADRAIN TCSETSW
15d31b7e 62# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
7a26b73d
PB
63# else
64# ifdef TCSETA
65# define TCSANOW TCSETA
66# define TCSADRAIN TCSETAW
15d31b7e 67# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
7a26b73d
PB
68# else
69# define TCSANOW TIOCSETA
70# define TCSADRAIN TIOCSETAW
15d31b7e 71# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
7a26b73d
PB
72# endif
73# endif
15d31b7e 74# define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
7a26b73d
PB
75# define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
76# ifdef CIBAUD
77# define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
78# else
79# define cfgetispeed(ptr) cfgetospeed(ptr)
80# endif
81# endif /* TCSANOW */
6055a9f6 82#endif /* USE_TERMIO */
e767b7ab 83
b307f09e
GM
84static fd_set ibits, obits, xbits;
85
86
15d31b7e 87 void
b307f09e
GM
88init_sys()
89{
90 tout = fileno(stdout);
91 tin = fileno(stdin);
92 FD_ZERO(&ibits);
93 FD_ZERO(&obits);
94 FD_ZERO(&xbits);
95
96 errno = 0;
97}
98
e767b7ab 99
15d31b7e 100 int
448f9c06 101TerminalWrite(buf, n)
15d31b7e
DB
102 char *buf;
103 int n;
e767b7ab 104{
448f9c06 105 return write(tout, buf, n);
e767b7ab
GM
106}
107
15d31b7e 108 int
448f9c06 109TerminalRead(buf, n)
15d31b7e
DB
110 char *buf;
111 int n;
e767b7ab 112{
448f9c06 113 return read(tin, buf, n);
e767b7ab
GM
114}
115
116/*
117 *
118 */
119
15d31b7e 120 int
310e7d0b 121TerminalAutoFlush()
e767b7ab
GM
122{
123#if defined(LNOFLSH)
124 int flush;
125
126 ioctl(0, TIOCLGET, (char *)&flush);
127 return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
128#else /* LNOFLSH */
129 return 1;
130#endif /* LNOFLSH */
131}
132
6055a9f6
PB
133#ifdef KLUDGELINEMODE
134extern int kludgelinemode;
135#endif
e767b7ab
GM
136/*
137 * TerminalSpecialChars()
138 *
139 * Look at an input character to see if it is a special character
140 * and decide what to do.
141 *
142 * Output:
143 *
144 * 0 Don't add this character.
145 * 1 Do add this character
146 */
147
15d31b7e 148 int
310e7d0b 149TerminalSpecialChars(c)
15d31b7e 150 int c;
e767b7ab 151{
310e7d0b 152 void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
e767b7ab 153
6055a9f6 154 if (c == termIntChar) {
e767b7ab
GM
155 intp();
156 return 0;
6055a9f6
PB
157 } else if (c == termQuitChar) {
158#ifdef KLUDGELINEMODE
159 if (kludgelinemode)
160 sendbrk();
161 else
162#endif
163 sendabort();
e767b7ab 164 return 0;
6055a9f6
PB
165 } else if (c == termEofChar) {
166 if (my_want_state_is_will(TELOPT_LINEMODE)) {
167 sendeof();
168 return 0;
169 }
170 return 1;
171 } else if (c == termSuspChar) {
172 sendsusp();
173 return(0);
174 } else if (c == termFlushChar) {
e767b7ab
GM
175 xmitAO(); /* Transmit Abort Output */
176 return 0;
177 } else if (!MODE_LOCAL_CHARS(globalmode)) {
6055a9f6 178 if (c == termKillChar) {
e767b7ab
GM
179 xmitEL();
180 return 0;
6055a9f6 181 } else if (c == termEraseChar) {
e767b7ab
GM
182 xmitEC(); /* Transmit Erase Character */
183 return 0;
184 }
185 }
186 return 1;
187}
188
189
190/*
191 * Flush output to the terminal
192 */
193
15d31b7e 194 void
310e7d0b 195TerminalFlushOutput()
e767b7ab 196{
7daa10bf 197#ifdef TIOCFLUSH
e767b7ab 198 (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
6055a9f6
PB
199#else
200 (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
201#endif
e767b7ab
GM
202}
203
15d31b7e 204 void
310e7d0b 205TerminalSaveState()
e767b7ab 206{
6055a9f6 207#ifndef USE_TERMIO
e767b7ab
GM
208 ioctl(0, TIOCGETP, (char *)&ottyb);
209 ioctl(0, TIOCGETC, (char *)&otc);
210 ioctl(0, TIOCGLTC, (char *)&oltc);
6570c863 211 ioctl(0, TIOCLGET, (char *)&olmode);
e767b7ab
GM
212
213 ntc = otc;
214 nltc = oltc;
215 nttyb = ottyb;
0e29050b 216
6055a9f6 217#else /* USE_TERMIO */
7a26b73d 218 tcgetattr(0, &old_tc);
6055a9f6
PB
219
220 new_tc = old_tc;
221
7a26b73d 222#ifndef VDISCARD
4a8a7128 223 termFlushChar = CONTROL('O');
7a26b73d
PB
224#endif
225#ifndef VWERASE
4a8a7128 226 termWerasChar = CONTROL('W');
7a26b73d
PB
227#endif
228#ifndef VREPRINT
4a8a7128 229 termRprntChar = CONTROL('R');
7a26b73d
PB
230#endif
231#ifndef VLNEXT
4a8a7128 232 termLiteralNextChar = CONTROL('V');
7a26b73d
PB
233#endif
234#ifndef VSTART
4a8a7128 235 termStartChar = CONTROL('Q');
7a26b73d
PB
236#endif
237#ifndef VSTOP
4a8a7128 238 termStopChar = CONTROL('S');
7a26b73d
PB
239#endif
240#ifndef VSTATUS
241 termAytChar = CONTROL('T');
242#endif
6055a9f6
PB
243#endif /* USE_TERMIO */
244}
245
15d31b7e 246 cc_t *
6055a9f6 247tcval(func)
15d31b7e 248 register int func;
6055a9f6
PB
249{
250 switch(func) {
87b60187
PB
251 case SLC_IP: return(&termIntChar);
252 case SLC_ABORT: return(&termQuitChar);
253 case SLC_EOF: return(&termEofChar);
254 case SLC_EC: return(&termEraseChar);
255 case SLC_EL: return(&termKillChar);
256 case SLC_XON: return(&termStartChar);
257 case SLC_XOFF: return(&termStopChar);
4a8a7128 258 case SLC_FORW1: return(&termForw1Char);
7a26b73d
PB
259#ifdef USE_TERMIO
260 case SLC_FORW2: return(&termForw2Char);
261# ifdef VDISCARD
87b60187 262 case SLC_AO: return(&termFlushChar);
7a26b73d
PB
263# endif
264# ifdef VSUSP
87b60187 265 case SLC_SUSP: return(&termSuspChar);
7a26b73d
PB
266# endif
267# ifdef VWERASE
87b60187 268 case SLC_EW: return(&termWerasChar);
7a26b73d
PB
269# endif
270# ifdef VREPRINT
87b60187 271 case SLC_RP: return(&termRprntChar);
7a26b73d
PB
272# endif
273# ifdef VLNEXT
87b60187 274 case SLC_LNEXT: return(&termLiteralNextChar);
7a26b73d
PB
275# endif
276# ifdef VSTATUS
277 case SLC_AYT: return(&termAytChar);
278# endif
4a8a7128 279#endif
6055a9f6
PB
280
281 case SLC_SYNCH:
282 case SLC_BRK:
6055a9f6 283 case SLC_EOR:
6055a9f6 284 default:
87b60187 285 return((cc_t *)0);
6055a9f6
PB
286 }
287}
288
15d31b7e 289 void
6055a9f6
PB
290TerminalDefaultChars()
291{
292#ifndef USE_TERMIO
293 ntc = otc;
294 nltc = oltc;
295 nttyb.sg_kill = ottyb.sg_kill;
296 nttyb.sg_erase = ottyb.sg_erase;
297#else /* USE_TERMIO */
298 memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
7a26b73d 299# ifndef VDISCARD
4a8a7128 300 termFlushChar = CONTROL('O');
7daa10bf
PB
301# endif
302# ifndef VWERASE
4a8a7128 303 termWerasChar = CONTROL('W');
7daa10bf
PB
304# endif
305# ifndef VREPRINT
4a8a7128 306 termRprntChar = CONTROL('R');
7daa10bf
PB
307# endif
308# ifndef VLNEXT
4a8a7128 309 termLiteralNextChar = CONTROL('V');
7daa10bf
PB
310# endif
311# ifndef VSTART
4a8a7128 312 termStartChar = CONTROL('Q');
7daa10bf
PB
313# endif
314# ifndef VSTOP
4a8a7128 315 termStopChar = CONTROL('S');
7daa10bf 316# endif
7a26b73d
PB
317# ifndef VSTATUS
318 termAytChar = CONTROL('T');
319# endif
6055a9f6 320#endif /* USE_TERMIO */
e767b7ab
GM
321}
322
4a8a7128 323#ifdef notdef
e767b7ab 324void
310e7d0b 325TerminalRestoreState()
e767b7ab
GM
326{
327}
4a8a7128 328#endif
e767b7ab
GM
329
330/*
331 * TerminalNewMode - set up terminal to a specific mode.
6055a9f6
PB
332 * MODE_ECHO: do local terminal echo
333 * MODE_FLOW: do local flow control
334 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
335 * MODE_EDIT: do local line editing
336 *
337 * Command mode:
338 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
339 * local echo
340 * local editing
341 * local xon/xoff
342 * local signal mapping
343 *
344 * Linemode:
345 * local/no editing
346 * Both Linemode and Single Character mode:
347 * local/remote echo
348 * local/no xon/xoff
349 * local/no signal mapping
e767b7ab
GM
350 */
351
352
15d31b7e 353 void
448f9c06 354TerminalNewMode(f)
15d31b7e 355 register int f;
e767b7ab
GM
356{
357 static int prevmode = 0;
6055a9f6
PB
358#ifndef USE_TERMIO
359 struct tchars tc;
360 struct ltchars ltc;
e767b7ab 361 struct sgttyb sb;
6570c863 362 int lmode;
6055a9f6
PB
363#else /* USE_TERMIO */
364 struct termio tmp_tc;
365#endif /* USE_TERMIO */
e767b7ab
GM
366 int onoff;
367 int old;
15d31b7e 368 cc_t esc;
e767b7ab 369
6055a9f6 370 globalmode = f&~MODE_FORCE;
e767b7ab
GM
371 if (prevmode == f)
372 return;
6055a9f6
PB
373
374 /*
375 * Write any outstanding data before switching modes
376 * ttyflush() returns 0 only when there is no more data
377 * left to write out, it returns -1 if it couldn't do
378 * anything at all, otherwise it returns 1 + the number
379 * of characters left to write.
7a26b73d
PB
380#ifndef USE_TERMIO
381 * We would really like ask the kernel to wait for the output
382 * to drain, like we can do with the TCSADRAIN, but we don't have
383 * that option. The only ioctl that waits for the output to
384 * drain, TIOCSETP, also flushes the input queue, which is NOT
385 * what we want (TIOCSETP is like TCSADFLUSH).
386#endif
6055a9f6
PB
387 */
388 old = ttyflush(SYNCHing|flushout);
389 if (old < 0 || old > 1) {
7a26b73d 390#ifdef USE_TERMIO
15d31b7e 391 tcgetattr(tin, &tmp_tc);
6055a9f6
PB
392#endif /* USE_TERMIO */
393 do {
394 /*
395 * Wait for data to drain, then flush again.
396 */
7a26b73d 397#ifdef USE_TERMIO
15d31b7e 398 tcsetattr(tin, TCSADRAIN, &tmp_tc);
6055a9f6
PB
399#endif /* USE_TERMIO */
400 old = ttyflush(SYNCHing|flushout);
401 } while (old < 0 || old > 1);
402 }
403
e767b7ab 404 old = prevmode;
6055a9f6
PB
405 prevmode = f&~MODE_FORCE;
406#ifndef USE_TERMIO
e767b7ab 407 sb = nttyb;
6055a9f6
PB
408 tc = ntc;
409 ltc = nltc;
6570c863 410 lmode = olmode;
6055a9f6
PB
411#else
412 tmp_tc = new_tc;
413#endif
414
415 if (f&MODE_ECHO) {
416#ifndef USE_TERMIO
417 sb.sg_flags |= ECHO;
418#else
419 tmp_tc.c_lflag |= ECHO;
420 tmp_tc.c_oflag |= ONLCR;
15d31b7e
DB
421 if (crlf)
422 tmp_tc.c_iflag |= ICRNL;
6055a9f6
PB
423#endif
424 } else {
425#ifndef USE_TERMIO
426 sb.sg_flags &= ~ECHO;
427#else
428 tmp_tc.c_lflag &= ~ECHO;
429 tmp_tc.c_oflag &= ~ONLCR;
7daa10bf 430# ifdef notdef
15d31b7e
DB
431 if (crlf)
432 tmp_tc.c_iflag &= ~ICRNL;
7daa10bf 433# endif
6055a9f6
PB
434#endif
435 }
e767b7ab 436
6055a9f6
PB
437 if ((f&MODE_FLOW) == 0) {
438#ifndef USE_TERMIO
7a26b73d
PB
439 tc.t_startc = _POSIX_VDISABLE;
440 tc.t_stopc = _POSIX_VDISABLE;
6055a9f6
PB
441#else
442 tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON);
443 } else {
444 tmp_tc.c_iflag |= IXANY|IXOFF|IXON;
445#endif
446 }
e767b7ab 447
6055a9f6
PB
448 if ((f&MODE_TRAPSIG) == 0) {
449#ifndef USE_TERMIO
7a26b73d
PB
450 tc.t_intrc = _POSIX_VDISABLE;
451 tc.t_quitc = _POSIX_VDISABLE;
452 tc.t_eofc = _POSIX_VDISABLE;
453 ltc.t_suspc = _POSIX_VDISABLE;
454 ltc.t_dsuspc = _POSIX_VDISABLE;
6055a9f6
PB
455#else
456 tmp_tc.c_lflag &= ~ISIG;
457#endif
458 localchars = 0;
459 } else {
460#ifdef USE_TERMIO
461 tmp_tc.c_lflag |= ISIG;
462#endif
463 localchars = 1;
464 }
465
466 if (f&MODE_EDIT) {
467#ifndef USE_TERMIO
468 sb.sg_flags &= ~CBREAK;
469 sb.sg_flags |= CRMOD;
470#else
471 tmp_tc.c_lflag |= ICANON;
472#endif
473 } else {
474#ifndef USE_TERMIO
475 sb.sg_flags |= CBREAK;
476 if (f&MODE_ECHO)
e767b7ab 477 sb.sg_flags |= CRMOD;
6055a9f6
PB
478 else
479 sb.sg_flags &= ~CRMOD;
480#else
481 tmp_tc.c_lflag &= ~ICANON;
482 tmp_tc.c_iflag &= ~ICRNL;
483 tmp_tc.c_cc[VMIN] = 1;
484 tmp_tc.c_cc[VTIME] = 0;
485#endif
486 }
e767b7ab 487
4a8a7128
PB
488 if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
489#ifndef USE_TERMIO
7a26b73d 490 ltc.t_lnextc = _POSIX_VDISABLE;
4a8a7128
PB
491#else
492# ifdef VLNEXT
7a26b73d 493 tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
4a8a7128
PB
494# endif
495#endif
496 }
497
498 if (f&MODE_SOFT_TAB) {
499#ifndef USE_TERMIO
500 sb.sg_flags |= XTABS;
501#else
502# ifdef OXTABS
503 tmp_tc.c_oflag |= OXTABS;
504# endif
505# ifdef TABDLY
506 tmp_tc.c_oflag &= ~TABDLY;
507 tmp_tc.c_oflag |= TAB3;
508# endif
509#endif
510 } else {
511#ifndef USE_TERMIO
512 sb.sg_flags &= ~XTABS;
513#else
514# ifdef OXTABS
515 tmp_tc.c_oflag &= ~OXTABS;
516# endif
517# ifdef TABDLY
518 tmp_tc.c_oflag &= ~TABDLY;
519# endif
520#endif
521 }
522
523 if (f&MODE_LIT_ECHO) {
524#ifndef USE_TERMIO
15d31b7e 525 lmode &= ~LCTLECH;
4a8a7128
PB
526#else
527# ifdef ECHOCTL
528 tmp_tc.c_lflag &= ~ECHOCTL;
529# endif
530#endif
531 } else {
532#ifndef USE_TERMIO
15d31b7e 533 lmode |= LCTLECH;
4a8a7128
PB
534#else
535# ifdef ECHOCTL
536 tmp_tc.c_lflag |= ECHOCTL;
537# endif
538#endif
539 }
540
6055a9f6
PB
541 if (f == -1) {
542 onoff = 0;
543 } else {
6570c863 544#ifndef USE_TERMIO
7daa10bf 545 if (f & MODE_OUTBIN)
6570c863
PB
546 lmode |= LLITOUT;
547 else
548 lmode &= ~LLITOUT;
7daa10bf
PB
549
550 if (f & MODE_INBIN)
6570c863
PB
551 lmode |= LPASS8;
552 else
553 lmode &= ~LPASS8;
554#else
7a26b73d
PB
555 if (f & MODE_INBIN)
556 tmp_tc.c_iflag &= ~ISTRIP;
6570c863 557 else
7a26b73d
PB
558 tmp_tc.c_iflag |= ISTRIP;
559 if (f & MODE_OUTBIN) {
7daa10bf
PB
560 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
561 tmp_tc.c_cflag |= CS8;
7a26b73d 562 tmp_tc.c_oflag &= ~OPOST;
7daa10bf 563 } else {
7a26b73d
PB
564 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
565 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
566 tmp_tc.c_oflag |= OPOST;
7daa10bf 567 }
6570c863 568#endif
6055a9f6
PB
569 onoff = 1;
570 }
571
6055a9f6 572 if (f != -1) {
7daa10bf 573#ifdef SIGTSTP
7a26b73d
PB
574 static SIG_FUNC_RET susp();
575#endif /* SIGTSTP */
576#ifdef SIGINFO
577 static SIG_FUNC_RET ayt();
578#endif SIGINFO
6055a9f6 579
7a26b73d
PB
580#ifdef SIGTSTP
581 (void) signal(SIGTSTP, susp);
7daa10bf 582#endif /* SIGTSTP */
7a26b73d
PB
583#ifdef SIGINFO
584 (void) signal(SIGINFO, ayt);
585#endif SIGINFO
586#if defined(USE_TERMIO) && defined(NOKERNINFO)
587 tmp_tc.c_lflag |= NOKERNINFO;
588#endif
4a8a7128
PB
589 /*
590 * We don't want to process ^Y here. It's just another
591 * character that we'll pass on to the back end. It has
592 * to process it because it will be processed when the
593 * user attempts to read it, not when we send it.
594 */
595#ifndef USE_TERMIO
7a26b73d 596 ltc.t_dsuspc = _POSIX_VDISABLE;
4a8a7128
PB
597#else
598# ifdef VDSUSP
7a26b73d 599 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
f12a5902
TH
600# endif
601#endif
87b60187 602#ifdef USE_TERMIO
87b60187
PB
603 /*
604 * If the VEOL character is already set, then use VEOL2,
605 * otherwise use VEOL.
606 */
15d31b7e
DB
607 esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
608 if ((tmp_tc.c_cc[VEOL] != esc)
7a26b73d 609# ifdef VEOL2
15d31b7e 610 && (tmp_tc.c_cc[VEOL2] != esc)
7a26b73d 611# endif
15d31b7e 612 ) {
7a26b73d 613 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
15d31b7e 614 tmp_tc.c_cc[VEOL] = esc;
4a8a7128 615# ifdef VEOL2
7a26b73d 616 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
15d31b7e 617 tmp_tc.c_cc[VEOL2] = esc;
4a8a7128 618# endif
7a26b73d 619 }
87b60187 620#else
7a26b73d 621 if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
15d31b7e 622 tc.t_brkc = esc;
87b60187 623#endif
6055a9f6 624 } else {
7a26b73d
PB
625#ifdef SIGINFO
626 SIG_FUNC_RET ayt_status();
627
628 (void) signal(SIGINFO, ayt_status);
629#endif SIGINFO
7daa10bf 630#ifdef SIGTSTP
6055a9f6 631 (void) signal(SIGTSTP, SIG_DFL);
4a8a7128 632 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
7daa10bf
PB
633#endif /* SIGTSTP */
634#ifndef USE_TERMIO
635 ltc = oltc;
636 tc = otc;
637 sb = ottyb;
4a8a7128
PB
638 lmode = olmode;
639#else
640 tmp_tc = old_tc;
7daa10bf 641#endif
e767b7ab 642 }
7daa10bf
PB
643#ifndef USE_TERMIO
644 ioctl(tin, TIOCLSET, (char *)&lmode);
645 ioctl(tin, TIOCSLTC, (char *)&ltc);
646 ioctl(tin, TIOCSETC, (char *)&tc);
7a26b73d 647 ioctl(tin, TIOCSETN, (char *)&sb);
7daa10bf 648#else
7a26b73d
PB
649 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
650 tcsetattr(tin, TCSANOW, &tmp_tc);
7daa10bf
PB
651#endif
652
e767b7ab 653#if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
448f9c06
GM
654 ioctl(tin, FIONBIO, (char *)&onoff);
655 ioctl(tout, FIONBIO, (char *)&onoff);
e767b7ab
GM
656#endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
657#if defined(TN3270)
4ad36dea 658 if (noasynchtty == 0) {
448f9c06 659 ioctl(tin, FIOASYNC, (char *)&onoff);
e767b7ab
GM
660 }
661#endif /* defined(TN3270) */
15d31b7e 662
e767b7ab
GM
663}
664
7daa10bf
PB
665#ifndef B19200
666# define B19200 B9600
667#endif
668
669#ifndef B38400
670# define B38400 B19200
671#endif
672
673/*
674 * This code assumes that the values B0, B50, B75...
675 * are in ascending order. They do not have to be
676 * contiguous.
677 */
678struct termspeeds {
679 long speed;
680 long value;
681} termspeeds[] = {
682 { 0, B0 }, { 50, B50 }, { 75, B75 },
683 { 110, B110 }, { 134, B134 }, { 150, B150 },
684 { 200, B200 }, { 300, B300 }, { 600, B600 },
685 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
686 { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 },
687 { 38400, B38400 }, { -1, B38400 }
688};
689
15d31b7e 690 void
445e62ba 691TerminalSpeeds(ispeed, ospeed)
15d31b7e
DB
692 long *ispeed;
693 long *ospeed;
445e62ba 694{
7daa10bf 695 register struct termspeeds *tp;
7a26b73d
PB
696 register long in, out;
697
7a26b73d 698 out = cfgetospeed(&old_tc);
15d31b7e
DB
699 in = cfgetispeed(&old_tc);
700 if (in == 0)
701 in = out;
7daa10bf
PB
702
703 tp = termspeeds;
7a26b73d 704 while ((tp->speed != -1) && (tp->value < in))
7daa10bf
PB
705 tp++;
706 *ispeed = tp->speed;
707
708 tp = termspeeds;
7a26b73d 709 while ((tp->speed != -1) && (tp->value < out))
7daa10bf
PB
710 tp++;
711 *ospeed = tp->speed;
445e62ba
GM
712}
713
15d31b7e 714 int
445e62ba 715TerminalWindowSize(rows, cols)
15d31b7e 716 long *rows, *cols;
445e62ba 717{
6055a9f6 718#ifdef TIOCGWINSZ
445e62ba
GM
719 struct winsize ws;
720
6055a9f6
PB
721 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
722 *rows = ws.ws_row;
723 *cols = ws.ws_col;
724 return 1;
445e62ba 725 }
3942e0c3 726#endif /* TIOCGWINSZ */
6055a9f6 727 return 0;
445e62ba 728}
e767b7ab 729
15d31b7e 730 int
0ea35455 731NetClose(fd)
15d31b7e 732 int fd;
e767b7ab 733{
0ea35455 734 return close(fd);
e767b7ab
GM
735}
736
737
15d31b7e 738 void
310e7d0b 739NetNonblockingIO(fd, onoff)
15d31b7e
DB
740 int fd;
741 int onoff;
e767b7ab
GM
742{
743 ioctl(fd, FIONBIO, (char *)&onoff);
744}
745
80a47e22 746#if defined(TN3270)
15d31b7e 747 void
310e7d0b 748NetSigIO(fd, onoff)
15d31b7e
DB
749 int fd;
750 int onoff;
e767b7ab
GM
751{
752 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
753}
754
15d31b7e 755 void
310e7d0b 756NetSetPgrp(fd)
15d31b7e 757 int fd;
e767b7ab
GM
758{
759 int myPid;
760
761 myPid = getpid();
344def17 762 fcntl(fd, F_SETOWN, myPid);
e767b7ab 763}
80a47e22 764#endif /*defined(TN3270)*/
310e7d0b
GM
765\f
766/*
767 * Various signal handling routines.
768 */
769
15d31b7e
DB
770 /* ARGSUSED */
771 static SIG_FUNC_RET
7a26b73d 772deadpeer(sig)
15d31b7e 773 int sig;
310e7d0b
GM
774{
775 setcommandmode();
776 longjmp(peerdied, -1);
777}
778
15d31b7e
DB
779 /* ARGSUSED */
780 static SIG_FUNC_RET
7a26b73d 781intr(sig)
15d31b7e 782 int sig;
310e7d0b
GM
783{
784 if (localchars) {
785 intp();
786 return;
787 }
788 setcommandmode();
789 longjmp(toplevel, -1);
790}
e767b7ab 791
15d31b7e
DB
792 /* ARGSUSED */
793 static SIG_FUNC_RET
7a26b73d 794intr2(sig)
15d31b7e 795 int sig;
310e7d0b
GM
796{
797 if (localchars) {
6055a9f6
PB
798#ifdef KLUDGELINEMODE
799 if (kludgelinemode)
800 sendbrk();
801 else
802#endif
803 sendabort();
310e7d0b
GM
804 return;
805 }
806}
e767b7ab 807
7a26b73d 808#ifdef SIGTSTP
15d31b7e
DB
809 /* ARGSUSED */
810 static SIG_FUNC_RET
7a26b73d 811susp(sig)
15d31b7e 812 int sig;
87b60187 813{
15d31b7e
DB
814 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
815 return;
87b60187
PB
816 if (localchars)
817 sendsusp();
818}
7a26b73d 819#endif
87b60187 820
7a26b73d 821#ifdef SIGWINCH
15d31b7e
DB
822 /* ARGSUSED */
823 static SIG_FUNC_RET
7a26b73d 824sendwin(sig)
15d31b7e 825 int sig;
445e62ba
GM
826{
827 if (connected) {
828 sendnaws();
829 }
830}
7a26b73d
PB
831#endif
832
833#ifdef SIGINFO
15d31b7e
DB
834 /* ARGSUSED */
835 static SIG_FUNC_RET
7a26b73d 836ayt(sig)
15d31b7e 837 int sig;
7a26b73d
PB
838{
839 if (connected)
840 sendayt();
841 else
842 ayt_status();
843}
844#endif
445e62ba 845
310e7d0b 846\f
15d31b7e 847 void
b307f09e
GM
848sys_telnet_init()
849{
7a26b73d
PB
850 (void) signal(SIGINT, intr);
851 (void) signal(SIGQUIT, intr2);
852 (void) signal(SIGPIPE, deadpeer);
6055a9f6 853#ifdef SIGWINCH
7a26b73d 854 (void) signal(SIGWINCH, sendwin);
87b60187
PB
855#endif
856#ifdef SIGTSTP
7a26b73d
PB
857 (void) signal(SIGTSTP, susp);
858#endif
859#ifdef SIGINFO
860 (void) signal(SIGINFO, ayt);
6055a9f6 861#endif
310e7d0b 862
6055a9f6 863 setconnmode(0);
b307f09e
GM
864
865 NetNonblockingIO(net, 1);
866
867#if defined(TN3270)
4ad36dea 868 if (noasynchnet == 0) { /* DBX can't handle! */
b307f09e
GM
869 NetSigIO(net, 1);
870 NetSetPgrp(net);
871 }
872#endif /* defined(TN3270) */
873
874#if defined(SO_OOBINLINE)
80a47e22
GM
875 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
876 perror("SetSockOpt");
877 }
b307f09e
GM
878#endif /* defined(SO_OOBINLINE) */
879}
880
881/*
882 * Process rings -
883 *
884 * This routine tries to fill up/empty our various rings.
885 *
886 * The parameter specifies whether this is a poll operation,
887 * or a block-until-something-happens operation.
888 *
889 * The return value is 1 if something happened, 0 if not.
890 */
891
15d31b7e 892 int
b307f09e 893process_rings(netin, netout, netex, ttyin, ttyout, poll)
15d31b7e 894 int poll; /* If 0, then block until something to do */
b307f09e
GM
895{
896 register int c;
897 /* One wants to be a bit careful about setting returnValue
898 * to one, since a one implies we did some useful work,
899 * and therefore probably won't be called to block next
900 * time (TN3270 mode only).
901 */
902 int returnValue = 0;
903 static struct timeval TimeValue = { 0 };
904
905 if (netout) {
906 FD_SET(net, &obits);
907 }
908 if (ttyout) {
909 FD_SET(tout, &obits);
910 }
911#if defined(TN3270)
912 if (ttyin) {
913 FD_SET(tin, &ibits);
914 }
915#else /* defined(TN3270) */
916 if (ttyin) {
917 FD_SET(tin, &ibits);
918 }
919#endif /* defined(TN3270) */
920#if defined(TN3270)
921 if (netin) {
922 FD_SET(net, &ibits);
923 }
924# else /* !defined(TN3270) */
925 if (netin) {
926 FD_SET(net, &ibits);
927 }
928# endif /* !defined(TN3270) */
929 if (netex) {
930 FD_SET(net, &xbits);
931 }
932 if ((c = select(16, &ibits, &obits, &xbits,
933 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
934 if (c == -1) {
935 /*
936 * we can get EINTR if we are in line mode,
937 * and the user does an escape (TSTP), or
938 * some other signal generator.
939 */
940 if (errno == EINTR) {
941 return 0;
942 }
943# if defined(TN3270)
944 /*
945 * we can get EBADF if we were in transparent
946 * mode, and the transcom process died.
947 */
948 if (errno == EBADF) {
949 /*
950 * zero the bits (even though kernel does it)
951 * to make sure we are selecting on the right
952 * ones.
953 */
954 FD_ZERO(&ibits);
955 FD_ZERO(&obits);
956 FD_ZERO(&xbits);
957 return 0;
958 }
959# endif /* defined(TN3270) */
960 /* I don't like this, does it ever happen? */
961 printf("sleep(5) from telnet, after select\r\n");
b307f09e 962 sleep(5);
b307f09e
GM
963 }
964 return 0;
965 }
966
967 /*
968 * Any urgent data?
969 */
970 if (FD_ISSET(net, &xbits)) {
971 FD_CLR(net, &xbits);
972 SYNCHing = 1;
4a8a7128 973 (void) ttyflush(1); /* flush already enqueued data */
b307f09e
GM
974 }
975
976 /*
977 * Something to read from the network...
978 */
979 if (FD_ISSET(net, &ibits)) {
980 int canread;
981
982 FD_CLR(net, &ibits);
983 canread = ring_empty_consecutive(&netiring);
984#if !defined(SO_OOBINLINE)
985 /*
986 * In 4.2 (and some early 4.3) systems, the
987 * OOB indication and data handling in the kernel
988 * is such that if two separate TCP Urgent requests
989 * come in, one byte of TCP data will be overlaid.
990 * This is fatal for Telnet, but we try to live
991 * with it.
992 *
993 * In addition, in 4.2 (and...), a special protocol
994 * is needed to pick up the TCP Urgent data in
995 * the correct sequence.
996 *
997 * What we do is: if we think we are in urgent
998 * mode, we look to see if we are "at the mark".
999 * If we are, we do an OOB receive. If we run
1000 * this twice, we will do the OOB receive twice,
1001 * but the second will fail, since the second
1002 * time we were "at the mark", but there wasn't
1003 * any data there (the kernel doesn't reset
1004 * "at the mark" until we do a normal read).
1005 * Once we've read the OOB data, we go ahead
1006 * and do normal reads.
1007 *
1008 * There is also another problem, which is that
1009 * since the OOB byte we read doesn't put us
1010 * out of OOB state, and since that byte is most
1011 * likely the TELNET DM (data mark), we would
1012 * stay in the TELNET SYNCH (SYNCHing) state.
1013 * So, clocks to the rescue. If we've "just"
1014 * received a DM, then we test for the
1015 * presence of OOB data when the receive OOB
1016 * fails (and AFTER we did the normal mode read
1017 * to clear "at the mark").
1018 */
1019 if (SYNCHing) {
1020 int atmark;
49e7660e 1021 static int bogus_oob = 0, first = 1;
b307f09e
GM
1022
1023 ioctl(net, SIOCATMARK, (char *)&atmark);
1024 if (atmark) {
1025 c = recv(net, netiring.supply, canread, MSG_OOB);
1026 if ((c == -1) && (errno == EINVAL)) {
1027 c = recv(net, netiring.supply, canread, 0);
1028 if (clocks.didnetreceive < clocks.gotDM) {
1029 SYNCHing = stilloob(net);
1030 }
49e7660e
PB
1031 } else if (first && c > 0) {
1032 /*
1033 * Bogosity check. Systems based on 4.2BSD
1034 * do not return an error if you do a second
1035 * recv(MSG_OOB). So, we do one. If it
1036 * succeeds and returns exactly the same
1037 * data, then assume that we are running
1038 * on a broken system and set the bogus_oob
1039 * flag. (If the data was different, then
1040 * we probably got some valid new data, so
1041 * increment the count...)
1042 */
1043 int i;
1044 i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
1045 if (i == c &&
1046 bcmp(netiring.supply, netiring.supply + c, i) == 0) {
1047 bogus_oob = 1;
1048 first = 0;
1049 } else if (i < 0) {
1050 bogus_oob = 0;
1051 first = 0;
1052 } else
1053 c += i;
1054 }
1055 if (bogus_oob && c > 0) {
1056 int i;
1057 /*
1058 * Bogosity. We have to do the read
1059 * to clear the atmark to get out of
1060 * an infinate loop.
1061 */
1062 i = read(net, netiring.supply + c, canread - c);
1063 if (i > 0)
1064 c += i;
b307f09e
GM
1065 }
1066 } else {
1067 c = recv(net, netiring.supply, canread, 0);
1068 }
1069 } else {
1070 c = recv(net, netiring.supply, canread, 0);
1071 }
1072 settimer(didnetreceive);
1073#else /* !defined(SO_OOBINLINE) */
1074 c = recv(net, netiring.supply, canread, 0);
1075#endif /* !defined(SO_OOBINLINE) */
1076 if (c < 0 && errno == EWOULDBLOCK) {
1077 c = 0;
1078 } else if (c <= 0) {
1079 return -1;
1080 }
1081 if (netdata) {
1082 Dump('<', netiring.supply, c);
1083 }
ad1c581e
GM
1084 if (c)
1085 ring_supplied(&netiring, c);
b307f09e
GM
1086 returnValue = 1;
1087 }
1088
1089 /*
1090 * Something to read from the tty...
1091 */
1092 if (FD_ISSET(tin, &ibits)) {
1093 FD_CLR(tin, &ibits);
448f9c06 1094 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
b307f09e
GM
1095 if (c < 0 && errno == EWOULDBLOCK) {
1096 c = 0;
1097 } else {
b307f09e 1098 /* EOF detection for line mode!!!! */
75ec5474 1099 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
b307f09e
GM
1100 /* must be an EOF... */
1101 *ttyiring.supply = termEofChar;
1102 c = 1;
1103 }
b307f09e
GM
1104 if (c <= 0) {
1105 return -1;
1106 }
40cc3fc2
GM
1107 if (termdata) {
1108 Dump('<', ttyiring.supply, c);
1109 }
ad1c581e 1110 ring_supplied(&ttyiring, c);
b307f09e 1111 }
b307f09e
GM
1112 returnValue = 1; /* did something useful */
1113 }
1114
1115 if (FD_ISSET(net, &obits)) {
1116 FD_CLR(net, &obits);
1117 returnValue |= netflush();
1118 }
1119 if (FD_ISSET(tout, &obits)) {
1120 FD_CLR(tout, &obits);
6055a9f6 1121 returnValue |= (ttyflush(SYNCHing|flushout) > 0);
b307f09e
GM
1122 }
1123
1124 return returnValue;
1125}