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