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