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