1 #define CKUTIO_C
2 
3 #ifdef aegis
4 char *ckxv = "Aegis Communications support, 9.0.329, 18 September 2020";
5 #else
6 #ifdef Plan9
7 char *ckxv = "Plan 9 Communications support, 9.0.329, 18 September 2020";
8 #else
9 char *ckxv = "UNIX Communications support, 9.0.329, 18 September 2020";
10 #endif /* Plan9 */
11 #endif /* aegis */
12 
13 /*  C K U T I O  */
14 
15 /* C-Kermit interrupt, communications control and I/O functions for UNIX */
16 
17 /*
18   Author: Frank da Cruz (fdc@columbia.edu),
19   The Kermit Project, Bronx, NY.
20 
21   Copyright (C) 1985, 2020,
22     Trustees of Columbia University in the City of New York.
23     All rights reserved.  See the C-Kermit COPYING.TXT file or the
24     copyright text in the ckcmai.c module for disclaimer and permissions.
25 */
26 
27 /*
28   NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
29   compatible with C preprocessors that support only #ifdef, #else, #endif,
30   #define, and #undef.  Please do not use #if, logical operators, or other
31   preprocessor features in any of the portable C-Kermit modules.  You can,
32   of course, use these constructions in platform-specific modules when they
33   are supported by all compilers/preprocessors that could be used on that
34   platform.
35 */
36 
37 extern int nettype;			/* Defined in ckcmai.c */
38 extern int duplex;
39 
40 /* Includes */
41 
42 #include "ckcsym.h"			/* This must go first   */
43 #include "ckcdeb.h"			/* This must go second  */
44 
45 #ifdef OSF13
46 #ifdef CK_ANSIC
47 #ifdef _NO_PROTO
48 #undef _NO_PROTO
49 #endif /* _NO_PROTO */
50 #endif /* CK_ANSIC */
51 #endif /* OSF13 */
52 
53 #ifndef HPUXPRE65
54 #include <errno.h>			/* Error number symbols */
55 #else
56 #ifndef ERRNO_INCLUDED
57 #include <errno.h>			/* Error number symbols */
58 #endif	/* ERRNO_INCLUDED */
59 #endif	/* HPUXPRE65 */
60 
61 #ifdef __386BSD__
62 #define ENOTCONN 57
63 #else
64 #ifdef __bsdi__
65 #define ENOTCONN 57
66 #else
67 #ifdef __FreeBSD__
68 #define ENOTCONN 57
69 #endif /* __FreeBSD__ */
70 #endif /* __bsdi__ */
71 #endif /* __386BSD__ */
72 
73 #ifdef SCO_OSR504
74 #define NBBY 8
75 #endif /* SCO_OSR504 */
76 
77 #ifdef Plan9
78 #define SELECT
79 #include <sys/time.h>
80 #include <select.h>
81 #define FD_SETSIZE (3 * sizeof(long) * 8)
82 static struct timeval tv;
83 #endif /* Plan9 */
84 
85 #ifdef CLIX
86 #include <sys/time.h>
87 #endif /* CLIX */
88 
89 #include "ckcnet.h"			/* Symbols for network types. */
90 #ifdef CK_SSL
91 #include "ck_ssl.h"
92 #endif /* CK_SSL */
93 
94 /*
95   The directory-related includes are here because we need to test some
96   file-system-related symbols to find out which system we're being compiled
97   under.  For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
98 */
99 #ifdef SDIRENT				/* Directory bits... */
100 #define DIRENT
101 #endif /* SDIRENT */
102 
103 #ifdef XNDIR
104 #include <sys/ndir.h>
105 #else /* !XNDIR */
106 #ifdef NDIR
107 #include <ndir.h>
108 #else /* !NDIR, !XNDIR */
109 #ifdef RTU
110 #include "/usr/lib/ndir.h"
111 #else /* !RTU, !NDIR, !XNDIR */
112 #ifdef DIRENT
113 #ifdef SDIRENT
114 #include <sys/dirent.h>
115 #else
116 #include <dirent.h>
117 #endif /* SDIRENT */
118 #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
119 #include <sys/dir.h>
120 #endif /* DIRENT */
121 #endif /* RTU */
122 #endif /* NDIR */
123 #endif /* XNDIR */
124 
125 #ifdef QNX
126 #include <sys/dev.h>
127 #endif /* QNX */
128 
129 #ifdef HPUX5
130 #ifndef TCPSOCKET
131 /* I don't know why this is needed here since we never reference bzero(). */
132 /* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
133 void
bzero(s,n)134 bzero(s,n) char *s; int n; {
135     extern char * memset();
136     memset(s,0,n);
137 }
138 #endif /* TCPSOCKET */
139 #endif /* HPUX5 */
140 
141 /* Definition of HZ, used in msleep() */
142 
143 #ifdef MIPS
144 #define HZ ( 1000 / CLOCK_TICK )
145 #else  /* MIPS */
146 #ifdef ATTSV
147 #ifndef NAP
148 #ifdef TRS16
149 #define HZ ( 1000 / CLOCK_TICK )
150 #endif /* TRS16 */
151 #ifdef NAPHACK
152 #define nap(x) (void)syscall(3112, (x))
153 #define NAP
154 #endif /* NAPHACK */
155 #endif /* NAP */
156 #endif /* ATTSV */
157 #endif /* MIPS */
158 
159 #ifdef M_UNIX
160 #undef NGROUPS_MAX		/* Prevent multiple definition warnings */
161 #endif /* M_UNIX */
162 
163 /*
164   NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
165   library routine, so _poll comes up undefined at link time.
166 */
167 #ifdef CK_POLL
168 #ifndef AIXRS			/* IBM AIX needs special handling */
169 #include <poll.h>		/* "standard" (SVID) i/o multiplexing, etc */
170 #else /* AIXRS */
171 #ifdef SVR4			/* AIX 3.2 is like SVID... */
172 #include <poll.h>
173 #else				/* But AIX 3.1 is not ... */
174 #include <sys/poll.h>		/* The include file is in include/sys */
175 #define events reqevents	/* And it does not map IBM-specific member */
176 #define revents rtnevents	/* names to the System V equivalents */
177 #endif /* SVR4 */
178 #endif /* AIXRS */
179 #endif /* CK_POLL */
180 
181 #include <signal.h>                     /* Signals */
182 
183 /* For setjmp and longjmp */
184 
185 #ifndef ZILOG
186 #include <setjmp.h>
187 #else
188 #include <setret.h>
189 #endif /* ZILOG */
190 
191 /*
192   The following test differentiates between 4.1 BSD and 4.2 & later.
193   If you have a 4.1BSD system with the DIRENT library, this test could
194   mistakenly diagnose 4.2BSD and then later enable the use of system calls
195   that aren't defined.  If indeed there are such systems, we can use some
196   other way of testing for 4.1BSD, or add yet another compile-time switch.
197 */
198 #ifdef BSD4
199 #ifdef MAXNAMLEN
200 #ifndef FT21				/* Except for Fortune. */
201 #ifndef FT18
202 #ifndef BELLV10				/* And Bell Labs Research UNIX V10 */
203 #define BSD42
204 #endif /* BELLV10 */
205 #endif /* FT18 */
206 #endif /* FT21 */
207 #endif /* MAXNAMLEN */
208 #endif /* BSD4 */
209 
210 #ifdef SUNOS41				/* From Christian Corti */
211 #define BSD44ORPOSIX			/* Uni Stuttgart */
212 #define SVORPOSIX			/* February 2010 */
213 #include <termios.h>
214 #include <sys/ioctl.h>
215 #include <unistd.h>
216 #include <limits.h>
217 #endif	/* SUNOS41 */
218 
219 #ifdef SNI542
220 #include <sys/filio.h>			/* 299 for FIONREAD */
221 #endif	/* SNI542 */
222 
223 /*
224   Minix 2.0 support added by Terry McConnell,
225   Syracuse University <tmc@barnyard.syr.edu>
226   No more sgtty interface, posix compliant.
227 */
228 #ifdef MINIX2
229 #define _MINIX   /* Needed for some Minix header files */
230 #define BSD44ORPOSIX
231 #define SVORPOSIX
232 #ifndef MINIX3
233 #define DCLTIMEVAL
234 #endif	/* MINIX3 */
235 #define NOFILEH
236 #include <sys/types.h>
237 #include <sys/ioctl.h>
238 #include <termios.h>
239 #include <limits.h>
240 #undef TIOCGETC    /* defined in sys/ioctl.h, but not really supported */
241 #define TANDEM 0
242 #endif /* MINIX2 */
243 
244 /*
245  MINIX 1.0 support added by Charles Hedrick,
246  Rutgers University <hedrick@aramis.rutgers.edu>.
247  MINIX also has V7 enabled.
248 */
249 #ifdef MINIX
250 #define TANDEM 0
251 #define MYREAD
252 #define NOSYSIOCTLH
253 #include <limits.h>
254 #endif /* MINIX */
255 
256 #ifdef CK_REDIR		/* <sys/wait.h> needed only for REDIRECT command. */
257 /*
258   If anybody can figure out how to make this work with NeXTSTEP, be
259   my guest!  (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
260 */
261 #ifndef CK_WAIT_H			/* If wait.h not already included... */
262 #ifdef OSF				/* force OSF to select POSIX wait */
263 #ifdef _BSD				/* instead of BSD (see ckcdeb.h) */
264 #define CK_OSF_BSD
265 #undef _BSD
266 #endif /* _BSD */
267 #endif /* OSF */
268 #include <sys/wait.h>			/* Include it */
269 #ifdef OSF
270 #ifdef CK_OSF_BSD
271 #define _BSD				/* Restore it */
272 #undef CK_OSF_BSD
273 #endif /* CK_OSF_BSD */
274 #endif /* OSF */
275 #endif /* CK_WAIT_H */
276 #endif /* CK_REDIR */
277 
278 #include "ckuver.h"			/* Version herald */
279 char *ckxsys = HERALD;
280 
281 #ifdef CK_UTSNAME
282 #include <sys/utsname.h>
283 
284 #ifdef TRU64				/* Tru64 UNIX 4.0 and later */
285 /* Verified on Tru64 4.0F - might break on 4.0E or earlier */
286 #include <sys/sysinfo.h>		/* (don't know about OSF/1 or DU) */
287 #include <machine/hal_sysinfo.h>
288 #endif /* TRU64 */
289 
290 #ifdef SOLARIS25			/* Solaris 2.5 and later */
291 #include <sys/systeminfo.h>		/* (don't know about earlier ones) */
292 #endif /* SOLARIS25 */
293 
294 #ifdef UW7
295 #ifndef SYS_NMLN
296 #define SYS_NMLN 257
297 #endif /* NMLN */
298 #endif /* UW7 */
299 #ifdef HPUX9PLUS
300 static int hpis800 = 0;
301 #endif /* HPUX9PLUS */
302 #ifdef SYS_NMLN
303 #define CK_SYSNMLN SYS_NMLN
304 #else
305 #ifdef _SYS_NMLN
306 #define CK_SYSNMLN _SYS_NMLN
307 #else
308 #ifdef UTSLEN
309 #define CK_SYSNMLN UTSLEN
310 #else
311 #define CK_SYSNMLN 31
312 #endif /* UTSLEN */
313 #endif /* _SYS_NMLN */
314 #endif /* SYS_NMLN */
315 char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
316 char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
317 char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
318 char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
319 char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
320 #endif /* CK_UTSNAME */
321 
322 #ifdef CIE
323 #include <stat.h>			/* For chasing symlinks, etc. */
324 #else
325 #include <sys/stat.h>
326 #endif /* CIE */
327 
328 #ifdef QNX				/* 299 */
329 #ifndef IXANY
330 #define IXANY 0
331 #endif	/* IXANY */
332 #endif	/* QNX */
333 
334 /* UUCP lockfile material... */
335 
336 #ifndef NOUUCP
337 #ifdef USETTYLOCK
338 #ifdef HAVE_LOCKDEV			/* Red Hat baudboy/lockdev */
339 /*
340   Watch out: baudboy.h references open() without making sure it has been
341   declared, resulting in warnings on at least Red Hat 7.3.  It's declared in
342   fcntl.h, but we don't include that until later.  In this case only, we
343   include it here, and then the second include is harmless because in Red Hat
344   Linux (the only place where you find baudboy.h) fcntl.h is protected from
345   multiple inclusion by _FCNTL_H.   - fdc, 10 May 2004.
346 
347   NOTE: Although Linux /usr/sbin/lockdev obviates the need for setuid or
348   setgid bits to access the lockfile, C-Kermit will still need them to access
349   the serial port itself unless the port is open for world read/write.
350   Normally setgid uucp does the trick.
351 
352   Extra: HAVE_LOCKDEV has been added als openSuSE >= 11.3 doesn't use baudboy
353   but ttylock.  - jb, 26 Jul 2010
354 */
355 #include <fcntl.h>			/* This has to come before baudboy */
356 #ifdef HAVE_BAUDBOY			/* Red Hat baudboy/lockdev */
357 #include <baudboy.h>
358 #else  /* !HAVE_BAUDBOY */		/* openSuSE lock via ttylock */
359 #include <ttylock.h>
360 #endif  /* HAVE_BAUDBOY */
361 #define LOCK_DIR "/var/lock"		/* (even though we don't care) */
362 
363 #else  /* !HAVE_LOCKDEV */
364 
365 #ifdef USE_UU_LOCK
366 #ifdef __FreeBSD__
367 #include <libutil.h>			/* FreeBSD */
368 #else
369 #include <util.h>			/* OpenBSD */
370 #endif /* HAVE_LOCKDEV */
371 #endif /* __FreeBSD */
372 #endif /* USE_UU_LOCK */
373 #else  /* USETTYLOCK */
374 
375 /* Name of UUCP tty device lockfile */
376 
377 #ifdef LINUXFSSTND
378 #ifndef HDBUUCP
379 #define HDBUUCP
380 #endif /* HDBUUCP */
381 #endif /* LINUXFSSTND */
382 
383 #ifdef ACUCNTRL
384 #define LCKDIR
385 #endif /* ACUCNTRL */
386 
387 /*
388   PIDSTRING means use ASCII string to represent pid in lockfile.
389 */
390 #ifndef PIDSTRING
391 #ifdef HDBUUCP
392 #define PIDSTRING
393 #else
394 #ifdef BSD44
395 #define PIDSTRING
396 #else
397 #ifdef RTAIX
398 #define PIDSTRING
399 #else
400 #ifdef AIXRS
401 #define PIDSTRING
402 #else
403 #ifdef COHERENT
404 #define PIDSTRING
405 #endif /* COHERENT */
406 #endif /* AIXRS */
407 #endif /* RTAIX */
408 #endif /* BSD44 */
409 #endif /* HDBUUCP */
410 #endif /* PIDSTRING */
411 
412 /* Now the PIDSTRING exceptions... */
413 
414 #ifdef PIDSTRING
415 #ifdef HPUX
416 #undef PIDSTRING
417 #endif /* HPUX */
418 #endif /* PIDSTRING */
419 
420 #ifdef __bsdi__				/* BSDI (at least thru 1.1) */
421 #ifdef PIDSTRING
422 #undef PIDSTRING
423 #endif /* PIDSTRING */
424 #endif /* __bsdi__ */
425 
426 #ifdef OSF32				/* Digital UNIX (OSF/1) 3.2 */
427 #ifdef PIDSTRING
428 #undef PIDSTRING
429 #endif /* PIDSTRING */
430 #endif /* OSF32 */
431 
432 /*
433   LOCK_DIR is the name of the lockfile directory.
434   If LOCK_DIR is already defined (e.g. on command line), we don't change it.
435 */
436 
437 #ifndef LOCK_DIR
438 #ifdef MACOSX
439 #define LOCK_DIR "/var/spool/lock"
440 #endif /* MACOSX */
441 #endif/* LOCK_DIR */
442 
443 #ifndef LOCK_DIR
444 #ifdef BSD44
445 #ifdef __386BSD__
446 #define LOCK_DIR "/var/spool/lock"
447 #else
448 #ifdef __FreeBSD__
449 #define LOCK_DIR "/var/spool/lock"
450 #else
451 #ifdef __NetBSD__
452 #define LOCK_DIR "/var/spool/lock"
453 #else
454 #ifdef __OpenBSD__
455 #define LOCK_DIR "/var/spool/lock"
456 #else
457 /* So which ones is this for? */
458 /* Probably original 4.4BSD on Vangogh */
459 /* Plus who knows about Mac OS X... It doesn't even have a cu program */
460 #define LOCK_DIR "/var/spool/uucp"
461 #endif /* __OpenBSD__ */
462 #endif /* __NetBSD__ */
463 #endif /* __FreeBSD__ */
464 #endif /* __386BSD__ */
465 #else
466 #ifdef DGUX430
467 #define LOCK_DIR "/var/spool/locks"
468 #else
469 #ifdef HPUX10
470 #define LOCK_DIR "/var/spool/locks"
471 #else
472 #ifdef RTAIX				/* IBM RT PC AIX 2.2.1 */
473 #define LOCK_DIR "/etc/locks"
474 #else
475 #ifdef AIXRS
476 #define LOCK_DIR "/etc/locks"
477 #else
478 #ifdef ISIII
479 #define LOCK_DIR "/etc/locks"
480 #else
481 #ifdef HDBUUCP
482 #ifdef M_SYS5
483 #define LOCK_DIR "/usr/spool/uucp"
484 #else
485 #ifdef M_UNIX
486 #define LOCK_DIR "/usr/spool/uucp"
487 #else
488 #ifdef SVR4
489 #define LOCK_DIR "/var/spool/locks"
490 #else
491 #ifdef SUNOS4
492 #define LOCK_DIR "/var/spool/locks"
493 #else
494 #ifdef LINUXFSSTND
495 #define LOCK_DIR "/var/lock";
496 #else
497 #define LOCK_DIR "/usr/spool/locks"
498 #endif /* LINUXFSSTND */
499 #endif /* SUNOS4 */
500 #endif /* SVR4 */
501 #endif /* M_UNIX */
502 #endif /* M_SYS5 */
503 #else
504 #ifdef LCKDIR
505 #define LOCK_DIR "/usr/spool/uucp/LCK"
506 #else
507 #ifdef COHERENT
508 #define LOCK_DIR "/usr/spool/uucp"
509 #else
510 #define LOCK_DIR "/usr/spool/uucp"
511 #endif /* COHERENT */
512 #endif /* LCKDIR */
513 #endif /* HDBUUCP */
514 #endif /* ISIII */
515 #endif /* AIXRS */
516 #endif /* RTAIX */
517 #endif /* HPUX10 */
518 #endif /* DGUX430 */
519 #endif /* BSD44 */
520 #endif /* !LOCK_DIR (outside ifndef) */
521 
522 #ifdef OSF2				/* OSF/1 2.0 or later */
523 #ifdef LOCK_DIR				/* (maybe 1.x too, who knows...) */
524 #undef LOCK_DIR
525 #define LOCK_DIR "/var/spool/locks"
526 #endif /* LOCK_DIR */
527 #endif /* OSF2 */
528 
529 #ifdef COMMENT
530 /* Sorry no more lockf() -- we lock first and THEN open the device. */
531 #ifdef SVR4
532 #ifndef BSD44
533 #ifndef LOCKF
534 #define LOCKF				/* Use lockf() on tty device in SVR4 */
535 #endif /* LOCKF */
536 #endif /* BSD44 */
537 #endif /* SVR4 */
538 #endif /* COMMENT */
539 
540 #ifdef NOLOCKF				/* But NOLOCKF cancels LOCKF */
541 #ifdef LOCKF
542 #undef LOCKF
543 #endif /* LOCKF */
544 #endif /* NOLOCKF */
545 
546 /* More about this below... */
547 
548 #endif /* USETTYLOCK */
549 #endif /* NOUUCP */
550 
551 /*
552   MYREAD means use our internally defined nonblocking buffered read routine.
553 */
554 #ifdef ATTSV
555 #define MYREAD
556 #endif /* ATTSV */
557 
558 #ifdef ATT7300
559 #ifndef MYREAD
560 #define MYREAD
561 #endif /* MYREAD */
562 /* bits for attmodem: internal modem in use, restart getty */
563 #define ISMODEM 1
564 #define DOGETY 512
565 #endif  /* ATT7300 */
566 
567 #ifdef BSD42
568 #define MYREAD
569 #endif /* BSD42 */
570 
571 #ifdef POSIX
572 #define MYREAD
573 #endif /* POSIX */
574 #ifdef __bsdi__
575 #ifndef O_NDELAY
576 #define O_NDELAY O_NONBLOCK
577 #endif /* O_NDELAY */
578 #endif /* __bsdi__ */
579 
580 /*
581  Variables available to outside world:
582 
583    dftty  -- Pointer to default tty name string, like "/dev/tty".
584    dfloc  -- 0 if dftty is console, 1 if external line.
585    dfprty -- Default parity
586    dfflow -- Default flow control
587    ckxech -- Flag for who echoes console typein:
588      1 - The program (system echo is turned off)
589      0 - The system (or front end, or terminal).
590    functions that want to do their own echoing should check this flag
591    before doing so.
592 
593    flfnam  -- Name of lock file, including its path, e.g.,
594                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
595    lkflfn  -- Name of link to lock file, including its paths
596    haslock -- Flag set if this kermit established a uucp lock.
597    lockpid -- PID of other process that has desired line open, as string.
598    backgrd -- Flag indicating program executing in background ( & on
599                 end of shell command). Used to ignore INT and QUIT signals.
600    rtu_bug -- Set by stptrap().  RTU treats ^Z as EOF (but only when we handle
601                 SIGTSTP)
602 
603  Functions for assigned communication line (either external or console tty):
604 
605    sysinit()               -- System dependent program initialization
606    syscleanup()            -- System dependent program shutdown
607    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
608    ttclos()                -- Close & reset the tty, releasing any access lock.
609    ttsspd(cps)             -- Set the transmission speed of the tty.
610    ttgspd()                -- Get (read) the the transmission speed of the tty.
611    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
612    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
613                                 or in DIALING or CONNECTED modem control state.
614    ttres()                 -- Restore original tty modes.
615    ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
616    ttinl(dest,max,timo)    -- Timed read line from the tty.
617    ttinc(timo)             -- Timed read character from tty.
618    myread()                -- Raw mode bulk buffer read, gives subsequent
619                                 chars one at a time and simulates FIONREAD.
620    myunrd(c)               -- Places c back in buffer to be read (one only)
621    ttchk()                 -- See how many characters in tty input buffer.
622    ttxin(n,buf)            -- Read n characters from tty (untimed).
623    ttol(string,length)     -- Write a string to the tty.
624    ttoc(c)                 -- Write a character to the tty.
625    ttflui()                -- Flush tty input buffer.
626    ttsndb()                -- Send BREAK signal.
627    ttsndlb()               -- Send Long BREAK signal.
628 
629    ttlock(ttname)          -- "Lock" tty device against uucp collisions.
630    ttunlck()               -- Unlock tty device.
631 
632                               For ATT7300/Unix PC, System V:
633    attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
634    offgetty(ttname)        -- Turns off getty(1m) for comms line
635    ongetty(ttname)         -- Restores getty() to comms line
636 */
637 
638 /*
639 Functions for console terminal:
640 
641    congm()   -- Get console terminal modes.
642    concb(esc) -- Put the console in single-character wakeup mode with no echo.
643    conbin(esc) -- Put the console in binary (raw) mode.
644    conres()  -- Restore the console to mode obtained by congm().
645    conoc(c)  -- Unbuffered output, one character to console.
646    conol(s)  -- Unbuffered output, null-terminated string to the console.
647    conola(s) -- Unbuffered output, array of strings to the console.
648    conxo(n,s) -- Unbuffered output, n characters to the console.
649    conchk()  -- Check if characters available at console (bsd 4.2).
650                 Check if escape char (^\) typed at console (System III/V).
651    coninc(timo)  -- Timed get a character from the console.
652    congks(timo)  -- Timed get keyboard scan code.
653    conint()  -- Enable terminal interrupts on the console if not background.
654    connoi()  -- Disable terminal interrupts on the console if not background.
655 
656 Time functions
657 
658    msleep(m) -- Millisecond sleep
659    ztime(&s) -- Return pointer to date/time string
660    rtimer() --  Reset timer
661    gtimer()  -- Get elapsed time since last call to rtimer()
662 */
663 
664 /* Conditional Includes */
665 
666 /* Whether to include <sys/file.h> */
667 
668 #ifdef RTU				/* RTU doesn't */
669 #define NOFILEH
670 #endif /* RTU */
671 
672 #ifdef CIE				/* CIE does. */
673 #undef NOFILEH
674 #endif /* CIE */
675 
676 #ifdef BSD41				/* 4.1 BSD doesn't */
677 #define NOFILEH
678 #endif /* BSD41 */
679 
680 #ifdef is68k				/* Integrated Solutions 68000 UNIX  */
681 #define NOFILEH				/* e.g. on Plexux P60 and Sun-1 */
682 #endif /* is68k */
683 
684 #ifdef MINIX				/* MINIX */
685 #define NOFILEH
686 #endif /* MINIX */
687 
688 #ifdef COHERENT				/* Coherent */
689 #define NOFILEH
690 #endif /* COHERENT */
691 
692 #ifndef NOFILEH				/* Now include if selected. */
693 #include <sys/file.h>
694 #endif /* NOFILEH */
695 
696 /* POSIX */
697 
698 #ifdef BSD44ORPOSIX			/* POSIX uses termios.h */
699 #define TERMIOS
700 #ifdef __bsdi__
701 #ifdef POSIX
702 #undef _POSIX_SOURCE			/* Get extra stuff from termios.h */
703 #endif /* POSIX */
704 #endif /* __bsdi__ */
705 #include <termios.h>
706 #ifdef LINUX
707 #include <sys/ioctl.h>
708 #endif /* LINUX */
709 #ifdef QNX16
710 #include <ioctl.h>
711 #else
712 #ifdef QNX6
713 #include <ioctl.h>
714 #endif /* QNX6 */
715 #endif /* QNX16 */
716 #ifdef __bsdi__
717 #ifdef POSIX
718 #define _POSIX_SOURCE
719 #endif /* POSIX */
720 #endif /* __bsdi__ */
721 #ifndef BSD44				/* Really POSIX */
722 #ifndef CK_QNX32			/* was CK_QNX32 */
723 #define NOSYSIOCTLH			/* No ioctl's allowed. */
724 #undef ultrix				/* Turn off any ultrix features. */
725 #endif /* CK_QNX32 */
726 #endif /* BSD44 */
727 #endif /* POSIX */
728 
729 /* System III, System V */
730 
731 #ifdef ATTSV
732 #ifndef BSD44
733 #ifndef POSIX
734 #include <termio.h>
735 #endif /* POSIX */
736 #endif /* BSD44 */
737 #ifdef TERMIOX
738 /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
739 #include <termiox.h>
740   struct termiox rctsx;
741 #else
742 #ifdef STERMIOX
743 #ifdef SCO_OSR504
744 /* Sorry, this is truly disgusting but it's SCO's fault. */
745 #ifndef _SVID3
746 #define _CK_SVID3_X
747 #define _SVID3
748 #endif /* _SVID3 */
749 #endif /* SCO_OSR504 */
750 #include <sys/termiox.h>
751   struct termiox rctsx;
752 #ifdef CK_SVID3_X
753 #undef _SVID3
754 #undef CK_SVID3_X
755 #endif /* CK_SVID3_X */
756 #endif /* STERMIOX */
757 #endif /* TERMIOX */
758 #endif /* ATTSV */
759 
760 #ifdef COHERENT			/* Use termio.h, not sgtty.h for Coherent */
761 #include <termio.h>
762 #endif /* COHERENT */
763 
764 #ifdef MINIX				/* MINIX uses ioctl's */
765 #define NOSYSIOCTLH			/* but has no <sys/ioctl.h> */
766 #endif /* MINIX */
767 
768 /* Others */
769 
770 #ifndef NOSYSIOCTLH			/* Others use ioctl() */
771 #ifdef SUN4S5
772 /*
773   This is to get rid of cpp warning messages that occur because all of
774   these symbols are defined by both termios.h and ioctl.h on the SUN.
775 */
776 #undef ECHO
777 #undef NL0
778 #undef NL1
779 #undef TAB0
780 #undef TAB1
781 #undef TAB2
782 #undef XTABS
783 #undef CR0
784 #undef CR1
785 #undef CR2
786 #undef CR3
787 #undef FF0
788 #undef FF1
789 #undef BS0
790 #undef BS1
791 #undef TOSTOP
792 #undef FLUSHO
793 #undef PENDIN
794 #undef NOFLSH
795 #endif /* SUN4S5 */
796 #include <sys/ioctl.h>
797 #endif /* NOSYSIOCTLH */
798 /*
799   We really, really, REALLY want FIONREAD, because it is the only way to find
800   out not just *if* stuff is waiting to be read, but how much, which is
801   critical to our sliding-window and streaming procedures, not to mention
802   efficiency of CONNECT, etc.
803 */
804 #ifdef BELLV10
805 #include <sys/filio.h>			/* For FIONREAD */
806 #ifdef FIONREAD
807 #define MYREAD
808 #endif /* MYREAD */
809 #endif /* BELLV10 */
810 
811 #ifndef FIONREAD
812 /* It wasn't found in ioctl.h or term*.h - try these places: */
813 #ifdef UNIXWARE
814 #include <sys/filio.h>
815 #else
816 #ifdef SOLARIS
817 #include <sys/filio.h>
818 #endif /* SOLARIS */
819 #endif /* UNIXWARE */
820 #endif /* FIONREAD */
821 
822 #ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
823 /*
824   <sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
825   something.  Due to this, in_chk() uses the FIONREAD instead of RDCHK
826   and the hot keys during file transfer (X to cancel file etc) do not
827   work because FIONREAD doesn't work even though it is defined.
828 
829   NOTE: This might also be true elsewhere.
830 */
831 #ifdef FIONREAD
832 #undef FIONREAD
833 #endif /* FIONREAD */
834 #endif /* XENIX */
835 
836 #ifdef CK_SCOV5				/* Ditto for SCO OpenServer 5.0 */
837 #ifndef SCO_OSR507			/* 299 */
838 #ifdef FIONREAD
839 #undef FIONREAD
840 #endif /* FIONREAD */
841 #endif	/* SCO_OSR507 */
842 #endif /* CK_SCOV5 */
843 
844 #ifdef SCO_OSR507			/* 299 */
845 #ifdef RDCHK
846 #undef RDCHK
847 #endif	/* RDCHK */
848 #endif	/* SCO_OSR507 */
849 
850 /* Whether to include <fcntl.h> */
851 
852 #ifndef is68k				/* Only a few don't have this one. */
853 #ifndef BSD41
854 #ifndef FT21
855 #ifndef FT18
856 #ifndef COHERENT
857 #include <fcntl.h>
858 #endif /* COHERENT */
859 #endif /* FT18 */
860 #endif /* FT21 */
861 #endif /* BSD41 */
862 #endif /* not is68k */
863 
864 #ifdef COHERENT
865 #ifdef _I386
866 #include <fcntl.h>
867 #else
868 #include <sys/fcntl.h>
869 #endif /* _I386 */
870 #endif /* COHERENT */
871 
872 #ifdef ATT7300				/* Unix PC, internal modem dialer */
873 #include <sys/phone.h>
874 #endif /* ATT7300 */
875 
876 #ifdef HPUX				/* HP-UX variations. */
877 #define HPUXJOBCTL
878 #include <sys/modem.h>			/* HP-UX modem signals */
879 #ifdef hp9000s500			/* Model 500 */
880 #undef HPUXJOBCTL
881 #endif /* hp9000s500 */
882 #ifdef HPUXPRE65
883 #undef HPUXJOBCTL
884 typedef long mflag;
885 #endif /* HPUXPRE65 */
886 #ifdef HPUXJOBCTL
887 #include <sys/bsdtty.h>			/* HP-UX Berkeley tty support */
888 #endif /* HPUXJOBCTL */
889 #endif /* HPUX */
890 
891 /*
892   Which time.h files to include... See ckcdeb.h for defaults.
893   Note that 0, 1, 2, or all 3 of these can be included according to
894   the symbol definitions.
895 */
896 #ifndef NOTIMEH
897 #ifdef TIMEH
898 #include <time.h>
899 #endif /* TIMEH */
900 #endif /* NOTIMEH */
901 
902 #ifndef NOSYSTIMEH
903 #ifdef SYSTIMEH
904 #include <sys/time.h>
905 #endif /* SYSTIMEH */
906 #endif /* NOSYSTIMEH */
907 
908 #ifndef NOSYSTIMEBH
909 #ifdef SYSTIMEBH
910 #include <sys/timeb.h>
911 #endif /* SYSTIMEBH */
912 #endif /* NOSYSTIMEBH */
913 
914 #ifndef NODCLTIMEVAL
915 #ifdef DCLTIMEVAL
916 /*
917   In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
918   define the structs we need to access the higher speeds, so we have to
919   do it ourselves.
920 */
921 struct timeval {
922     long tv_sec;
923     long tv_usec;
924 };
925 struct timezone {
926     int tz_minuteswest;
927     int tz_dsttime;
928 };
929 #endif /* DCLTIMEVAL */
930 #endif /* NODCLTIMEVAL */
931 
932 #ifdef __linux__
933 /* THIS IS OBSOLETE since about Linux 0.92 */
934 #ifdef OLINUXHISPEED
935 #include <linux/serial.h>
936 #endif /* OLINUXHISPEED */
937 #ifdef __alpha__			/* Linux on DEC Alpha */
938 #ifndef __GLIBC__			/* But not with glibc */
939 #include <asm/termios.h>
940 #endif /* __GLIBC__ */
941 #endif /* __alpha__ */
942 #endif /* __linux__ */
943 
944 #ifdef NOIEXTEN				/* This is broken on some systems */
945 #undef IEXTEN				/* like Convex/OS 9.1 */
946 #endif /* NOIEXTEN */
947 #ifndef IEXTEN				/* Turn off ^O/^V processing. */
948 #define IEXTEN 0			/* Needed, at least, on BSDI. */
949 #endif /* IEXTEN */
950 /*
951   Pick up definitions needed for select() if we don't have them already.
952   Normally they come from <sys/types.h> but some systems get them from
953   <sys/select.h>...  Rather than hardwire all of them into the source, we
954   include it if SELECT_H is defined in compile-time CFLAGS.
955 */
956 #ifndef SCO_OSR504
957 #ifdef SELECT_H
958 #include <sys/select.h>
959 #endif /* SELECT_H */
960 #endif /* SCO_OSR504 */
961 
962 #ifdef aegis
963 #include "/sys/ins/base.ins.c"
964 #include "/sys/ins/error.ins.c"
965 #include "/sys/ins/ios.ins.c"
966 #include "/sys/ins/sio.ins.c"
967 #include "/sys/ins/pad.ins.c"
968 #include "/sys/ins/time.ins.c"
969 #include "/sys/ins/pfm.ins.c"
970 #include "/sys/ins/pgm.ins.c"
971 #include "/sys/ins/ec2.ins.c"
972 #include "/sys/ins/type_uids.ins.c"
973 #include <default_acl.h>
974 #undef TIOCEXCL
975 #undef FIONREAD
976 #endif /* aegis */
977 
978 #ifdef sxaE50				/* PFU Compact A SX/A TISP V10/L50 */
979 #undef FIONREAD
980 #endif /* sxaE50 */
981 
982 /* The following #defines are catch-alls for those systems */
983 /* that didn't have or couldn't find <file.h>... */
984 
985 #ifndef FREAD
986 #define FREAD 0x01
987 #endif /* FREAD */
988 
989 #ifndef FWRITE
990 #define FWRITE 0x10
991 #endif /* FWRITE */
992 
993 #ifndef O_RDONLY
994 #define O_RDONLY 000
995 #endif /* O_RDONLY */
996 
997 /* This is for ancient Unixes that don't have these tty symbols defined. */
998 
999 #ifndef PENDIN
1000 #define PENDIN ICANON
1001 #endif /* PENDIN */
1002 #ifndef FLUSHO
1003 #define FLUSHO ICANON
1004 #endif /* FLUSHO */
1005 #ifndef EXTPROC
1006 #define EXTPROC ICANON
1007 #endif /* EXTPROC */
1008 
1009 #ifdef SVORPOSIX
1010 /*
1011   Modem signals are also forbidden in the POSIX world.  But some POSIX-based
1012   platforms let us at them anyway if we know where to look.
1013 */
1014 #ifndef NEEDMDMDEFS
1015 /* Doesn't work for Linux */
1016 #ifdef UNIXWARE7
1017 #define NEEDMDMDEFS
1018 #endif /* UNIXWARE7 */
1019 #endif /* NEEDMDMDEFS */
1020 
1021 #ifdef NEEDMDMDEFS
1022 #ifndef TIOCMGET
1023 #define TIOCMGET (('t'<<8)|29)
1024 #endif /* TIOCMGET */
1025 
1026 #ifndef TIOCM_DTR
1027 #define TIOCM_DTR 0x0002
1028 #endif /* TIOCM_DTR */
1029 #ifndef TIOCM_RTS
1030 #define TIOCM_RTS 0x0004
1031 #endif /* TIOCM_RTS */
1032 #ifndef TIOCM_CTS
1033 #define TIOCM_CTS 0x0020
1034 #endif /* TIOCM_CTS */
1035 #ifndef TIOCM_CAR
1036 #define TIOCM_CAR 0x0040
1037 #endif /* TIOCM_CAR */
1038 #ifndef TIOCM_RNG
1039 #define TIOCM_RNG 0x0080
1040 #endif /* TIOCM_RNG */
1041 #ifndef TIOCM_DSR
1042 #define TIOCM_DSR 0x0100
1043 #endif /* TIOCM_DSR */
1044 #endif /* NEEDMDMDEFS */
1045 #endif /* SVORPOSIX */
1046 
1047 /* Declarations */
1048 
1049 #ifdef OXOS
1050 #undef TCGETA
1051 #undef TCSETA
1052 #undef TCSETAW
1053 #undef TCSETAF
1054 #define TCGETA TCGETS
1055 #define TCSETA TCSETS
1056 #define TCSETAW TCSETSW
1057 #define TCSETAF TCSETSF
1058 #define termio termios
1059 #endif /* OXOS */
1060 
1061 #ifdef SVORPOSIX			/* AT&T Sys V or POSIX */
1062 #ifdef UNIXWAREPOSIX			/* UnixWare 7 POSIX build */
1063 /*
1064   In Unixware POSIX builds, <[sys/]time.h> refuses to define the
1065   structs we need to access the higher speeds, so we have to do it
1066   ourselves.
1067 */
1068 struct timeval {
1069     long tv_sec;
1070     long tv_usec;
1071 };
1072 struct timezone {
1073     int tz_minuteswest;
1074     int tz_dsttime;
1075 };
1076 #endif /* UNIXWAREPOSIX */
1077 #endif /* SVORPOSIX */
1078 
1079 #ifdef __GNUC__
1080 #ifdef XENIX
1081 /*
1082   Because Xenix <time.h> doesn't declare time() if we're using gcc.
1083 */
1084 time_t time();
1085 #endif /* XENIX */
1086 #endif /* __GNUC__ */
1087 
1088 /* Special stuff for V7 input buffer peeking */
1089 
1090 #ifdef  V7
1091 int kmem[2] = { -1, -1};
1092 char *initrawq(), *qaddr[2]={0,0};
1093 #define CON 0
1094 #define TTY 1
1095 #endif /* V7 */
1096 
1097 /* dftty is the device name of the default device for file transfer */
1098 /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
1099 
1100 #ifdef BEOS
1101     char * dftty = NULL;
1102     char * dfmdm = "none";
1103     int dfloc = 0;                  /* that goes in local mode by default */
1104 #else
1105 #ifndef DFTTY
1106 #ifdef PROVX1
1107     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
1108     char *dfmdm = "none";
1109     int dfloc = 1;                  /* that goes in local mode by default */
1110 #else
1111     char *dftty = CTTNAM;               /* Remote by default, use normal */
1112     char *dfmdm = "none";
1113     int dfloc = 0;                      /* controlling terminal name. */
1114 #endif /* PROVX1 */
1115 #else
1116     char *dftty = DFTTY;		/* Default location specified on */
1117     char *dfmdm = "none";		/* command line. */
1118     int dfloc = 1;                      /* controlling terminal name. */
1119 #endif /* DFTTY */
1120 #endif /* BEOS */
1121 
1122 #define CON_RES 0			/* Console state is "reset" */
1123 #define CON_CB  1			/* Console state is CBREAK */
1124 #define CON_BIN 2			/* Console state is binary */
1125     static int constate = CON_RES;
1126 
1127 #define CONI_RES 0			/* Console interrupts are "reset" */
1128 #define CONI_INT 1			/* Console intterupts are set */
1129 #define CONI_NOI 2			/* Console intterupts are disabled */
1130     static int conistate = CONI_RES;
1131 
1132 #ifdef CK_SMALL
1133 #define CONBUFSIZ 15
1134 #else
1135 #define CONBUFSIZ 255
1136 #endif /* CK_SMALL */
1137     static char conbuf[CONBUFSIZ];	/* Console readahead buffer */
1138     static int  conbufn = 0;		/* Chars in readahead buffer */
1139     static char *conbufp = conbuf;	/* Next char in readahead buffer */
1140 
1141     char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
1142 
1143 #ifdef RTU
1144     int rtu_bug = 0;		    /* set to 1 when returning from SIGTSTP */
1145 #endif /* RTU */
1146 
1147     int dfprty = DEFPAR;                /* Default parity (0 = none) */
1148     int ttprty = 0;                     /* The parity that is in use. */
1149     static int ttpmsk = 0xff;		/* Parity stripping mask. */
1150     int ttmdm = 0;                      /* Modem in use. */
1151     int ttcarr = CAR_AUT;		/* Carrier handling mode. */
1152     int dfflow = FLO_NONE;		/* Default flow control is NONE */
1153     int backgrd = 0;                    /* Assume in foreground (no '&' ) */
1154 #ifdef F_SETFL
1155     int iniflags = -1;			/* fcntl flags for ttyfd */
1156 #endif /* F_SETFL */
1157     int fdflag = 0;			/* Flag for redirected stdio */
1158     int ttfdflg = 0;			/* Open File descriptor was given */
1159     int tvtflg = 0;			/* Flag that ttvt has been called */
1160     long ttspeed = -1L;			/* For saving speed */
1161     int ttflow = -9;			/* For saving flow */
1162     int ttld = -1;			/* Line discipline */
1163 
1164 #ifdef sony_news
1165     static int km_con = -1;		/* Kanji mode for console tty */
1166     static int km_ext = -1;		/* Kanji mode for external device */
1167 #endif /* sony_news */
1168 
1169 #ifdef PARSENSE
1170     static int needpchk = 1;		/* Need parity check */
1171 #else
1172     static int needpchk = 0;
1173 #endif /* PARSENSE */
1174 
1175     extern int stopbits;		/* Stop bits */
1176 #ifdef HWPARITY
1177 /*
1178   Unfortunately we must do this with global variables rather than through the
1179   tt...() APIs to avoid changing the APIs and the many modules that use them.
1180   If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
1181   bits + parity or 8 data bits and no parity, and overrides the regular parity
1182   variable, which is communicated to this module thru ttpkt(), and represented
1183   locally by the ttprty variable.
1184 */
1185     extern int hwparity;		/* Hardware parity */
1186 #endif /* HWPARITY */
1187 
1188 #ifdef TCPSOCKET
1189 #ifdef TCP_NODELAY
1190 static int nodelay_sav = -1;
1191 #endif /* TCP_NODELAY */
1192 #endif /* TCPSOCKET */
1193 
1194 static int sigint_ign = 0;		/* SIGINT is ignored */
1195 
1196 /*
1197   Having this module rely on external globals is bad, but fixing this
1198   requires overhaul of the ck*tio.c modules for all the different operating
1199   systems supported by C-Kermit.  Left for a future release.
1200 */
1201 extern int ttnproto;			/* Defined in ckcnet.c */
1202 extern int ttnet;			/* Defined in ckcnet.c */
1203 extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
1204 extern int xsuspend, wasclosed;
1205 extern int inserver, local;
1206 
1207 int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
1208 
1209 int ckmaxfiles = 0;			/* Max number of open files */
1210 
1211 #ifdef CK_ENCRYPTION			/* Kerberos */
1212 #include "ckuath.h"
1213 extern int me_encrypt, u_encrypt;
1214 #endif /* CK_ENCRYPTION */
1215 
1216 /* Declarations of variables global within this module */
1217 
1218 #ifdef TTLEBUF				/* See ckcnet.h */
1219 int ttpush = -1;
1220 #define LEBUFSIZ 4096
1221 static CHAR le_buf[LEBUFSIZ];
1222 static int le_start = 0, le_end = 0, le_data = 0;
1223 #endif /* TTLEBUF */
1224 
1225 #define MSGBUF_SIZE 1024		/* For debugging */
1226 static char msgbuf[MSGBUF_SIZE];
1227 
1228 static int gotsigs = 0;
1229 
1230 static time_t tcount = (time_t)0;	/* Elapsed time counter */
1231 
1232 static SIGTYP (*saval)()     = NULL;	/* For saving alarm() handler */
1233 static SIGTYP (*savquit)()   = NULL;	/* and other signal handlers */
1234 #ifdef SIGUSR1
1235 static SIGTYP (*savusr1)()   = NULL;
1236 #endif /* SIGUSR1 */
1237 #ifdef SIGUSR2
1238 static SIGTYP (*savusr2)()   = NULL;
1239 #endif /* SIGUSR2 */
1240 #ifdef SIGPIPE
1241 static SIGTYP (*savpipe)()   = NULL;
1242 #endif /* SIGPIPE */
1243 #ifdef SIGDANGER
1244 static SIGTYP (*savdanger)() = NULL;
1245 #endif /* SIGDANGER */
1246 
1247 #ifndef NOJC
1248 static SIGTYP (*jchdlr)()    = NULL;	/* For checking suspend handler */
1249 #endif /* NOJC */
1250 static int jcshell = -1;		/* And flag for result */
1251 
1252 /*
1253   BREAKNULS is defined for systems that simulate sending a BREAK signal
1254   by sending a bunch of NUL characters at low speed.
1255 */
1256 #ifdef PROVX1
1257 #ifndef BREAKNULS
1258 #define BREAKNULS
1259 #endif /* BREAKNULS */
1260 #endif /* PROVX1 */
1261 
1262 #ifdef V7
1263 #ifndef BREAKNULS
1264 #define BREAKNULS
1265 #endif /* BREAKNULS */
1266 #endif /* V7 */
1267 
1268 #ifdef BREAKNULS
1269 static char				/* A string of nulls */
1270 *brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
1271 #endif /* BREAKNULS */
1272 
1273 #ifdef CK_POSIX_SIG			/* Longjump buffers */
1274 static sigjmp_buf sjbuf;		/* POSIX signal handling */
1275 #else
1276 static jmp_buf sjbuf;
1277 #endif /* CK_POSIX_SIG */
1278 
1279 #ifdef V7
1280 static jmp_buf jjbuf;
1281 #endif /* V7 */
1282 
1283 /* static */				/* (Not static any more) */
1284 int ttyfd = -1;				/* TTY file descriptor */
1285 
1286 int ttpipe = 0;				/* NETCMD: Use pipe instead of ttyfd */
1287 int ttpty  = 0;                         /* NETPTY: Use pty instead of ttfyd */
1288 
1289 #ifdef NETPTY				/* These are in ckupty.c */
1290 extern PID_T pty_fork_pid;
1291 extern int pty_master_fd, pty_slave_fd;
1292 #endif	/* NETPTY */
1293 
1294 #ifdef NETCMD
1295 #ifdef NETCONN
1296 static int pipe0[2], pipe1[2];		/* Pipes for net i/o */
1297 #endif /* NETCONN */
1298 static PID_T ttpid = 0;			/* Process ID for fork */
1299 static int fdin, fdout;			/* File descriptors for pipe */
1300 static FILE * ttout = NULL;		/* File pointer for output pipe */
1301 #ifdef DCLFDOPEN
1302 /* fdopen() needs declaring because it's not declared in <stdio.h> */
1303 _PROTOTYP( FILE * fdopen, (int, char *) );
1304 #endif /* DCLFDOPEN */
1305 #endif /* NETCMD */
1306 
1307 extern int pexitstat, quiet;
1308 
1309 #ifdef Plan9
1310 int ttyctlfd  = -1;   /* TTY control channel - What? UNIX doesn't have one? */
1311 int consctlfd = -1;			/* Console control channel */
1312 int noisefd = -1;			/* tone channel */
1313 static int ttylastspeed = -1;		/* So we can lie about the speed */
1314 #endif /* Plan9 */
1315 
1316 int telnetfd = 0;			/* File descriptor is for telnet */
1317 #ifdef NETCONN
1318 int x25fd = 0;				/* File descriptor is for X.25 */
1319 #endif /* NETCONN */
1320 
1321 char lockpid[16] = { '\0', '\0' };	/* PID stored in lockfile, as string */
1322 
1323 static int lkf = 0,                     /* Line lock flag */
1324     cgmf = 0,                           /* Flag that console modes saved */
1325     xlocal = 0,                         /* Flag for tty local or remote */
1326     curcarr = 0;			/* Carrier mode: require/ignore. */
1327 
1328 static int netconn = 0;			/* 1 if network connection active */
1329 
1330 static char escchr;                     /* Escape or attn character */
1331 
1332 #ifdef CK_SCO32V4
1333 #include <sys/time.h>
1334 #endif /* CK_SCO32V4 */
1335 
1336 #ifdef HAVE_TV
1337     static struct timeval tv;		/* For getting time, from sys/time.h */
1338 #endif /* HAVE_TV */
1339 #ifdef HAVE_TZ
1340     static struct timezone tz;
1341 #endif /* HAVE_TZ */
1342 
1343 #ifdef OSF
1344     static struct timeb ftp;            /* And from sys/timeb.h */
1345 #endif /* OSF */
1346 
1347 #ifdef BSD29
1348     static long xclock;			/* For getting time from sys/time.h */
1349     static struct timeb ftp;            /* And from sys/timeb.h */
1350 #endif /* BSD29 */
1351 
1352 #ifdef BSD41
1353     static long xclock;			/* For getting time from sys/time.h */
1354     static struct timeb ftp;            /* And from sys/timeb.h */
1355 #endif /* BSD41 */
1356 
1357 #ifdef BELLV10
1358     static long xclock;			/* For getting time from sys/time.h */
1359     static struct timeb ftp;            /* And from sys/timeb.h */
1360 #endif /* BELLV10 */
1361 
1362 #ifdef FT21
1363     static long xclock;			/* For getting time from sys/time.h */
1364     static struct timeb ftp;            /* And from sys/timeb.h */
1365 #endif /* FT21 */
1366 
1367 #ifdef TOWER1
1368     static long xclock;			/* For getting time from sys/time.h */
1369     static struct timeb ftp;		/* And from sys/timeb.h */
1370 #endif /* TOWER1 */
1371 
1372 #ifdef COHERENT
1373     static long xclock;			/* For getting time from sys/time.h */
1374     static struct timeb ftp;		/* And from sys/timeb.h */
1375 #endif /* COHERENT */
1376 
1377 #ifdef V7
1378     static long xclock;
1379 #endif /* V7 */
1380 
1381 /* sgtty/termio information... */
1382 
1383 #ifdef BSD44ORPOSIX			/* POSIX or BSD44 */
1384   static struct termios
1385     ttold, ttraw, tttvt, ttcur,
1386     ccold, ccraw, cccbrk;
1387 #else					/* BSD, V7, etc */
1388 
1389 #ifdef COHERENT				/* Hack alert... */
1390 #define ATTSV
1391 #endif /* COHERENT */
1392 
1393 #ifdef ATTSV
1394   static struct termio ttold = {0};	/* Init'd for word alignment, */
1395   static struct termio ttraw = {0};	/* which is important for some */
1396   static struct termio tttvt = {0};	/* systems, like Zilog... */
1397   static struct termio ttcur = {0};
1398   static struct termio ccold = {0};
1399   static struct termio ccraw = {0};
1400   static struct termio cccbrk = {0};
1401 #else
1402   static struct sgttyb                  /* sgtty info... */
1403     ttold, ttraw, tttvt, ttcur, 	/* for communication line */
1404     ccold, ccraw, cccbrk;		/* and for console */
1405 #ifdef BELLV10
1406   static struct ttydevb			/* Device info... */
1407     tdold, tdcur;			/* for communication device */
1408 #endif /* BELLV10 */
1409 #ifdef TIOCGETC
1410   static struct tchars tchold, tchnoi;
1411 
1412   static int tcharf;
1413 #endif /* TIOCGETC */
1414 #ifdef TIOCGLTC
1415   static struct ltchars ltchold, ltchnoi;
1416   static int ltcharf;
1417 #endif /* TIOCGLTC */
1418   int lmodef = 0;			/* Local modes */
1419   int lmode = 0;
1420 #endif /* ATTSV */
1421 #endif /* BSD44ORPOSIX */
1422 
1423 #ifdef COMMENT
1424 /* It picks up the speeds but they don't work */
1425 #ifdef UNIXWARE				/* For higher serial speeds */
1426 #ifdef UW7				/* in Unixware 7.0 */
1427 #include <sys/asyc.h>			/* This picks up 57600 and 115200 */
1428 #endif /* UW7 */
1429 #endif /* UNIXWARE */
1430 #endif /* COMMENT */
1431 
1432 #ifdef PROVX1
1433   static struct sgttyb ttbuf;
1434 #endif /* PROVX1 */
1435 
1436 #ifdef ultrix
1437 /* do we really need this? */
1438   static struct sgttyb vanilla;
1439 #endif /* ultrix */
1440 
1441 #ifdef ATT7300
1442 static int attmodem = 0;                /* ATT7300 internal-modem status */
1443 struct updata dialer = {0};		/* Condition dialer for data call */
1444 #endif /* ATT7300 */
1445 
1446 #ifndef NOUUCP
1447 #define FLFNAML 128
1448 #ifndef USETTYLOCK
1449 #ifdef RTAIX
1450 char lkflfn[FLFNAML] = { '\0', '\0' };	/* and possible link to it */
1451 #endif /* RTAIX */
1452 char lock2[FLFNAML] =  { '\0', '\0' };	/* Name of second lockfile */
1453 #endif /* USETTYLOCK */
1454 #else
1455 #define FLFNAML 7
1456 #endif /* NOUUCP */
1457 char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
1458 
1459 int haslock = 0;			/* =1 if this kermit locked uucp */
1460 
1461 #ifndef OXOS
1462 #ifdef SVORPOSIX
1463 static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
1464 #else
1465 #ifdef V7
1466 static int conesc = 0;
1467 #else
1468 #ifdef C70
1469 static int conesc = 0;
1470 #endif /* C70 */
1471 #endif /* V7 */
1472 #endif /* SVORPOSIX */
1473 #endif /* OXOS */
1474 
1475 /* Local copy of comm device name or network host */
1476 static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
1477 #ifdef USETTYLOCK
1478 static char lockname[DEVNAMLEN+1];	/* Ditto, the part after "/dev/". */
1479 #endif /* USETTYLOCK */
1480 
1481 #ifdef aegis
1482 static status_$t st;                    /* error status return value */
1483 static short concrp = 0;                /* true if console is CRP pad */
1484 static uid_$t ttyuid;                   /* tty type uid */
1485 static uid_$t conuid;                   /* stdout type uid */
1486 
1487 /* APOLLO Aegis main()
1488  * establish acl usage and cleanup handling
1489  *    this makes sure that CRP pads
1490  *    get restored to a usable mode
1491  */
main(argc,argv)1492 main(argc,argv) int argc; char **argv; {
1493         status_$t status;
1494         pfm_$cleanup_rec dirty;
1495 
1496         PID_T pid = getpid();
1497 
1498         /* acl usage according to invoking environment */
1499         default_acl(USE_DEFENV);
1500 
1501         /* establish a cleanup continuation */
1502         status = pfm_$cleanup(dirty);
1503         if (status.all != pfm_$cleanup_set) {
1504                 /* only handle faults for the original process */
1505                 if (pid == getpid() && status.all > pgm_$max_severity) {
1506 		    /* blew up in main process */
1507 		    status_$t quo;
1508 		    pfm_$cleanup_rec clean;
1509 
1510 		    /* restore the console in any case */
1511 		    conres();
1512 
1513 		    /* attempt a clean exit */
1514 		    debug(F101, "cleanup fault status", "", status.all);
1515 
1516 		    /* doexit(), then send status to continuation */
1517 		    quo = pfm_$cleanup(clean);
1518 		    if (quo.all == pfm_$cleanup_set)
1519 		      doexit(pgm_$program_faulted,-1);
1520 		    else if (quo.all > pgm_$max_severity)
1521 		      pfm_$signal(quo); /* blew up in doexit() */
1522                 }
1523                 /* send to the original continuation */
1524                 pfm_$signal(status);
1525                 /*NOTREACHED*/
1526 	    }
1527         return(ckcmai(argc, argv));
1528 }
1529 #endif /* aegis */
1530 
1531 /* ANSI-style prototypes for internal functions. */
1532 /* Functions used outside this module are prototyped in ckcker.h. */
1533 
1534 #ifdef apollo
1535 _PROTOTYP( SIGTYP timerh, () );
1536 _PROTOTYP( SIGTYP cctrap, () );
1537 _PROTOTYP( SIGTYP esctrp, () );
1538 _PROTOTYP( SIGTYP sig_ign, () );
1539 #else
1540 _PROTOTYP( SIGTYP timerh, (int) );
1541 _PROTOTYP( SIGTYP cctrap, (int) );
1542 _PROTOTYP( SIGTYP esctrp, (int) );
1543 #endif /* apollo */
1544 _PROTOTYP( int do_open, (char *) );
1545 _PROTOTYP( static int in_chk, (int, int) );
1546 _PROTOTYP( static int ttrpid, (char *) );
1547 _PROTOTYP( static int ttchkpid, (char *) );
1548 _PROTOTYP( static int ttlock, (char *) );
1549 _PROTOTYP( static int ttunlck, (void) );
1550 _PROTOTYP( static VOID sigchld_handler, (int) );
1551 _PROTOTYP( int mygetbuf, (void) );
1552 _PROTOTYP( int myfillbuf, (void) );
1553 _PROTOTYP( VOID conbgt, (int) );
1554 #ifdef ACUCNTRL
1555 _PROTOTYP( VOID acucntrl, (char *, char *) );
1556 #endif /* ACUCNTRL */
1557 
1558 #ifdef BSD44ORPOSIX
1559 _PROTOTYP( int carrctl, (struct termios *, int) );
1560 #else
1561 #ifdef ATTSV
1562 _PROTOTYP( int carrctl, (struct termio *, int) );
1563 #else
1564 _PROTOTYP( int carrctl, (struct sgttyb *, int) );
1565 #endif /* ATTSV */
1566 #endif /* BSD44ORPOSIX */
1567 
1568 #ifdef ATT7300
1569 _PROTOTYP( int attdial, (char *, long, char *) );
1570 _PROTOTYP( int offgetty, (char *) );
1571 _PROTOTYP( int ongetty, (char *) );
1572 #endif /* ATT7300 */
1573 
1574 #ifdef BEOSORBEBOX
1575 #ifdef SELECT
1576     /* BeOS is not capable of using SELECT on anything but sockets */
1577 #undef SELECT
1578 #endif /* SELECT */
1579 #include <kernel/OS.h>
1580 /* #ifdef BE_DR_7 */
1581 static double time_started = 0.0;
1582 struct ALARM_STRUCT {
1583     thread_id thread;
1584     int time;
1585 };
1586 static thread_id alarm_thread = -1;
1587 static struct ALARM_STRUCT alarm_struct;
1588 _PROTOTYP( long do_alarm, (void *) );
1589 _PROTOTYP( unsigned int alarm, (unsigned int) );
1590 _PROTOTYP( void alarm_expired, (void) );
1591 /* #endif */ /* BE_DR_7 */
1592 #endif /* BEOSORBEBOX */
1593 
1594 #ifndef xunchar
1595 #define xunchar(ch) (((ch) - 32 ) & 0xFF )	/* Character to number */
1596 #endif /* xunchar */
1597 
1598 #ifdef CK_ANSIC
1599 static char *
xxlast(char * s,char c)1600 xxlast(char *s, char c)
1601 #else
1602 static char *
1603 xxlast(s,c) char *s; char c;
1604 #endif /* CK_ANSIC */
1605 /* xxlast */ {		/*  Last occurrence of character c in string s. */
1606     int i;
1607     for (i = (int)strlen(s); i > 0; i--)
1608       if (s[i-1] == c ) return(s + (i - 1));
1609     return(NULL);
1610 }
1611 
1612 /* Timeout handler for communication line input functions */
1613 
1614 /*ARGSUSED*/
1615 SIGTYP
timerh(foo)1616 timerh(foo) int foo; {
1617     ttimoff();
1618 #ifdef BEOSORBEBOX
1619 /* #ifdef BE_DR_7 */
1620     alarm_expired();
1621 /* #endif */ /* BE_DR_7 */
1622 #endif /* BEOSORBEBOX */
1623 #ifdef CK_POSIX_SIG
1624     siglongjmp(sjbuf,1);
1625 #else
1626     longjmp(sjbuf,1);
1627 #endif /* CK_POSIX_SIG */
1628 }
1629 
1630 /*ARGSUSED*/
1631 SIGTYP
xtimerh(foo)1632 xtimerh(foo) int foo; {			/* Like timerh() but does */
1633 #ifdef BEOSORBEBOX			/* not reset the timer itself */
1634 /* #ifdef BE_DR_7 */
1635     alarm_expired();
1636 /* #endif */ /* BE_DR_7 */
1637 #endif /* BEOSORBEBOX */
1638 #ifdef CK_POSIX_SIG
1639     siglongjmp(sjbuf,1);
1640 #else
1641     longjmp(sjbuf,1);
1642 #endif /* CK_POSIX_SIG */
1643 }
1644 
1645 
1646 /* Control-C trap for communication line input functions */
1647 
1648 int cc_int;				/* Flag */
1649 SIGTYP (* occt)();			/* For saving old SIGINT handler */
1650 
1651 /*ARGSUSED*/
1652 SIGTYP
cctrap(foo)1653 cctrap(foo) int foo; {			/* Needs arg for ANSI C */
1654   cc_int = 1;				/* signal() prototype. */
1655   return;
1656 }
1657 
1658 /*  S Y S I N I T  --  System-dependent program initialization.  */
1659 
1660 /*
1661  * ttgwsiz() returns:
1662  *	1    tt_rows and tt_cols are known, both altered, both > 0
1663  *	0    tt_rows and/or tt_cols are known, both altered, one or both <= 0
1664  *	-1   tt_rows and tt_cols are unknown and unaltered
1665  */
1666 
1667 extern int tt_rows, tt_cols;
1668 
1669 static int
xttgwsiz()1670 xttgwsiz() {
1671     char *p;
1672     int rows = 0, cols = 0;
1673     p = getenv("LINES");
1674     debug(F110,"xttgwsiz LINES",p,0);
1675     if (p) {
1676 	rows = atol(p);
1677 	if (rows > 0) {
1678 	    p = getenv("COLUMNS");
1679 	    debug(F110,"xttgwsiz COLUMNS",p,0);
1680 	    if (p) {
1681 		cols = atol(p);
1682 		if (cols > 0) {
1683 		    tt_rows = rows;
1684 		    tt_cols = cols;
1685 		    return(1);
1686 		}
1687 		return(0);
1688 	    }
1689 	}
1690     }
1691     return(-1);
1692 }
1693 
1694 #ifdef TTLEBUF
1695 VOID
le_init()1696 le_init() {				/* LocalEchoInit() */
1697     int i;
1698     for (i = 0; i < LEBUFSIZ; i++)
1699       le_buf[i] = '\0';
1700     le_start = 0;
1701     le_end = 0;
1702     le_data = 0;
1703 }
1704 
1705 VOID
le_clean()1706 le_clean() {				/* LocalEchoCleanup() */
1707     le_init();
1708     return;
1709 }
1710 
1711 int
le_inbuf()1712 le_inbuf() {
1713     int rc = 0;
1714     if (le_start != le_end) {
1715 	rc = (le_end -
1716 	      le_start +
1717 	      LEBUFSIZ) % LEBUFSIZ;
1718     }
1719     debug(F111,"le_inbuf","chars waiting",rc);
1720     return(rc);
1721 }
1722 
1723 int
1724 #ifdef CK_ANSIC
le_putchar(CHAR ch)1725 le_putchar(CHAR ch)
1726 #else
1727 le_putchar(ch) CHAR ch;
1728 #endif /* CK_ANSIC */
1729 /* le_putchar */ {
1730 #ifdef COMMENT
1731     /* In UNIX we do not have another thread taking chars out of the buffer */
1732     while ((le_start - le_end == 1) ||
1733             (le_start == 0 && le_end == LEBUFSIZ - 1)) {
1734 	/* Buffer is full */
1735         debug(F111,"le_putchar","Buffer is Full",ch);
1736         ReleaseLocalEchoMutex() ;
1737         msleep(250);
1738         RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
1739     }
1740 #else
1741     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
1742         debug(F110,"le_putchar","buffer is full",0);
1743         return(-1);
1744     }
1745 #endif /* COMMENT */
1746     le_buf[le_end++] = ch;
1747     if (le_end == LEBUFSIZ)
1748       le_end = 0;
1749     le_data = 1;
1750     return(0);
1751 }
1752 
1753 int
1754 #ifdef CK_ANSIC
le_puts(CHAR * s,int n)1755 le_puts(CHAR * s, int n)
1756 #else
1757 le_puts(s,n) CHAR * s; int n;
1758 #endif /* CK_ANSIC */
1759 /* le_puts */ {
1760     int rc = 0;
1761     int i = 0;
1762     CHAR * p = (CHAR *)"le_puts";
1763     ckhexdump(p,s,n);
1764     for (i = 0; i < n; i++)
1765       rc = le_putchar((char)s[i]);
1766     debug(F101,"le_puts","",rc);
1767     return(rc);
1768 }
1769 
1770 int
1771 #ifdef CK_ANSIC
le_putstr(CHAR * s)1772 le_putstr(CHAR * s)
1773 #else
1774 le_putstr(s) CHAR * s;
1775 #endif /* CK_ANSIC */
1776 /* le_puts */ {
1777     CHAR * p;
1778     int rc = 0;
1779     p = (CHAR *)"le_putstr";
1780     ckhexdump(p,s,(int)strlen((char *)s));
1781     for (p = s; *p && !rc; p++)
1782       rc = le_putchar(*p);
1783     return(rc);
1784 }
1785 
1786 int
1787 #ifdef CK_ANSIC
le_getchar(CHAR * pch)1788 le_getchar(CHAR * pch)
1789 #else /* CK_ANSIC */
1790 le_getchar(pch) CHAR * pch;
1791 #endif /* CK_ANSIC */
1792 /* le_gatchar */ {
1793     int rc = 0;
1794     if (le_start != le_end) {
1795         *pch = le_buf[le_start];
1796         le_buf[le_start] = 0;
1797         le_start++;
1798 
1799         if (le_start == LEBUFSIZ)
1800           le_start = 0;
1801 
1802         if (le_start == le_end) {
1803             le_data = 0;
1804         }
1805         rc++;
1806     } else {
1807         *pch = 0;
1808     }
1809     return(rc);
1810 }
1811 #endif /* TTLEBUF */
1812 
1813 #ifdef COMMENT
1814 /*
1815   Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
1816   But as far as I know, whenever TIOCGSIZE is defined, it is
1817   equated to TIOCGWINSZ.  For cases where this is not done, try this:
1818 */
1819 #ifndef TIOCGWINSZ
1820 #ifdef TIOCGSIZE
1821 #define TIOCGWINSZ TIOCGSIZE
1822 #endif /* TIOCGSIZE */
1823 #endif /* TIOCGWINSZ */
1824 #endif /* COMMENT */
1825 
1826 static int tt_xpixel = 0, tt_ypixel = 0;
1827 
1828 int
ttgwsiz()1829 ttgwsiz() {
1830     int x = 0;
1831 #ifndef NONAWS
1832 #ifdef QNX
1833 /*
1834   NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
1835   This code works for both the 16- and 32-bit versions.
1836 */
1837     extern int dev_size(int, int, int, int *, int *);
1838     int r, c;
1839 
1840     if (dev_size(0, -1, -1, &r, &c) == 0) {
1841 	debug(F101,"ttgwsiz QNX r","",r);
1842 	debug(F101,"ttgwsiz QNX c","",c);
1843 	tt_rows = r;
1844 	tt_cols = c;
1845 	return ((r > 0 && c > 0) ? 1 : 0);
1846     } else return(xttgwsiz());
1847 #else /* QNX */
1848 #ifdef TIOCGWINSZ
1849 
1850 /* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
1851 #ifdef XENIX				/* SCO UNIX 3.2v4.0 */
1852 #include <sys/stream.h>			/* typedef mblk_t needed by ptem.h */
1853 #include <sys/ptem.h>			/* for ttgwsiz() */
1854 #endif /* XENIX */
1855 
1856 #ifdef I386IX				/* Ditto for Interactive */
1857 #include <sys/stream.h>
1858 #include <sys/ptem.h>
1859 #endif /* I386IX */
1860 
1861 /* Note, the above might be needed for some other older SVR3 Intel makes... */
1862 
1863     struct winsize w;
1864     tt_xpixel = 0;
1865     tt_ypixel = 0;
1866 
1867 #ifdef IKSD
1868     if (inserver)
1869       return(xttgwsiz());
1870 #endif /* IKSD */
1871     x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
1872     debug(F101,"ttgwsiz TIOCGWINSZ","",x);
1873     if (x < 0) {
1874 	return(xttgwsiz());
1875     } else if (w.ws_row > 0 && w.ws_col > 0) {
1876 	tt_rows = w.ws_row;
1877 	tt_cols = w.ws_col;
1878 	tt_xpixel = w.ws_xpixel;
1879 	tt_ypixel = w.ws_ypixel;
1880 	debug(F101,"ttgwsiz tt_rows","",tt_rows);
1881 	debug(F101,"ttgwsiz tt_cols","",tt_cols);
1882 	return(1);
1883     } else {
1884 	debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
1885 	return(xttgwsiz());
1886     }
1887 #else
1888     return(xttgwsiz());
1889 #endif /* TIOCGWINSZ */
1890 #endif /* QNX */
1891 #endif /* NONAWS */
1892 }
1893 
1894 
1895 #ifdef RLOGCODE
1896 _PROTOTYP( int rlog_naws, (void) );
1897 #endif	/* RLOGCODE */
1898 
1899 #ifndef NOSIGWINCH
1900 #ifdef SIGWINCH
1901 SIGTYP
winchh(foo)1902 winchh(foo) int foo; {			/* SIGWINCH handler */
1903     int x = 0;
1904 #ifdef CK_TTYFD
1905 #ifndef VMS
1906     extern int ttyfd;
1907 #endif /* VMS */
1908 #endif /* CK_TTYFD */
1909     extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
1910 #ifdef DEBUG
1911     if (deblog) {
1912 	debug(F100,"***************","",0);
1913 	debug(F100,"SIGWINCH caught","",0);
1914 	debug(F100,"***************","",0);
1915 #ifdef NETPTY
1916 	debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
1917 #endif /* NETPTY */
1918     }
1919 #endif /* DEUB */
1920     signal(SIGWINCH,winchh);            /* Re-arm the signal */
1921     x = ttgwsiz();                      /* Get new window size */
1922     cmd_rows = tt_rows;			/* Adjust command screen too */
1923     cmd_cols = tt_cols;
1924 
1925 #ifdef CK_TTYFD
1926     if					/* If we don't have a connection */
1927 #ifdef VMS				/* we're done. */
1928       (vmsttyfd() == -1)
1929 #else
1930       (ttyfd == -1)
1931 #endif /* VMS */
1932 #else
1933       (!local)
1934 #endif /* CK_TTYFD */
1935         return;
1936 
1937 #ifdef NETPTY
1938     if (pty_fork_pid > -1) {		/* "set host" to a PTY? */
1939 	int x;
1940 
1941 #ifdef TIOCSWINSZ
1942 	struct winsize w;		/* Resize the PTY */
1943 	errno = 0;
1944 	w.ws_col = tt_cols;
1945 	w.ws_row = tt_rows;
1946 	w.ws_xpixel = tt_xpixel;
1947 	w.ws_ypixel = tt_ypixel;
1948 	x = ioctl(ttyfd,TIOCSWINSZ,&w);
1949 	debug(F101,"winchh TIOCSWINSZ","",x);
1950 	debug(F101,"winchh TIOCSWINSZ errno","",errno);
1951 #endif /* TIOCSWINSZ */
1952 
1953 	errno = 0;
1954 	x = kill(pty_fork_pid,SIGWINCH);
1955 	debug(F101,"winchh kill","",x);
1956 	debug(F101,"winchh kill errno","",errno);
1957     }
1958 #endif /* NETPTY */
1959 
1960 /*
1961   This should be OK.  It might seem that sending this from
1962   interrupt level could interfere with another TELNET IAC string
1963   that was in the process of being sent.  But we always send
1964   TELNET strings with a single write(), which should prevent mixups.
1965   blah_snaws() should protect themselves from being called on the
1966   wrong kind of connection.
1967 */
1968 #ifdef TCPSOCKET
1969 #ifndef NOTTGWSIZ
1970     if (x > 0 && tt_rows > 0 && tt_cols > 0) {
1971         tn_snaws();
1972 #ifdef RLOGCODE
1973         rlog_naws();
1974 #endif /* RLOGCODE */
1975     }
1976 #endif /* NOTTGWSIZ */
1977 #endif /* TCPSOCKET */
1978     SIGRETURN;
1979 }
1980 #endif /* SIGWINCH */
1981 #endif /* NOSIGWINCH */
1982 
1983 SIGTYP
sighup(foo)1984 sighup(foo) int foo; {			/* SIGHUP handler */
1985     backgrd = 1;
1986     debug(F100,"***************","",0);
1987     debug(F100,"SIGHUP received","",0);
1988     debug(F100,"***************","",0);
1989     doexit(BAD_EXIT,-1);
1990     /*NOTREACHED*/
1991     SIGRETURN;				/* Shut picky compilers up... */
1992 }
1993 
1994 #ifdef CK_SCO32V4
1995 /* Exists but there is no prototype in the header files */
1996 _PROTOTYP( char * ttyname, (int) );
1997 #else
1998 #ifdef SV68R3V6
1999 _PROTOTYP( char * ttyname, (int) );
2000 #else
2001 #ifdef ultrix
2002 _PROTOTYP( char * ttyname, (int) );
2003 #else
2004 #ifdef HPUX6
2005 _PROTOTYP( char * ttyname, (int) );
2006 #else
2007 #ifdef HPUX5
2008 _PROTOTYP( char * ttyname, (int) );
2009 #else
2010 #ifdef PS2AIX10
2011 _PROTOTYP( char * ttyname, (int) );
2012 #else
2013 #ifdef BSD42
2014 _PROTOTYP( char * ttyname, (int) );
2015 #endif /* BSD42 */
2016 #endif /* PS2AIX10 */
2017 #endif /* HPUX5 */
2018 #endif /* HPUX6 */
2019 #endif /* ultrix */
2020 #endif /* SV68R3V6 */
2021 #endif /* CK_SCO32V4 */
2022 
2023 #ifndef SIGUSR1				/* User-defined signals */
2024 #define SIGUSR1 30
2025 #endif /* SIGUSR1 */
2026 
2027 #ifndef SIGUSR2
2028 #define SIGUSR2 31
2029 #endif /* SIGUSR2 */
2030 
2031 /*
2032   ignorsigs() sets certain signals to SIG_IGN.  But when a signal is
2033   ignored, it remains ignored across exec(), so we have to restore these
2034   signals before exec(), which is the purpose of restorsigs().
2035 */
2036 static VOID
ignorsigs()2037 ignorsigs() {				/* Ignore these signals */
2038     savquit = signal(SIGQUIT,SIG_IGN);	/* Ignore Quit signal */
2039 
2040 #ifdef SIGDANGER			/* Ignore danger signals */
2041 /*
2042   This signal is sent when the system is low on swap space.  Processes
2043   that don't handle it are candidates for termination.  If swap space doesn't
2044   clear out enough, we still might be terminated via kill() -- nothing we can
2045   do about that!  Conceivably, this could be improved by installing a real
2046   signal handler that warns the user, but that would be pretty complicated,
2047   since we are not always in control of the screen -- e.g. during remote-mode
2048   file transfer.
2049 */
2050     savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
2051 #endif /* SIGDANGER */
2052 #ifdef SIGPIPE
2053 /*
2054   This one comes when a TCP/IP connection is broken by the remote.
2055   We prefer to catch this situation by examining error codes from write().
2056 */
2057     savpipe = signal(SIGPIPE,SIG_IGN);
2058 #endif /* SIGPIPE */
2059     savusr1 = signal(SIGUSR1,SIG_IGN);	/* Ignore user-defined signals */
2060     savusr2 = signal(SIGUSR2,SIG_IGN);
2061 }
2062 
2063 VOID
restorsigs()2064 restorsigs() {				/* Restore these signals */
2065     (VOID) signal(SIGQUIT,savquit);	/* (used in ckufio.c) */
2066 #ifdef SIGDANGER
2067     (VOID) signal(SIGDANGER,savdanger);
2068 #endif /* SIGDANGER */
2069 #ifdef SIGPIPE
2070     (VOID) signal(SIGPIPE,savpipe);
2071 #endif /* SIGPIPE */
2072     (VOID) signal(SIGUSR1,savusr1);
2073     (VOID) signal(SIGUSR2,savusr2);
2074 }
2075 
2076 int
sysinit()2077 sysinit() {
2078     int x;
2079     char * s;
2080 #ifdef CK_UTSNAME
2081     struct utsname name;
2082 #endif /* CK_UTSNAME */
2083 
2084     extern char startupdir[];
2085 /*
2086   BEFORE ANYTHING ELSE: Initialize the setuid package.
2087   Change to the user's real user and group ID.
2088   If this can't be done, don't run at all.
2089 */
2090     x = priv_ini();
2091 #ifdef SUIDDEBUG
2092     fprintf(stderr,"PRIV_INI=%d\n",x);
2093 #endif /* SUIDDEBUG */
2094     if (x) {
2095 	if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
2096 	if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
2097 	if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
2098 	exit(1);
2099     }
2100     signal(SIGINT,SIG_IGN);		/* Ignore interrupts at first */
2101     signal(SIGFPE,SIG_IGN);		/* Ignore floating-point exceptions */
2102     signal(SIGHUP,sighup);		/* Catch SIGHUP */
2103 #ifndef NOSIGWINCH
2104 #ifdef SIGWINCH
2105     signal(SIGWINCH,winchh);		/* Catch window-size change */
2106 #endif /* SIGWINCH */
2107 #endif /* NOSIGWINCH */
2108 
2109 #ifdef SIGXFSZ
2110     signal(SIGXFSZ,SIG_IGN);		/* Ignore writing past file limit */
2111 #endif	/* SIGXFSZ */
2112 
2113 #ifndef NOJC
2114 /*
2115   Get the initial job control state.
2116   If it is SIG_IGN, that means the shell does not support job control,
2117   and so we'd better not suspend ourselves.
2118 */
2119 #ifdef SIGTSTP
2120     jchdlr = signal(SIGTSTP,SIG_IGN);
2121     if (jchdlr == SIG_IGN) {
2122 	jcshell = 0;
2123 	debug(F100,"sysinit jchdlr: SIG_IGN","",0);
2124     } else if (jchdlr == SIG_DFL) {
2125 	debug(F100,"sysinit jchdlr: SIG_DFL","",0);
2126 	jcshell = 1;
2127     } else {
2128 	debug(F100,"sysinit jchdlr: other","",0);
2129 	jcshell = 3;
2130     }
2131     (VOID) signal(SIGTSTP,jchdlr);	/* Put it back... */
2132 #endif /* SIGTSTP */
2133 #endif /* NOJC */
2134 
2135     conbgt(0);				/* See if we're in the background */
2136     congm();				/* Get console modes */
2137 
2138     (VOID) signal(SIGALRM,SIG_IGN);	/* Ignore alarms */
2139 
2140     ignorsigs();			/* Ignore some other signals */
2141 
2142 #ifdef F_SETFL
2143     iniflags = fcntl(0,F_GETFL,0);	/* Get stdin flags */
2144 #endif /* F_SETFL */
2145 
2146 #ifdef ultrix
2147     gtty(0,&vanilla);			/* Get sgtty info */
2148 #else
2149 #ifdef AUX
2150     set42sig();				/* Don't ask! (hakanson@cs.orst.edu) */
2151 #endif /* AUX */
2152 #endif /* ultrix */
2153 /*
2154   Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
2155   never closes it.  If it is called often enough, we run out of file
2156   descriptors and subsequent open()'s of other devices or files can fail.
2157 */
2158     s = NULL;
2159 #ifndef MINIX
2160     if (isatty(0))			/* Name of controlling terminal */
2161       s = ttyname(0);
2162     else if (isatty(1))
2163       s = ttyname(1);
2164     else if (isatty(2))
2165       s = ttyname(2);
2166     debug(F110,"sysinit ttyname(0)",s,0);
2167 #endif /* MINIX */
2168 
2169 #ifdef BEOS
2170     if (!dftty)
2171       makestr(&dftty,s);
2172 #endif /* BEOS */
2173 
2174     if (s)
2175       ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
2176 #ifdef SVORPOSIX
2177 #ifndef ANDROID
2178     if (!cttnam[0])
2179       ctermid(cttnam);
2180 #endif /* ANDROID */
2181 #endif /* SVORPOSIX */
2182     if (!cttnam[0])
2183       ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
2184     debug(F110,"sysinit CTTNAM",CTTNAM,0);
2185     debug(F110,"sysinit cttnam",cttnam,0);
2186 
2187     ttgwsiz();				/* Get window (screen) dimensions. */
2188 
2189 #ifndef NOSYSCONF
2190 #ifdef _SC_OPEN_MAX
2191     ckmaxfiles = sysconf(_SC_OPEN_MAX);
2192 #endif /* _SC_OPEN_MAX */
2193 #endif /* NOSYSCONF */
2194 
2195 #ifdef Plan9
2196     if (!backgrd) {
2197     	consctlfd = open("/dev/consctl", O_WRONLY);
2198     	/*noisefd = open("/dev/noise", O_WRONLY)*/
2199     }
2200     ckxech = 1;
2201 #endif /* Plan9 */
2202 
2203 #ifdef CK_UTSNAME
2204     if (uname(&name) > -1) {
2205 	ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
2206 	ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
2207 	ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
2208 	ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
2209 #ifdef DEBUG
2210 	if (deblog) {
2211 	    debug(F110,"sysinit uname machine",unm_mch,0);
2212 	    debug(F110,"sysinit uname sysname",unm_nam,0);
2213 	    debug(F110,"sysinit uname release",unm_rel,0);
2214 	    debug(F110,"sysinit uname version",unm_ver,0);
2215 	}
2216 #endif /* DEBUG */
2217 
2218 #ifdef HPUX9PLUS
2219 	if (name.machine[5] == '8')
2220 	  hpis800 = 1;
2221 	else
2222 	  hpis800 = 0;
2223 	debug(F101,"sysinit hpis800","",hpis800);
2224 #endif /* HPUX9PLUS */
2225 #ifdef TRU64
2226         getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
2227         debug(F110,"sysinit getsysinfo model",unm_mod,0);
2228 #endif /* TRU64 */
2229 #ifdef SOLARIS25
2230         sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
2231         debug(F110,"sysinit sysinfo model",unm_mod,0);
2232 #endif /* SOLARIS25 */
2233     }
2234 #endif /* CK_UTSNAME */
2235 
2236 #ifdef CK_ENVIRONMENT
2237     {
2238 #ifdef TNCODE
2239 	extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
2240 	tn_env_prnt[], tn_env_sys[];
2241 #endif /* TNCODE */
2242 	extern char uidbuf[];
2243         extern char * whoami();
2244 	char *p;
2245 #ifdef CKSENDUID
2246         uidbuf[0] = '\0';
2247 #ifdef IKSD
2248         if (!inserver) {
2249 #endif /* IKSD */
2250             p = getenv("USER");
2251             debug(F110,"sysinit uidbuf from USER",uidbuf,0);
2252 	    if (!p) p = "";
2253             if (!*p) {
2254                 p = getenv("LOGNAME");
2255                 debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
2256             }
2257 	    if (!p) p = "";
2258             if (!*p) {
2259                 p = whoami();
2260                 debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
2261             }
2262 	    if (!p) p = "";
2263 	    ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
2264 #ifdef IKSD
2265         }
2266 #endif /* IKSD */
2267 	debug(F110,"sysinit final uidbuf",uidbuf,0);
2268 #endif /* CKSENDUID */
2269 
2270 #ifdef TNCODE
2271 	if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
2272 	if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
2273 	if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
2274 	if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
2275 #ifdef aegis
2276 	ckstrncpy(tn_env_sys,"Aegis",64);
2277 #else
2278 #ifdef Plan9
2279 	ckstrncpy(tn_env_sys,"Plan9",64);
2280 #else
2281 	ckstrncpy(tn_env_sys,"UNIX",64);
2282 #endif /* Plan9 */
2283 #endif /* aegis */
2284 #endif /* TNCODE */
2285     }
2286 #endif /* CK_ENVIRONMENT */
2287 #ifdef CK_SNDLOC
2288     {
2289 	extern char * tn_loc;
2290 	char *p;
2291 	if (p = getenv("LOCATION"))
2292 	  if (tn_loc = (char *)malloc((int)strlen(p)+1))
2293 	    strcpy(tn_loc,p);		/* safe */
2294     }
2295 #endif /* CK_SNDLOC */
2296 
2297     ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
2298     startupdir[CKMAXPATH] = '\0';
2299     x = strlen(startupdir);
2300     if (x <= 0) {
2301 	startupdir[0] = '/';
2302 	startupdir[1] = '\0';
2303     } else if (startupdir[x-1] != '/') {
2304 	startupdir[x] = '/';
2305 	startupdir[x+1] = '\0';
2306     }
2307     debug(F110,"sysinit startupdir",startupdir,0);
2308 #ifdef TTLEBUF
2309     le_init();
2310 #endif /* TTLEBUF */
2311 #ifdef BSD44ORPOSIX
2312     /* This should catch the ncurses platforms */
2313     /* Some platforms don't have putenv(), like NeXTSTEP */
2314     putenv("NCURSES_NO_SETBUF=1");
2315 #endif /* BSD44ORPOSIX */
2316     return(0);
2317 }
2318 
2319 /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
2320 
2321 int
syscleanup()2322 syscleanup() {
2323 #ifdef F_SETFL
2324     if (iniflags > -1)
2325       fcntl(0,F_SETFL,iniflags);	/* Restore stdin flags */
2326 #endif /* F_SETFL */
2327 #ifdef ultrix
2328     stty(0,&vanilla);                   /* Get sgtty info */
2329 #endif /* ultrix */
2330 #ifdef NETCMD
2331     if (ttpid) kill(ttpid,9);
2332 #endif /* NETCMD */
2333     return(0);
2334 }
2335 
2336 /*  T T O P E N  --  Open a tty for exclusive access.  */
2337 
2338 /*
2339   Call with:
2340     ttname: character string - device name or network host name.
2341     lcl:
2342   If called with lcl < 0, sets value of lcl as follows:
2343   0: the terminal named by ttname is the job's controlling terminal.
2344   1: the terminal named by ttname is not the job's controlling terminal.
2345   But watch out: if a line is already open, or if requested line can't
2346   be opened, then lcl remains (and is returned as) -1.
2347     modem:
2348   Less than zero: ttname is a network host name.
2349   Zero or greater: ttname is a terminal device name.
2350   Zero means a local connection (don't use modem signals).
2351   Positive means use modem signals.
2352    timo:
2353   0 = no timer.
2354   nonzero = number of seconds to wait for open() to return before timing out.
2355 
2356   Returns:
2357     0 on success
2358    -5 if device is in use
2359    -4 if access to device is denied
2360    -3 if access to lock directory denied
2361    -2 upon timeout waiting for device to open
2362    -1 on other error
2363 */
2364 static int ttotmo = 0;			/* Timeout flag */
2365 /* Flag kept here to avoid being clobbered by longjmp.  */
2366 
2367 int
ttopen(ttname,lcl,modem,timo)2368 ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
2369 
2370 #ifdef BSD44
2371 #define ctermid(x) strcpy(x,"")
2372 #else
2373 #ifdef SVORPOSIX
2374 #ifndef CIE
2375 #ifndef ANDROID
2376     extern char *ctermid();		/* Wish they all had this! */
2377 #endif /* ANDROID */
2378 #else					/* CIE Regulus */
2379 #define ctermid(x) strcpy(x,"")
2380 #endif /* CIE */
2381 #endif /* SVORPOSIX */
2382 #endif /* BSD44 */
2383 
2384 #ifdef ultrix
2385     int temp = 0;
2386 #endif /* ultrix */
2387 
2388 #ifndef OPENFIRST
2389     char fullname[DEVNAMLEN+1];
2390 #endif /* OPENFIRST */
2391 
2392     char * fnam;			/* Full name after expansion */
2393 
2394     int y;
2395 
2396 #ifndef pdp11
2397 #define NAMEFD	 /* Feature to allow name to be an open file descriptor */
2398 #endif /* pdp11 */
2399 
2400 #ifdef NAMEFD
2401     char *p;
2402     debug(F101,"ttopen telnetfd","",telnetfd);
2403 #endif /* NAMEFD */
2404 
2405     debug(F110,"ttopen ttname",ttname,0);
2406     debug(F110,"ttopen ttnmsv",ttnmsv,0);
2407     debug(F101,"ttopen modem","",modem);
2408     debug(F101,"ttopen netconn","",netconn);
2409     debug(F101,"ttopen ttyfd","",ttyfd);
2410     debug(F101,"ttopen *lcl","",*lcl);
2411     debug(F101,"ttopen ttmdm","",ttmdm);
2412     debug(F101,"ttopen ttnet","",ttnet);
2413 
2414     ttpmsk = 0xff;
2415     lockpid[0] = '\0';
2416 
2417     if (ttyfd > -1) {			/* If device already opened */
2418         if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
2419 	  return(0);			/* Yes, nothing to do - just return */
2420 	ttnmsv[0] = '\0';		/* No, clear out old name */
2421 	ttclos(ttyfd);			/* close old connection.  */
2422     }
2423     wasclosed = 0;			/* New connection, not closed yet. */
2424     ttpipe = 0;				/* Assume it's not a pipe */
2425     ttpty = 0;				/* or a pty... */
2426 
2427 #ifdef NETCONN
2428 /*
2429   This is a bit tricky...  Suppose that previously Kermit had dialed a telnet
2430   modem server ("set host xxx:2001, set modem type usr, dial ...").  Then the
2431   connection was closed (ttyfd = -1), and then a REDIAL command was given.  At
2432   this point we've obliterated the negative modem type hack, and so would
2433   treat the IP hostname as a device name, and would then fail because of "No
2434   such device or directory".  But the previous connection has left behind some
2435   clues, so let's use them...
2436 */
2437     if (ttyfd < 0) {			/* Connection is not open */
2438 	if (!strcmp(ttname,ttnmsv)) {	/* Old and new names the same? */
2439 	    if (((netconn > 0) && (ttmdm < 0)) ||
2440 		((ttnet > 0) &&
2441 		 (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
2442 		) {
2443 		int x, rc;
2444 		x = (ttmdm < 0) ? -ttmdm : ttnet;
2445 		rc = netopen(ttname, lcl, x);
2446 		debug(F111,"ttopen REOPEN netopen",ttname,rc);
2447 		if (rc > -1) {
2448 		    netconn = 1;
2449 		    xlocal = *lcl = 1;
2450 		} else {
2451 		    netconn = 0;
2452 		}
2453 		gotsigs = 0;
2454 		return(rc);
2455 	    }
2456 	}
2457     }
2458 #endif /* NETCONN */
2459 
2460 #ifdef MAXNAMLEN
2461     debug(F100,"ttopen MAXNAMLEN defined","",0);
2462 #else
2463     debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
2464 #endif
2465 
2466 #ifdef BSD4
2467     debug(F100,"ttopen BSD4 defined","",0);
2468 #else
2469     debug(F100,"ttopen BSD4 *NOT* defined","",0);
2470 #endif /* BSD4 */
2471 
2472 #ifdef BSD42
2473     debug(F100,"ttopen BSD42 defined","",0);
2474 #else
2475     debug(F100,"ttopen BSD42 *NOT* defined","",0);
2476 #endif /* BSD42 */
2477 
2478 #ifdef MYREAD
2479     debug(F100,"ttopen MYREAD defined","",0);
2480 #else
2481     debug(F100,"ttopen MYREAD *NOT* defined","",0);
2482 #endif /* MYREAD */
2483 
2484 #ifdef	NETCONN
2485     if (modem < 0) {			/* modem < 0 = code for network */
2486 	int x;
2487 	ttmdm = modem;
2488 	modem = -modem;			/* Positive network type number */
2489 	fdflag = 0;			/* Stdio not redirected. */
2490 	netconn = 1;			/* And it's a network connection */
2491 	debug(F111,"ttopen net",ttname,modem);
2492 #ifdef NAMEFD
2493 	for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
2494  	if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
2495 	    ttyfd = atoi(ttname);	/* Is there a way to test it's open? */
2496 	    ttfdflg = 1;		/* We got an open file descriptor */
2497 	    debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
2498 	    debug(F101,"ttopen net ttyfd","",ttyfd);
2499 	    ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2500 	    x = 1;			/* Return code is "good". */
2501 	    if (telnetfd) {
2502 		ttnet = NET_TCPB;
2503 		if (ttnproto != NP_TCPRAW)
2504 		  ttnproto = NP_TELNET;
2505 #ifdef SUNX25
2506 	    } else if (x25fd) {
2507 		ttnet = NET_SX25;
2508 		ttnproto = NP_NONE;
2509 #endif /* SUNX25 */
2510 	    }
2511 	} else {			/* Host name or address given */
2512 #ifdef NETPTY
2513 	    if (modem == NET_PTY) {
2514 		int x;
2515 		if (nopush) {
2516 		    debug(F100,"ttopen PTY: nopush","",0);
2517 		    return(-1);
2518 		}
2519                 ttnet = NET_PTY;
2520 		ttnproto = NP_NONE;
2521                 netconn = 1;            /* but we don't use network i/o */
2522                 ttpty = 1;
2523                 debug(F110,"ttopen PTY",ttname,0);
2524 		x = do_pty(&ttyfd,ttname,0);
2525 		if (x > -1) {
2526 		    ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2527 		    xlocal = *lcl = 1;	/* It's local */
2528 		} else {
2529 		    ttpty = 0;
2530 		    netconn = 0;
2531 		}
2532 		gotsigs = 0;
2533 		return(x);
2534 	    }
2535 #endif /* NETPTY */
2536 #ifdef NETCMD
2537 /*
2538   dup2() is not available on older System V platforms like AT&T 3Bx.  For
2539   those systems we punt by not defining NETCMD, but we might be able to do
2540   better -- see workarounds for this problem in ckufio.c (search for dup2).
2541 */
2542 	    if (modem == NET_CMD) {
2543 		if (nopush) {
2544 		    debug(F100,"ttopen pipe: nopush","",0);
2545 		    return(-1);
2546 		}
2547 		if (pipe(pipe0) || pipe(pipe1)) {
2548 		    perror("Pipe error");
2549 		    return(-1);
2550 		}
2551 		ttpid = fork();		/* Make a fork */
2552 
2553 		switch (ttpid) {
2554 		  case -1:		/* Error making fork */
2555 		    close(pipe0[0]);
2556 		    close(pipe0[1]);
2557 		    close(pipe1[0]);
2558 		    close(pipe1[1]);
2559 		    perror("Fork error");
2560 		    return(-1);
2561 		  case 0:		/* Child. */
2562 		    close(pipe0[0]);
2563 		    close(pipe1[1]);
2564 		    dup2(pipe0[1], 1);
2565 		    close(pipe0[1]);
2566 		    dup2(pipe1[0], 0);
2567 		    close(pipe1[0]);
2568 /*
2569   I can't image what this is; system() executes a shell command.
2570   ttname holds the name of terminal device, it's not a command.
2571   --fdc Fri Sep 18 15:51:18 2020
2572 		    system(ttname);
2573 */
2574 		    _exit(0);
2575 		  default:		/* Parent */
2576 		    close(pipe0[1]);
2577 		    close(pipe1[0]);
2578 		    fdin = pipe0[0];	/* Read from pipe */
2579 		    fdout = pipe1[1];	/* Write to pipe */
2580 		    ttout = fdopen(fdout,"w"); /* Get stream so we can */
2581 		    if (!ttout) {	/* make it unbuffered. */
2582 			perror("fdopen failure");
2583 			return(-1);
2584 		    }
2585 		    setbuf(ttout,NULL);
2586 		    ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2587 		    xlocal = *lcl = 1;	/* It's local */
2588 		    netconn = 1;	/* Call it a network connection */
2589 		    ttmdm = modem;	/* Remember network type */
2590 		    ttyfd = fdin;
2591 		    ttpipe = 1;
2592 		    gotsigs = 0;
2593 		    return(0);
2594 		}
2595 	    }
2596 #endif /* NETCMD */
2597 #endif /* NAMEFD */
2598 	    x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
2599 	    if (x > -1) {
2600 		ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2601 	    } else netconn = 0;
2602 #ifdef NAMEFD
2603 	}
2604 #endif /* NAMEFD */
2605 
2606 #ifdef sony_news			/* Sony NEWS */
2607 	if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
2608 	    perror("ttopen error getting Kanji mode (network)");
2609 	    debug(F111,"ttopen error getting Kanji mode","network",0);
2610 	    km_ext = -1;		/* Make sure this stays undefined. */
2611 	}
2612 #endif /* sony_news */
2613 
2614 	xlocal = *lcl = 1;		/* Network connections are local. */
2615 	debug(F101,"ttopen net x","",x);
2616 #ifdef COMMENT
2617 /* Let netopen() do this */
2618 	if (x > -1 && !x25fd)
2619 	  x = tn_ini();			/* Initialize TELNET protocol */
2620 #endif /* COMMENT */
2621 	gotsigs = 0;
2622 	return(x);
2623     } else {				/* Terminal device */
2624 #endif	/* NETCONN */
2625 
2626 #ifdef NAMEFD
2627 /*
2628   This code lets you give Kermit an open file descriptor for a serial
2629   communication device, rather than a device name.  Kermit assumes that the
2630   line is already open, locked, conditioned with the right parameters, etc.
2631 */
2632 	for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
2633 	if (*p == '\0') {
2634 	    ttyfd = atoi(ttname);	/* Is there a way to test it's open? */
2635 	    debug(F111,"ttopen got open fd",ttname,ttyfd);
2636 	    ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2637 	    if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
2638 	      xlocal = *lcl = 0;	/* we're in remote mode */
2639 	    else			/* otherwise */
2640 	      xlocal = *lcl = 1;	/* local mode. */
2641 	    netconn = 0;		/* Assume it's not a network. */
2642 	    tvtflg = 0;			/* Might need to initialize modes. */
2643 	    ttmdm = modem;		/* Remember modem type. */
2644 	    fdflag = 0;			/* Stdio not redirected. */
2645 	    ttfdflg = 1;		/* Flag we were opened this way. */
2646 	    debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
2647 	    debug(F101,"ttopen non-net ttyfd","",ttyfd);
2648 
2649 #ifdef sony_news			/* Sony NEWS */
2650 	    /* Get device Kanji mode */
2651 	    if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
2652 		perror("ttopen error getting Kanji mode");
2653 		debug(F101,"ttopen error getting Kanji mode","",0);
2654 		km_ext = -1;		/* Make sure this stays undefined. */
2655 	    }
2656 #endif /* sony_news */
2657 	    gotsigs = 0;
2658 	    return(0);			/* Return success */
2659 	}
2660 #endif /* NAMEFD */
2661 #ifdef NETCONN
2662     }
2663 #endif /* NETCONN */
2664 
2665 /* Here we have to open a serial device of the given name. */
2666 
2667     netconn = 0;			/* So it's not a network connection */
2668     occt = signal(SIGINT, cctrap);	/* Set Control-C trap, save old one */
2669     sigint_ign = 0;
2670 
2671     tvtflg = 0;			/* Flag for use by ttvt(). */
2672 				/* 0 = ttvt not called yet for this device */
2673 
2674     fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
2675     debug(F101,"ttopen fdflag","",fdflag);
2676 
2677     ttmdm = modem;                      /* Make this available to other fns */
2678     xlocal = *lcl;                      /* Make this available to other fns */
2679 
2680 /* Code for handling bidirectional tty lines goes here. */
2681 /* Use specified method for turning off logins and suppressing getty. */
2682 
2683 #ifdef ACUCNTRL
2684     /* Should put call to priv_on() here, but that would be very risky! */
2685     acucntrl("disable",ttname);         /* acucntrl() program. */
2686     /* and priv_off() here... */
2687 #else
2688 #ifdef ATT7300
2689     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
2690       attmodem |= offgetty(ttname);	/* Remember response.  */
2691 #endif /* ATT7300 */
2692 #endif /* ACUCNTRL */
2693 
2694 #ifdef OPENFIRST
2695 /*
2696  1985-2001: opens device first then gets lock; reason:
2697  Kermit usually has to run setuid or setgid in order to create a lockfile.
2698  If you give a SET LINE command for a device that happens to be your job's
2699  controlling terminal, Kermit doesn't have to create a lockfile, and in fact
2700  should not create one, and would fail if it tried to if it did not have the
2701  required privileges.  But you can't find out if two tty device names are
2702  equivalent until you have a file descriptor that you can give to ttyname().
2703  But this can cause a race condition between Kermit and [m]getty.  So see
2704  the [#]else part...
2705 */
2706 
2707 /*
2708  In the following section, we open the tty device for read/write.
2709  If a modem has been specified via "set modem" prior to "set line"
2710  then the O_NDELAY parameter is used in the open, provided this symbol
2711  is defined (e.g. in fcntl.h), so that the program does not hang waiting
2712  for carrier (which in most cases won't be present because a connection
2713  has not been dialed yet).  O_NDELAY is removed later on in ttopen().  It
2714  would make more sense to first determine if the line is local before
2715  doing this, but because ttyname() requires a file descriptor, we have
2716  to open it first.  See do_open().
2717 
2718  Now open the device using the desired treatment of carrier.
2719  If carrier is REQUIRED, then open could hang forever, so an optional
2720  timer is provided.  If carrier is not required, the timer should never
2721  go off, and should do no harm...
2722 */
2723     ttotmo = 0;				/* Flag no timeout */
2724     debug(F101,"ttopen timo","",timo);
2725     debug(F101,"ttopen xlocal","",xlocal);
2726     if (timo > 0) {
2727 	int xx;
2728 	saval = signal(SIGALRM,timerh);	/* Timed, set up timer. */
2729 	xx = alarm(timo);		/* Timed open() */
2730 	debug(F101,"ttopen alarm","",xx);
2731 	if (
2732 #ifdef CK_POSIX_SIG
2733 	    sigsetjmp(sjbuf,1)
2734 #else
2735 	    setjmp(sjbuf)
2736 #endif /* CK_POSIX_SIG */
2737 	    ) {
2738 	    ttotmo = 1;			/* Flag timeout. */
2739 	} else ttyfd = do_open(ttname);
2740 	ttimoff();
2741 	debug(F111,"ttopen","modem",modem);
2742 	debug(F101,"ttopen ttyfd","",ttyfd);
2743 	debug(F101,"ttopen alarm return","",ttotmo);
2744     } else {
2745 	errno = 0;
2746 	ttyfd = do_open(ttname);
2747     }
2748     debug(F111,"ttopen ttyfd",ttname,ttyfd);
2749     if (ttyfd < 0) {			/* If couldn't open, fail. */
2750 	debug(F101,"ttopen errno","",errno);
2751 	if (errno > 0 && !quiet)
2752 	  perror(ttname);		/* Print message */
2753 
2754 #ifdef ATT7300
2755 	if (attmodem & DOGETY)		/* was getty(1m) running before us? */
2756 	  ongetty(ttnmsv);		/* yes, restart on tty line */
2757 	attmodem &= ~DOGETY;		/* no phone in use, getty restored */
2758 #else
2759 #ifdef ACUCNTRL
2760         /* Should put call to priv_on() here, but that would be risky! */
2761 	acucntrl("enable",ttname);	/* acucntrl() program. */
2762 	/* and priv_off() here... */
2763 #endif /* ACUNTRL */
2764 #endif /* ATT7300 */
2765 
2766 	signal(SIGINT,occt);		/* Put old Ctrl-C trap back. */
2767 	if (errno == EACCES) {		/* Device is protected against user */
2768 	    debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
2769 	    return(-4);
2770 	} else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
2771     }
2772 
2773 #ifdef QNX
2774     {
2775 	extern int qnxportlock;
2776 	x = qnxopencount();
2777 	debug(F101,"ttopen qnxopencount","",x);
2778 	debug(F101,"ttopen qnxportlock","",qnxportlock);
2779 	if (x < 0 && qnxportlock) {
2780 	    ttclos(0);
2781 	    printf("?Can't get port open count\n");
2782 	    printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
2783 	    return(-1);			/* Indicate device is in use */
2784 	}
2785 	if (x > 1) {			/* 1 == me */
2786 	    if (qnxportlock)
2787 	      ttclos(0);
2788 	      return(-2);		/* Indicate device is in use */
2789 	    else if (!quiet)
2790 	      printf("WARNING: \"%s\" looks busy...\n",ttdev);
2791 	}
2792     }
2793 #endif /* QNX */
2794 
2795 #ifdef Plan9
2796     /* take this opportunity to open the control channel */
2797     if (p9openttyctl(ttname) < 0)
2798 #else
2799     /* Make sure it's a real tty. */
2800     if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
2801 #endif /* Plan9 */
2802       {
2803 	fprintf(stderr,"%s is not a terminal device\n",ttname);
2804 	debug(F111,"ttopen not a tty",ttname,errno);
2805 	close(ttyfd);
2806 	ttyfd = -1;
2807 	wasclosed = 1;
2808 	signal(SIGINT,occt);
2809 	return(-1);
2810     }
2811 
2812 #ifdef aegis
2813 	/* Apollo C runtime claims that console pads are tty devices, which
2814 	 * is reasonable, but they aren't any good for packet transfer. */
2815 	ios_$inq_type_uid((short)ttyfd, ttyuid, st);
2816 	if (st.all != status_$ok) {
2817 	    fprintf(stderr, "problem getting tty object type: ");
2818 	    error_$print(st);
2819 	} else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
2820 	    close(ttyfd); ttyfd = -1;
2821 	    wasclosed = 1;
2822 	    errno = ENOTTY; perror(ttname);
2823 	    signal(SIGINT,occt);
2824 	    return(-1);
2825 	}
2826 #endif /* aegis */
2827 
2828     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2829 
2830     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);	/* Keep copy of name locally. */
2831 
2832 /* Caller wants us to figure out if line is controlling tty */
2833 
2834     if (*lcl < 0) {
2835         if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
2836             xlocal = 0;
2837 	    debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
2838         } else if (strcmp(ttname,cttnam) == 0) {
2839             xlocal = 0;
2840 	    debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
2841 	} else if (cttnam[0]) {
2842 #ifdef BEBOX_DR7
2843             x = ttnmsv;			/* ttyname() is broken */
2844 #else
2845             x = ttyname(ttyfd);         /* Get real name of ttname. */
2846 #endif /* BEBOX_DR7 */
2847 	    if (!x) x = "";
2848 	    if (*x)
2849 	      xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
2850 	    else
2851 	      xlocal = 1;
2852             debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
2853         }
2854     }
2855 
2856 #ifndef NOFDZERO
2857 /* Note, the following code was added so that Unix "idle-line" snoopers */
2858 /* would not think Kermit was idle when it was transferring files, and */
2859 /* maybe log people out. */
2860     if (xlocal == 0) {			/* Remote mode */
2861 	if (fdflag == 0) {		/* Standard i/o is not redirected */
2862 	    debug(F100,"ttopen setting ttyfd = 0","",0);
2863 #ifdef LYNXOS
2864 	    /* On Lynx OS, fd 0 is open for read only. */
2865 	    dup2(ttyfd,0);
2866 #endif /* LYNXOS */
2867 	    close(ttyfd);		/* Use file descriptor 0 */
2868 	    ttyfd = 0;
2869 	} else {			/* Standard i/o is redirected */
2870 	    debug(F101,"ttopen stdio redirected","",ttyfd);
2871 	}
2872     }
2873 #endif /* NOFDZERO */
2874 
2875 /* Now check if line is locked -- if so fail, else lock for ourselves */
2876 /* Note: After having done this, don't forget to delete the lock if you */
2877 /* leave ttopen() with an error condition. */
2878 
2879     lkf = 0;                            /* Check lock */
2880     if (xlocal > 0) {
2881 	int xx; int xpid;
2882         if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
2883             debug(F111,"ttopen ttlock fails",ttname,xx);
2884 	    /* WARNING - This close() can hang if tty is an empty socket... */
2885             close(ttyfd);		/* Close the device. */
2886 	    ttyfd = -1;			/* Erase its file descriptor. */
2887 	    wasclosed = 1;
2888 	    signal(SIGINT,occt);	/* Put old SIGINT back. */
2889 	    sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2890 	    if (xx == -2) {		/* If lockfile says device in use, */
2891 #ifndef NOUUCP
2892 		debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2893 		xpid = ttrpid(flfnam);	/* Try to read pid from lockfile */
2894 		if (xpid > -1) {	/* If we got a pid */
2895                     if (!quiet)
2896 		      printf("Locked by process %d\n",xpid); /* tell them. */
2897 		    sprintf(lockpid,"%d",xpid);	/* Record it too */
2898 		    debug(F110,"ttopen lockpid",lockpid,0);
2899 		} else if (*flfnam) {
2900 		    extern char *DIRCMD;
2901 		    char *p = NULL;
2902 		    int x;
2903 		    x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2904 		    p = malloc(x);	/* Print a directory listing. */
2905 /*
2906   Note: priv_on() won't help here, because we do not pass privs along to
2907   to inferior processes, in this case ls.  So if the real user does not have
2908   directory-listing access to the lockfile directory, this will result in
2909   something like "not found".  That's why we try this only as a last resort.
2910 */
2911 		    if (p) {		/* If we got the space... */
2912 			ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2913 			zsyscmd(p);	/* Get listing. */
2914 			if (p) {	/* free the space */
2915 			    free(p);
2916 			    p = NULL;
2917 			}
2918 		    }
2919 		}
2920 #endif /* NOUUCP */
2921 		return(-5);		/* Code for device in use */
2922 	    } else return(-3);		/* Access denied */
2923         } else lkf = 1;
2924     }
2925 #else  /* OPENFIRST */
2926 
2927 /*
2928   27 Oct 2001: New simpler code that gets the lock first and then opens the
2929   device, which eliminates the race condition.  The downside is you can no
2930   longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
2931   terminal, without trying to create a lockfile, which fails if C-Kermit lacks
2932   privs, and if it succeeds, it has created a lockfile where it didn't create
2933   one before.
2934 */
2935     xlocal = *lcl;			/* Is the device my login terminal? */
2936     debug(F111,"ttopen xlocal","A",xlocal);
2937     fnam = ttname;
2938     if (strcmp(ttname,CTTNAM) && netconn == 0) {
2939 	if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
2940 	    if ((int)strlen(fullname) > 0)
2941 	      fnam = fullname;
2942 	}
2943     }
2944     debug(F110,"ttopen fnam",fnam,0);
2945     if (xlocal < 0) {
2946 	xlocal = (strcmp(fnam,CTTNAM) != 0);
2947     }
2948     debug(F111,"ttopen xlocal","B",xlocal);
2949 
2950     lkf = 0;                            /* No lock yet */
2951     if (xlocal > 0) {			/* If not... */
2952 	int xx; int xpid;
2953 	xx = ttlock(fnam);		/* Try to lock it. */
2954 	debug(F101,"ttopen ttlock","",xx);
2955         if (xx < 0) {			/* Can't lock it. */
2956             debug(F111,"ttopen ttlock fails",fnam,xx);
2957 	    if (xx == -2) {		/* If lockfile says device in use, */
2958 #ifndef NOUUCP
2959 		debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2960 		xpid = ttrpid(flfnam);	/* Try to read pid from lockfile */
2961 		if (xpid > -1) {	/* If we got a pid */
2962                     if (!quiet)
2963 		      printf("Locked by process %d\n",xpid); /* tell them. */
2964 		    ckstrncpy(lockpid,ckitoa(xpid),16);
2965 		    debug(F110,"ttopen lockpid",lockpid,0);
2966 #ifndef NOPUSH
2967 		} else if (flfnam[0] && !nopush) {
2968 		    extern char *DIRCMD;
2969 		    char *p = NULL;
2970 		    int x;
2971 		    x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2972 		    p = malloc(x);	/* Print a directory listing. */
2973 /*
2974   Note: priv_on() won't help here, because we do not pass privs along to
2975   to inferior processes, in this case ls.  So if the real user does not have
2976   directory-listing access to the lockfile directory, this will result in
2977   something like "not found".  That's why we try this only as a last resort.
2978 */
2979 		    if (p) {		/* If we got the space... */
2980 			ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2981 			zsyscmd(p);	/* Get listing. */
2982 			if (p) {	/* free the space */
2983 			    free(p);
2984 			    p = NULL;
2985 			}
2986 		    }
2987 #endif /* NOPUSH */
2988 		}
2989 #endif /* NOUUCP */
2990 		return(-5);		/* Code for device in use */
2991 	    } else return(-3);		/* Access denied */
2992         } else lkf = 1;
2993     }
2994     /* Have lock -- now it's safe to open the device */
2995 
2996     debug(F101,"ttopen lkf","",lkf);
2997     debug(F101,"ttopen timo","",timo);
2998 
2999     ttotmo = 0;				/* Flag no timeout */
3000     if (timo > 0) {
3001 	int xx;
3002 	saval = signal(SIGALRM,timerh);	/* Timed, set up timer. */
3003 	xx = alarm(timo);		/* Timed open() */
3004 	debug(F101,"ttopen alarm","",xx);
3005 	if (
3006 #ifdef CK_POSIX_SIG
3007 	    sigsetjmp(sjbuf,1)
3008 #else
3009 	    setjmp(sjbuf)
3010 #endif /* CK_POSIX_SIG */
3011 	    ) {
3012 	    ttotmo = 1;			/* Flag timeout. */
3013 	} else {
3014 	    ttyfd = do_open(fnam);
3015 	}
3016 	ttimoff();
3017 	debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
3018     } else {
3019 	errno = 0;
3020 	ttyfd = do_open(fnam);
3021 	debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
3022     }
3023     if (ttyfd < 0) {			/* If couldn't open, fail. */
3024 	debug(F111,"ttopen errno",fnam,errno);
3025 	debug(F111,"ttopen xlocal","C",xlocal);
3026 	if (xlocal == 0) {
3027 	    debug(F100,"ttopen substituting 0","",0);
3028 	    ttyfd = 0;
3029 	} else {
3030 	    if (errno > 0 && !quiet) {
3031 	        debug(F111,"ttopen perror",fnam,errno);
3032 		perror(fnam);		/* Print message */
3033 	    }
3034 	    if (ttunlck())                  /* Release the lock file */
3035 	      fprintf(stderr,"Warning, problem releasing lock\r\n");
3036 	}
3037     }
3038 
3039     if (ttyfd < 0) {			/* ttyfd is still < 0? */
3040 #ifdef ATT7300
3041 	if (attmodem & DOGETY)		/* was getty(1m) running before us? */
3042 	  ongetty(ttnmsv);		/* yes, restart on tty line */
3043 	attmodem &= ~DOGETY;		/* no phone in use, getty restored */
3044 #else
3045 #ifdef ACUCNTRL
3046         /* Should put call to priv_on() here, but that would be risky! */
3047 	acucntrl("enable",fnam);	/* acucntrl() program. */
3048 	/* and priv_off() here... */
3049 #endif /* ACUNTRL */
3050 #endif /* ATT7300 */
3051 
3052 	signal(SIGINT,occt);		/* Put old Ctrl-C trap back. */
3053 	if (errno == EACCES) {		/* Device is protected against user */
3054 	    debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
3055 	    return(-4);
3056 	} else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
3057     }
3058 
3059 /* Make sure it's a real tty. */
3060 
3061 #ifdef Plan9
3062     /* take this opportunity to open the control channel */
3063     if (p9openttyctl(fnam) < 0)
3064 #else
3065       if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
3066 #endif /* Plan9 */
3067 	{
3068 	    fprintf(stderr,"%s is not a terminal device\n",fnam);
3069 	    debug(F111,"ttopen not a tty",fnam,errno);
3070 	    if (ttunlck())		/* Release the lock file */
3071 	      fprintf(stderr,"Warning, problem releasing lock\r\n");
3072 	    close(ttyfd);
3073 	    ttyfd = -1;
3074 	    wasclosed = 1;
3075 	    signal(SIGINT,occt);
3076 	    return(-1);
3077 	}
3078 
3079 #ifdef aegis
3080     /*
3081       Apollo C runtime claims that console pads are tty devices, which
3082       is reasonable, but they aren't any good for packet transfer.
3083     */
3084     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
3085     if (st.all != status_$ok) {
3086 	fprintf(stderr, "problem getting tty object type: ");
3087 	error_$print(st);
3088     } else if (ttyuid != sio_$uid) {	/* Reject non-SIO lines */
3089 	close(ttyfd); ttyfd = -1;
3090 	wasclosed = 1;
3091 	errno = ENOTTY; perror(fnam);
3092 	signal(SIGINT,occt);
3093 	return(-1);
3094     }
3095 #endif /* aegis */
3096 
3097     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3098 
3099     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);	/* Keep copy of name locally. */
3100 
3101 /* Caller wants us to figure out if line is controlling tty */
3102 
3103     if (*lcl < 0) {
3104 	char * s;
3105         if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
3106             xlocal = 0;
3107 	    debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
3108         } else if (strcmp(fnam,cttnam) == 0) {
3109             xlocal = 0;
3110 	    debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
3111 	} else if (cttnam[0]) {
3112 #ifdef BEBOX_DR7
3113             s = ttnmsv;			/* ttyname() is broken */
3114 #else
3115             s = ttyname(ttyfd);         /* Get real name of ttname. */
3116 #endif /* BEBOX_DR7 */
3117 	    if (!s) s = "";
3118 	    if (*s)
3119 	      xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
3120 	    else
3121 	      xlocal = 1;
3122             debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
3123         }
3124     }
3125 
3126 #ifndef NOFDZERO
3127 /* Note, the following code was added so that Unix "idle-line" snoopers */
3128 /* would not think Kermit was idle when it was transferring files, and */
3129 /* maybe log people out. */
3130     if (xlocal == 0) {			/* Remote mode */
3131 	if (fdflag == 0) {		/* Standard i/o is not redirected */
3132 	    debug(F100,"ttopen setting ttyfd = 0","",0);
3133 #ifdef LYNXOS
3134 	    /* On Lynx OS, fd 0 is open for read only. */
3135 	    dup2(ttyfd,0);
3136 #endif /* LYNXOS */
3137 	    close(ttyfd);		/* Use file descriptor 0 */
3138 	    ttyfd = 0;
3139 	} else {			/* Standard i/o is redirected */
3140 	    debug(F101,"ttopen stdio redirected","",ttyfd);
3141 	}
3142     }
3143 #endif /* NOFDZERO */
3144 #endif /* OPENFIRST */
3145 
3146 /* Got the line, now set the desired value for local. */
3147 
3148     if (*lcl != 0) *lcl = xlocal;
3149 
3150 /* Some special stuff for v7... */
3151 
3152 #ifdef  V7
3153 #ifndef MINIX
3154     if (kmem[TTY] < 0) {		/*  If open, then skip this.  */
3155 	qaddr[TTY] = initrawq(ttyfd);   /* Init the queue. */
3156 	if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
3157 	    fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
3158 	    perror("/dev/kmem");
3159 	    exit(1);
3160 	}
3161     }
3162 #endif /* !MINIX */
3163 #endif /* V7 */
3164 
3165 /* No failure returns after this point */
3166 
3167 #ifdef ultrix
3168     ioctl(ttyfd, TIOCMODEM, &temp);
3169 #ifdef TIOCSINUSE
3170     if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
3171 	if (!quiet)
3172 	  perror(fnam);
3173     }
3174 #endif /* TIOCSINUSE */
3175 #endif /* ultrix */
3176 
3177 /* Get tty device settings  */
3178 
3179 #ifdef BSD44ORPOSIX			/* POSIX */
3180     tcgetattr(ttyfd,&ttold);
3181     debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
3182     tcgetattr(ttyfd,&ttraw);
3183     debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
3184     tcgetattr(ttyfd,&tttvt);
3185     debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
3186 #else					/* BSD, V7, and all others */
3187 #ifdef ATTSV				/* AT&T UNIX */
3188     ioctl(ttyfd,TCGETA,&ttold);
3189     debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
3190     ioctl(ttyfd,TCGETA,&ttraw);
3191     ioctl(ttyfd,TCGETA,&tttvt);
3192 #else
3193 #ifdef BELLV10
3194     ioctl(ttyfd,TIOCGETP,&ttold);
3195     debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
3196     ioctl(ttyfd,TIOCGDEV,&tdold);
3197     debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
3198 #else
3199     gtty(ttyfd,&ttold);
3200     debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
3201 #endif /* BELLV10 */
3202 
3203 #ifdef sony_news			/* Sony NEWS */
3204     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
3205 	perror("ttopen error getting Kanji mode");
3206 	debug(F101,"ttopen error getting Kanji mode","",0);
3207 	km_ext = -1;			/* Make sure this stays undefined. */
3208     }
3209 #endif /* sony_news */
3210 
3211 #ifdef TIOCGETC
3212     debug(F100,"ttopen TIOCGETC","",0);
3213     tcharf = 0;				/* In remote mode, also get */
3214     if (xlocal == 0) {			/* special characters */
3215 	if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
3216 	    debug(F100,"ttopen TIOCGETC failed","",0);
3217 	} else {
3218 	    tcharf = 1;			/* It worked. */
3219 	    ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
3220 	    debug(F100,"ttopen TIOCGETC ok","",0);
3221 	}
3222     }
3223 #else
3224     debug(F100,"ttopen TIOCGETC not defined","",0);
3225 #endif /* TIOCGETC */
3226 
3227 #ifdef TIOCGLTC
3228     debug(F100,"ttopen TIOCGLTC","",0);
3229     ltcharf = 0;			/* In remote mode, also get */
3230     if (xlocal == 0) {			/* local special characters */
3231 	if (ioctl(ttyfd,TIOCGLTC,&ltchold) < 0) {
3232 	    debug(F100,"ttopen TIOCGLTC failed","",0);
3233 	} else {
3234 	    ltcharf = 1;		/* It worked. */
3235 	    ioctl(ttyfd,TIOCGLTC,&ltchnoi); /* Get another copy */
3236 	    debug(F100,"ttopen TIOCGLTC ok","",0);
3237 	}
3238     }
3239 #else
3240     debug(F100,"ttopen TIOCGLTC not defined","",0);
3241 #endif /* TIOCGLTC */
3242 
3243 #ifdef TIOCLGET
3244     debug(F100,"ttopen TIOCLGET","",0);
3245     lmodef = 0;
3246     if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
3247 	debug(F100,"ttopen TIOCLGET failed","",0);
3248     } else {
3249 	lmodef = 1;
3250 	debug(F100,"ttopen TIOCLGET ok","",0);
3251     }
3252 #endif /* TIOCLGET */
3253 
3254 #ifdef BELLV10
3255     ioctl(ttyfd,TIOCGETP,&ttraw);
3256     ioctl(ttyfd,TIOCGETP,&tttvt);
3257 #else
3258     gtty(ttyfd,&ttraw);                 /* And a copy of it for packets*/
3259     gtty(ttyfd,&tttvt);                 /* And one for virtual tty service */
3260 #endif /* BELLV10 */
3261 
3262 #endif /* ATTSV */
3263 #endif /* BSD44ORPOSIX */
3264 
3265 /* Section for changing line discipline.  It's restored in ttres(). */
3266 
3267 #ifdef AIXRS
3268 #ifndef AIX41
3269     { union txname ld_name; int ld_idx = 0;
3270       ttld = 0;
3271         do {
3272   	  ld_name.tx_which = ld_idx++;
3273   	  ioctl(ttyfd, TXGETCD, &ld_name);
3274 	  if (!strncmp(ld_name.tx_name, "rts", 3))
3275   	    ttld |= 1;
3276         } while (*ld_name.tx_name);
3277         debug(F101,"AIX line discipline","",ttld);
3278       }
3279 #endif /* AIX41 */
3280 #endif /* AIXRS */
3281 
3282 #ifdef BSD41
3283 /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
3284     { int k;
3285       ioctl(ttyfd, TIOCGETD, &ttld);	/* Get and save line discipline */
3286       debug(F101,"4.1bsd line discipline","",ttld);
3287       k = OTTYDISC;			/* Switch to "old" discipline */
3288       k = ioctl(ttyfd, TIOCSETD, &k);
3289       debug(F101,"4.1bsd tiocsetd","",k);
3290     }
3291 #endif /* BSD41 */
3292 
3293 #ifdef aegis
3294     /* This was previously done before the last two TCGETA or gtty above,
3295      * in both the ATTSV and not-ATTSV case.  If it is not okay to have only
3296      * one copy if it here instead, give us a shout!
3297      */
3298     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
3299     if (xlocal) {       /* ignore breaks from local line */
3300         sio_$control((short)ttyfd, sio_$int_enable, false, st);
3301         sio_$control((short)ttyfd, sio_$quit_enable, false, st);
3302     }
3303 #endif /* aegis */
3304 
3305 #ifdef VXVE
3306     ttraw.c_line = 0;                   /* STTY line 0 for VX/VE */
3307     tttvt.c_line = 0;                   /* STTY line 0 for VX/VE */
3308     ioctl(ttyfd,TCSETA,&ttraw);
3309 #endif /* vxve */
3310 
3311 /* If O_NDELAY was used during open(), then remove it now. */
3312 
3313 #ifdef O_NDELAY
3314     debug(F100,"ttopen O_NDELAY","",0);
3315     if (xlocal > 0) {
3316       if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
3317 	debug(F100,"ttopen fcntl O_NDELAY","",0);
3318 #ifndef aegis
3319 	if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
3320 	    debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
3321 	    perror("Can't unset O_NDELAY");
3322 	}
3323 #endif /* aegis */
3324 	/* Some systems, notably Xenix (don't know how common this is in
3325 	 * other systems), need special treatment to get rid of the O_NDELAY
3326 	 * behaviour on read() with respect to carrier presence (i.e. read()
3327 	 * returning 0 when carrier absent), even though the above fcntl()
3328 	 * is enough to make read() wait for input when carrier is present.
3329 	 * This magic, in turn, requires CLOCAL for working when the carrier
3330 	 * is absent. But if xlocal == 0, presumably you already have CLOCAL
3331 	 * or you have a carrier, otherwise you wouldn't be running this.
3332 	 */
3333 	debug(F101,"ttopen xlocal","",xlocal);
3334 #ifdef ATTSV
3335 #ifdef BSD44ORPOSIX
3336 #ifdef COMMENT				/* 12 Aug 1997 */
3337 #ifdef __bsdi__
3338 	if (xlocal)
3339 	  ttraw.c_cflag |= CLOCAL;
3340 #else
3341 #ifdef __FreeBSD__
3342 	if (xlocal)
3343 	  ttraw.c_cflag |= CLOCAL;
3344 #endif /* __FreeBSD__ */
3345 #endif /* __bsdi__ */
3346 #else /* Not COMMENT */
3347 #ifdef CLOCAL
3348 	if (xlocal)			/* Unset this if it's defined. */
3349 	  ttraw.c_cflag |= CLOCAL;
3350 #endif /* CLOCAL */
3351 #endif /* COMMENT */
3352 	debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
3353 	if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
3354 	    debug(F100,"ttopen POSIX tcseattr fails","",0);
3355 	    perror("tcsetattr");
3356 	}
3357 #else /* !BSD44ORPOSIX */
3358 	if (xlocal) {
3359 	    ttraw.c_cflag |= CLOCAL;
3360 	    debug(F100,"ttopen calling ioctl(TCSETA)","",0);
3361 	    errno = 0;
3362 	    if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
3363                 debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
3364                 perror("ioctl(TCSETA)");
3365             }
3366 	}
3367 #endif /* BSD44ORPOSIX */
3368 #endif /* ATTSV */
3369 #ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
3370 /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
3371 	debug(F100,"ttopen executing close/open","",0);
3372 	close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
3373 #endif /* NOCOTFMC */
3374       }
3375     }
3376 #endif /* O_NDELAY */
3377 
3378 /* Instruct the system how to treat the carrier, and set a few other tty
3379  * parameters.
3380  *
3381  * This also undoes the temporary setting of CLOCAL that may have been done
3382  * for the close(open()) above (except in Xenix).  Also throw in ~ECHO, to
3383  * prevent the other end of the line from sitting there talking to itself,
3384  * producing garbage when the user performs a connect.
3385  *
3386  * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
3387  * Now it thinks CLOCAL is always on. It seems the only real solution for
3388  * Xenix is to switch between the lower and upper case device names.
3389  *
3390  * This section may at some future time expand into setting a complete
3391  * collection of tty parameters, or call a function shared with ttpkt()/
3392  * ttvt() that does so.  On the other hand, the initial parameters are not
3393  * that important, since ttpkt() or ttvt() should always fix that before
3394  * any communication is done.  Well, we'll see...
3395  */
3396     if (xlocal) {
3397     	curcarr = -2;
3398 	debug(F100,"ttopen calling carrctl","",0);
3399 	carrctl(&ttraw, ttcarr == CAR_ON);
3400 	debug(F100,"ttopen carrctl ok","",0);
3401 
3402 #ifdef COHERENT
3403 #define SVORPOSIX
3404 #endif /* COHERENT */
3405 
3406 #ifdef SVORPOSIX
3407 	ttraw.c_lflag &= ~ECHO;
3408 	ttold.c_lflag &= ~ECHO;
3409 #ifdef BSD44ORPOSIX
3410 	y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
3411 	debug(F101,"ttopen tcsetattr","",y);
3412 #else
3413 	y = ioctl(ttyfd, TCSETA, &ttraw);
3414 	debug(F100,"ttopen ioctl","",y);
3415 #endif /* BSD44ORPOSIX */
3416 
3417 #else /* BSD, etc */
3418 	ttraw.sg_flags &= ~ECHO;
3419 	ttold.sg_flags &= ~ECHO;
3420 #ifdef BELLV10
3421 	y = ioctl(ttyfd,TIOCSETP,&ttraw);
3422 	debug(F100,"ttopen ioctl","",y);
3423 #else
3424 	y = stty(ttyfd,&ttraw);
3425 	debug(F100,"ttopen stty","",y);
3426 #endif /* BELLV10 */
3427 #endif /* SVORPOSIX */
3428 
3429 #ifdef COHERENT
3430 #undef SVORPOSIX
3431 #endif /* COHERENT */
3432 
3433 	/* ttflui(); */  /*  This fails for some reason.  */
3434     }
3435 
3436     /* Get current speed */
3437 
3438 #ifndef BEBOX
3439     ttspeed = ttgspd();
3440 #else
3441     ttspeed = 19200;
3442 #endif /* !BEBOX */
3443     debug(F101,"ttopen ttspeed","",ttspeed);
3444 
3445     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
3446 
3447     debug(F101,"ttopen ttyfd","",ttyfd);
3448     debug(F101,"ttopen *lcl","",*lcl);
3449     debug(F111,"ttopen lock file",flfnam,lkf);
3450     signal(SIGINT,occt);
3451     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3452     gotsigs = 0;
3453     return(0);
3454 }
3455 
3456 
3457 /*  D O _ O P E N  --  Do the right kind of open() call for the tty. */
3458 
3459 int
do_open(ttname)3460 do_open(ttname) char *ttname; {
3461     int flags;
3462 
3463 #ifdef QNX6
3464     /* O_NONBLOCK on /dev/tty makes open() fail */
3465     return(priv_opn(ttname, O_RDWR |
3466 		    (
3467 		     ((int)strcmp(ttname,"/dev/tty") == 0) ?
3468 		     0 :
3469 		     (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
3470 		    )
3471 	   );
3472 #else  /* !QNX6 */
3473 
3474 #ifndef	O_NDELAY			/* O_NDELAY not defined */
3475     return(priv_opn(ttname,2));
3476 #else					/* O_NDELAY defined */
3477 
3478 #ifdef ATT7300
3479 /*
3480  Open comms line without waiting for carrier so initial call does not hang
3481  because state of "modem" is likely unknown at the initial call  -jrd.
3482  If this is needed for the getty stuff to work, and the open would not work
3483  without O_NDELAY when getty is still on, then this special case is ok.
3484  Otherwise, get rid of it. -ske
3485 */
3486     return(priv_opn(ttname, O_RDWR | O_NDELAY));
3487 
3488 #else	/* !ATT7300 */
3489 
3490     /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
3491     flags = O_RDWR;
3492     debug(F101,"do_open xlocal","",xlocal);
3493     debug(F111,"do_open flags A",ttname,flags);
3494     if (xlocal && (ttcarr != CAR_ON))
3495       flags |= O_NDELAY;
3496     debug(F111,"do_open flags B",ttname,flags);
3497     return(priv_opn(ttname, flags));
3498 #endif /* !ATT7300 */
3499 #endif /* O_NDELAY */
3500 #endif /* QNX6 */
3501 }
3502 
3503 /*  T T C L O S  --  Close the TTY, releasing any lock.  */
3504 
3505 static int ttc_state = 0;		/* ttclose() state */
3506 static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
3507 
3508 int
ttclos(foo)3509 ttclos(foo) int foo; {			/* Arg req'd for signal() prototype */
3510     int xx, x = 0;
3511     extern int exithangup;
3512 
3513     debug(F101,"ttclos ttyfd","",ttyfd);
3514     debug(F101,"ttclos netconn","",netconn);
3515     debug(F101,"ttclos xlocal","",xlocal);
3516 #ifdef NOFDZERO
3517     debug(F100,"ttclos NOFDZERO","",0);
3518 #endif /* NOFDZERO */
3519 
3520 #ifdef COMMENT
3521 #ifdef TTLEBUF
3522     le_init();				/* No need for any of this */
3523 #endif /* TTLEBUF */
3524 #endif /* COMMENT */
3525 
3526     if (ttyfd < 0)			/* Wasn't open. */
3527       return(0);
3528 
3529     if (ttfdflg)			/* If we inherited ttyfd from */
3530       return(0);			/* another process, don't close it. */
3531 
3532     tvtflg = 0;				/* (some day get rid of this...) */
3533     gotsigs = 0;
3534 
3535 #ifdef IKSD
3536     if (inserver) {
3537 #ifdef TNCODE
3538           tn_push();                    /* Place any waiting data into input*/
3539           tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
3540           TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
3541           tn_reset();                   /* The Reset Telnet Option table.  */
3542 #endif /* TNCODE */
3543 #ifdef CK_SSL
3544 	  if (ssl_active_flag) {
3545 	      if (ssl_debug_flag)
3546 		BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
3547 	      SSL_shutdown(ssl_con);
3548 	      SSL_free(ssl_con);
3549 	      ssl_con = NULL;
3550 	      ssl_active_flag = 0;
3551 	  }
3552 	  if (tls_active_flag) {
3553 	      if (ssl_debug_flag)
3554 		BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
3555 	      SSL_shutdown(tls_con);
3556 	      SSL_free(tls_con);
3557 	      tls_con = NULL;
3558 	      tls_active_flag = 0;
3559 	  }
3560 #endif /* CK_SSL */
3561     }
3562 #endif /* IKSD */
3563 #ifdef NETCMD
3564     if (ttpipe) {			/* We've been using a pipe */
3565 	/* ttpipe = 0; */
3566 	if (ttpid > 0) {
3567 	    int wstat;
3568 	    int statusp;
3569 	    close(fdin);		/* Close these. */
3570 	    close(fdout);
3571 	    fdin = fdout = -1;
3572 	    kill(ttpid,1);		/* Kill fork with SIGHUP */
3573 	    while (1) {
3574 		wstat = wait(&statusp);
3575 		if (wstat == ttpid || wstat == -1)
3576 		  break;
3577 		pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
3578 	    }
3579 	    ttpid = 0;
3580 	}
3581 	netconn = 0;
3582 	wasclosed = 1;
3583 	ttyfd = -1;
3584 	return(0);
3585     }
3586 #endif /* NETCMD */
3587 #ifdef NETPTY
3588     if (ttpty) {
3589 #ifndef NODOPTY
3590         end_pty();
3591 #endif /* NODOPTY */
3592         close(ttyfd);
3593 	netconn = 0;
3594 	wasclosed = 1;
3595         ttpty = 0;
3596         ttyfd = -1;
3597         return(0);
3598     }
3599 #endif /* NETPTY */
3600 
3601 #ifdef	NETCONN
3602     if (netconn) {			/* If it's a network connection. */
3603 	debug(F100,"ttclos closing net","",0);
3604 	netclos();			/* Let the network module close it. */
3605 	netconn = 0;			/* No more network connection. */
3606 	debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
3607 	return(0);
3608     }
3609 #endif	/* NETCONN */
3610 
3611     if (xlocal) {			/* We're closing a SET LINE device */
3612 #ifdef FT21				/* Fortune 2.1-specific items ... */
3613 	ioctl(ttyfd,TIOCHPCL, NULL);
3614 #endif /* FT21 */
3615 #ifdef ultrix				/* Ultrix-specific items ... */
3616 #ifdef TIOCSINUSE
3617 	/* Unset the INUSE flag that we set in ttopen() */
3618 	ioctl(ttyfd, TIOCSINUSE, NULL);
3619 #endif /* TIOCSINUSE */
3620 	ioctl(ttyfd, TIOCNMODEM, &x);
3621 #ifdef COMMENT
3622 	/* What was this? */
3623 	ioctl(ttyfd, TIOCNCAR, NULL);
3624 #endif /* COMMENT */
3625 #endif /* ultrix */
3626     }
3627 
3628     /* This is to prevent us from sticking in tthang() or close(). */
3629 
3630 #ifdef O_NDELAY
3631 #ifndef aegis
3632     if (ttyfd > 0) {			/* But skip it on stdin. */
3633 	debug(F100,"ttclos setting O_NDELAY","",0);
3634 	x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
3635 #ifdef DEBUG
3636 	if (deblog && x == -1) {
3637 	    perror("Warning - Can't set O_NDELAY");
3638 	    debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
3639 	}
3640 #endif /* DEBUG */
3641     }
3642 #endif /* aegis */
3643 #endif /* O_NDELAY */
3644 
3645     x = 0;
3646     ttc_state = 0;
3647     if (xlocal
3648 #ifdef NOFDZERO
3649 	|| ttyfd > 0
3650 #endif /* NOFDZERO */
3651 	) {
3652 	saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
3653 	xx = alarm(8);			/* Allow 8 seconds. */
3654 	debug(F101,"ttclos alarm","",xx);
3655 	if (
3656 #ifdef CK_POSIX_SIG
3657 	    sigsetjmp(sjbuf,1)
3658 #else
3659 	    setjmp(sjbuf)
3660 #endif /* CK_POSIX_SIG */
3661 	    ) {				/* Timer went off? */
3662 	    x = -1;
3663 #ifdef DEBUG
3664 	    debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
3665 	    printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
3666 #endif /* DEBUG */
3667 	}
3668 	/* Hang up the device (drop DTR) */
3669 
3670 	errno = 0;
3671 	debug(F111,"ttclos A",ckitoa(x),ttc_state);
3672 	if (ttc_state < 1) {
3673 	    ttc_state = 1;
3674 	    debug(F101,"ttclos exithangup","",exithangup);
3675 	    if (exithangup) {
3676 		alarm(8);		/* Re-arm the timer */
3677 		debug(F101,"ttclos calling tthang()","",x);
3678 		x = tthang();		/* Hang up first, then... */
3679 		debug(F101,"ttclos tthang()","",x);
3680 	    }
3681 #ifndef CK_NOHUPCL
3682 /*
3683   Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF.
3684   Suggested by Soewono Effendi.
3685 */
3686 #ifdef HUPCL
3687 	    else {
3688 		ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */
3689 #ifdef BSD44ORPOSIX
3690 		tcsetattr(ttyfd,TCSANOW,&ttold);
3691 #else /* !BSD44ORPOSIX */
3692 #ifdef ATTSV
3693 		ioctl(ttyfd,TCSETAW,&ttold);
3694 #else  /* !ATTSV */
3695 		stty(ttyfd,&ttold);
3696 #endif	/* ATTSV */
3697 #endif	/* BSD44ORPOSIX */
3698 	    }
3699 #endif	/* HUPCL */
3700 #endif	/* CK_NOHUPCL */
3701 	}
3702 	/* Put back device modes as we found them */
3703 
3704 	errno = 0;
3705 	debug(F111,"ttclos B",ckitoa(x),ttc_state);
3706 	if (ttc_state < 2) {
3707 	    ttc_state = 2;
3708 	    /* Don't try to mess with tty modes if tthang failed() */
3709 	    /* since it probably won't work. */
3710 	    if (x > -1) {
3711 		debug(F101,"ttclos calling ttres()","",x);
3712 		signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
3713 		alarm(8);		/* Re-arm the timer */
3714 		x = ttres();		/* Reset device modes. */
3715 		debug(F101,"ttclos ttres()","",x);
3716 		alarm(0);
3717 	    }
3718 	}
3719 	/* Close the device */
3720 
3721 	errno = 0;
3722 	debug(F101,"ttclos C","",ttc_state);
3723 	if (ttc_state < 3) {
3724 	    ttc_state = 3;
3725 	    errno = 0;
3726 	    debug(F101,"ttclos calling close","",x);
3727 	    signal(SIGALRM,xtimerh);	/* Re-enable alarm. */
3728 	    alarm(8);			/* Re-arm the timer */
3729 	    x = close(ttyfd);		/* Close the device. */
3730 	    debug(F101,"ttclos close()","",x);
3731 	    if (x > -1)
3732 	      ttc_state = 3;
3733 	}
3734 	debug(F101,"ttclos D","",ttc_state);
3735 	ttimoff();			/* Turn off timer. */
3736 	if (x < 0) {
3737 	    printf("?WARNING - close failed: %s\n",ttnmsv);
3738 #ifdef DEBUG
3739 	    if (deblog) {
3740 		printf("errno = %d\n", errno);
3741 		debug(F101,"ttclos failed","",errno);
3742 	    }
3743 #endif /* DEBUG */
3744 	}
3745 	/* Unlock after closing but before any getty mumbo jumbo */
3746 
3747 	debug(F100,"ttclos about to call ttunlck","",0);
3748         if (ttunlck())                  /* Release uucp-style lock */
3749 	  fprintf(stderr,"Warning, problem releasing lock\r\n");
3750     }
3751 
3752 /* For bidirectional lines, restore getty if it was there before. */
3753 
3754 #ifdef ACUCNTRL				/* 4.3BSD acucntrl() method. */
3755     if (xlocal) {
3756 	debug(F100,"ttclos ACUCNTRL","",0);
3757 	acucntrl("enable",ttnmsv);	/* Enable getty on the device. */
3758     }
3759 #else
3760 #ifdef ATT7300				/* ATT UNIX PC (3B1, 7300) method. */
3761     if (xlocal) {
3762 	debug(F100,"ttclos ATT7300 ongetty","",0);
3763 	if (attmodem & DOGETY)		/* Was getty(1m) running before us? */
3764 	  ongetty(ttnmsv);		/* Yes, restart getty on tty line */
3765 	attmodem &= ~DOGETY;		/* No phone in use, getty restored */
3766     }
3767 #endif /* ATT7300 */
3768 #endif /* System-dependent getty-restoring methods */
3769 
3770 #ifdef sony_news
3771     km_ext = -1;			/* Invalidate device's Kanji-mode */
3772 #endif /* sony_news */
3773 
3774     ttyfd = -1;                         /* Invalidate the file descriptor. */
3775     wasclosed = 1;
3776     debug(F100,"ttclos done","",0);
3777     return(0);
3778 }
3779 
3780 /*  T T H A N G  --  Hangup phone line or network connection.  */
3781 /*
3782   Returns:
3783   0 if it does nothing.
3784   1 if it believes that it hung up successfully.
3785  -1 if it believes that the hangup attempt failed.
3786 */
3787 
3788 #define HUPTIME 500			/* Milliseconds for hangup */
3789 
3790 #ifdef COMMENT
3791 /* The following didn't work but TIOCSDTR does work */
3792 #ifdef UNIXWARE
3793 /* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
3794 #ifndef POSIX				/* Such as Unixware 1.x, 2.x */
3795 #ifndef HUP_POSIX
3796 #define HUP_POSIX
3797 #endif /* HUP_POSIX */
3798 #endif /* POSIX */
3799 #endif /* UNIXWARE */
3800 #endif /* COMMENT */
3801 
3802 #ifndef USE_TIOCSDTR
3803 #ifdef __NetBSD__
3804 /* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
3805 #ifdef TIOCSDTR
3806 #ifdef TIOCCDTR
3807 #define USE_TIOCSDTR
3808 #endif /* TIOCCDTR */
3809 #endif /* TIOCSDTR */
3810 #endif /* __NetBSD__ */
3811 #endif /* USE_TIOCSDTR */
3812 
3813 #ifndef HUP_CLOSE_POSIX
3814 #ifdef OU8
3815 #define HUP_CLOSE_POSIX
3816 #else
3817 #ifdef CK_SCOV5
3818 #define HUP_CLOSE_POSIX
3819 #endif /* CK_SCOV5 */
3820 #endif /* OU8 */
3821 #endif /* HUP_CLOSE_POSIX */
3822 
3823 #ifdef NO_HUP_CLOSE_POSIX
3824 #ifdef HUP_CLOSE_POSIX
3825 #undef HUP_CLOSE_POSIX
3826 #endif /* HUP_CLOSE_POSIX */
3827 #endif /* NO_HUP_CLOSE_POSIX */
3828 
3829 int
tthang()3830 tthang() {
3831 #ifdef NOLOCAL
3832     return(0);
3833 #else
3834     int x = 0;				/* Sometimes used as return code. */
3835 #ifndef POSIX
3836     int z;				/* worker */
3837 #endif /* POSIX */
3838 
3839 #ifdef COHERENT
3840 #define SVORPOSIX
3841 #endif /* COHERENT */
3842 
3843 #ifdef SVORPOSIX			/* AT&T, POSIX, HPUX declarations. */
3844     int spdsav;				/* for saving speed */
3845 #ifdef HUP_POSIX
3846     int spdsavi;
3847 #else
3848 #ifdef BSD44ORPOSIX
3849     int spdsavi;
3850 #endif /* BSD44ORPOSIX */
3851 #endif /* HUP_POSIX */
3852 #ifdef HPUX
3853 /*
3854   Early versions of HP-UX omitted the mflag typedef.  If you get complaints
3855   about it, just change it to long (or better still, unsigned long).
3856 */
3857     mflag
3858       dtr_down = 00000000000,
3859       modem_rtn,
3860       modem_sav;
3861     char modem_state[64];
3862 #endif /* HPUX */
3863     int flags;				/* fcntl flags */
3864     unsigned short ttc_save;
3865 #endif /* SVORPOSIX */
3866 
3867     if (ttyfd < 0) return(0);           /* Don't do this if not open  */
3868     if (xlocal < 1) return(0);		/* Don't do this if not local */
3869 
3870 #ifdef NETCMD
3871     if (ttpipe)
3872       return((ttclos(0) < 0) ? -1 : 1);
3873 #endif /* NETCMD */
3874 #ifdef NETPTY
3875     if (ttpty)
3876       return((ttclos(0) < 0) ? -1 : 1);
3877 #endif /* NETPTY */
3878 #ifdef NETCONN
3879     if (netconn) {			/* Network connection. */
3880 #ifdef TN_COMPORT
3881         if (istncomport()) {
3882             int rc = tnc_set_dtr_state(0);
3883             if (rc >= 0) {
3884                 msleep(HUPTIME);
3885                 rc = tnc_set_dtr_state(1);
3886             }
3887             return(rc >= 0 ? 1 : -1);
3888         } else
3889 #endif /* TN_COMPORT */
3890 	  return((netclos() < 0) ? -1 : 1); /* Just close it. */
3891   }
3892 #endif /* NETCONN */
3893 
3894 /* From here down, we handle real tty devices. */
3895 #ifdef HUP_POSIX
3896 /*
3897   e.g. for Unixware 2, where we don't have a full POSIX build, we
3898   still have to use POSIX-style hangup.  Thus the duplication of this
3899   and the next case, the only difference being we use a local termios
3900   struct here, since a different model is used elsewhere.
3901 
3902   NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
3903   even though it compiles and executes without error, doesn't actually
3904   work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
3905 */
3906     {
3907 	struct termios ttcur;
3908 	int x;
3909 	debug(F100,"tthang HUP_POSIX style","",0);
3910 	x = tcgetattr(ttyfd, &ttcur);	/* Get current attributes */
3911 	debug(F111,"tthang tcgetattr",ckitoa(errno),x);
3912 	if (x < 0) return(-1);
3913 	spdsav = cfgetospeed(&ttcur);	/* Get current speed */
3914 	debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
3915 	spdsavi = cfgetispeed(&ttcur);	/* Get current speed */
3916 	debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
3917 	x = cfsetospeed(&ttcur,B0);	/* Replace by 0 */
3918 	debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
3919 	if (x < 0) return(-1);
3920 	x = cfsetispeed(&ttcur,B0);
3921 	debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
3922 	if (x < 0) return(-1);
3923 	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3924 	debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
3925 	if (x < 0) return(-1);
3926 	msleep(HUPTIME);		/* Sleep 0.5 sec */
3927 	x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
3928 	if (x < 0) return(-1);
3929 	debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
3930 	x = cfsetispeed(&ttcur,spdsavi);
3931 	debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
3932 	if (x < 0) return(-1);
3933 	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3934 	debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
3935 	if (x < 0) return(-1);
3936 	return(1);
3937     }
3938 #else
3939 #ifdef BSD44ORPOSIX
3940 #ifdef QNX
3941     {
3942 	int x;
3943 	x = tcdropline(ttyfd,500);
3944 	debug(F101,"tthang QNX tcdropline","",x);
3945 	ttcur.c_cflag |= CLOCAL;
3946 	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3947 	debug(F101,"tthang QNX tcsetattr restore","",x);
3948 	if (x < 0) {
3949 	    debug(F101,"tthang QNX tcsetattr restore errno","",errno);
3950 	    return(-1);
3951 	}
3952 	/* Fix flags - ensure O_NONBLOCK is off */
3953 
3954 	errno = 0;
3955 	debug(F101,"tthang QNX iniflags","",iniflags);
3956 	if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
3957 	    debug(F101,"tthang QNX F_SETFL errno","",errno);
3958 	    return(-1);
3959 	}
3960 	return(x);
3961     }
3962 #else  /* QNX */
3963     {
3964 	int x;
3965 #ifdef USE_TIOCSDTR
3966 	debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
3967 	errno = 0;
3968 	x = ioctl(ttyfd, TIOCCDTR, NULL);
3969 	debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
3970 	if (x < 0) return(-1);
3971 	msleep(HUPTIME);		/* Sleep 0.5 sec */
3972 	errno = 0;
3973 	x = ioctl(ttyfd, TIOCSDTR, NULL);
3974 	debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
3975 	if (x < 0) return(-1);
3976 #else  /* USE_TIOCSDTR */
3977 
3978 #ifdef HUP_CLOSE_POSIX
3979 /*
3980   In OSR5 versions where TIOCSDTR is not defined (up to and including at
3981   least 5.0.6a) the POSIX APIs in the "#else" part below are available but
3982   don't work, and no other APIs are available that do work.  In this case
3983   we have to drop DTR by brute force: close and reopen the port.  This
3984   code actually works, but all the steps are crucial: setting CLOCAL, the
3985   O_NDELAY manipulations, etc.
3986 */
3987 	debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
3988 	debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
3989 	debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
3990 	errno = 0;
3991 	x = tcgetattr(ttyfd, &ttcur);	/* Get current attributes */
3992 	debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
3993 	if (x < 0) {
3994 	    debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
3995 	    return(-1);
3996 	}
3997 	errno = 0;
3998 
3999 	x = close(ttyfd);		/* Close without releasing lock */
4000 	if (x < 0) {
4001 	    debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
4002 	    return(-1);
4003 	}
4004 	errno = 0;
4005 	x = msleep(500);		/* Pause half a second */
4006 	if (x < 0) {			/* Or if that doesn't work, 1 sec */
4007 	    debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
4008 	    sleep(1);
4009 	}
4010 	errno = 0;
4011 	ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
4012 	debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
4013 	if (ttyfd < 0) {
4014 	    debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
4015 	    return(-1);
4016 	}
4017 	debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
4018 
4019 	/* Restore previous attributes */
4020 
4021 	errno = 0;
4022 	tvtflg = 0;
4023 	ttcur.c_cflag |= CLOCAL;
4024 	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4025 	debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
4026 	if (x < 0) {
4027 	    debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
4028 		  "",errno);
4029 	    return(-1);
4030 	}
4031 	/* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
4032 
4033 	errno = 0;
4034         if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
4035 	    debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
4036 	    return(-1);
4037 	}
4038 	debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4039 	errno = 0;
4040         x &= ~(O_NONBLOCK|O_NDELAY);
4041 	debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
4042 	debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
4043 	if (fcntl(ttyfd, F_SETFL, x) == -1) {
4044 	    debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
4045 	    return(-1);
4046 	}
4047 #ifdef DEBUG
4048 	if (deblog) {
4049 	    if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
4050 		debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4051 		debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
4052 		      "",x&O_NONBLOCK);
4053 		debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
4054 		      "",x&O_NDELAY);
4055 	    }
4056 	}
4057 #endif /* DEBUG */
4058 
4059 #else  /* HUP_CLOSE_POSIX */
4060 
4061 	/* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
4062 
4063 	debug(F100,"tthang BSD44ORPOSIX B0","",0);
4064 	x = tcgetattr(ttyfd, &ttcur);	/* Get current attributes */
4065 	debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
4066 	if (x < 0) return(-1);
4067 	spdsav = cfgetospeed(&ttcur);	/* Get current speed */
4068 	debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
4069 	spdsavi = cfgetispeed(&ttcur);	/* Get current speed */
4070 	debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
4071 	x = cfsetospeed(&ttcur,B0);	/* Replace by 0 */
4072 	debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
4073 	if (x < 0) return(-1);
4074 	x = cfsetispeed(&ttcur,B0);
4075 	debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
4076 	if (x < 0) return(-1);
4077 	/* This gets EINVAL on NetBSD 1.4.1 because of B0... */
4078 	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4079 	debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
4080 	if (x < 0) return(-1);
4081 	msleep(HUPTIME);		/* Sleep 0.5 sec */
4082 	debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
4083 	x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
4084 	debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
4085 	if (x < 0) return(-1);
4086 	debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
4087 	x = cfsetispeed(&ttcur,spdsavi);
4088 	debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
4089 	if (x < 0) return(-1);
4090 	ttcur.c_cflag |= CLOCAL;	/* Don't expect CD after hangup */
4091 	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4092 	debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
4093 	if (x < 0) return(-1);
4094 
4095 #endif /* HUP_CLOSE_POSIX */
4096 #endif /* USE_TIOCSDTR */
4097 
4098 	return(1);
4099     }
4100 
4101 #endif /* QNX */
4102 #else /* BSD44ORPOSIX */
4103 
4104 #ifdef aegis				/* Apollo Aegis */
4105     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
4106     msleep(HUPTIME);					/* pause */
4107     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
4108     return(1);
4109 #endif /* aegis */
4110 
4111 #ifdef ANYBSD				/* Any BSD version. */
4112 #ifdef TIOCCDTR				/* Except those that don't have this */
4113     debug(F100,"tthang BSD style","",0);
4114     if (ioctl(ttyfd,TIOCCDTR,0) < 0) {	/* Clear DTR. */
4115 	debug(F101,"tthang TIOCCDTR fails","",errno);
4116 	return(-1);
4117     }
4118     msleep(HUPTIME);			/* For about 1/2 sec */
4119     errno = 0;
4120     x = ioctl(ttyfd,TIOCSDTR,0);	/* Restore DTR */
4121     if (x < 0) {
4122 	/*
4123 	  For some reason, this tends to fail with "no such device or address"
4124 	  but the operation still works, probably because of the close/open
4125 	  later on.  So let's not scare the user unnecessarily here.
4126 	*/
4127 	debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
4128 	x = 1;				/* Pretend we succeeded */
4129     } else if (x == 0) x = 1;		/* Success */
4130 #ifdef COMMENT
4131 #ifdef FT21
4132     ioctl(ttyfd, TIOCSAVEMODES, 0);
4133     ioctl(ttyfd, TIOCHPCL, 0);
4134     close(ttyfd);			/* Yes, must do this twice */
4135     if ((ttyfd = open(ttnmsv,2)) < 0)	/* on Fortune computers... */
4136       return(-1);			/* (but why?) */
4137     else x = 1;
4138 #endif /* FT21 */
4139 #endif /* COMMENT */
4140 #endif /* TIOCCDTR */
4141     close(do_open(ttnmsv));		/* Clear i/o error condition */
4142     errno = 0;
4143 #ifdef COMMENT
4144 /* This is definitely dangerous.  Why was it here? */
4145     z = ttvt(ttspeed,ttflow);		/* Restore modes. */
4146     debug(F101,"tthang ttvt returns","",z);
4147     return(z < 0 ? -1 : 1);
4148 #else
4149     return(x);
4150 #endif /* COMMENT */
4151 #endif /* ANYBSD */
4152 
4153 #ifdef ATTSV
4154 /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
4155 
4156 #ifdef HPUX
4157 /* Hewlett Packard allows explicit manipulation of modem signals. */
4158 
4159 #ifdef COMMENT
4160 /* Old way... */
4161     debug(F100,"tthang HP-UX style","",0);
4162     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0)        /* lower DTR */
4163       return(-1);		    	           /* oops, can't. */
4164     msleep(HUPTIME);			           /* Pause half a second. */
4165     x = 1;				           /* Set return code */
4166     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) {     /* Get line status. */
4167 	if ((modem_rtn & MDCD) != 0)      	   /* Check if CD is low. */
4168 	  x = -1;                                  /* CD didn't drop, fail. */
4169     } else x = -1;
4170 
4171     /* Even if above calls fail, RTS & DTR should be turned back on. */
4172     modem_rtn = MRTS | MDTR;
4173     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
4174     return(x);
4175 #else
4176 /* New way, from Hellmuth Michaelis */
4177     debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
4178     if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
4179 	debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
4180 	return(-1);
4181     }
4182     sprintf(modem_state,"%#lx",modem_rtn);
4183     debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
4184     modem_sav = modem_rtn;		/* Save current modem signals */
4185     modem_rtn &= ~MDTR;			/* Turn DTR bit off */
4186     sprintf(modem_state,"%#lx",modem_rtn);
4187     debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
4188     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
4189 	debug(F100,"tthang HP-UX: can't lower DTR!","",0);
4190 	return(-1);			/* oops, can't. */
4191     }
4192     msleep(HUPTIME);			/* Pause half a second. */
4193     x = 1;				/* Set return code */
4194     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
4195 	sprintf(modem_state,"%#lx",modem_rtn);
4196 	debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
4197 	if ((modem_rtn & MDCD) != 0) {	/* Check if CD is low. */
4198 	    debug(F100,"tthang HP-UX: DCD not down","",0);
4199 	    x = -1;			/* CD didn't drop, fail. */
4200 	} else {
4201 	    debug(F100,"tthang HP-UX: DCD down","",0);
4202 	}
4203     } else {
4204 	x = -1;
4205 	debug(F100,"tthang HP-UX: can't get DCD status !","",0);
4206     }
4207 
4208     /* Even if above calls fail, DTR should be turned back on. */
4209 
4210     modem_sav |= MDTR;
4211     if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
4212 	x = -1;
4213 	debug(F100,"tthang HP-UX: can't set saved state","",0);
4214     } else {
4215 	sprintf(modem_state,"%#lx",modem_sav);
4216 	debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
4217     }
4218     return(x);
4219 #endif /* COMMENT */
4220 
4221 #else /* AT&T but not HP-UX */
4222 
4223 /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
4224 /* It is not known how many, if any, systems actually implement them, */
4225 /* so we include them here in ifdef's. */
4226 
4227 /*
4228   Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
4229   gives error 22 (invalid argument).
4230 */
4231 #ifndef _IBMR2
4232 /*
4233   No modem-signal twiddling for IBM RT PC or RS/6000.
4234   In AIX 3.1 and earlier, the ioctl() call is broken.
4235   This code could be activated for AIX 3.1 with PTF 2006 or later
4236   (e.g. AIX 3.2), but close/open does the job too, so why bother.
4237 */
4238 #ifdef TIOCMBIS				/* Bit Set */
4239 #ifdef TIOCMBIC				/* Bit Clear */
4240 #ifdef TIOCM_DTR			/* DTR */
4241 
4242 /* Clear DTR, sleep 300 msec, turn it back on. */
4243 /* If any of the ioctl's return failure, go on to the next section. */
4244 
4245     z = TIOCM_DTR;			/* Code for DTR. */
4246 #ifdef COMMENT
4247 /*
4248   This was the cause of the troubles with the Solaris Port Monitor.
4249   The problem is: RTS never comes back on.  Moral: Don't do it!
4250   (But why doesn't it come back on?  See the TIOCMBIS call...)
4251 */
4252 #ifdef TIOCM_RTS			/* Lower RTS too if symbol is known. */
4253     z |= TIOCM_RTS;
4254 #endif /* TIOCM_RTS */
4255 #endif /* COMMENT */
4256 
4257     debug(F101,"tthang TIOCM signal mask","",z);
4258     if (ioctl(ttyfd,TIOCMBIC,&z) > -1) {   /* Try to lower DTR. */
4259 	debug(F100,"tthang TIOCMBIC ok","",0);
4260 	msleep(HUPTIME);		   /* Pause half a second. */
4261 	if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
4262 	    debug(F100,"tthang TIOCMBIS ok","",0);
4263 #ifndef CLSOPN
4264 	    return(1);			/* Success, done. */
4265 #endif /* CLSOPN */
4266 	} else {			/* Couldn't raise, continue. */
4267 	    debug(F101,"tthang TIOCMBIS errno","",errno);
4268 	}
4269     } else {				/* Couldn't lower, continue. */
4270  	debug(F101,"tthang TIOCMBIC errno","",errno);
4271     }
4272 #endif /* TIOCM_DTR */
4273 #endif /* TIOCMBIC */
4274 #endif /* TIOCMBIS */
4275 #endif /* _IBMR2 */
4276 
4277 /*
4278   General AT&T UNIX case, not HPUX.  The following code is highly suspect.  No
4279   two AT&T-based systems seem to do this the same way.  The object is simply
4280   to turn off DTR and then turn it back on.  SVID says the universal method
4281   for turning off DTR is to set the speed to zero, and this does seem to do
4282   the trick in all cases.  But neither SVID nor any known man pages say how to
4283   turn DTR back on again.  Some variants, like most Xenix implementations,
4284   raise DTR again when the speed is restored to a nonzero value.  Others
4285   require the device to be closed and opened again, but this is risky because
4286   getty could seize the device during the instant it is closed.
4287 */
4288 
4289 /* Return code for ioctl failures... */
4290 #ifdef ATT6300
4291     x = 1;				/* ATT6300 doesn't want to fail... */
4292 #else
4293     x = -1;
4294 #endif /* ATT6300 */
4295 
4296     debug(F100,"tthang get settings","",0);
4297     if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
4298       return(x);			/* Fail if this doesn't work. */
4299     if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
4300       return(x);
4301     ttc_save = ttcur.c_cflag;		/* Remember current speed. */
4302     spdsav = ttc_save & CBAUD;
4303     debug(F101,"tthang speed","",spdsav);
4304 
4305 #ifdef O_NDELAY
4306     debug(F100,"tthang turning O_NDELAY on","",0);
4307     fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
4308 #endif /* O_NDELAY */
4309 
4310 #ifdef ATT7300 /* This is the way it is SUPPOSED to work */
4311     ttcur.c_cflag &= ~CBAUD;		/* Change the speed to zero.  */
4312 #else
4313 #ifdef RTAIX
4314     ttcur.c_cflag &= ~CBAUD;		/* Change the speed to zero.  */
4315 #else          /* This way really works but may be dangerous */
4316 #ifdef u3b2
4317     ttcur.c_cflag = ~(CBAUD|CLOCAL);	/* Special for AT&T 3B2s */
4318 					/* (CLOCAL must be OFF) */
4319 #else
4320 #ifdef SCO3R2				/* SCO UNIX 3.2 */
4321 /*
4322   This is complete nonsense, but an SCO user claimed this change made
4323   hanging up work.  Comments from other SCO UNIX 3.2 users would be
4324   appreciated.
4325 */
4326     ttcur.c_cflag = CBAUD|B0;
4327 #else
4328 #ifdef AIXRS				/* AIX on RS/6000 */
4329 /*
4330   Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
4331   even though you can do it on the built-in port and the 8- and 16-port
4332   adapters.  (Untested on 128-port adapter.)
4333 */
4334     ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
4335 #else					/* None of the above */
4336 /*
4337   Set everything, including the speed, to zero, except for the CLOCAL
4338   and HUPCL bits.
4339 */
4340     ttcur.c_cflag = CLOCAL|HUPCL;
4341 #endif /* AIXRS */
4342 #endif /* SCO3R2 */
4343 #endif /* u3b2 */
4344 #endif /* RTAIX */
4345 #endif /* ATT7300 */
4346 
4347 #ifdef COMMENT
4348     /* and if none of those work, try one of these... */
4349     ttcur.c_cflag = 0;
4350     ttcur.c_cflag = CLOCAL;
4351     ttcur.c_cflag &= ~(CBAUD|HUPCL);
4352     ttcur.c_cflag &= ~(CBAUD|CREAD);
4353     ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
4354     /* or other combinations */
4355 #endif /* COMMENT */
4356 
4357 #ifdef TCXONC
4358     debug(F100,"tthang TCXONC","",0);
4359     if (ioctl(ttyfd, TCXONC, 1) < 0) {
4360 	debug(F101,"tthang TCXONC failed","",errno);
4361     }
4362 #endif /* TCXONC */
4363 
4364 #ifdef TIOCSTART
4365     debug(F100,"tthang TIOCSTART","",0);
4366     if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
4367 	debug(F101,"tthang TIOCSTART failed","",errno);
4368     }
4369 #endif /* TIOCSTART */
4370 
4371     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
4372 	debug(F101,"tthang TCSETAF failed","",errno);
4373 	fcntl(ttyfd, F_SETFL, flags);	/* Restore flags */
4374 	return(-1);			/* before returning. */
4375     }
4376     msleep(300);			/* Give modem time to notice. */
4377 
4378 #ifndef NOCOTFMC
4379 
4380 /* Now, even though it doesn't say this in SVID or any man page, we have */
4381 /* to close and reopen the device.  This is not necessary for all systems, */
4382 /* but it's impossible to predict which ones need it and which ones don't. */
4383 
4384 #ifdef ATT7300
4385 /*
4386   Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
4387   related ioctl's for their internal modems.  attmodem has getty status and
4388   modem-in-use bit.  Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
4389   but also ruins the file descriptor, and no other phone(7) ioctl call can fix
4390   it.  Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
4391   The only way to undo the damage is to close the fd and then reopen it.
4392 */
4393     if (attmodem & ISMODEM) {
4394 	debug(F100,"tthang attmodem close/open","",0);
4395 	ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
4396 	ioctl(ttyfd,PIOCDISC,&dialer);	/* Disconnect phone. */
4397 	close(ttyfd);			/* Close and reopen the fd. */
4398 	ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
4399 	attmodem &= ~ISMODEM;		/* Phone no longer in use. */
4400     }
4401 #else /* !ATT7300 */
4402 /* It seems we have to close and open the device for other AT&T systems */
4403 /* too, and this is the place to do it.  The following code does the */
4404 /* famous close(open(...)) magic by default.  If that doesn't work for you, */
4405 /* then try uncommenting the following statement or putting -DCLSOPN in */
4406 /* the makefile CFLAGS. */
4407 
4408 /* #define CLSOPN */
4409 
4410 #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
4411 
4412 #ifdef O_NDELAY
4413 #define OPENFLGS O_RDWR | O_NDELAY
4414 #else
4415 #define OPENFLGS O_RDWR
4416 #endif
4417 
4418 #ifndef CLSOPN
4419 /* This method is used by default, i.e. unless CLSOPN is defined. */
4420 /* It is thought to be safer because there is no window where getty */
4421 /* can seize control of the device.  The drawback is that it might not work. */
4422 
4423     debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
4424     close(priv_opn(ttnmsv, OPENFLGS));
4425 
4426 #else
4427 /* This method is used if you #define CLSOPN.  It is more likely to work */
4428 /* than the previous method, but it's also more dangerous. */
4429 
4430     debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
4431     close(ttyfd);
4432     msleep(10);
4433     ttyfd = priv_opn(ttnmsv, OPENFLGS);	/* Open it again */
4434 #endif /* CLSOPN */
4435 #undef OPENFLGS
4436 
4437 #endif /* SCO32 */
4438 #endif /* ATT7300 */
4439 
4440 #endif /* NOCOTFMC */
4441 
4442 /* Now put all flags & modes back the way we found them. */
4443 /* (Does the order of ioctl & fcntl matter ? ) */
4444 
4445     debug(F100,"tthang restore settings","",0);
4446     ttcur.c_cflag = ttc_save;		/* Get old speed back. */
4447     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
4448       return(-1);
4449 #ifdef O_NDELAY
4450 /*
4451   This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
4452   After closing a modem line, the modem will probably not be asserting
4453   carrier any more, so we should not require carrier any more.  If this
4454   causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
4455   than O_NDELAY.
4456 */
4457     flags &= ~O_NDELAY;			/* Don't require carrier on reopen */
4458 #endif /* O_NDELAY */
4459     if (fcntl(ttyfd,F_SETFL,flags) < 0)	/* fcntl parameters */
4460       return(-1);
4461 
4462     return(1);
4463 #endif /* not HPUX */
4464 #endif /* ATTSV */
4465 #endif /* BSD44ORPOSIX */
4466 #endif /* HUP_POSIX */
4467 #endif /* NOLOCAL */
4468 }
4469 
4470 /*
4471   Major change in 5A(174).  We used to use LPASS8, if it was defined, to
4472   allow 8-bit data and Xon/Xoff flow control at the same time.  But this
4473   LPASS8 business seems to have been causing trouble for everybody but me!
4474   For example, Annex terminal servers, commonly used with Encore computers,
4475   do not support LPASS8 even though the Encore itself does.  Ditto for many
4476   other terminal servers, TELNET connections, rlogin connections, etc etc.
4477   Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
4478   serial lines, even though LPASS8 is a feature of 4.3BSD.  So let's turn it
4479   off for everybody.  That means we goes back to using raw mode, with no
4480   flow control.  Phooey.
4481 
4482   NOTE: This must be done before the first reference to LPASS8 in this file,
4483   and after the last #include statment.
4484 */
4485 #ifdef LPASS8
4486 #undef LPASS8
4487 #endif /* LPASS8 */
4488 
4489 /*  T T R E S  --  Restore terminal to "normal" mode.  */
4490 
4491 /* ske@pkmab.se: There are two choices for what this function should do.
4492  * (1) Restore the tty to current "normal" mode, with carrier treatment
4493  * according to ttcarr, to be used after every kermit command. (2) Restore
4494  * the tty to the state it was in before kermit opened it. These choices
4495  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
4496  * is currently being called as in choice (1), but ttold basically holds
4497  * the initial parameters, as in (2), and the description at the beginning
4498  * of this file says (2).
4499  *
4500  * I don't think restoring tty parameters after all kermit commands makes
4501  * much of a difference.  Restoring them upon exit from kermit may be of
4502  * some use in some cases (when the line is not restored automatically on
4503  * close, by the operating system).
4504  *
4505  * I can't choose which one it should be, so I haven't changed it. It
4506  * probably works as it is, too. It would probably even work even with
4507  * ttres() entirely deleted...
4508  *
4509  * (from fdc: Actually, this function operates in remote mode too, so
4510  * it restores the console (command) terminal to whatever mode it was
4511  * in before packet operations began, so that commands work right again.)
4512  */
4513 int
ttres()4514 ttres() {                               /* Restore the tty to normal. */
4515     int x;
4516 
4517     if (ttyfd < 0) return(-1);          /* Not open. */
4518 
4519     if (ttfdflg) return(0);		/* Don't mess with terminal modes if */
4520 					/* we got ttyfd from another process */
4521 #ifdef	NETCONN
4522     if (netconn) {			/* Network connection */
4523         tvtflg = 0;
4524 #ifdef TCPSOCKET
4525 #ifdef TCP_NODELAY
4526         {
4527 	    extern int tcp_nodelay;	/* Just put this back if necessary */
4528 	    if (ttnet == NET_TCPB) {
4529 		if (nodelay_sav > -1) {
4530 		    no_delay(ttyfd,nodelay_sav);
4531 		    nodelay_sav = -1;
4532 		}
4533 	    }
4534         }
4535 #endif /* TCP_NODELAY */
4536 #ifdef TN_COMPORT
4537         if (istncomport()) {
4538             int rc = -1;
4539             if ((rc = tnsetflow(ttflow)) < 0)
4540 	      return(rc);
4541             if (ttspeed <= 0)
4542 	      ttspeed = tnc_get_baud();
4543             else if ((rc = tnc_set_baud(ttspeed)) < 0)
4544 	      return(rc);
4545             tnc_set_datasize(8);
4546 	    tnc_set_stopsize(stopbits);
4547 
4548 #ifdef HWPARITY
4549             if (hwparity) {
4550                 switch (hwparity) {
4551 		  case 'e':			/* Even */
4552                     debug(F100,"ttres 8 bits + even parity","",0);
4553                     tnc_set_parity(3);
4554                     break;
4555 		  case 'o':			/* Odd */
4556                     debug(F100,"ttres 8 bits + odd parity","",0);
4557                     tnc_set_parity(2);
4558                     break;
4559 		  case 'm':			/* Mark */
4560                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
4561                     tnc_set_parity(4);
4562                     break;
4563 		  case 's':			/* Space */
4564                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
4565                     tnc_set_parity(5);
4566                     break;
4567                 }
4568             } else
4569 #endif /* HWPARITY */
4570 	    {
4571                 tnc_set_parity(1);              /* None */
4572             }
4573             tvtflg = 0;
4574             return(0);
4575         }
4576 #endif /* TN_COMPORT */
4577 #endif /* TCPSOCKET */
4578 	return(0);
4579     }
4580 #endif	/* NETCONN */
4581 #ifdef NETCMD
4582     if (ttpipe) return(0);
4583 #endif /* NETCMD */
4584 #ifdef NETPTY
4585     if (ttpty) return(0);
4586 #endif /* NETPTY */
4587 
4588 /* Real terminal device, so restore its original modes */
4589 
4590 #ifdef BSD44ORPOSIX			/* For POSIX like this */
4591     debug(F100,"ttres BSD44ORPOSIX","",0);
4592     x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
4593 #else					/* For all others... */
4594 #ifdef ATTSV                            /* For AT&T versions... */
4595     debug(F100,"ttres ATTSV","",0);
4596     x = ioctl(ttyfd,TCSETAW,&ttold);	/* Restore tty modes this way. */
4597 #else
4598 /* Here we restore the modes for BSD */
4599 
4600 #ifdef LPASS8				/* Undo "pass8" if it were done */
4601     if (lmodef) {
4602 	if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4603 	  debug(F100,"ttres TIOCLSET failed","",0);
4604 	else
4605 	  debug(F100,"ttres TIOCLSET ok","",0);
4606     }
4607 #endif /* LPASS8 */
4608 
4609 #ifdef CK_DTRCTS		   /* Undo hardware flow if it were done */
4610     if (lmodef) {
4611  	if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4612  	  debug(F100,"ttres TIOCLSET failed","",0);
4613  	else
4614  	  debug(F100,"ttres TIOCLSET ok","",0);
4615     }
4616 #endif /* CK_DTRCTS */
4617 
4618 #ifdef TIOCGETC				/* Put back special characters */
4619     if (tcharf && (xlocal == 0)) {
4620 	if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
4621 	  debug(F100,"ttres TIOCSETC failed","",0);
4622 	else
4623 	  debug(F100,"ttres TIOCSETC ok","",0);
4624     }
4625 #endif /* TIOCGETC */
4626 
4627 #ifdef TIOCGLTC				/* Put back local special characters */
4628     if (ltcharf && (xlocal == 0)) {
4629 	if (ioctl(ttyfd,TIOCSLTC,&ltchold) < 0)
4630 	  debug(F100,"ttres TIOCSLTC failed","",0);
4631 	else
4632 	  debug(F100,"ttres TIOCSLTC ok","",0);
4633     }
4634 #endif /* TIOCGLTC */
4635 
4636 #ifdef BELLV10
4637     debug(F100,"ttres BELLV10","",0);
4638     x = ioctl(ttyfd,TIOCSETP,&ttold);	/* Restore both structs */
4639     x = ioctl(ttyfd,TIOCSDEV,&tdold);
4640 #else
4641     debug(F100,"ttres stty","",0);
4642     x = stty(ttyfd,&ttold);             /* Restore tty modes the old way. */
4643 #endif /* BELLV10 */
4644 
4645     if (!xlocal)
4646       msleep(100);			/* This replaces sleep(1)... */
4647 					/* Put back sleep(1) if tty is */
4648 					/* messed up after close. */
4649 #endif /* ATTSV */
4650 #endif /* BSD44ORPOSIX */
4651 
4652     debug(F101,"ttres result","",x);
4653 #ifndef QNX
4654     if (x < 0) debug(F101,"ttres errno","",errno);
4655 #endif /* QNX */
4656 
4657 #ifdef AIXRS
4658 #ifndef AIX41
4659     x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
4660     debug(F101,"ttres AIX line discipline rts restore","",x);
4661 #endif /* AIX41 */
4662 #endif /* AIXRS */
4663 
4664 #ifdef BSD41
4665     if (ttld > -1) {			/* Put back line discipline */
4666 	x = ioctl(ttyfd, TIOCSETD, &ttld);
4667 	debug(F101,"ttres BSD41 line discipline restore","",x);
4668 	if (x < 0) debug(F101,"...ioctl errno","",errno);
4669 	ttld = -1;
4670     }
4671 #endif /* BSD41 */
4672 
4673 #ifdef sony_news
4674     x = xlocal ? km_ext : km_con;	/* Restore Kanji mode. */
4675     if (x != -1) {			/* Make sure we know original modes. */
4676 	if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
4677 	    perror("ttres can't set Kanji mode");
4678 	    debug(F101,"ttres error setting Kanji mode","",x);
4679 	    return(-1);
4680 	}
4681     }
4682     debug(F100,"ttres set Kanji mode ok","",0);
4683 #endif /* sony_news */
4684 
4685     tvtflg = 0;				/* Invalidate terminal mode settings */
4686     debug(F101,"ttres return code","",x);
4687     return(x);
4688 }
4689 
4690 #ifndef NOUUCP
4691 
4692 /*  T T C H K P I D  --  Check lockfile pid  */
4693 /*
4694   Read pid from lockfile named f, check that it's still valid.
4695   If so, return 1.
4696   On failure to read pid, return 1.
4697   Otherwise, try to delete lockfile f and return 0 if successful, else 1.
4698 */
4699 static int
ttchkpid(f)4700 ttchkpid(f) char *f; {
4701     int pid, mypid, x;
4702     pid = ttrpid(f);			/* Read pid from file. */
4703     if (pid > -1) {			/* If we were able to read the pid.. */
4704 	debug(F101,"ttchkpid lock pid","",pid);
4705 	errno = 0;			/* See if process still exists. */
4706 	mypid = (int)getpid();		/* Get my own pid. */
4707 	debug(F101,"ttchkpid my pid","",mypid);
4708 	if (pid == mypid) {		/* It's me! */
4709 	    x = -1;			/* So I can delete it */
4710 	    errno = ESRCH;		/* pretend it's invalid */
4711 	} else {			/* It's not me */
4712 	    x = kill((PID_T)pid, 0);	/* See if it's a live process */
4713 	    debug(F101,"ttchkpid kill errno","",errno);
4714 	}
4715 	debug(F101,"ttchkpid pid test","",x);
4716 	if (x < 0 && errno == ESRCH) { /* pid is invalid */
4717 	    debug(F111,"removing stale lock",f,pid);
4718 	    if (!backgrd)
4719 	      printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
4720 	    priv_on();
4721 	    x = unlink(f);		/* Remove the lockfile. */
4722 	    priv_off();
4723 	    debug(F111,"ttchkpid unlink",f,x);
4724 	    if (x > -1)
4725 	      return(0);		/* Device is not locked after all */
4726 	    else if (!backgrd)
4727 	      perror(f);
4728 	}
4729 	return(1);
4730     }
4731     return(1);				/* Failure to read pid */
4732 }
4733 
4734 #ifdef HPUX
4735 
4736 /* Aliases (different drivers) for HP-UX dialout devices: */
4737 
4738 static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
4739 static int ttydexists = 0;
4740 
4741 #endif /* HPUX */
4742 
4743 /*  T T R P I D  --  Read pid from lockfile "name" */
4744 
4745 static int
ttrpid(name)4746 ttrpid(name) char *name; {
4747     long len;
4748     int x, fd, pid;
4749     short spid;
4750     char buf[32];
4751 
4752     debug(F110,"ttrpid",name,0);
4753     if (!name) return(-1);
4754     if (!*name) return(-1);
4755     priv_on();
4756     len = zchki(name);			/* Get file length */
4757     priv_off();
4758     debug(F101,"ttrpid zchki","",len);
4759     if (len < 0)
4760       return(-1);
4761     if (len > 31)
4762       return(-1);
4763     priv_on();
4764     fd = open(name,O_RDONLY);		/* Try to open lockfile. */
4765     priv_off();
4766     debug(F101,"ttrpid fd","",fd);
4767     if (fd <= 0)
4768       return(-1);
4769 /*
4770   Here we try to be flexible and allow for all different binary and string
4771   formats at runtime, rather than a specific format for each configuration
4772   hardwired at compile time.
4773 */
4774     pid = -1;
4775 #ifndef COHERENT
4776 /*
4777   COHERENT uses a string PID but without leading spaces or 0's, so there is
4778   no way to tell from the file's length whether it contains a string or binary
4779   pid.  So for COHERENT only, we only allow string pids.  For all others, we
4780   decide based on the size of the lockfile.
4781 */
4782     if (len > 4) {			/* If file > 4 bytes it's a string */
4783 #endif /* COHERENT */
4784 	x = read(fd,buf,(int)len);
4785 	debug(F111,"ttrpid string read",buf,x);
4786 	if (x < 0) {
4787 	    pid = -1;
4788 	} else {
4789 	    buf[31] = '\0';
4790 	    x = sscanf(buf,"%d",&pid);	/* Get the integer pid from it. */
4791 	}
4792 #ifndef COHERENT
4793     } else if (len == 4) {		/* 4 bytes so binary */
4794 	x = read(fd, (char *)&pid, 4);	/* Read the bytes into an int */
4795 	debug(F101,"ttrpid integer read","",x);
4796 	if (x < 4)
4797 	  pid = -1;
4798     } else if (len == 2) {		/* 2 bytes binary */
4799 	x = read(fd, (char *)&spid, 2);	/* Read the bytes into a short */
4800 	debug(F101,"ttrpid short read","",x);
4801 	if (x < 2)
4802 	  pid = -1;
4803 	else
4804 	  pid = spid;
4805     } else
4806       pid = -1;
4807 #endif /* COHERENT */
4808     close(fd);				/* Close the lockfile */
4809     debug(F101,"ttrpid pid","",pid);
4810     return(pid);
4811 }
4812 #endif /* NOUUCP */
4813 
4814 /*  T T L O C K  */
4815 
4816 /*
4817   This function attempts to coordinate use of the communication device with
4818   other copies of Kermit and any other program that follows the UUCP
4819   device-locking conventions, which, unfortunately, vary among different UNIX
4820   implementations.  The idea is to look for a file of a certain name, the
4821   "lockfile", in a certain directory.  If such a file is found, then the line
4822   is presumed to be in use, and Kermit should not use it.  If no such file is
4823   found, Kermit attempts to create one so that other programs will not use the
4824   same line at the same time.  Because the lockfile and/or the directory it's
4825   in might lack write permission for the person running Kermit, Kermit could
4826   find itself running setuid to uucp or other user that does have the
4827   necessary permissions.  At startup, Kermit has changed its effective uid to
4828   the user's real uid, and so ttlock() must switch back to the original
4829   effective uid in order to create the lockfile, and then back again to the
4830   real uid to prevent unauthorized access to other directories or files owned
4831   by the user the program is setuid to.
4832 
4833   Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
4834   based on suggestions from Warren Tucker.  Call with pointer to name of
4835   tty device.  Returns:
4836 
4837    0 on success
4838   -1 on failure
4839 
4840   Note: Once privileges are turned on using priv_on(), it is essential that
4841   they are turned off again before this function returns.
4842 */
4843 #ifdef SVR4				/* Lockfile uses device numbers. */
4844 /*
4845   Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
4846   it is the behavior of the "reference version" of SVR4, i.e. the Intel
4847   port from UNIX Systems Laboratories, then called Univel UnixWare,
4848   then called Novell UnixWare, then called SCO Unixware, then called Caldera
4849   Open UNIX...  It also makes much more sense than device-name-based lockfiles
4850   since there can be multiple names for the same device, symlinks, etc.
4851 */
4852 #ifndef NOLFDEVNO
4853 #ifndef LFDEVNO				/* Define this for SVR4 */
4854 #ifndef AIXRS				/* But not for RS/6000 AIX 3.2, etc. */
4855 #ifndef BSD44				/* If anybody else needs it... */
4856 #ifndef __386BSD__
4857 #ifndef __FreeBSD__
4858 #ifndef HPUX10
4859 #ifndef IRIX51				/* SGI IRIX 5.1 or later */
4860 #ifndef CK_SCOV5			/* SCO Open Server 5.0 */
4861 #define LFDEVNO
4862 #endif /* CK_SCOV5 */
4863 #endif /* IRIX51 */
4864 #endif /* HPUX10 */
4865 #endif /* __FreeBSD__ */
4866 #endif /* __386BSD__ */
4867 #endif /* BSD44 */
4868 #endif /* AIXRS */
4869 #endif /* LFDEVNO */			/* ... define it here or on CC */
4870 #endif /* NOLFDEVNO */
4871 #endif /* SVR4 */			/* command line. */
4872 
4873 #ifdef COHERENT
4874 #define LFDEVNO
4875 #endif /* COHERENT */
4876 
4877 /*
4878   For platforms where the lockfile name is made from device/major/minor
4879   device number, as in SVR4.  Which, if we must have lockfiles at all, is
4880   by far the best format, since it eliminates all the confusion that stems
4881   from multiple names (or drivers) for the same port, not to mention
4882   symlinks.  It might even be a good idea to start using this form even
4883   on platforms where it's not supported, alongside the normal forms for those
4884   platforms, in order to get people used to it...
4885 */
4886 #ifdef LFDEVNO
4887 #ifndef major				/* If we didn't find it */
4888 #ifdef SVR4				/* then for Sys V R4 */
4889 #include <sys/mkdev.h>			/* look here */
4890 #else					/* or for SunOS versions */
4891 #ifdef SUNOS4				/* ... */
4892 #include <sys/sysmacros.h>		/* look here */
4893 #else					/* Otherwise take a chance: */
4894 #define	major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
4895 #define	minor(dev) ( (int) ( (dev) & 0xff))
4896 #endif /* SUNOS4 */
4897 #endif /* SVR4 */
4898 #endif /* major */
4899 #endif /* LFDEVNO */
4900 
4901 /* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
4902 
4903 #ifdef LOCKF
4904 #ifndef F_TLOCK
4905 #undef LOCKF
4906 #ifndef NOLOCKF
4907 #define NOLOCKF
4908 #endif /* NOLOCKF */
4909 #endif /* F_TLOCK */
4910 #endif /* LOCKF */
4911 
4912 #ifdef LOCKF
4913 #ifndef F_ULOCK
4914 #undef LOCKF
4915 #ifndef NOLOCKF
4916 #define NOLOCKF
4917 #endif /* NOLOCKF */
4918 #endif /* F_ULOCK */
4919 #endif /* LOCKF */
4920 
4921 static char linkto[DEVNAMLEN+1];
4922 static char * linkdev = NULL;
4923 
4924 #ifndef NOUUCP
4925 #ifdef USETTYLOCK
4926 #ifdef LOCK_DIR
4927 char * uucplockdir = LOCK_DIR;
4928 #else
4929 char * uucplockdir = "";
4930 #endif /* LOCK_DIR */
4931 #else
4932 #ifdef LOCK_DIR
4933 char * uucplockdir = LOCK_DIR;
4934 #else
4935 char * uucplockdir = "";
4936 #endif /* LOCK_DIR */
4937 #endif /* USETTYLOCK */
4938 #else
4939 char * uucplockdir = "";
4940 #endif /* NOUUCP */
4941 
4942 #ifdef QNX				/* Only for QNX4 */
4943 int					/* Visible to outside world */
qnxopencount()4944 qnxopencount() {			/* Get QNX device open count */
4945     struct _dev_info_entry info;
4946     int x;
4947 
4948     x = -1;				/* Unknown */
4949     if (ttyfd > -1) {
4950 	if (!dev_info(ttyfd, &info)) {
4951 	    debug(F101,"ttlock QNX open_count","",info.open_count);
4952 	    x = info.open_count;
4953 	}
4954     }
4955     return(x);
4956 }
4957 #endif /* QNX */
4958 
4959 char *
ttglckdir()4960 ttglckdir() {				/* Get Lockfile directory name */
4961 #ifdef __OpenBSD__
4962     return("/var/spool/lock");
4963 #else /* __OpenBSD__ */
4964 #ifdef __FreeBSD__
4965     return("/var/spool/lock");
4966 #else  /* __FreeBSD__ */
4967 #ifdef LOCK_DIR
4968     char * s = LOCK_DIR;
4969 #endif /* LOCK_DIR */
4970 #ifdef NOUUCP
4971     return("");
4972 #else  /* NOUUCP */
4973 #ifdef LOCK_DIR
4974     return(s);
4975 #else  /* LOCK_DIR */
4976     return("");
4977 #endif /* LOCK_DIR */
4978 #endif /* NOUUCP */
4979 #endif /* __FreeBSD__ */
4980 #endif /* __OpenBSD__ */
4981 }
4982 
4983 static int
ttlock(ttdev)4984 ttlock(ttdev) char *ttdev; {
4985 
4986     int x, n;
4987     int islink = 0;
4988 #ifdef __FreeBSD__
4989     char *devname;
4990 #endif	/* __FreeBSD__ */
4991 
4992 #ifdef NOUUCP
4993     debug(F100,"ttlock NOUUCP","",0);
4994     ckstrncpy(flfnam,"NOLOCK",FLFNAML);
4995     haslock = 1;
4996     return(0);
4997 #else /* !NOUUCP */
4998 
4999 #ifdef USETTYLOCK
5000     haslock = 0;                        /* Not locked yet. */
5001     *flfnam = '\0';			/* Lockfile name is empty. */
5002 #ifdef __FreeBSD__
5003     if ((devname = xxlast(ttdev,'/')) != NULL)
5004 #ifdef FREEBSD8
5005       ckstrncat(lockname,devname+1,DEVNAMLEN-ckstrncpy(lockname,"pts",4));
5006 #else
5007       ckstrncpy(lockname,devname+1,DEVNAMLEN);
5008 #endif	/* FREEBSD8 */
5009 #else
5010     if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
5011       ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
5012 #endif	/* __FreeBSD__ */
5013     else
5014       ckstrncpy(lockname,ttdev,DEVNAMLEN);
5015 /*
5016   This might be overkill, but it's not clear from the man pages whether
5017   ttylock() can be called without calling ttylocked() first, since the doc
5018   says that ttylocked() removes any stale lockfiles, but it does not say this
5019   about ttylock().  Also the docs don't say what ttylocked() returns in the
5020   case when it finds and removes a stale lockfile.  So one or both calls to
5021   to ttylocked() might be superfluous, but they should do no harm.  Also I'm
5022   assuming that we have to do all the same ID swapping, etc, with these
5023   routines as we do without them.  Thus the priv_on/off() sandwich.
5024 */
5025 #ifdef USE_UU_LOCK
5026     priv_on();				/* Turn on privs */
5027     x = uu_lock(lockname);		/* Try to set the lock */
5028     priv_off();				/* Turn privs off */
5029     debug(F111,"ttlock uu_lock",lockname,x);
5030     switch (x) {
5031       case UU_LOCK_INUSE:
5032 	return(-2);
5033       case UU_LOCK_OK:
5034 #ifdef BSD44
5035 	ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
5036 #endif /* BSD44 */
5037 	haslock = 1;
5038 	return(0);
5039       default:
5040 	return(-1);
5041     }
5042 #else  /* USE_UU_LOCK */
5043     priv_on();				/* Turn on privs */
5044     if (ttylocked(lockname)) {		/* This should remove any stale lock */
5045 	if (ttylocked(lockname)) {	/* so check again. */
5046 	    priv_off();
5047 	    return(-5);			/* Still locked, fail. */
5048 	}
5049     }
5050     x = ttylock(lockname);		/* Lock it. */
5051     priv_off();				/* Turn off privs */
5052 
5053     debug(F111,"ttlock lockname",lockname,x);
5054     if (x > -1) {
5055 	/*
5056 	  We don't really know the name of the lockfile, but
5057 	  this is what the man page says it is.  In USETTYLOCK
5058           builds, it is used only for display by SHOW COMM.
5059 	*/
5060 	ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
5061 	haslock = 1;
5062     }
5063     return(x);
5064 #endif /* USE_UU_LOCK */
5065 #else  /* Systems that don't have ttylock()... */
5066 
5067 #ifndef HPUX
5068 
5069     int lockfd;				/* File descriptor for lock file. */
5070     PID_T pid;				/* Process id of this process. */
5071     int tries;				/* How many times we've tried... */
5072     int dummy;
5073     struct stat devbuf;			/* For device numbers (SVR4). */
5074 
5075 #ifdef PIDSTRING
5076     char pid_str[32];			/* My pid in string format. */
5077 #endif /* PIDSTRING */
5078 
5079     char *device, *devname;
5080 
5081 /* Note: ridiculously long to prevent gcc complaints when used in sprintf */
5082 #define LFNAML 5126			/* Max length for lock file name. */
5083     char lockfil[LFNAML];		/* Lock file name */
5084 #ifdef RTAIX
5085     char lklockf[LFNAML];		/* Name for link to lock file  */
5086 #endif /* RTAIX */
5087 #ifdef CKSYMLINK
5088     char symlock[LFNAML];		/* Name for symlink lockfile name */
5089 #endif /* CKSYMLINK */
5090     char tmpnam[LFNAML+30];		/* Temporary lockfile name. */
5091     char *lockdir = LOCK_DIR;		/* Defined near top of this file, */
5092 					/* or on cc command line. */
5093     haslock = 0;                        /* Not locked yet. */
5094     *flfnam = '\0';			/* Lockfile name is empty. */
5095     lock2[0] = '\0';			/* Clear secondary lockfile name. */
5096     pid = getpid();			/* Get id of this process. */
5097 
5098 /*  Construct name of lockfile and temporary file */
5099 
5100 /*  device  = name of tty device without the path, e.g. "ttyh8" */
5101 /*  lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
5102 
5103     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5104 
5105     if (stat(ttdev,&devbuf) < 0)
5106       return(-1);
5107 
5108 #ifdef CKSYMLINK
5109     islink = 1;				/* Assume it's a symlink */
5110     linkto[0] = '\0';			/* But we don't know to what */
5111 #ifdef COMMENT
5112 /*
5113   This is undependable.  If it worked it would save the readlink call if
5114   we knew the device name was not a link.
5115 */
5116 #ifdef S_ISLNK
5117     islink = S_ISLNK(devbuf.st_mode);
5118     debug(F101,"ttlock stat S_ISLNK","",islink);
5119 #endif /* S_ISLNK */
5120 #endif /* COMMENT */
5121     if (islink) {
5122 	n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
5123 	debug(F111,"ttlock readlink",ttdev,n);
5124 	if (n > -1)			/* It is */
5125 	  linkto[n] = '\0';
5126 	else				/* It's not */
5127 	  islink = 0;
5128 	debug(F111,"ttlock link",linkto,islink);
5129     }
5130     if (islink) {
5131 	linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5132 	debug(F110,"ttlock linkdev",linkdev,0);
5133     }
5134 #endif /* CKSYMLINK */
5135 
5136 /*
5137   On SCO platforms, if we don't have a symlink, then let's pretend the
5138   name given for the device is a symlink, because later we will change
5139   the name if it contains any uppercase characters.
5140 */
5141 #ifdef CK_SCOV5				/* SCO Open Server 5.0 */
5142     if (!islink) {
5143 	islink = 1;
5144 	ckstrncpy(linkto,ttdev,DEVNAMLEN);
5145 	linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5146 	debug(F110,"ttlock linkdev",linkdev,0);
5147     }
5148 #else
5149 #ifdef M_XENIX				/* SCO Xenix or UNIX */
5150     if (!islink) {
5151 	islink = 1;
5152 	ckstrncpy(linkto,ttdev,DEVNAMLEN);
5153 	linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5154 	debug(F110,"ttlock linkdev",linkdev,0);
5155     }
5156 #endif /* M_XENIX */
5157 #endif /* CK_SCOV5 */
5158 
5159 #ifdef ISIII				/* Interactive System III, PC/IX */
5160     ckstrncpy(lockfil, device, DEVNAMLEN);
5161 #else  /* not ISIII */
5162 #ifdef LFDEVNO				/* Lockfilename has device numbers. */
5163 #ifdef COHERENT
5164     sprintf(lockfil,"LCK..%d.%d",	/* SAFE */
5165 	    major(devbuf.st_rdev),	   /* major device number */
5166 	    0x1f & minor(devbuf.st_rdev)); /* minor device number */
5167 #else
5168     /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
5169     /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
5170     sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
5171 	    major(devbuf.st_dev),	/* device */
5172 	    major(devbuf.st_rdev),	/* major device number */
5173 	    minor(devbuf.st_rdev));	/* minor device number */
5174 #endif /* COHERENT */
5175 #else  /* Not LFDEVNO */
5176 #ifdef PTX				/* Dynix PTX */
5177     if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
5178 	if ((int)strlen(device) + 8 < LFNAML)
5179 	  sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
5180 	else
5181 	  ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5182     } else
5183 #endif /* PTX */
5184       if ((int)strlen(device) + 5 < LFNAML)
5185 	sprintf(lockfil,"LCK..%s", device);
5186       else
5187 	ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5188 #ifdef RTAIX
5189     ckstrncpy(lklockf,device,DEVNAMLEN);
5190 #endif /* RTAIX */
5191 #ifdef CKSYMLINK
5192     symlock[0] = '\0';
5193     if (islink)
5194       ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
5195 #endif /* CKSYMLINK */
5196 #endif /* LFDEVNO */
5197 #endif /* ISIII */
5198 
5199 #ifdef CK_SCOV5				/* SCO Open Server 5.0 */
5200     {
5201 	/* Lowercase the entire filename. */
5202         /* SCO says we must do this in V5.0 and later. */
5203 	/* BUT... watch out for devices -- like Digiboard Portserver */
5204 	/* That can have hundreds of ports... */
5205 	char *p = (char *)(lockfil + 5);
5206 	while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
5207     }
5208 #ifdef CKSYMLINK
5209     if (islink) {			/* If no change */
5210 	if (!strcmp(lockfil,symlock)) {	/* then no second lockfile needed */
5211 	    islink = 0;
5212 	    symlock[0] = '\0';
5213 	}
5214     }
5215 #endif /* CKSYMLINK */
5216 #else
5217 #ifdef M_XENIX				/* SCO Xenix or UNIX */
5218     {
5219 	int x; char c;
5220 	x = (int)strlen(lockfil) - 1;	/* Get last letter of device name. */
5221 	if (x > 0) {			/* If it's uppercase, lower it. */
5222 	    c = lockfil[x];
5223 	    if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
5224 	}
5225     }
5226 #ifdef CKSYMLINK
5227     if (islink) {
5228 	if (!strcmp(lockfil,symlock)) {	/* No change */
5229 	    islink = 0;			/* so no second lockfile */
5230 	    symlock[0] = '\0';
5231 	}
5232     }
5233 #endif /* CKSYMLINK */
5234 #endif /* M_XENIX */
5235 #endif /* CK_SCOV5 */
5236 
5237 /*  flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
5238 /*  tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
5239 
5240     ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
5241 
5242 #ifdef RTAIX
5243     ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
5244 #endif /* RTAIX */
5245 
5246 #ifndef LFDEVNO
5247 #ifdef CKSYMLINK
5248     /* If it's a link then also make a lockfile for the real name */
5249     debug(F111,"ttlock link symlock",symlock,islink);
5250     if (islink && symlock[0]) {
5251 	/* But only if the lockfile names would be different. */
5252 	/* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
5253 	ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
5254 	debug(F110,"ttlock lock2",lock2,0);
5255 	if (!strcmp(lock2,flfnam)) {	/* Are lockfile names the same? */
5256 	    debug(F100,"ttlock lock2 cleared","",0);
5257 	    lock2[0] = '\0';		/* Clear secondary lockfile name. */
5258 	}
5259     }
5260 #endif /* CKSYMLINK */
5261 #endif /* LFDEVNO */
5262 
5263     sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
5264     debug(F110,"ttlock flfnam",flfnam,0);
5265     debug(F110,"ttlock tmpnam",tmpnam,0);
5266 
5267     priv_on();				/* Turn on privileges if possible. */
5268     lockfd = creat(tmpnam, 0444);	/* Try to create temp lock file. */
5269     if (lockfd < 0) {			/* Create failed. */
5270 	debug(F111,"ttlock creat failed",tmpnam,errno);
5271 	if (errno == ENOENT) {
5272 	    perror(lockdir);
5273 	    printf("UUCP not installed or Kermit misconfigured\n");
5274 	} else {
5275 	    if (!quiet)
5276 	      perror(lockdir);
5277 	    unlink(tmpnam);		/* Get rid of the temporary file. */
5278 	}
5279 	priv_off();			/* Turn off privileges!!! */
5280 	return(-1);			/* Return failure code. */
5281     }
5282 /* Now write the pid into the temp lockfile in the appropriate format */
5283 
5284 #ifdef PIDSTRING			/* For Honey DanBer UUCP, */
5285     sprintf(				/* write PID as decimal string */
5286 	    pid_str,
5287 #ifdef LINUXFSSTND			/* The "Linux File System Standard" */
5288 #ifdef FSSTND10				/* Version 1.0 calls for */
5289 	    "%010d\n",			/* leading zeros */
5290 #else					/* while version 1.2 calls for */
5291 	    "%10d\n",			/* leading spaces */
5292 #endif /* FSSTND10 */
5293 #else
5294 #ifdef COHERENT
5295 	    "%d\n",			/* with leading nothing */
5296 #else
5297 	    "%10d\n",			/* with leading blanks */
5298 #endif /* COHERENT */
5299 #endif /* LINUXFSSTND */
5300 	    (int) pid
5301 	    );				/* safe */
5302     dummy = write(lockfd, pid_str, 11);
5303     debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
5304 
5305 #else /* Not PIDSTRING, use integer PID */
5306 
5307     write(lockfd, (char *)&pid, sizeof(pid) );
5308     debug(F101,"ttlock pid","",(int) pid);
5309 
5310 #endif /* PIDSTRING */
5311 
5312 /* Now try to rename the temp file to the real lock file name. */
5313 /* This will fail if a lock file of that name already exists.  */
5314 
5315     close(lockfd);			/* Close the temp lockfile. */
5316     chmod(tmpnam,0444);			/* Permission for a valid lock. */
5317     tries = 0;
5318     while (!haslock && tries++ < 2) {
5319         haslock = 0;
5320         dummy = link(tmpnam,flfnam);    /* Create a link to it. */
5321         if (dummy == 0) haslock = 1;
5322 	if (haslock) {                  /* If we got the lockfile */
5323 #ifdef RTAIX
5324 	    link(flfnam,lkflfn);
5325 #endif /* RTAIX */
5326 #ifdef CKSYMLINK
5327 #ifndef LFDEVNO
5328 	    if (islink && lock2[0])
5329 	      dummy = link(flfnam,lock2);
5330 #endif /* LFDEVNO */
5331 #endif /* CKSYMLINK */
5332 
5333 #ifdef COMMENT
5334 /* Can't do this any more because device is not open yet so no ttyfd. */
5335 #ifdef LOCKF
5336 /*
5337   Advisory file locking works on SVR4, so we use it.  In fact, it is
5338   necessary in some cases, e.g. when SLIP is involved.  But it still doesn't
5339   seem to prevent multiple users accessing the same device by different names.
5340 */
5341             while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
5342                 debug(F111, "ttlock lockf returns errno", "", errno);
5343                 if ((++tries >= 3) || (errno != EAGAIN)) {
5344                     x = unlink(flfnam); /* remove the lockfile */
5345 #ifdef RTAIX
5346 		    unlink(lkflfn);	/* And any links to it... */
5347 #endif /* RTAIX */
5348 #ifdef CKSYMLINK
5349 #ifndef LFDEVNO
5350 		    if (islink && lock2[0])
5351 		      unlink(lock2);	/* ditto... */
5352 #endif /* LFDEVNO */
5353 #endif /* CKSYMLINK */
5354                     debug(F111,"ttlock unlink",flfnam,x);
5355                     haslock = 0;
5356 		    break;
5357 		}
5358                 sleep(2);
5359 	    }
5360 	    if (haslock)		/* If we got an advisory lock */
5361 #endif /* LOCKF */
5362 #endif /* COMMENT */
5363 	      break;			/* We're done. */
5364 
5365 	} else {			/* We didn't create a new lockfile. */
5366 	    priv_off();
5367 	    if (ttchkpid(flfnam)) {	/* Check existing lockfile */
5368 		priv_on();		/* cause ttchkpid turns priv_off... */
5369 		unlink(tmpnam);		/* Delete the tempfile */
5370 		debug(F100,"ttlock found tty locked","",0);
5371 		priv_off();		/* Turn off privs */
5372 		return(-2);		/* Code for device is in use. */
5373 	    }
5374 	    priv_on();
5375 	}
5376     }
5377     unlink(tmpnam);			/* Unlink (remove) the temp file. */
5378     priv_off();				/* Turn off privs */
5379     return(haslock ? 0 : -1);		/* Return link's return code. */
5380 
5381 #else /* HPUX */
5382 
5383 /*
5384   HP-UX gets its own copy of this routine, modeled after the observed behavior
5385   of the HP-UX 'cu' program.  HP-UX serial device names consist of a base name
5386   such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
5387   designator which is a string of digits, possibly containing an imbedded
5388   letter "p".  Examples (for base name "tty"):
5389 
5390      /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
5391 
5392   According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
5393   used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
5394   on other models.  In HP-UX 10.00, "0p0" notation was adopted for all models.
5395   However, we make and enforce no such distinctions; either notation is
5396   accepted on any model or HP-UX version as a valid unit designator.
5397 
5398   If a valid unit is specified (as opposed to a designer name or symlink), we
5399   check for all aliases of the given unit according to the devprefix[] array.
5400   If no lockfiles are found for the given unit, we can have the device; we
5401   create a lockfile LCK..name in the lockfile directory appropriate for the
5402   HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
5403   9.xx and earlier).  If it is a "cua" or "cul" device, a second lockfile is
5404   created with the "ttyd" prefix.  This is exactly what cu does.
5405 
5406   If the "set line" device does not have a valid unit designator, then it is
5407   used literally and no synomyms are searched for and only one lockfile is
5408   created.
5409 
5410   -fdc, March 1998.
5411 */
5412 #define LFNAML 80			/* Max length for lock file name. */
5413 
5414     int lockfd;				/* File descriptor for lock file. */
5415     PID_T pid;				/* Process ID of this process. */
5416     int fpid;				/* pid found in existing lockfile. */
5417     int tries;				/* How many times we've tried... */
5418     int i, k;				/* Workers */
5419 
5420     char *device, *devname;		/* "/dev/xxx", "xxx" */
5421     char *unit, *p;			/* <instance>p<port> part of xxx */
5422 
5423     char lockfil[LFNAML];		/* Lockfile name (no path) */
5424     char tmpnam[LFNAML];		/* Temporary lockfile name. */
5425 
5426 #ifdef HPUX10				/* Lockfile directory */
5427     char *lockdir = "/var/spool/locks";	/* Always this for 10.00 and higher */
5428 #else  /* HP-UX 9.xx and below */
5429 #ifdef LOCK_DIR
5430     char *lockdir = LOCK_DIR;		/* Defined near top of this file */
5431 #else
5432     char *lockdir = "/usr/spool/uucp";	/* or not... */
5433 #endif /* LOCK_DIR */
5434 #endif /* HPUX10 */
5435 
5436     haslock = 0;                        /* Not locked yet. */
5437     *flfnam = '\0';			/* Lockfile name is empty. */
5438     lock2[0] = '\0';			/* Second one too. */
5439     pid = getpid();			/* Get my process ID */
5440 /*
5441   Construct name of lockfile and temporary file...
5442   device  = name of tty device without the path, e.g. "tty0p0"
5443   lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
5444 */
5445     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5446     debug(F110,"TTLOCK device",device,0);
5447     ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
5448 
5449     k = 0;				/* Assume device is not locked */
5450     n = 0;				/* Digit counter */
5451     unit = device;			/* Unit = <instance>p<port> */
5452     while (*unit && !isdigit(*unit))	/* Search for digit... */
5453       unit++;
5454     p = unit;				/* Verify <num>p<num> format... */
5455     debug(F110,"TTLOCK unit 1",unit,0);
5456 /*
5457   The unit number is recognized as:
5458   (a) any sequence of digits that runs to the end of the string.
5459   (b) any (a) that includes one and only one letter "p", with at least
5460       one digit before and after it.
5461 */
5462     while (isdigit(*p)) p++, n++;	/* Get a run of digits */
5463     if (*p && n > 0) {			/* Have a "p"? */
5464 	if (*p == 'p' && isdigit(*(p+1))) {
5465 	    p++;
5466 	    n = 0;
5467 	    while (isdigit(*p)) p++, n++;
5468 	}
5469     }
5470     if (n == 0 || *p) unit = "";
5471     debug(F110,"TTLOCK unit 2",unit,0);
5472 
5473     if (*unit) {			/* Device name has unit number. */
5474 	/* The following loop not only searches for the various lockfile    */
5475 	/* synonyms, but also removes all -- not just one -- stale lockfile */
5476 	/* for the device, should there be more than one.  See ttchkpid().  */
5477 	ttydexists = 0;
5478 	for (i = 0; *devprefix[i]; i++) { /* For each driver... */
5479 	    /* Make device name */
5480 	    ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
5481 	    priv_on();			/* Privs on */
5482 	    k = zchki(lock2) != -1;	/* See if device exists */
5483 	    priv_off();			/* Privs off */
5484 	    debug(F111,"TTLOCK exist",lock2,k);
5485             if (k) {
5486 		if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
5487 		  ttydexists = 1;
5488 		/* Make lockfile name */
5489 		ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
5490 		debug(F110,"TTLOCK checking",lock2,0);
5491 		priv_on();		/* Privs on */
5492 		k = zchki(lock2) != -1;	/* See if lockfile exists */
5493 		priv_off();		/* Privs off */
5494 		debug(F111,"TTLOCK check for lock A",lock2,k);
5495 		if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
5496 		    ckstrncpy(flfnam,lock2,FLFNAML);
5497 		    return(-2);
5498 		}
5499 	    }
5500 	}
5501     } else {				/* Some other device-name format */
5502 	/* This takes care of symbolic links, etc... */
5503 	/* But does not chase them down! */
5504 	ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
5505 	priv_on();
5506 	k = zchki(lock2) != -1;		/* Check for existing lockfile */
5507 	priv_off();
5508 	debug(F111,"TTLOCK check for lock B",lock2,k);
5509 	if (k) if (ttchkpid(lock2)) {	/* Check pid from lockfile */
5510 	    ckstrncpy(flfnam,lock2,FLFNAML);
5511 	    debug(F110,"TTLOCK in use",device,0);
5512 	    debug(F101,"TTLOCK returns","",-2);
5513 	    return(-2);
5514 	}
5515     }
5516 /*
5517   Get here only if there is no (more) lockfile, so now we make one (or two)...
5518   flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
5519   tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
5520 */
5521     ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
5522 
5523     /* If dialout device, also make one for corresponding dialin device */
5524     lock2[0] = '\0';
5525     if (!strncmp(device,"cu",2) && *unit && ttydexists)
5526       ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
5527 
5528     if ((int)strlen(lockdir)+12 < LFNAML)
5529       sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
5530 #ifdef DEBUG
5531     if (deblog) {
5532 	debug(F110,"TTLOCK flfnam",flfnam,0);
5533 	debug(F110,"TTLOCK lock2",lock2,0);
5534 	debug(F110,"TTLOCK tmpnam",tmpnam,0);
5535     }
5536 #endif /* DEBUG */
5537 /*
5538    Lockfile permissions...
5539    444 is standard, HP-UX 10.00 uses 664.  It doesn't matter.
5540    Kermit uses 444; the difference lets us tell whether Kermit created
5541    the lock file.
5542 */
5543     priv_on();				/* Turn on privileges. */
5544     lockfd = creat(tmpnam, 0444);	/* Try to create temporary file. */
5545     if (lockfd < 0) {			/* Create failed. */
5546 	debug(F111,"TTLOCK creat failed",tmpnam,errno);
5547 	if (errno == ENOENT) {
5548 	    perror(lockdir);
5549 	    printf("UUCP not installed or Kermit misconfigured\n");
5550 	} else {
5551 	    if (!quiet)
5552 	      perror(lockdir);
5553 	    unlink(tmpnam);		/* Get rid of the temporary file. */
5554 	}
5555 	priv_off();			/* Turn off privileges!!! */
5556 	debug(F101,"TTLOCK returns","",-1);
5557 	return(-1);			/* Return failure code. */
5558     }
5559     debug(F110,"TTLOCK temp ok",tmpnam,0);
5560 
5561 /* Now write our pid into the temp lockfile in integer format. */
5562 
5563     i = write(lockfd, (char *)&pid, sizeof(pid));
5564 
5565 #ifdef DEBUG
5566     if (deblog) {
5567 	debug(F101,"TTLOCK pid","",pid);
5568 	debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
5569 	debug(F101,"TTLOCK write pid returns","",i);
5570     }
5571 #endif /* DEBUG */
5572 
5573 /*
5574   Now try to rename the temporary file to the real lockfile name.
5575   This will fail if a lock file of that name already exists, which
5576   will catch race conditions with other users.
5577 */
5578     close(lockfd);			/* Close the temp lockfile. */
5579     chmod(tmpnam,0444);
5580 
5581     tries = 0;
5582     while (!haslock && tries++ < 2) {
5583 	haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5584 	debug(F101,"TTLOCK link","",haslock);
5585 	if (haslock) {			/* If we made the lockfile... */
5586 
5587 #ifdef COMMENT
5588 /* We can't do this any more because we don't have a file descriptor yet. */
5589 #ifdef LOCKF				/* Can be canceled with -DNOLOCKF */
5590 /*
5591   Create an advisory lock on the device through its file descriptor.
5592   This code actually seems to work.  If it is executed, and then another
5593   process tries to open the same device under a different name to circumvent
5594   the lockfile, they get a "device busy" error.
5595 */
5596 	    debug(F100,"TTLOCK LOCKF code...","",0);
5597             while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
5598                 debug(F111, "TTLOCK lockf error", "", errno);
5599                 if ((++tries >= 3) || (errno != EAGAIN)) {
5600                     x = unlink(flfnam); /* Remove the lockfile */
5601 		    if (errno == EACCES && !quiet)
5602 		      printf("Device already locked by another process\n");
5603                     haslock = 0;
5604 		    break;
5605 		}
5606                 sleep(2);
5607 	    }
5608 #endif /* LOCKF */
5609 #endif /* COMMENT */
5610 
5611 	    if (haslock) {		/* If we made the lockfile ... */
5612 		if (lock2[0]) {		/* if there is to be a 2nd lockfile */
5613 		    lockfd = creat(lock2, 0444); /* Create it */
5614 		    debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
5615 		    if (lockfd > -1) {	/* Created OK, write pid. */
5616 			write(lockfd, (char *)&pid, sizeof(pid) );
5617 			close(lockfd);	/* Close and */
5618 			chmod(lock2, 0444); /* set permissions. */
5619 		    } else {		 /* Not OK, but don't fail. */
5620 			lock2[0] = '\0'; /* Just remember it's not there. */
5621 		    }
5622 		}
5623 		break;			/* and we're done. */
5624 	    }
5625 	}
5626     }
5627     unlink(tmpnam);			/* Unlink (remove) the temp file. */
5628     priv_off();				/* Turn off privs */
5629     i = haslock ? 0 : -1;		/* Our return value */
5630     debug(F101,"TTLOCK returns","",i);
5631     return(i);
5632 #endif /* HPUX */
5633 #endif /* USETTYLOCK */
5634 #endif /* !NOUUCP */
5635 }
5636 
5637 /*  T T U N L O C K  */
5638 
5639 static int
ttunlck()5640 ttunlck() {                             /* Remove UUCP lockfile(s). */
5641 #ifndef NOUUCP
5642     int x;
5643 
5644     debug(F111,"ttunlck",flfnam,haslock);
5645 
5646 #ifdef USETTYLOCK
5647 
5648     if (haslock && *flfnam) {
5649 	int x;
5650 	priv_on();			/* Turn on privs */
5651 #ifdef USE_UU_LOCK
5652 	x = uu_unlock(lockname);
5653 #else  /* USE_UU_LOCK */
5654 	x = ttyunlock(lockname);	/* Try to unlock */
5655 #endif /* USE_UU_LOCK */
5656 	priv_off();			/* Turn off privs */
5657 	if (x < 0 && !quiet)
5658 	  printf("Warning - Can't remove lockfile: %s\n", flfnam);
5659 
5660 	*flfnam = '\0';			/* Erase the name. */
5661 	haslock = 0;
5662 	return(0);
5663     }
5664 
5665 #else  /* No ttylock()... */
5666 
5667     if (haslock && *flfnam) {
5668 	/* Don't remove lockfile if we didn't make it ourselves */
5669 	if ((x = ttrpid(flfnam)) != (int)getpid()) {
5670 	    debug(F111,"ttunlck lockfile seized",flfnam,x);
5671 	    printf("Warning - Lockfile %s seized by pid %d\n",
5672 		   flfnam,
5673 		   x
5674 		   );
5675 	    return(0);
5676 	}
5677 	priv_on();			/* Turn privileges on.  */
5678 	errno = 0;
5679 	x = unlink(flfnam);		/* Remove the lockfile. */
5680 	debug(F111,"ttunlck unlink",flfnam,x);
5681 	if (x < 0) {
5682 	    if (errno && !quiet)
5683 	      perror(ttnmsv);
5684 	    printf("Warning - Can't remove lockfile: %s\n", flfnam);
5685 	}
5686 	haslock = 0;
5687 	*flfnam = '\0';			/* Erase the name. */
5688 
5689 #ifdef RTAIX
5690 	errno = 0;
5691 	x = unlink(lkflfn);		/* Remove link to lockfile */
5692 	debug(F111,"ttunlck AIX link unlink",lkflfn,x);
5693 	if (x < 0) {
5694 	    if (errno && !quiet)
5695 	      perror(ttnmsv);
5696 	    printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
5697 	}
5698 	*lkflfn = '\0';
5699 #else
5700 	if (lock2[0]) {			/* If there is a second lockfile, */
5701 	    errno = 0;
5702 	    x = unlink(lock2);		/*  remove it too. */
5703 	    debug(F111,"ttunlck lock2 unlink",lock2,x);
5704 	    if (x < 0) {
5705 		if (errno && !quiet)
5706 		  perror(ttnmsv);
5707 		printf("Warning - Can't remove secondary lockfile: %s\n",
5708 		       lock2
5709 		       );
5710 	    }
5711 	    lock2[0] = '\0';		/* Forget its name. */
5712 	}
5713 #endif /* RTAIX */
5714 
5715 #ifdef COMMENT
5716 #ifdef LOCKF
5717         (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
5718 #endif /* LOCKF */
5719 #endif /* COMMENT */
5720 
5721 	priv_off();			/* Turn privileges off. */
5722     }
5723 #endif /* USETTYLOCK */
5724 #endif /* !NOUUCP */
5725     return(0);
5726 }
5727 
5728 /*
5729   4.3BSD-style UUCP line direction control.
5730   (Stan Barber, Rice U, 1980-something...)
5731 */
5732 #ifndef NOUUCP
5733 #ifdef ACUCNTRL
5734 VOID
acucntrl(flag,ttname)5735 acucntrl(flag,ttname) char *flag, *ttname; {
5736     char x[DEVNAMLEN+32], *device, *devname;
5737 
5738     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
5739       return;				/* just return. */
5740     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
5741     if (strncmp(device,"LCK..",4) == 0) device += 5;
5742     ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
5743     debug(F110,"called ",x,0);
5744     zsyscmd(x);
5745 }
5746 #endif /* ACUCNTRL */
5747 #endif /* NOUUCP */
5748 
5749 /*
5750   T T H F L O W  --  Set or Reset hardware flow control.
5751 
5752   This is an attempt to collect all hardware-flow-control related code
5753   into a single module.  Thanks to Rick Sladkey and John Kohl for lots of
5754   help here.  Overview:
5755 
5756   Hardware flow control is not supported in many UNIX implementions.  Even
5757   when it is supported, there is no (ha ha) "standard" for the programming
5758   interface.  In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
5759   SunOS, AIX, etc, have totally different methods.  (And, not strictly
5760   relevant here, the programming interface often brings one only to a no-op
5761   in the device driver!)
5762 
5763   Among all these, we have two major types of APIs: those in which hardware
5764   flow control is determined by bits in the same termio/termios/sgtty mode
5765   word(s) that are used for controlling such items as CBREAK vs RAW mode, and
5766   which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
5767   for changing terminal modes.  And those that use entirely different
5768   mechanisms.
5769 
5770   In the first category, it is important that any change in the mode bits be
5771   reflected in the relevant termio(s)/sgtty structure, so that subsequent
5772   changes to that structure do not wipe out the effects of this routine.  That
5773   is why a pointer, attrs, to the appropriate structure is passed as a
5774   parameter to this routine.
5775 
5776   The second category should give us no worries, since any changes to hardware
5777   flow control accomplished by this routine should not affect the termio(s)/
5778   sgtty structures, and therefore will not be undone by later changes to them.
5779 
5780   The second argument, status, means to turn on hardware flow control if
5781   nonzero, and to turn it off if zero.
5782 
5783   Returns: 0 on apparent success, -1 on probable failure.
5784 */
5785 
5786 /*
5787   The following business is for BSDI, where it was discovered that two
5788   separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
5789   but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
5790   bits, so hwfc only works in one direction if you use CRTSCTS to control it.
5791   Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
5792   define CRTSCTS correctly.
5793 */
5794 #ifdef FIXCRTSCTS
5795 #ifdef CRTSCTS
5796 #ifdef CCTS_OFLOW
5797 #ifdef CRTS_IFLOW
5798 #undef CRTSCTS
5799 #define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
5800 #endif /* CRTS_IFLOW */
5801 #endif /* CCTS_OFLOW */
5802 #endif /* CRTSCTS */
5803 #endif /* FIXCRTSCTS */
5804 
5805 static int
tthflow(flow,status,attrs)5806 tthflow(flow, status, attrs)
5807     int flow,				/* Type of flow control (ckcdeb.h) */
5808     status;				/* Nonzero = turn it on */
5809 					/* Zero = turn it off */
5810 #ifdef BSD44ORPOSIX			/* POSIX or BSD44 */
5811     struct termios *attrs;
5812 #else					/* System V */
5813 #ifdef ATTSV
5814 #ifdef ATT7300
5815 #ifdef UNIX351M
5816 /* AT&T UNIX 3.51m can set but not test for hardware flow control */
5817 #define RTSFLOW CTSCD
5818 #define CTSFLOW CTSCD
5819 #endif /* ATT7300 */
5820 #endif /* UNIX351M */
5821     struct termio *attrs;
5822 #else					/* BSD, V7, etc */
5823     struct sgttyb *attrs;		/* sgtty info... */
5824 #endif /* ATTSV */
5825 #endif /* BSD44ORPOSIX */
5826 /* tthflow */ {
5827 
5828     int x = 0;				/* tthflow() return code */
5829 
5830 #ifdef Plan9
5831     return p9tthflow(flow, status);
5832 #else
5833 
5834 #ifndef OXOS				/* NOT Olivetti X/OS... */
5835 /*
5836   For SunOS 4.0 and later in the BSD environment ...
5837 
5838   The declarations are copied and interpreted from the System V header files,
5839   so we don't actually have to pull in all the System V junk when building
5840   C-Kermit for SunOS in the BSD environment, which would be dangerous because
5841   having those symbols defined would cause us to take the wrong paths through
5842   the code.  The code in this section is used in both the BSD and Sys V SunOS
5843   versions.
5844 */
5845 #ifdef SUNOS41
5846 /*
5847   In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
5848   because GNU CC uses different formats for the _IOxxx macros than regular CC;
5849   the POSIX forms work for both.  But the POSIX calls are not available in
5850   SunOS 4.0.
5851 */
5852 #define CRTSCTS 0x80000000		/* RTS/CTS flow control */
5853 #define TCSANOW 0			/* Do it now */
5854 
5855     struct termios {
5856 	unsigned long c_iflag;		/* Input modes */
5857 	unsigned long c_oflag;		/* Output modes */
5858 	unsigned long c_cflag;		/* Control modes */
5859 	unsigned long c_lflag;		/* Line discipline modes */
5860 	char c_line;
5861 	CHAR c_cc[17];
5862     };
5863     struct termios temp;
5864 
5865 _PROTOTYP( int tcgetattr, (int, struct termios *) );
5866 _PROTOTYP( int tcsetattr, (int, int, struct termios *) );
5867 /*
5868   When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
5869   asserted.  So we don't set CRTSCTS unless CD is up.  This should be OK,
5870   since we don't need RTS/CTS during dialing, and after dialing is complete,
5871   we should have CD.  If not, we still communicate, but without RTS/CTS.
5872 */
5873     int mflags;				/* Modem signal flags */
5874 
5875 #ifdef NETCMD
5876     if (ttpipe) return(0);
5877 #endif /* NETCMD */
5878 #ifdef NETPTY
5879     if (ttpty) return(0);
5880 #endif /* NETPTY */
5881 
5882     debug(F101,"tthflow SUNOS41 entry status","",status);
5883     if (!status) {			/* Turn hard flow off */
5884 	if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5885 	    (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5886 	    temp.c_cflag &= ~CRTSCTS;	/* It's there, remove it */
5887 	    x = tcsetattr(ttyfd,TCSANOW,&temp);
5888 	}
5889     } else {				/* Turn hard flow on */
5890 	if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
5891 	    (mflags & TIOCM_CAR)) {		/* Check for CD */
5892 	    debug(F100,"tthflow SunOS has CD","",0);
5893 	    if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5894 		!(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5895 		temp.c_cflag |= CRTSCTS;	/* Not there, add it */
5896 		x = tcsetattr(ttyfd,TCSANOW,&temp);
5897 	    }
5898 	} else {
5899 	    x = -1;
5900 	    debug(F100,"tthflow SunOS no CD","",0);
5901 	}
5902     }
5903 #else
5904 #ifdef QNX
5905     struct termios temp;
5906 #ifdef NETCMD
5907     if (ttpipe) return(0);
5908 #endif /* NETCMD */
5909 #ifdef NETPTY
5910     if (ttpty) return(0);
5911 #endif /* NETPTY */
5912     debug(F101,"tthflow QNX entry status","",status);
5913     if (tcgetattr(ttyfd, &temp) > -1) {	/* Get device attributes */
5914 	if (!status) {			/* Turn hard flow off */
5915 	    if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
5916 		temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
5917 		attrs->c_cflag &= ~(IHFLOW|OHFLOW);
5918 		x = tcsetattr(ttyfd,TCSANOW,&temp);
5919 	    }
5920 	} else {			/* Turn hard flow on */
5921 	    if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
5922 		temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
5923 		temp.c_iflag &= ~(IXON|IXOFF);   /* Bye to IXON/IXOFF */
5924 		ttraw.c_lflag |= IEXTEN;         /* Must be on */
5925 		x = tcsetattr(ttyfd,TCSANOW,&temp);
5926 		attrs->c_cflag |= (IHFLOW|OHFLOW);
5927 		attrs->c_iflag &= ~(IXON|IXOFF);
5928 	    }
5929 	}
5930     } else {
5931 	x = -1;
5932 	debug(F100, "tthflow QNX getattr fails", "", 0);
5933     }
5934 #else
5935 #ifdef POSIX_CRTSCTS
5936 /*
5937   POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
5938   Note: Do not assume CRTSCTS is a one-bit field!
5939 */
5940     struct termios temp;
5941 #ifdef NETCMD
5942     if (ttpipe) return(0);
5943 #endif /* NETCMD */
5944 #ifdef NETPTY
5945     if (ttpty) return(0);
5946 #endif /* NETPTY */
5947     debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
5948     errno = 0;
5949     x = tcgetattr(ttyfd, &temp);
5950     debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
5951     errno = 0;
5952     if (x < 0) {
5953 	x = -1;
5954     } else {
5955 	if (!status) {			/* Turn hard flow off */
5956 	    if (
5957 #ifdef COMMENT
5958 		/* This can fail because of sign extension */
5959 		/* e.g. in Linux where it's Bit 31 */
5960 		(temp.c_cflag & CRTSCTS) == CRTSCTS
5961 #else
5962 		(temp.c_cflag & CRTSCTS) != 0
5963 #endif /* COMMENT */
5964 		) {
5965 		temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
5966 		attrs->c_cflag &= ~CRTSCTS;
5967 		x = tcsetattr(ttyfd,TCSANOW,&temp);
5968 		debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
5969 		      ckitoa(x),errno);
5970 	    } else {			/* John Dunlap 2010-01-26 */
5971 		debug(F001,
5972 		      "tthflow before forcing off attrs CRTSCTS",
5973 		      "",
5974 		      attrs->c_cflag&CRTSCTS
5975 		      );
5976 		attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */
5977 		debug(F001,
5978 		      "tthflow after forcing off attrs CRTSCTS",
5979 		      "",
5980 		      attrs->c_cflag&CRTSCTS
5981 		      );
5982 		}
5983 	} else {			/* Turn hard flow on */
5984 	    if (
5985 #ifdef COMMENT
5986 		/* This can fail because of sign extension */
5987 		(temp.c_cflag & CRTSCTS) != CRTSCTS
5988 #else
5989 		(temp.c_cflag & CRTSCTS) == 0
5990 #endif /* COMMENT */
5991 		) {
5992 		temp.c_cflag |= CRTSCTS; /* Not there, add it */
5993 		temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
5994 		x = tcsetattr(ttyfd,TCSANOW,&temp);
5995 		debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
5996 		      ckitoa(x),errno);
5997 		attrs->c_cflag |= CRTSCTS;
5998 		attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
5999 	    }
6000 	}
6001     }
6002 #else
6003 #ifdef SUNOS4
6004 /*
6005   SunOS 4.0 (and maybe earlier?).  This code is dangerous because it
6006   prevents compilation with GNU gcc, which uses different formats for the
6007   _IORxxx macros than regular cc.  SunOS 4.1 and later can use the POSIX
6008   routines above, which work for both cc and gcc.
6009 */
6010 #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
6011 #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
6012 #define CRTSCTS 0x80000000		  /* RTS/CTS flow control */
6013 
6014     struct termios {
6015 	unsigned long c_iflag;		/* Input modes */
6016 	unsigned long c_oflag;		/* Output modes */
6017 	unsigned long c_cflag;		/* Control modes */
6018 	unsigned long c_lflag;		/* Line discipline modes */
6019 	char c_line;
6020 	CHAR c_cc[17];
6021     };
6022     struct termios temp;
6023 #ifdef NETCMD
6024     if (ttpipe) return(0);
6025 #endif /* NETCMD */
6026 #ifdef NETPTY
6027     if (ttpty) return(0);
6028 #endif /* NETPTY */
6029     debug(F101,"tthflow entry status","",status);
6030     if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
6031 	if (status) {			/* Turn hard flow on */
6032 	    temp.c_cflag |= CRTSCTS;	/* Add RTS/CTS to them. */
6033 	    x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
6034 	    attrs->c_cflag |= CRTSCTS;	/* Add to global info. */
6035 	} else {			/* Turn hard flow off */
6036 	    temp.c_cflag &= ~CRTSCTS;
6037 	    x = ioctl(ttyfd,TCSETS,&temp);
6038 	    attrs->c_cflag &= ~CRTSCTS;
6039 	}
6040     }
6041 #else					/* Not SunOS 4.0 or later */
6042 #ifdef AIXRS				/* IBM AIX RS/6000 */
6043 #ifndef AIX41				/* But only pre-4.x == SVR4 */
6044 #ifdef NETCMD
6045     if (ttpipe) return(0);
6046 #endif /* NETCMD */
6047 #ifdef NETPTY
6048     if (ttpty) return(0);
6049 #endif /* NETPTY */
6050     if (status) {
6051 	if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
6052 	  debug(F100,"hardflow TXADDCD (rts) error", "", 0);
6053     } else {
6054 	if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
6055 	  debug(F100,"hardflow TXDELCD (rts) error", "", 0);
6056     }
6057 #endif /* AIX41 */
6058 #else					/* Not AIX RS/6000 */
6059 
6060 #ifdef ATTSV				/* System V... */
6061 
6062 #ifdef CK_SCOV5				/* SCO Open Server 5.0 */
6063 #define CK_SCOUNIX
6064 #else
6065 #ifdef M_UNIX				/* SCO UNIX 3.2v4.x or earlier */
6066 #define CK_SCOUNIX
6067 #endif /* M_UNIX */
6068 #endif /* CK_SCOV5 */
6069 
6070 #ifdef SCO_FORCE_RTSXOFF
6071 #ifdef CK_SCOUNIX			/* But not SCO OpenServer 5.0.4 */
6072 #ifdef SCO_OSR504			/* or later... */
6073 #undef CK_SCOUNIX
6074 #endif /* SCO_OSR504 */
6075 #endif /* CK_SCOUNIX */
6076 #endif /* SCO_FORCE_RTSXOFF */
6077 
6078 #ifdef CK_SCOUNIX
6079 #ifdef POSIX
6080     struct termios temp;
6081 #ifdef NETCMD
6082     if (ttpipe) return(0);
6083 #endif /* NETCMD */
6084 #ifdef NETPTY
6085     if (ttpty) return(0);
6086 #endif /* NETPTY */
6087     debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
6088     errno = 0;
6089     x = tcgetattr(ttyfd, &temp);
6090     debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
6091 #else /* POSIX */
6092     struct termio temp;
6093 #ifdef NETCMD
6094     if (ttpipe) return(0);
6095 #endif /* NETCMD */
6096 #ifdef NETPTY
6097     if (ttpty) return(0);
6098 #endif /* NETPTY */
6099     debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
6100     x = ioctl(ttyfd, TCGETA, &temp);
6101     debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
6102 #endif /* POSIX */
6103 /*
6104   This is not really POSIX, since POSIX does not deal with hardware flow
6105   control, but we are using the POSIX APIs.  In fact, RTSFLOW and CTSFLOW
6106   are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif.  So
6107   let's try forcing their definitions here.
6108 */
6109 #ifndef CTSFLOW
6110 #define CTSFLOW 0020000
6111     debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
6112 #else
6113     debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
6114 #endif /* CTSFLOW */
6115 #ifndef RTSFLOW
6116 #define RTSFLOW 0040000
6117     debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
6118 #else
6119     debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
6120 #endif /* RTSFLOW */
6121 #ifndef ORTSFL
6122 #define ORTSFL 0100000
6123     debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
6124 #else
6125     debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
6126 #endif /* ORTSFL */
6127 
6128     if (x != -1) {
6129 	if (status) {			/* Turn it ON */
6130 	    temp.c_cflag |= RTSFLOW|CTSFLOW;
6131 	    attrs->c_cflag |= RTSFLOW|CTSFLOW;
6132 #ifdef ORTSFL
6133 	    temp.c_cflag &= ~ORTSFL;
6134 	    attrs->c_cflag &= ~ORTSFL;
6135 #endif /* ORTSFL */
6136 	    temp.c_iflag &= ~(IXON|IXOFF|IXANY);
6137 	    attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
6138 	} else {			/* Turn it OFF */
6139 #ifdef ORTSFL
6140 	    temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6141 	    attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6142 #else  /* ORTSFL */
6143 	    temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
6144 	    attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
6145 #endif /* ORTSFL */
6146 	}
6147 #ifdef POSIX
6148 	x = tcsetattr(ttyfd, TCSADRAIN, &temp);
6149 #else
6150 	x = ioctl(ttyfd, TCSETA, &temp);
6151 #endif /* POSIX */
6152 	debug(F101,"tthflow SCO set modes","",x);
6153     }
6154 #else /* Not SCO UNIX */
6155 #ifdef NETCMD
6156     if (ttpipe) return(0);
6157 #endif /* NETCMD */
6158 #ifdef NETPTY
6159     if (ttpty) return(0);
6160 #endif /* NETPTY */
6161     if (!status) {			/* Turn it OFF */
6162 #ifdef RTSXOFF
6163 	debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
6164 	rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
6165 #ifdef TCSETX
6166 	x = ioctl(ttyfd,TCSETX,&rctsx);
6167 	debug(F101,"tthflow ATTSV TCSETX OFF","",x);
6168 #else
6169 	x = -1
6170 	debug(F100,"tthflow TCSETX not defined","",0);
6171 #endif /* TCSETX */
6172 #else
6173 	debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
6174 #endif /* RTSXOFF */
6175 #ifdef DTRXOFF
6176 	debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
6177 	rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6178 	x = ioctl(ttyfd,TCSETX,&rctsx);
6179 	debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
6180 #else
6181 	debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6182 #endif /* DTRXOFF */
6183     } else {				/* Turn it ON. */
6184 	if (flow == FLO_RTSC) {	/* RTS/CTS Flow control... */
6185 	    debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
6186 #ifdef RTSXOFF
6187 	    /* This is the preferred way, according to SVID3 */
6188 #ifdef TCGETX
6189 	    x = ioctl(ttyfd,TCGETX,&rctsx);
6190 	    debug(F101,"tthflow TCGETX","",x);
6191 	    if (x > -1) {
6192 		rctsx.x_hflag |= RTSXOFF | CTSXON;
6193 		x = ioctl(ttyfd,TCSETX,&rctsx);
6194 		debug(F100,"tthflow ATTSV ioctl","",x);
6195 	    }
6196 #else
6197 	    debug(F100,"tthflow TCGETX not defined","",0);
6198 	    x = -1
6199 #endif /* TCGETX */
6200 #else
6201 	    debug(F100,"tthflow RTSXOFF not defined","",0);
6202 	    x = -1;
6203 #endif /* RTSXOFF */
6204 	} else if (flow == FLO_DTRC) {	/* DTR/CD Flow control... */
6205 	    debug(F100,"tthflow ATTSV DTR/CD ON","",0);
6206 #ifdef DTRXOFF
6207 	    /* This is straight out of SVID R4 */
6208 	    if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
6209 		rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6210 		x = ioctl(ttyfd,TCSETX,&rctsx);
6211 	    }
6212 #else
6213 	    debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6214 	    x = -1;
6215 #endif /* DTRXOFF */
6216 	}
6217     }
6218 #endif /* CK_SCOUNIX */
6219 
6220 #else /* not System V... */
6221 
6222 #ifdef CK_DTRCTS
6223 #ifdef LDODTR
6224 #ifdef LDOCTS
6225 #ifdef NETCMD
6226     if (ttpipe) return(0);
6227 #endif /* NETCMD */
6228 #ifdef NETPTY
6229     if (ttpty) return(0);
6230 #endif /* NETPTY */
6231     x = LDODTR | LDOCTS;		/* Found only on UTEK? */
6232     if (flow == FLO_DTRT && status) {	/* Use hardware flow control */
6233 	if (lmodef) {
6234 	    x = ioctl(ttyfd,TIOCLBIS,&x);
6235 	    if (x < 0) {
6236 	        debug(F100,"hardflow TIOCLBIS error","",0);
6237 	    } else {
6238 		lmodef++;
6239 		debug(F100,"hardflow TIOCLBIS ok","",0);
6240 	    }
6241 	}
6242     } else {
6243 	if (lmodef) {
6244 	    x = ioctl(ttyfd,TIOCLBIC,&x);
6245 	    if (x < 0) {
6246 	        debug(F100,"hardflow TIOCLBIC error","",0);
6247 	    } else {
6248 		lmodef++;
6249 		debug(F100,"hardflow TIOCLBIC ok","",0);
6250 	    }
6251 	}
6252     }
6253 #endif /* LDODTR */
6254 #endif /* LDOCTS */
6255 #endif /* CK_DTRCTS */
6256 #endif /* ATTSV */
6257 #endif /* AIXRS */
6258 #endif /* SUNOS4 */
6259 #endif /* QNX */
6260 #endif /* POSIX_CRTSCTS */
6261 #endif /* SUNOS41 */
6262 
6263 #else /* OXOS */
6264 
6265     struct termios temp;		/* Olivetti X/OS ... */
6266 
6267 #ifdef NETCMD
6268     if (ttpipe) return(0);
6269 #endif /* NETCMD */
6270 #ifdef NETPTY
6271     if (ttpty) return(0);
6272 #endif /* NETPTY */
6273     x = ioctl(ttyfd,TCGETS,&temp);
6274     if (x == 0) {
6275 	temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
6276 	if (status) {
6277 	    switch (flow) {
6278 	      case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
6279 		break;
6280 	      case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
6281 		break;
6282 	    }
6283 	}
6284 	x = ioctl(ttyfd,TCSETS,&temp);
6285     }
6286 #endif /* OXOS */
6287     return(x);
6288 
6289 #endif /* Plan9 */
6290 }
6291 
6292 /*  T T P K T  --  Condition the communication line for packets */
6293 /*                 or for modem dialing */
6294 
6295 /*
6296   If called with speed > -1, also set the speed.
6297   Returns 0 on success, -1 on failure.
6298 
6299   NOTE: the "xflow" parameter is supposed to be the currently selected
6300   type of flow control, but for historical reasons, this parameter is also
6301   used to indicate that we are dialing.  Therefore, when the true flow
6302   control setting is needed, we access the external variable "flow", rather
6303   than trusting our "xflow" argument.
6304 */
6305 int
6306 #ifdef CK_ANSIC
ttpkt(long speed,int xflow,int parity)6307 ttpkt(long speed, int xflow, int parity)
6308 #else
6309 ttpkt(speed,xflow,parity) long speed; int xflow, parity;
6310 #endif /* CK_ANSIC */
6311 /* ttpkt */ {
6312 #ifndef NOLOCAL
6313     int s2;
6314     int s = -1;
6315 #endif /* NOLOCAL */
6316     int x;
6317     extern int flow;			/* REAL flow-control setting */
6318 
6319     if (ttyfd < 0) return(-1);          /* Not open. */
6320 
6321     debug(F101,"ttpkt parity","",parity);
6322     debug(F101,"ttpkt xflow","",xflow);
6323     debug(F101,"ttpkt speed","",(int) speed);
6324 
6325     ttprty = parity;                    /* Let other tt functions see these. */
6326     ttspeed = speed;			/* Make global copy for this module */
6327     ttpmsk = ttprty ? 0177 : 0377;	/* Parity stripping mask */
6328 #ifdef PARSENSE
6329     needpchk = ttprty ? 0 : 1;		/* Parity check needed? */
6330 #else
6331     needpchk = 0;
6332 #endif /* PARSENSE */
6333 
6334     debug(F101,"ttpkt ttpmsk","",ttpmsk);
6335     debug(F101,"ttpkt netconn","",netconn);
6336 
6337 #ifdef NETCONN				/* No mode-changing for telnet */
6338     if (netconn) {
6339 #ifdef TCPSOCKET
6340 #ifdef TCP_NODELAY
6341         if (ttnet == NET_TCPB) {	/* But turn off Nagle */
6342             extern int tcp_nodelay;
6343             nodelay_sav = tcp_nodelay;
6344             no_delay(ttyfd,1);
6345         }
6346 #endif /* TCP_NODELAY */
6347 #ifdef TN_COMPORT
6348         if (istncomport()) {
6349             int rc = -1;
6350             if (tvtflg == 0 && speed == ttspeed && flow == ttflow
6351                  /* && ttcarr == curcarr */ ) {
6352                 debug(F100,"ttpkt modes already set, skipping...","",0);
6353                 return(0);		/* Already been called. */
6354             }
6355             if (flow != ttflow) {
6356                 if ((rc = tnsetflow(flow)) < 0)
6357 		  return(rc);
6358                 ttflow = flow;
6359             }
6360             if (speed != ttspeed) {
6361                 if (speed <= 0)
6362 		  speed = tnc_get_baud();
6363                 else if ((rc = tnc_set_baud(speed)) < 0)
6364 		  return(rc);
6365                 ttspeed = speed;
6366             }
6367             tnc_set_datasize(8);
6368 	    tnc_set_stopsize(stopbits);
6369 
6370 #ifdef HWPARITY
6371             if (hwparity) {
6372                 switch (hwparity) {
6373 		  case 'e':			/* Even */
6374                     debug(F100,"ttres 8 bits + even parity","",0);
6375                     tnc_set_parity(3);
6376                     break;
6377 		  case 'o':			/* Odd */
6378                     debug(F100,"ttres 8 bits + odd parity","",0);
6379                     tnc_set_parity(2);
6380                     break;
6381 		  case 'm':			/* Mark */
6382                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
6383                     tnc_set_parity(4);
6384                     break;
6385 		  case 's':			/* Space */
6386                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
6387                     tnc_set_parity(5);
6388                     break;
6389                 }
6390             } else
6391 #endif /* HWPARITY */
6392 	    {
6393                 tnc_set_parity(1);              /* None */
6394             }
6395             tvtflg = 0;
6396             return(0);
6397         }
6398 #endif /* TN_COMPORT */
6399 #endif /* TCPSOCKET */
6400         tvtflg = 0;
6401         return(0);
6402     }
6403 #endif /* NETCONN */
6404 #ifdef NETCMD
6405     if (ttpipe) return(0);
6406 #endif /* NETCMD */
6407 #ifdef NETPTY
6408     if (ttpty) return(0);
6409 #endif /* NETPTY */
6410 
6411 #ifndef Plan9
6412     if (ttfdflg && !isatty(ttyfd)) return(0);
6413 #endif /* Plan9 */
6414 
6415 #ifdef COHERENT
6416 #define SVORPOSIX
6417 #endif /* COHERENT */
6418 
6419 #ifndef SVORPOSIX			/* Berkeley, V7, etc. */
6420 #ifdef LPASS8
6421 /*
6422  For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
6423  after having previously set it to NONE without closing and reopening the
6424  device.  Unless there's something I overlooked below...
6425 */
6426     if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
6427 	debug(F101,"ttpkt executing horrible flow kludge","",0);
6428 	ttclos(0);			/* Close it */
6429 	x = 0;
6430 	ttopen(ttnmsv,&x,ttmdm,0);	/* Open it again */
6431     }
6432 #endif /* LPASS8 */
6433 #endif /* SVORPOSIX */
6434 
6435 #ifdef COHERENT				/* This must be vestigial since we */
6436 #undef SVORPOSIX			/* reverse it a few lines below... */
6437 #endif /* COHERENT */
6438 
6439     if (xflow != FLO_DIAL && xflow != FLO_DIAX)
6440       ttflow = xflow;			/* Now make this available too. */
6441 
6442 #ifndef NOLOCAL
6443     if (xlocal) {
6444 	s2 = (int) (speed / 10L);	/* Convert bps to cps */
6445 	debug(F101,"ttpkt calling ttsspd","",s2);
6446 	s = ttsspd(s2);			/* Check and set the speed */
6447 	debug(F101,"ttpkt ttsspd result","",s);
6448  	carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
6449 		&& (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
6450 	tvtflg = 0;			/* So ttvt() will work next time */
6451     }
6452 #endif /* NOLOCAL */
6453 
6454 #ifdef COHERENT
6455 #define SVORPOSIX
6456 #endif /* COHERENT */
6457 
6458 #ifndef SVORPOSIX			/* BSD section */
6459     if (flow == FLO_RTSC ||		/* Hardware flow control */
6460 	flow == FLO_DTRC ||
6461 	flow == FLO_DTRT) {
6462 	tthflow(flow, 1, &ttraw);
6463 	debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
6464 	ttraw.sg_flags &= ~TANDEM;	/* Turn off software flow control */
6465 	ttraw.sg_flags |= RAW;		/* Enter raw mode */
6466     } else if (flow == FLO_NONE) {	/* No flow control */
6467 	debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
6468 	ttraw.sg_flags &= ~TANDEM;	/* Turn off software flow control */
6469 	tthflow(flow, 0, &ttraw);	/* Turn off any hardware f/c too */
6470 	ttraw.sg_flags |= RAW;		/* Enter raw mode */
6471     } else if (flow == FLO_KEEP) {	/* Keep device's original setting */
6472 	debug(F100,"ttpkt keeping original TANDEM","",0);
6473 	ttraw.sg_flags &= ~TANDEM;
6474 	ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
6475 	/* NOTE: We should also handle hardware flow control here! */
6476     }
6477 
6478 /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
6479 
6480     if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
6481 	debug(F100,"ttpkt turning on TANDEM","",0);
6482 	ttraw.sg_flags |= TANDEM;	/* So ask for it. */
6483 
6484 #ifdef LPASS8				/* Can pass 8-bit data through? */
6485 /* If the LPASS8 local mode is available, then flow control can always  */
6486 /* be used, even if parity is none and we are transferring 8-bit data.  */
6487 /* But we only need to do all this if Xon/Xoff is requested. */
6488 /* BUT... this tends not to work through IP or LAT connections, terminal */
6489 /* servers, telnet, rlogin, etc, so it is currently disabled. */
6490 	x = LPASS8;			/* If LPASS8 defined, then */
6491 	debug(F100,"ttpkt executing LPASS8 code","",0);
6492 	if (lmodef) {			/* TIOCLBIS must be too. */
6493 	    x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
6494 	    if (x < 0) {
6495 		debug(F100,"ttpkt TIOCLBIS error","",0);
6496 	    } else {
6497 		lmodef++;
6498 		debug(F100,"ttpkt TIOCLBIS ok","",0);
6499 	    }
6500 	}
6501 /*
6502  But if we use LPASS8 mode, we must explicitly turn off
6503  terminal interrupts of all kinds.
6504 */
6505 #ifdef TIOCGETC				/* Not rawmode, */
6506 	if (tcharf && (xlocal == 0)) {	/* must turn off */
6507 	    tchnoi.t_intrc = -1;	/* interrupt character */
6508 	    tchnoi.t_quitc = -1;	/* and quit character. */
6509 	    tchnoi.t_startc = 17;	/* Make sure xon */
6510 	    tchnoi.t_stopc = 19;	/* and xoff not ignored. */
6511 #ifndef NOBRKC
6512 	    tchnoi.t_eofc = -1;		/* eof character. */
6513 	    tchnoi.t_brkc = -1;		/* brk character. */
6514 #endif /* NOBRKC */
6515 	    if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6516 		debug(F100,"ttpkt TIOCSETC failed","",0);
6517 	    } else {
6518 		tcharf = 1;
6519 		debug(F100,"ttpkt TIOCSETC ok","",0);
6520 	    }
6521 #ifdef COMMENT
6522 /* only for paranoid debugging */
6523 	    if (tcharf) {
6524 		struct tchars foo;
6525 		char tchbuf[100];
6526 		ioctl(0,TIOCGETC,&foo);
6527 		sprintf(tchbuf,
6528 		    "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
6529 		    foo.t_intrc, foo.t_quitc, foo.t_startc,
6530 		    foo.t_stopc, foo.t_eofc,  foo.t_brkc);
6531 		debug(F110,"ttpkt chars",tchbuf,0);
6532 	    }
6533 #endif /* COMMENT */
6534 	}
6535 	ttraw.sg_flags |= CBREAK;	/* Needed for unknown reason */
6536 #endif /* TIOCGETC */
6537 
6538 /* Prevent suspend during packet mode */
6539 #ifdef TIOCGLTC				/* Not rawmode, */
6540 	if (ltcharf && (xlocal == 0)) {	/* must turn off */
6541 	    ltchnoi.t_suspc = -1;	/* suspend character */
6542 	    ltchnoi.t_dsuspc = -1;	/* and delayed suspend character */
6543 	    if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6544 		debug(F100,"ttpkt TIOCSLTC failed","",0);
6545 	    } else {
6546 		ltcharf = 1;
6547 		debug(F100,"ttpkt TIOCSLTC ok","",0);
6548 	    }
6549 	}
6550 #endif /* TIOCGLTC */
6551 
6552 #else /* LPASS8 not defined */
6553 
6554 /* Previously, BSD-based implementations always */
6555 /* used rawmode for packets.  Now, we use rawmode only if parity is NONE. */
6556 /* This allows the flow control requested above to actually work, but only */
6557 /* if the user asks for parity (which also means they get 8th-bit quoting). */
6558 
6559 	if (parity) {			/* If parity, */
6560 	    ttraw.sg_flags &= ~RAW;	/* use cooked mode */
6561 #ifdef COMMENT
6562 /* WHY??? */
6563 	    if (xlocal)
6564 #endif /* COMMENT */
6565 	      ttraw.sg_flags |= CBREAK;
6566 	    debug(F101,"ttpkt cooked, cbreak, parity","",parity);
6567 #ifdef TIOCGETC				/* Not rawmode, */
6568 	    if (tcharf && (xlocal == 0)) { /* must turn off */
6569 		tchnoi.t_intrc = -1;	/* interrupt character */
6570 		tchnoi.t_quitc = -1;	/* and quit character. */
6571 		tchnoi.t_startc = 17;	/* Make sure xon */
6572 		tchnoi.t_stopc = 19;	/* and xoff not ignored. */
6573 #ifndef NOBRKC
6574 		tchnoi.t_eofc = -1;	/* eof character. */
6575 		tchnoi.t_brkc = -1;	/* brk character. */
6576 #endif /* NOBRKC */
6577 		if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6578 		    debug(F100,"ttpkt TIOCSETC failed","",0);
6579 		} else {
6580 		    tcharf = 1;
6581 		    debug(F100,"ttpkt TIOCSETC ok","",0);
6582 		}
6583 	    }
6584 #endif /* TIOCGETC */
6585 #ifdef TIOCGLTC				/* Not rawmode, */
6586 /* Prevent suspend during packet mode */
6587 	    if (ltcharf && (xlocal == 0)) { /* must turn off */
6588 		ltchnoi.t_suspc = -1;	/* suspend character */
6589 		ltchnoi.t_dsuspc = -1;	/* and delayed suspend character */
6590 		if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6591 		    debug(F100,"ttpkt TIOCSLTC failed","",0);
6592 		} else {
6593 		    ltcharf = 1;
6594 		    debug(F100,"ttpkt TIOCSLTC ok","",0);
6595 		}
6596 	    }
6597 #endif /* TIOCGLTC */
6598 	} else {			/* If no parity, */
6599 	    ttraw.sg_flags |= RAW;	/* must use 8-bit raw mode. */
6600 	    debug(F101,"ttpkt setting rawmode, parity","",parity);
6601 	}
6602 #endif /* LPASS8 */
6603     } /* End of Xon/Xoff section */
6604 
6605     /* Don't echo, don't map CR to CRLF on output, don't fool with case */
6606 #ifdef LCASE
6607     ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
6608 #else
6609     ttraw.sg_flags &= ~(ECHO|CRMOD);
6610 #endif /* LCASE */
6611 
6612 #ifdef TOWER1
6613     ttraw.sg_flags &= ~ANYP;            /* Must set this on old Towers */
6614 #endif /* TOWER1 */
6615 
6616 #ifdef BELLV10
6617     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
6618       return(-1);
6619 #else
6620     errno = 0;
6621     if (stty(ttyfd,&ttraw) < 0) {       /* Set the new modes. */
6622         debug(F101,"ttpkt stty failed","",errno);
6623         return(-1);
6624     }
6625 #endif /* BELLV10 */
6626     debug(F100,"ttpkt stty ok","",0);
6627 
6628 #ifdef sony_news
6629     x = xlocal ? km_ext : km_con;	/* Put line in ASCII mode. */
6630     if (x != -1) {			/* Make sure we know original modes. */
6631 	x &= ~KM_TTYPE;
6632 	x |= KM_ASCII;
6633 	if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
6634 	    perror("ttpkt can't set ASCII mode");
6635 	    debug(F101,"ttpkt error setting ASCII mode","",x);
6636 	    return(-1);
6637 	}
6638     }
6639     debug(F100,"ttpkt set ASCII mode ok","",0);
6640 #endif /* sony_news */
6641 
6642     if (xlocal == 0) {			/* Turn this off so we can read */
6643 	signal(SIGINT,SIG_IGN);		/* Ctrl-C chars typed at console */
6644 	sigint_ign = 1;
6645     }
6646     tvtflg = 0;				/* So ttvt() will work next time */
6647     debug(F100,"ttpkt success","",0);
6648     return(0);
6649 
6650 #endif /* Not ATTSV or POSIX */
6651 
6652 /* AT&T UNIX and POSIX */
6653 
6654 #ifdef COHERENT
6655 #define SVORPOSIX
6656 #endif /* COHERENT */
6657 
6658 #ifdef SVORPOSIX
6659     if (flow == FLO_XONX) {		/* Xon/Xoff */
6660 	ttraw.c_iflag |= (IXON|IXOFF);
6661 	tthflow(flow, 0, &ttraw);
6662     } else if (flow == FLO_NONE) {	/* None */
6663 	/* NOTE: We should also turn off hardware flow control here! */
6664 	ttraw.c_iflag &= ~(IXON|IXOFF);
6665 	tthflow(flow, 0, &ttraw);
6666     } else if (flow == FLO_KEEP) {	/* Keep */
6667 	ttraw.c_iflag &= ~(IXON|IXOFF);	/* Turn off Xon/Xoff flags */
6668 	ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
6669 	/* NOTE: We should also handle hardware flow control here! */
6670 #ifdef POSIX_CRTSCTS
6671 /* In Linux case, we do this, which is unlikely to be portable */
6672         ttraw.c_cflag &= ~CRTSCTS;	/* Turn off RTS/CTS flag */
6673         ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
6674 #endif /* POSIX_CRTSCTS */
6675     } else if (flow == FLO_RTSC ||	/* Hardware */
6676 	       flow == FLO_DTRC ||
6677 	       flow == FLO_DTRT) {
6678 	ttraw.c_iflag &= ~(IXON|IXOFF);	/* (190) */
6679 	tthflow(flow, 1, &ttraw);
6680     }
6681     ttraw.c_lflag &= ~(ICANON|ECHO);
6682     ttraw.c_lflag &= ~ISIG;		/* Do NOT check for interrupt chars */
6683 
6684 #ifndef OXOS
6685 #ifdef QNX
6686     if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
6687 #endif /* QNX */
6688 #ifndef COHERENT
6689       ttraw.c_lflag &= ~IEXTEN;		/* Turn off ^O/^V processing */
6690 #endif /* COHERENT */
6691 #else /* OXOS */
6692     ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
6693 #endif /* OXOS */
6694     ttraw.c_lflag |= NOFLSH;		/* Don't flush */
6695     ttraw.c_iflag |= IGNPAR;		/* Ignore parity errors */
6696 #ifdef ATTSV
6697 #ifdef BSD44
6698     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
6699 #else
6700     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
6701 #endif /* BSD44 */
6702 #else /* POSIX */
6703     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
6704 #endif /* ATTSV */
6705     ttraw.c_oflag &= ~OPOST;
6706     ttraw.c_cflag &= ~(CSIZE);
6707     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
6708 
6709 #ifdef CSTOPB
6710     if (xlocal) {
6711 	if (stopbits == 2) {
6712 	    ttraw.c_cflag |= CSTOPB;	/* 2 stop bits */
6713 	    debug(F100,"ttpkt 2 stopbits","",0);
6714 	} else if (stopbits == 1) {
6715 	    ttraw.c_cflag &= ~(CSTOPB);	/* 1 stop bit */
6716 	    debug(F100,"ttpkt 1 stopbit","",0);
6717 	}
6718     }
6719 #endif /* CSTOPB */
6720 
6721 #ifdef HWPARITY
6722     if (hwparity && xlocal) {		/* Hardware parity */
6723 	ttraw.c_cflag |= PARENB;	/* Enable parity */
6724 #ifdef COMMENT
6725 /* Uncomment this only if needed -- I don't think it is */
6726 	ttraw.c_cflag &= ~(CSIZE);	/* Clear out character-size mask */
6727 	ttraw.c_cflag |= CS8;		/* And set it to 8 */
6728 #endif /* COMMENT */
6729 #ifdef IGNPAR
6730 	ttraw.c_iflag |= IGNPAR;	/* Don't discard incoming bytes */
6731 	debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
6732 #endif /* IGNPAR */
6733 	switch (hwparity) {
6734 	  case 'e':			/* Even */
6735 	    ttraw.c_cflag &= ~(PARODD);
6736 	    debug(F100,"ttpkt 8 bits + even parity","",0);
6737 	    break;
6738 	  case 'o':			/* Odd */
6739 	    ttraw.c_cflag |= PARODD;
6740 	    debug(F100,"ttpkt 8 bits + odd parity","",0);
6741 	    break;
6742 	  case 'm':			/* Mark */
6743 	  case 's':			/* Space */
6744 	    /* PAREXT is mentioned in SVID but the details are not given. */
6745 	    /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
6746 	    debug(F100,"ttpkt 8 bits + invalid parity","",0);
6747 	    break;
6748 	}
6749     } else {				/* We handle parity ourselves */
6750 #endif /* HWPARITY */
6751 	ttraw.c_cflag &= ~(PARENB);	/* Don't enable parity */
6752 #ifdef HWPARITY
6753     }
6754 #endif /* HWPARITY */
6755 
6756 #ifdef IX370
6757     ttraw.c_cc[4] = 48;  /* So Series/1 doesn't interrupt on every char */
6758     ttraw.c_cc[5] = 1;
6759 #else
6760 #ifndef VEOF				/* for DGUX this is VEOF, not VMIN */
6761     ttraw.c_cc[4] = 1;   /* [VMIN]  return max of this many characters or */
6762 #else
6763 #ifndef OXOS
6764 #ifdef VMIN
6765     ttraw.c_cc[VMIN] = 1;
6766 #endif /* VMIN */
6767 #else /* OXOS */
6768     ttraw.c_min = 1;
6769 #endif /* OXOS */
6770 #endif /* VEOF */
6771 #ifndef VEOL				/* for DGUX this is VEOL, not VTIME */
6772     ttraw.c_cc[5] = 0;	 /* [VTIME] when this many secs/10 expire w/no input */
6773 #else
6774 #ifndef OXOS
6775 #ifdef VTIME
6776     ttraw.c_cc[VTIME] = 0;
6777 #endif /* VTIME */
6778 #else /* OXOS */
6779     ttraw.c_time = 0;
6780 #endif /* OXOS */
6781 #endif /* VEOL */
6782 #endif /* IX370 */
6783 
6784 #ifdef VINTR				/* Turn off interrupt character */
6785     if (xlocal == 0)			/* so ^C^C can break us out of */
6786       ttraw.c_cc[VINTR] = 0;		/* packet mode. */
6787 #endif /* VINTR */
6788 
6789 #ifdef Plan9
6790     if (p9ttyparity('n') < 0)
6791 	return -1;
6792 #else
6793 #ifdef BSD44ORPOSIX
6794     errno = 0;
6795 #ifdef BEOSORBEBOX
6796     ttraw.c_cc[VMIN] = 0;		/* DR7 can only poll. */
6797 #endif /* BEOSORBEBOX */
6798 
6799 #define TESTING234
6800 #ifdef TESTING234
6801     if (1) {
6802 	debug(F100,"ttpkt TESTING234 rawmode","",0);
6803 
6804 	/* iflags */
6805 	ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
6806 	ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF);
6807 	ttraw.c_iflag |= IGNBRK;
6808 #ifdef IMAXBEL
6809 	ttraw.c_iflag &= ~IMAXBEL;
6810 #endif	/* IMAXBEL */
6811 #ifdef IXANY
6812 	ttraw.c_iflag &= ~IXANY;
6813 #endif	/* IXANY */
6814 #ifdef IUCLC
6815 	ttraw.c_iflag &= ~IUCLC;
6816 #endif /* IUCLC */
6817 
6818 	/* oflags */
6819 	ttraw.c_oflag &= ~OPOST;
6820 #ifdef OXTABS
6821 	ttraw.c_oflag &= ~OXTABS;
6822 #endif /* OXTABS */
6823 #ifdef ONOCR
6824 	ttraw.c_oflag &= ~ONOCR;
6825 #endif /* ONOCR */
6826 #ifdef ONLRET
6827 	ttraw.c_oflag &= ~ONLRET;
6828 #endif /* ONLRET */
6829 #ifdef ONLCR
6830 	ttraw.c_oflag &= ~ONLCR;
6831 #endif /* ONLCR */
6832 
6833 	/* lflags */
6834 	ttraw.c_lflag &= ~ECHO;
6835 #ifdef ECHOE
6836 	ttraw.c_lflag &= ~ECHOE;
6837 #endif /* ECHOE */
6838 #ifdef ECHONL
6839 	ttraw.c_lflag &= ~ECHONL;
6840 #endif /* ECHONL */
6841 #ifdef ECHOPRT
6842 	ttraw.c_lflag &= ~ECHOPRT;
6843 #endif /* ECHOPRT */
6844 #ifdef ECHOKE
6845 	ttraw.c_lflag &= ~ECHOKE;
6846 #endif /* ECHOKE */
6847 #ifdef ECHOCTL
6848 	ttraw.c_lflag &= ~ECHOCTL;
6849 #endif /* ECHOCTL */
6850 #ifdef ALTWERASE
6851 	ttraw.c_lflag &= ~ALTWERASE;
6852 #endif /* ALTWERASE */
6853 #ifdef EXTPROC
6854 	ttraw.c_lflag &= ~EXTPROC;
6855 #endif /* EXTPROC */
6856 	ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
6857 #ifdef NOKERNINFO
6858 	ttraw.c_lflag |= NOKERNINFO;
6859 #endif	/* NOKERNINFO */
6860 	/* ttraw.c_lflag |= NOFLSH; */
6861 	ttraw.c_lflag &= ~NOFLSH;
6862 
6863 	/* cflags */
6864 	ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD);
6865 	ttraw.c_cflag |= CS8|CREAD;
6866 #ifdef VMIN
6867 	ttraw.c_cc[VMIN] = 1;		/* Supposedly needed for AIX */
6868 #endif	/* VMIN */
6869 
6870     }
6871 #endif /* TESTING234 */
6872 
6873     debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
6874     x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
6875     debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
6876     if (x < 0) {
6877 	debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
6878         return(-1);
6879     }
6880 #else /* BSD44ORPOSIX */
6881     x = ioctl(ttyfd,TCSETAW,&ttraw);
6882     debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
6883     if (x < 0) {  /* set new modes . */
6884 	debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
6885         return(-1);
6886     }
6887 #endif /* BSD44ORPOSIX */
6888 #endif /* Plan9 */
6889     tvtflg = 0;
6890     debug(F100,"ttpkt ok","",0);
6891     return(0);
6892 #endif /* ATTSV */
6893 
6894 #ifdef COHERENT
6895 #undef SVORPOSIX
6896 #endif /* COHERENT */
6897 
6898 }
6899 
6900 /*  T T S E T F L O W  --  Set flow control immediately.  */
6901 
6902 #ifdef COHERENT
6903 #define SVORPOSIX
6904 #endif /* COHERENT */
6905 
6906 int
ttsetflow(flow)6907 ttsetflow(flow) int flow; {
6908     if (ttyfd < 0)			/* A channel must be open */
6909       return(-1);
6910 
6911     debug(F101,"ttsetflow flow","",flow);
6912 
6913 #ifdef TN_COMPORT
6914     if (netconn && istncomport()) {
6915 	debug(F101,"ttsetflow net modem","",ttmdm);
6916 	return(tnsetflow(flow));
6917     }
6918 #endif /* TN_COMPORT */
6919 #ifdef NETCMD
6920     if (ttpipe) return(0);
6921 #endif /* NETCMD */
6922 #ifdef NETPTY
6923     if (ttpty) return(0);
6924 #endif /* NETPTY */
6925 
6926 #ifdef COMMENT
6927     /* This seems to hurt... */
6928     if (flow == FLO_KEEP)
6929       return(0);
6930 #endif /* COMMENT */
6931 
6932     if (flow == FLO_RTSC ||		/* Hardware flow control... */
6933 	flow == FLO_DTRC ||
6934 	flow == FLO_DTRT) {
6935 	tthflow(flow, 1, &ttraw);
6936 #ifndef SVORPOSIX
6937 	ttraw.sg_flags &= ~TANDEM;	/* Turn off software flow control */
6938 #else
6939 	ttraw.c_iflag &= ~(IXON|IXOFF);
6940 #endif /* SVORPOSIX */
6941 
6942     } else if (flow == FLO_XONX) {	/* Xon/Xoff... */
6943 
6944 #ifndef SVORPOSIX
6945 	ttraw.sg_flags |= TANDEM;
6946 #else
6947 	ttraw.c_iflag |= (IXON|IXOFF);
6948 #endif /* SVORPOSIX */
6949 	tthflow(FLO_RTSC, 0, &ttraw);	/* Turn off hardware flow control */
6950 
6951     } else if (flow == FLO_NONE) {	/* No flow control */
6952 
6953 #ifndef SVORPOSIX
6954 	ttraw.sg_flags &= ~TANDEM;	/* Turn off software flow control */
6955 #else
6956 	ttraw.c_iflag &= ~(IXON|IXOFF);
6957 #endif /* SVORPOSIX */
6958 	tthflow(FLO_RTSC, 0, &ttraw);	/* Turn off any hardware f/c too */
6959     }
6960 
6961 /* Set the new modes... */
6962 
6963 #ifndef SVORPOSIX			/* BSD and friends */
6964 #ifdef BELLV10
6965     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
6966       return(-1);
6967 #else
6968 #ifndef MINIX2
6969     if (stty(ttyfd,&ttraw) < 0)
6970       return(-1);
6971 #endif /* MINIX2 */
6972 #endif /* BELLV10 */
6973 #else
6974 #ifdef BSD44ORPOSIX			/* POSIX */
6975     if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
6976       return(-1);
6977 #else					/* System V */
6978     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
6979       return(-1);
6980 #endif /* BSD44ORPOSIX */
6981 #endif /* SVORPOSIX */
6982     return(0);
6983 }
6984 #ifdef COHERENT
6985 #undef SVORPOSIX
6986 #endif /* COHERENT */
6987 
6988 /*  T T V T -- Condition communication device for use as virtual terminal. */
6989 
6990 int
6991 #ifdef CK_ANSIC
ttvt(long speed,int flow)6992 ttvt(long speed, int flow)
6993 #else
6994 ttvt(speed,flow) long speed; int flow;
6995 #endif /* CK_ANSIC */
6996 /* ttvt */ {
6997     int s, s2, x;
6998 
6999     debug(F101,"ttvt ttyfd","",ttyfd);
7000     debug(F101,"ttvt tvtflg","",tvtflg);
7001     debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
7002     debug(F111,"ttvt flow",ckitoa(ttflow),flow);
7003     debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
7004 
7005 /* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
7006 /* Maybe it would be simpler to use it... */
7007 
7008     ttpmsk = 0xff;
7009 #ifdef NOLOCAL
7010     return(conbin((char)escchr));
7011 #else
7012     if (ttyfd < 0) {			/* Not open. */
7013 	if (ttchk() < 0)
7014 	  return(-1);
7015 	else				/* But maybe something buffered. */
7016 	  return(0);
7017     }
7018 #ifdef NETCMD
7019     if (ttpipe) return(0);
7020 #endif /* NETCMD */
7021 #ifdef NETPTY
7022     if (ttpty) return(0);
7023 #endif /* NETPTY */
7024 #ifdef NETCONN
7025     if (netconn) {
7026 #ifdef TCPSOCKET
7027 #ifdef TCP_NODELAY
7028         {
7029 	    extern int tcp_nodelay;
7030 	    if (ttnet == NET_TCPB) {
7031 		if (nodelay_sav > -1) {
7032 		    no_delay(ttyfd,nodelay_sav);
7033 		    nodelay_sav = -1;
7034 		}
7035 	    }
7036         }
7037 #endif /* TCP_NODELAY */
7038 #ifdef TN_COMPORT
7039         if (istncomport()) {
7040             int rc = -1;
7041             if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7042                  /* && ttcarr == curcarr */ ) {
7043                 debug(F100,"ttvt modes already set, skipping...","",0);
7044                 return(0);			/* Already been called. */
7045             }
7046             if (flow != ttflow) {
7047                 if ((rc = tnsetflow(flow)) < 0)
7048 		  return(rc);
7049                 ttflow = flow;
7050             }
7051             if (speed != ttspeed) {
7052                 if (speed <= 0)
7053 		  speed = tnc_get_baud();
7054                 else if ((rc = tnc_set_baud(speed)) < 0)
7055 		  return(rc);
7056                 ttspeed = speed;
7057             }
7058             tnc_set_datasize(8);
7059 	    tnc_set_stopsize(stopbits);
7060 
7061 #ifdef HWPARITY
7062             if (hwparity) {
7063                 switch (hwparity) {
7064 		  case 'e':		/* Even */
7065                     debug(F100,"ttres 8 bits + even parity","",0);
7066                     tnc_set_parity(3);
7067                     break;
7068 		  case 'o':		/* Odd */
7069                     debug(F100,"ttres 8 bits + odd parity","",0);
7070                     tnc_set_parity(2);
7071                     break;
7072 		  case 'm':		/* Mark */
7073                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
7074                     tnc_set_parity(4);
7075                     break;
7076 		  case 's':		/* Space */
7077                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
7078                     tnc_set_parity(5);
7079                     break;
7080                 }
7081             } else
7082 #endif /* HWPARITY */
7083             {
7084                 tnc_set_parity(1);	/* None */
7085             }
7086             tvtflg = 1;
7087             return(0);
7088         }
7089 #endif /* TN_COMPORT */
7090 #endif /* TCPSOCKET */
7091 	tvtflg = 1;			/* Network connections... */
7092 	debug(F100,"ttvt network connection, skipping...","",0);
7093 	return(0);			/* ... require no special setup */
7094     }
7095 #endif /* NETCONN */
7096 
7097     if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7098 	/* && ttcarr == curcarr */ )
7099       {
7100 	  debug(F100,"ttvt modes already set, skipping...","",0);
7101 	  return(0);			/* Already been called. */
7102       }
7103 
7104     if (ttfdflg
7105 #ifndef Plan9
7106 	&& !isatty(ttyfd)
7107 #endif /* Plan9 */
7108 	) {
7109 	debug(F100,"ttvt using external fd, skipping...","",0);
7110 	return(0);
7111     }
7112 
7113     debug(F100,"ttvt setting modes...","",0);
7114 
7115     if (xlocal) {			/* For external lines... */
7116 	s2 = (int) (speed / 10L);
7117 	s = ttsspd(s2);			/* Check/set the speed */
7118 	carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
7119 		&& (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
7120     } else
7121       s = s2 = -1;
7122 
7123 #ifdef COHERENT
7124 #define SVORPOSIX
7125 #endif /* COHERENT */
7126 
7127 #ifndef SVORPOSIX
7128     /* Berkeley, V7, etc */
7129     if (flow == FLO_RTSC ||		/* Hardware flow control */
7130 	flow == FLO_DTRC ||
7131 	flow == FLO_DTRT) {
7132 	tthflow(flow, 1, &tttvt);
7133 	debug(F100,"ttvt hard flow, TANDEM off","",0);
7134 	tttvt.sg_flags &= ~TANDEM;	/* Turn off software flow control */
7135     } else if (flow == FLO_XONX) {	/* Xon/Xoff flow control */
7136 	debug(F100,"ttvt TANDEM on","",0);
7137 	tttvt.sg_flags |= TANDEM;	/* Ask for it. */
7138 	tthflow(flow, 0, &tttvt);	/* Turn off hardware f/c */
7139     } else if (flow == FLO_NONE) {
7140 	debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
7141 	tttvt.sg_flags &= ~TANDEM;	/* Turn off software flow control */
7142 	tthflow(flow, 0, &tttvt);	/* Turn off any hardware f/c too */
7143 	tttvt.sg_flags |= RAW;		/* Enter raw mode */
7144     } else if (flow == FLO_KEEP) {	/* Keep device's original setting */
7145 	debug(F100,"ttvt keeping original TANDEM","",0);
7146 	tttvt.sg_flags &= ~TANDEM;
7147 	tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
7148 	/* NOTE: We should also handle hardware flow control here! */
7149     }
7150     tttvt.sg_flags |= RAW;              /* Raw mode in all cases */
7151 #ifdef TOWER1
7152     tttvt.sg_flags &= ~(ECHO|ANYP);     /* No echo or parity */
7153 #else
7154     tttvt.sg_flags &= ~ECHO;            /* No echo */
7155 #endif /* TOWER1 */
7156 
7157 #ifdef BELLV10
7158     if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
7159       return(-1);
7160 #else
7161     if (stty(ttyfd,&tttvt) < 0)		/* Set the new modes */
7162       return(-1);
7163 #endif /* BELLV10 */
7164 
7165 #else /* It is ATTSV or POSIX */
7166 
7167     if (flow == FLO_XONX) {		/* Software flow control */
7168 	tttvt.c_iflag |= (IXON|IXOFF);	/* On if requested. */
7169 	tthflow(flow, 0, &tttvt);	/* Turn off hardware f/c */
7170 	debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
7171     } else if (flow == FLO_NONE) {	/* NONE */
7172 	tttvt.c_iflag &= ~(IXON|IXOFF);	/* Turn off Xon/Xoff */
7173 	tthflow(flow, 0, &tttvt);	/* Turn off hardware f/c */
7174 	debug(F100,"ttvt SVORPOSIX flow NONE","",0);
7175     } else if (flow == FLO_KEEP) {
7176 	tttvt.c_iflag &= ~(IXON|IXOFF);	/* Turn off Xon/Xoff flags */
7177 	tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
7178 #ifdef POSIX_CRTSCTS
7179         tttvt.c_cflag &= ~CRTSCTS;	/* Turn off RTS/CTS flag */
7180         tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
7181 #endif /* POSIX_CRTSCTS */
7182 	debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
7183     } else if (flow == FLO_RTSC ||	/* Hardware flow control */
7184 	       flow == FLO_DTRC ||
7185 	       flow == FLO_DTRT) {
7186 	tttvt.c_iflag &= ~(IXON|IXOFF);	/* (196) */
7187 	tthflow(flow, 1, &tttvt);
7188 	debug(F100,"ttvt SVORPOSIX flow HARD","",0);
7189     }
7190 #ifndef OXOS
7191 #ifdef COHERENT
7192     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7193 #else
7194     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
7195 #endif /* COHERENT */
7196 #ifdef QNX
7197     /* Needed for hwfc */
7198     if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
7199       tttvt.c_lflag |= IEXTEN;
7200 #endif /* QNX */
7201 #else /* OXOS */
7202     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7203     tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
7204 #endif /* OXOS */
7205 
7206     tttvt.c_iflag |= (IGNBRK|IGNPAR);
7207 
7208 /* Stop bits */
7209 
7210 #ifdef CSTOPB
7211     if (xlocal) {
7212 	if (stopbits == 2) {
7213 	    tttvt.c_cflag |= CSTOPB;	/* 2 stop bits */
7214 	    debug(F100,"ttvt 2 stopbits","",0);
7215 	} else if (stopbits == 1) {
7216 	    tttvt.c_cflag &= ~(CSTOPB);	/* 1 stop bit */
7217 	    debug(F100,"ttvt 1 stopbit","",0);
7218 	}
7219     }
7220 #endif /* CSTOPB */
7221 
7222 /* Parity */
7223 
7224 #ifdef HWPARITY
7225     if (hwparity && xlocal) {		/* Hardware parity */
7226 #ifdef COMMENT
7227 /* Uncomment this only if needed -- I don't think it is */
7228 	ttraw.c_cflag &= ~(CSIZE);	/* Clear out character-size mask */
7229 	ttraw.c_cflag |= CS8;		/* And set it to 8 */
7230 #endif /* COMMENT */
7231 #ifdef IGNPAR
7232 	debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
7233 	tttvt.c_iflag |= IGNPAR;	/* Don't discard incoming bytes */
7234 #endif /* IGNPAR */
7235 	tttvt.c_cflag |= PARENB;	/* Enable parity */
7236 
7237 	switch (hwparity) {
7238 	  case 'e':			/* Even */
7239 	    tttvt.c_cflag &= ~(PARODD);
7240 	    debug(F100,"ttvt 8 bits + even parity","",0);
7241 	    break;
7242 	  case 'o':			/* Odd */
7243 	    tttvt.c_cflag |= PARODD;
7244 	    debug(F100,"ttvt 8 bits + odd parity","",0);
7245 	    break;
7246 	  case 'm':			/* Mark */
7247 	  case 's':			/* Space */
7248 	    /* PAREXT is mentioned in SVID but the details are not given. */
7249 	    /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
7250 	    debug(F100,"ttvt 8 bits + invalid parity","",0);
7251 	    break;
7252 	}
7253     } else {				/* We handle parity ourselves */
7254 #endif /* HWPARITY */
7255 	tttvt.c_cflag &= ~(PARENB);	/* Don't enable parity */
7256 #ifdef HWPARITY
7257     }
7258 #endif /* HWPARITY */
7259 
7260 #ifdef ATTSV
7261 #ifdef BSD44
7262     /* Things not to do... */
7263     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
7264 #else
7265     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
7266 #endif /* BSD44 */
7267 #else /* POSIX */
7268     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
7269 #endif /* ATTSV */
7270     tttvt.c_cflag &= ~(CSIZE);		/* Zero out the char size field */
7271     tttvt.c_cflag |= (CS8|CREAD|HUPCL);	/* Char size 8, enable receiver, hup */
7272     tttvt.c_oflag &= ~OPOST;		/* Don't postprocess output */
7273 #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
7274     tttvt.c_cc[4] = 1;
7275 #else
7276 #ifndef OXOS
7277 #ifdef VMIN
7278     tttvt.c_cc[VMIN] = 1;
7279 #endif /* VMIN */
7280 #else /* OXOS */
7281     tttvt.c_min = 1;
7282 #endif /* OXOS */
7283 #endif /* VEOF */
7284 #ifndef VEOL	/* DGUX termio has VEOL at entry 5, see comment above */
7285     tttvt.c_cc[5] = 0;
7286 #else
7287 #ifndef OXOS
7288 #ifdef VTIME
7289     tttvt.c_cc[VTIME] = 0;
7290 #endif /* VTIME */
7291 #else /* OXOS */
7292     tttvt.c_time = 0;
7293 #endif /* OXOS */
7294 #endif /* VEOL */
7295 
7296 #ifdef Plan9
7297     if (p9ttyparity('n') < 0)
7298       return -1;
7299 #else
7300 #ifdef BSD44ORPOSIX
7301     errno = 0;
7302 #ifdef BEOSORBEBOX
7303     tttvt.c_cc[VMIN] = 0;		/* DR7 can only poll. */
7304 #endif /* BEOSORBEBOX */
7305 
7306     x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
7307     debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
7308     if (x < 0) {
7309 	debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
7310 	return(-1);
7311     }
7312 #else /* ATTSV */
7313     x = ioctl(ttyfd,TCSETAW,&tttvt);
7314     debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
7315     if (x < 0) {			/* set new modes . */
7316 	debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
7317 	return(-1);
7318     }
7319 #endif /* BSD44ORPOSIX */
7320 #endif /* Plan9 */
7321 #endif /* ATTSV */
7322 
7323     ttspeed = speed;			/* Done, remember how we were */
7324     ttflow = flow;			/* called, so we can decide how to */
7325     tvtflg = 1;				/* respond next time. */
7326     debug(F100,"ttvt ok","",0);
7327     return(0);
7328 
7329 #ifdef COHERENT
7330 #undef SVORPOSIX
7331 #endif /* COHERENT */
7332 
7333 #endif /* NOLOCAL */
7334 }
7335 
7336 #ifndef NOLOCAL
7337 
7338 /* Serial speed department . . . */
7339 
7340 /*
7341   SCO OSR5.0.x might or might not support high speeds.  Sometimes they are not
7342   defined in the header files but they are supported (e.g. when building with
7343   UDK compiler rather than /bin/cc), sometimes vice versa.  Even though 5.0.4
7344   was the first release that came with high serial speeds standard, releases
7345   back to 5.0.0 could use them if certain patches (or "supplements") were
7346   applied to the SIO driver.  Plus a lot of SCO installations run third-party
7347   drivers.
7348 */
7349 #ifdef CK_SCOV5
7350 #ifndef B38400
7351 #define	B38400	0000017
7352 #endif /* B38400 */
7353 #ifndef B57600
7354 #define	B57600	0000021
7355 #endif /* B57600 */
7356 #ifndef B76800
7357 #define	B76800	0000022
7358 #endif /* B76800 */
7359 #ifndef B115200
7360 #define	B115200	0000023
7361 #endif /* B115200 */
7362 #ifndef B230400
7363 #define	B230400	0000024
7364 #endif /* B230400 */
7365 #ifndef B460800
7366 #define	B460800	0000025
7367 #endif /* B460800 */
7368 #ifndef B921600
7369 #define	B921600	0000026
7370 #endif /* B921600 */
7371 #endif /* CK_SCOV5 */
7372 /*
7373   Plan 9's native speed setting interface lets you set anything you like,
7374   but will fail if the hardware doesn't like it, so we allow all the common
7375   speeds.
7376 */
7377 #ifdef Plan9
7378 #ifndef B50
7379 #define B50 50
7380 #endif /* B50 */
7381 #ifndef B75
7382 #define B75 75
7383 #endif /* B75 */
7384 #ifndef B110
7385 #define B110 110
7386 #endif /* B110 */
7387 #ifndef B134
7388 #define B134 134
7389 #endif /* B134 */
7390 #ifndef B200
7391 #define B200 200
7392 #endif /* B200 */
7393 #ifndef B300
7394 #define B300 300
7395 #endif /* B300 */
7396 #ifndef B1200
7397 #define B1200 1200
7398 #endif /* B1200 */
7399 #ifndef B1800
7400 #define B1800 1800
7401 #endif /* B1800 */
7402 #ifndef B2400
7403 #define B2400 2400
7404 #endif /* B2400 */
7405 #ifndef B4800
7406 #define B4800 4800
7407 #endif /* B4800 */
7408 #ifndef B9600
7409 #define B9600 9600
7410 #endif /* B9600 */
7411 #ifndef B14400
7412 #define B14400 14400
7413 #endif /* B14400 */
7414 #ifndef B19200
7415 #define B19200 19200
7416 #endif /* B19200 */
7417 #ifndef B28800
7418 #define B28800 28800
7419 #endif /* B28800 */
7420 #ifndef B38400
7421 #define B38400 38400
7422 #endif /* B38400 */
7423 #ifndef B57600
7424 #define B57600 57600
7425 #endif /* B57600 */
7426 #ifndef B76800
7427 #define B76800 76800
7428 #endif /* B76800 */
7429 #ifndef B115200
7430 #define B115200 115200
7431 #endif /* B115200 */
7432 #ifndef B230400
7433 #define B230400 230400
7434 #endif /* B230400 */
7435 #ifndef B460800
7436 #define B460800 460800
7437 #endif /* B460800 */
7438 #ifndef B921600
7439 #define B921600 921600
7440 #endif /* B921600 */
7441 #endif /* Plan9 */
7442 
7443 /*  T T S S P D  --  Checks and sets transmission rate.  */
7444 
7445 /*  Call with speed in characters (not bits!) per second. */
7446 /*  Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
7447 
7448 #ifdef USETCSETSPEED
7449 /*
7450   The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
7451   to be used as a speed to be set, rather than forcing a choice from a
7452   predefined list.  It seems to be peculiar to UnixWare 7.
7453 
7454   These are the function codes to be passed to tc[gs]etspeed(),
7455   but for some reason they don't seem to be picked up from termios.h.
7456 */
7457 #ifndef TCS_ALL
7458 #define TCS_ALL 0
7459 #endif /* TCS_ALL */
7460 #ifndef TCS_IN
7461 #define TCS_IN 1
7462 #endif /* TCS_IN */
7463 #ifndef TCS_OUT
7464 #define TCS_OUT 2
7465 #endif /* TCS_OUT */
7466 #endif /* USETCSETSPEED */
7467 
7468 int
ttsspd(cps)7469 ttsspd(cps) int cps; {
7470     int x;
7471 #ifdef POSIX
7472 /* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
7473     speed_t
7474 #else
7475     int
7476 #endif /* POSIX */
7477       s, s2;
7478     int ok = 1;				/* Speed check result, assume ok */
7479 
7480 #ifdef OLINUXHISPEED
7481     unsigned int spd_flags = 0;
7482     struct serial_struct serinfo;
7483 #endif /* OLINUXHISPEED */
7484 
7485     debug(F101,"ttsspd cps","",cps);
7486     debug(F101,"ttsspd ttyfd","",ttyfd);
7487     debug(F101,"ttsspd xlocal","",xlocal);
7488 
7489     if (ttyfd < 0 || xlocal == 0)	/* Don't set speed on console */
7490       return(0);
7491 
7492 #ifdef	NETCONN
7493     if (netconn) {
7494 #ifdef TN_COMPORT
7495         if (istncomport())
7496 	  return(tnc_set_baud(cps * 10));
7497         else
7498 #endif /* TN_COMPORT */
7499 	return(0);
7500   }
7501 #endif	/* NETCONN */
7502 #ifdef NETCMD
7503     if (ttpipe) return(0);
7504 #endif /* NETCMD */
7505 #ifdef NETPTY
7506     if (ttpty) return(0);
7507 #endif /* NETPTY */
7508 
7509     if (cps < 0) return(-1);
7510     s = s2 = 0;				/* NB: s and s2 might be unsigned */
7511 
7512 #ifdef USETCSETSPEED
7513 
7514     s = cps * 10L;
7515 
7516     x = tcgetattr(ttyfd,&ttcur);	/* Get current speed */
7517     debug(F101,"ttsspd tcgetattr","",x);
7518     if (x < 0)
7519       return(-1);
7520     debug(F101,"ttsspd TCSETSPEED speed","",s);
7521 
7522     errno = 0;
7523     if (s == 8880L) {			/* 75/1200 split speed requested */
7524 	tcsetspeed(TCS_IN, &ttcur, 1200L);
7525 	tcsetspeed(TCS_OUT, &ttcur, 75L);
7526     } else
7527       tcsetspeed(TCS_ALL, &ttcur, s);	/* Put new speed in structs */
7528 #ifdef DEBUG
7529     if (errno & deblog) {
7530 	debug(F101,"ttsspd TCSETSPEED errno","",errno);
7531     }
7532 #endif /* DEBUG */
7533 
7534 #ifdef COMMENT
7535     tcsetspeed(TCS_ALL, &ttraw, s);
7536     tcsetspeed(TCS_ALL, &tttvt, s);
7537     tcsetspeed(TCS_ALL, &ttold, s);
7538 #else
7539     if (s == 8880L) {			/* 75/1200 split speed requested */
7540 	tcsetspeed(TCS_IN, &ttraw, 1200L);
7541 	tcsetspeed(TCS_OUT, &ttraw, 75L);
7542 	tcsetspeed(TCS_IN, &tttvt, 1200L);
7543 	tcsetspeed(TCS_OUT, &tttvt, 75L);
7544 	tcsetspeed(TCS_IN, &ttold, 1200L);
7545 	tcsetspeed(TCS_OUT, &ttold, 75L);
7546     } else {
7547 	tcsetspeed(TCS_ALL, &ttraw, s);
7548 	tcsetspeed(TCS_ALL, &tttvt, s);
7549 	tcsetspeed(TCS_ALL, &ttold, s);
7550     }
7551 #endif /* COMMENT */
7552 
7553     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
7554     debug(F101,"ttsspd tcsetattr","",x);
7555     if (x < 0)
7556       return(-1);
7557 
7558 #else  /* Not USETCSETSPEED */
7559 
7560     /* First check that the given speed is valid. */
7561 
7562     switch (cps) {
7563 #ifndef MINIX
7564       case 0:   s = B0;    break;
7565       case 5:   s = B50;   break;
7566       case 7:   s = B75;   break;
7567 #endif /* MINIX */
7568       case 11:  s = B110;  break;
7569 #ifndef MINIX
7570       case 13:  s = B134;  break;
7571       case 15:  s = B150;  break;
7572       case 20:  s = B200;  break;
7573 #endif /* MINIX */
7574       case 30:  s = B300;  break;
7575 #ifndef MINIX
7576       case 60:  s = B600;  break;
7577 #endif /* MINIX */
7578       case 120: s = B1200; break;
7579 #ifndef MINIX
7580       case 180: s = B1800; break;
7581 #endif /* MINIX */
7582       case 240: s = B2400; break;
7583       case 480: s = B4800; break;
7584 #ifndef MINIX
7585       case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
7586 #endif /* MINIX */
7587 #ifdef B7200
7588       case 720: s = B7200; break;
7589 #endif /* B7200 */
7590       case 960: s = B9600; break;
7591 #ifdef B14400
7592       case 1440: s = B14400; break;
7593 #endif /* B14400 */
7594 #ifdef B19200
7595       case 1920: s = B19200; break;
7596 #else
7597 #ifdef EXTA
7598       case 1920: s = EXTA; break;
7599 #endif /* EXTA */
7600 #endif /* B19200 */
7601 #ifdef B28800
7602       case 2880: s = B28800; break;
7603 #endif /* B28800 */
7604 #ifdef B38400
7605       case 3840: s = B38400;
7606 #ifdef OLINUXHISPEED
7607         spd_flags = ~ASYNC_SPD_MASK;	/* Nonzero, but zero flags */
7608 #endif /* OLINUXHISPEED */
7609 	break;
7610 #else /* B38400 not defined... */
7611 #ifdef EXTB
7612       case 3840: s = EXTB; break;
7613 #endif /* EXTB */
7614 #endif /* B38400 */
7615 
7616 #ifdef HPUX
7617 #ifdef _B57600
7618       case 5760: s = _B57600; break;
7619 #endif /* _B57600 */
7620 #ifdef _B115200
7621       case 11520: s = _B115200; break;
7622 #endif /* _B115200 */
7623 #else
7624 #ifdef OLINUXHISPEED
7625 /*
7626   This bit from <carlo@sg.tn.tudelft.nl>:
7627   "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
7628   setting the speed to 38400 will set the custom speed (and ttgspd returns
7629   38400), but speeds 57600 and 115200 won't work any more because I didn't
7630   want to mess up the speed flags when someone is doing sophisticated stuff
7631   like custom speeds..."
7632 */
7633       case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
7634       case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
7635 #else
7636 #ifdef B57600
7637       case 5760: s = B57600; break;
7638 #endif /* B57600 */
7639 #ifdef B76800
7640       case 7680: s = B76800; break;
7641 #endif /* B76800 */
7642 #ifdef B115200
7643       case 11520: s = B115200; break;
7644 #endif /* B115200 */
7645 #endif /* OLINUXHISPEED */
7646 #ifdef B153600
7647       case 15360: s = B153600; break;
7648 #endif /* B153600 */
7649 #ifdef B230400
7650       case 23040: s = B230400; break;
7651 #endif /* B230400 */
7652 #ifdef B307200
7653       case 30720: s = B307200; break;
7654 #endif /* B307200 */
7655 #ifdef B460800
7656       case 46080: s = B460800; break;
7657 #endif /* 460800 */
7658 #ifdef B921600
7659       case 92160: s = B921600; break;
7660 #endif /* B921600 */
7661 #endif /* HPUX */
7662       default:
7663 	ok = 0;				/* Good speed not found, so not ok */
7664 	break;
7665     }
7666     debug(F101,"ttsspd ok","",ok);
7667     debug(F101,"ttsspd s","",s);
7668 
7669     if (!ok) {
7670 	debug(F100,"ttsspd fails","",0);
7671 	return(-1);
7672     } else {
7673 	if (!s2) s2 = s;		/* Set input speed */
7674 #ifdef Plan9
7675 	if (p9ttsspd(cps) < 0)
7676 	  return(-1);
7677 #else
7678 #ifdef BSD44ORPOSIX
7679 	x = tcgetattr(ttyfd,&ttcur);	/* Get current speed */
7680 	debug(F101,"ttsspd tcgetattr","",x);
7681 	if (x < 0)
7682 	  return(-1);
7683 #ifdef OLINUXHISPEED
7684 	debug(F101,"ttsspd spd_flags","",spd_flags);
7685 	if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
7686 	    if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
7687 		debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
7688 		return(-1);
7689 	    } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
7690 	    serinfo.flags &= ~ASYNC_SPD_MASK;
7691 	    serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
7692 	    if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
7693 	      return(-1);
7694 	}
7695 #endif /* OLINUXHISPEED */
7696 	cfsetospeed(&ttcur,s);
7697 	cfsetispeed(&ttcur,s2);
7698 	cfsetospeed(&ttraw,s);
7699 	cfsetispeed(&ttraw,s2);
7700 	cfsetospeed(&tttvt,s);
7701 	cfsetispeed(&tttvt,s2);
7702 	cfsetospeed(&ttold,s);
7703 	cfsetispeed(&ttold,s2);
7704 	x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
7705 	debug(F101,"ttsspd tcsetattr","",x);
7706 	if (x < 0) return(-1);
7707 #else
7708 #ifdef ATTSV
7709 	if (cps == 888) return(-1);	/* No split speeds, sorry. */
7710 	x = ioctl(ttyfd,TCGETA,&ttcur);
7711 	debug(F101,"ttsspd TCGETA ioctl","",x);
7712 	if (x < 0) return(-1);
7713 	ttcur.c_cflag &= ~CBAUD;
7714 	ttcur.c_cflag |= s;
7715 	tttvt.c_cflag &= ~CBAUD;
7716 	tttvt.c_cflag |= s;
7717 	ttraw.c_cflag &= ~CBAUD;
7718 	ttraw.c_cflag |= s;
7719 	ttold.c_cflag &= ~CBAUD;
7720 	ttold.c_cflag |= s;
7721 	x = ioctl(ttyfd,TCSETAW,&ttcur);
7722 	debug(F101,"ttsspd TCSETAW ioctl","",x);
7723 	if (x < 0) return(-1);
7724 #else
7725 #ifdef BELLV10
7726 	x = ioctl(ttyfd,TIOCGDEV,&tdcur);
7727 	debug(F101,"ttsspd TIOCGDEV ioctl","",x);
7728 	if (x < 0) return(-1);
7729 	tdcur.ispeed = s2;
7730 	tdcur.ospeed = s;
7731 	errno = 0;
7732 	ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
7733 	debug(F101,"ttsspd BELLV10 ioctl","",ok);
7734 	if (ok < 0) {
7735 	    perror(ttnmsv);
7736 	    debug(F101,"ttsspd BELLV10 errno","",ok);
7737 	    return(-1);
7738 	}
7739 #else
7740 	x = gtty(ttyfd,&ttcur);
7741 	debug(F101,"ttsspd gtty","",x);
7742 	if (x < 0) return(-1);
7743 	ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
7744 	tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
7745 	ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
7746 	ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
7747 	x = stty(ttyfd,&ttcur);
7748 	debug(F101,"ttsspd stty","",x);
7749 	if (x < 0) return(-1);
7750 #endif /* BELLV10 */
7751 #endif /* ATTSV */
7752 #endif /* BSD44ORPOSIX */
7753 #endif /* Plan9 */
7754     }
7755     return(1);				/* Return 1 = success. */
7756 #endif /* USETCSETSPEED */
7757 }
7758 
7759 #endif /* NOLOCAL */
7760 
7761 /* C O N G S P D  -  Get speed of console terminal  */
7762 
7763 long
congspd()7764 congspd() {
7765 /*
7766   This is a disgusting hack.  The right way to do this would be to pass an
7767   argument to ttgspd(), but then we'd need to change the Kermit API and
7768   all of the ck?tio.c modules.  (Currently used only for rlogin.)
7769 */
7770     int t1;
7771     long spd;
7772 #ifdef NETCONN
7773     int t2 = netconn;
7774     netconn = 0;
7775 #endif /* NETCONN */
7776     t1 = ttyfd;
7777     ttyfd = -1;
7778     spd = ttgspd();
7779     debug(F101,"congspd","",spd);
7780 #ifdef NETCONN
7781     netconn = t2;
7782 #endif /* NETCONN */
7783     ttyfd = t1;
7784     return(spd);
7785 }
7786 
7787 /*  T T S P D L I S T  -- Get list of serial speeds allowed on this platform */
7788 
7789 #define NSPDLIST 64
7790 static long spdlist[NSPDLIST];
7791 /*
7792   As written, this picks up the speeds known at compile time, and thus
7793   apply to the system where C-Kermit was built, rather than to the one where
7794   it is running.  Suggestions for improvement are always welcome.
7795 */
7796 long *
ttspdlist()7797 ttspdlist() {
7798     int i;
7799     for (i = 0; i < NSPDLIST; i++)	/* Initialize the list */
7800       spdlist[i] = -1L;
7801     i = 1;
7802 
7803 #ifdef USETCSETSPEED			/* No way to find out what's legal */
7804     debug(F100,"ttspdlist USETCSETSPEED","",0);
7805     spdlist[i++] = 50L;
7806 #ifndef UW7
7807     spdlist[i++] = 75L;
7808 #endif /* UW7 */
7809     spdlist[i++] = 110L;
7810 #ifndef UW7
7811     spdlist[i++] = 134L;
7812 #endif /* UW7 */
7813     spdlist[i++] = 150L;
7814     spdlist[i++] = 200L;
7815     spdlist[i++] = 300L;
7816     spdlist[i++] = 600L;
7817     spdlist[i++] = 1200L;
7818     spdlist[i++] = 1800L;
7819     spdlist[i++] = 2400L;
7820     spdlist[i++] = 4800L;
7821     spdlist[i++] = 8880L;
7822     spdlist[i++] = 9600L;
7823     spdlist[i++] = 14400L;
7824     spdlist[i++] = 19200L;
7825     spdlist[i++] = 28800L;
7826 #ifndef UW7
7827     spdlist[i++] = 33600L;
7828 #endif /* UW7 */
7829     spdlist[i++] = 38400L;
7830     spdlist[i++] = 57600L;
7831     spdlist[i++] = 76800L;
7832     spdlist[i++] = 115200L;
7833 #ifndef UW7
7834     spdlist[i++] = 153600L;
7835     spdlist[i++] = 230400L;
7836     spdlist[i++] = 307200L;
7837     spdlist[i++] = 460800L;
7838     spdlist[i++] = 921600L;
7839 #endif /* UW7 */
7840 
7841 #else  /* USETCSETSPEED */
7842 
7843     debug(F100,"ttspdlist no USETCSETSPEED","",0);
7844 
7845 #ifdef B50
7846     debug(F101,"ttspdlist B50","",B50);
7847     spdlist[i++] = 50L;
7848 #endif /* B50 */
7849 #ifdef B75
7850     debug(F101,"ttspdlist B75","",B75);
7851     spdlist[i++] = 75L;
7852 #endif /* B75 */
7853 #ifdef B110
7854     debug(F101,"ttspdlist B110","",B110);
7855     spdlist[i++] = 110L;
7856 #endif /* B110 */
7857 #ifdef B134
7858     debug(F101,"ttspdlist B134","",B134);
7859     spdlist[i++] = 134L;
7860 #endif /* B134 */
7861 #ifdef B150
7862     debug(F101,"ttspdlist B150","",B150);
7863     spdlist[i++] = 150L;
7864 #endif /* B150 */
7865 #ifdef B200
7866     debug(F101,"ttspdlist B200","",B200);
7867     spdlist[i++] = 200L;
7868 #endif /* B200 */
7869 #ifdef B300
7870     debug(F101,"ttspdlist B300","",B300);
7871     spdlist[i++] = 300L;
7872 #endif /* B300 */
7873 #ifdef B600
7874     debug(F101,"ttspdlist B600","",B600);
7875     spdlist[i++] = 600L;
7876 #endif /* B600 */
7877 #ifdef B1200
7878     debug(F101,"ttspdlist B1200","",B1200);
7879     spdlist[i++] = 1200L;
7880 #endif /* B1200 */
7881 #ifdef B1800
7882     debug(F101,"ttspdlist B1800","",B1800);
7883     spdlist[i++] = 1800L;
7884 #endif /* B1800 */
7885 #ifdef B2400
7886     debug(F101,"ttspdlist B2400","",B2400);
7887     spdlist[i++] = 2400L;
7888 #endif /* B2400 */
7889 #ifdef B4800
7890     debug(F101,"ttspdlist B4800","",B4800);
7891     spdlist[i++] = 4800L;
7892 #endif /* B4800 */
7893 #ifdef B9600
7894     debug(F101,"ttspdlist B9600","",B9600);
7895     spdlist[i++] = 9600L;
7896 #endif /* B9600 */
7897 #ifdef B14400
7898     debug(F101,"ttspdlist B14400","",B14400);
7899     spdlist[i++] = 14400L;
7900 #endif /* B14400 */
7901 #ifdef B19200
7902     debug(F101,"ttspdlist B19200","",B19200);
7903     spdlist[i++] = 19200L;
7904 #else
7905 #ifdef EXTA
7906     debug(F101,"ttspdlist EXTA","",EXTA);
7907     spdlist[i++] = 19200L;
7908 #endif /* EXTA */
7909 #endif /* B19200 */
7910 #ifdef B28800
7911     debug(F101,"ttspdlist B28800","",B28800);
7912     spdlist[i++] = 28800L;
7913 #endif /* B28800 */
7914 #ifdef B33600
7915     debug(F101,"ttspdlist B33600","",B33600);
7916     spdlist[i++] = 33600L;
7917 #endif /* B33600 */
7918 #ifdef B38400
7919     debug(F101,"ttspdlist B38400","",B38400);
7920     spdlist[i++] = 38400L;
7921 #else
7922 #ifdef EXTB
7923     debug(F101,"ttspdlist EXTB","",EXTB);
7924     spdlist[i++] = 38400L;
7925 #endif /* EXTB */
7926 #endif /* B38400 */
7927 #ifdef _B57600
7928     debug(F101,"ttspdlist _B57600","",_B57600);
7929     spdlist[i++] = 57600L;
7930 #else
7931 #ifdef B57600
7932     debug(F101,"ttspdlist B57600","",B57600);
7933     spdlist[i++] = 57600L;
7934 #endif /* B57600 */
7935 #endif /* _B57600 */
7936 #ifdef B76800
7937     debug(F101,"ttspdlist B76800","",B76800);
7938     spdlist[i++] = 76800L;
7939 #endif /* B76800 */
7940 #ifdef _B115200
7941     debug(F101,"ttspdlist _B115200","",_B115200);
7942     spdlist[i++] = 115200L;
7943 #else
7944 #ifdef B115200
7945     debug(F101,"ttspdlist B115200","",B115200);
7946     spdlist[i++] = 115200L;
7947 #endif /* B115200 */
7948 #endif /* _B115200 */
7949 #ifdef B153600
7950     debug(F101,"ttspdlist B153600","",B153600);
7951     spdlist[i++] = 153600L;
7952 #endif /* B153600 */
7953 #ifdef B230400
7954     debug(F101,"ttspdlist B230400","",B230400);
7955     spdlist[i++] = 230400L;
7956 #endif /* B230400 */
7957 #ifdef B307200
7958     debug(F101,"ttspdlist B307200","",B307200);
7959     spdlist[i++] = 307200L;
7960 #endif /* B307200 */
7961 #ifdef B460800
7962     debug(F101,"ttspdlist B460800","",B460800);
7963     spdlist[i++] = 460800L;
7964 #endif /* B460800 */
7965 #ifdef B921600
7966     debug(F101,"ttspdlist B921600","",B921600);
7967     spdlist[i++] = 921600L;
7968 #endif /* B921600 */
7969 #endif /* USETCSETSPEED */
7970     spdlist[0] = i - 1;			/* Return count in 0th element */
7971     debug(F111,"ttspdlist spdlist","0",spdlist[0]);
7972     return((long *)spdlist);
7973 }
7974 
7975 /* T T G S P D  -  Get speed of currently selected tty line  */
7976 
7977 /*
7978   Unreliable.  After SET LINE, it returns an actual speed, but not necessarily
7979   the real speed.  On some systems, it returns the line's nominal speed, from
7980   /etc/ttytab.  Even if you SET SPEED to something else, this function might
7981   not notice.
7982 */
7983 long
ttgspd()7984 ttgspd() {				/* Get current serial device speed */
7985 #ifdef NOLOCAL
7986     return(-1L);
7987 #else
7988 #ifdef POSIX
7989     speed_t				/* Should be unsigned */
7990 #else
7991     int					/* Isn't unsigned */
7992 #endif /* POSIX */
7993       s;
7994     int x;
7995     long ss;
7996 #ifdef OLINUXHISPEED
7997     unsigned int spd_flags = 0;
7998     struct serial_struct serinfo;
7999 #endif /* OLINUXHISPEED */
8000 
8001 #ifdef NETCONN
8002     if (netconn) {
8003 #ifdef TN_COMPORT
8004 	if (istncomport())
8005 	  return(tnc_get_baud());
8006 	else
8007 #endif /* TN_COMPORT */
8008 	  return(-1);			/* -1 if network connection */
8009     }
8010 #endif /* NETCONN */
8011 #ifdef NETCMD
8012     if (ttpipe) return(-1);
8013 #endif /* NETCMD */
8014 #ifdef NETPTY
8015     if (ttpty) return(-1);
8016 #endif /* NETPTY */
8017 
8018     debug(F101,"ttgspd ttyfd","",ttyfd);
8019 
8020 #ifdef USETCSETSPEED
8021 
8022     x = tcgetattr(ttyfd,&ttcur);	/* Get current speed */
8023     debug(F101,"ttgspd tcgetattr","",x);
8024     if (x < 0)
8025       return(-1);
8026     errno = 0;
8027     s = tcgetspeed(TCS_ALL, &ttcur);
8028     debug(F101,"ttsspd TCGETSPEED speed","",s);
8029     if (s == 0) {
8030 	long s1, s2;
8031 	s1 = tcgetspeed(TCS_IN, &ttcur);
8032 	s2 = tcgetspeed(TCS_OUT, &ttcur);
8033 	if (s1 == 1200L && s2 == 75L)
8034 	  return(8880L);
8035     }
8036 #ifdef DEBUG
8037     if (errno & deblog) {
8038 	debug(F101,"ttsspd TCGETSPEED errno","",errno);
8039     }
8040 #endif /* DEBUG */
8041     return(s);
8042 
8043 #else  /* Not USETCSETSPEED */
8044 
8045 #ifdef Plan9
8046     if (ttyfd < 0)
8047       ss = -1;
8048     else
8049       ss = ttylastspeed;
8050 #else
8051 #ifdef OLINUXHISPEED
8052     debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
8053 #endif /* OLINUXHISPEED */
8054 
8055     if (ttyfd < 0) {
8056 #ifdef BSD44ORPOSIX
8057 	s = cfgetospeed(&ccold);
8058 	debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
8059 #else
8060 #ifdef ATTSV
8061 	s = ccold.c_cflag & CBAUD;
8062 	debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
8063 #else
8064 	s = ccold.sg_ospeed;		/* (obtained by congm()) */
8065 	debug(F101,"ttgspd sg_ospeed 1","",s);
8066 #endif /* ATTSV */
8067 #endif /* BSD44POSIX */
8068 
8069     } else {
8070 #ifdef BSD44ORPOSIX
8071 	if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
8072 	s = cfgetospeed(&ttcur);
8073 	debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
8074 #ifdef OLINUXHISPEED
8075 	if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
8076 	  spd_flags = serinfo.flags & ASYNC_SPD_MASK;
8077 	debug(F101,"ttgspd spd_flags","",spd_flags);
8078 #endif /* OLINUXHISPEED */
8079 #else
8080 #ifdef ATTSV
8081 	x = ioctl(ttyfd,TCGETA,&ttcur);
8082 	debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
8083 	debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
8084 	if (x < 0) return(-1);
8085 	s = ttcur.c_cflag & CBAUD;
8086 	debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
8087 #else
8088 #ifdef BELLV10
8089 	x = ioctl(ttyfd,TIOCGDEV,&tdcur);
8090 	debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
8091 	if (x < 0) return(-1);
8092 	s = tdcur.ospeed;
8093 	debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
8094 #else
8095 	x = gtty(ttyfd,&ttcur);
8096 	debug(F101,"ttgspd gtty 2 x","",x);
8097 	debug(F101,"ttgspd gtty 2 errno","",errno);
8098 	if (x < 0) return(-1);
8099 	s = ttcur.sg_ospeed;
8100 	debug(F101,"ttgspd gtty 2 speed","",s);
8101 #endif /* BELLV10 */
8102 #endif /* ATTSV */
8103 #endif /* BSD44ORPOSIX */
8104     }
8105     debug(F101,"ttgspd code","",s);
8106 #ifdef OLINUXHISPEED
8107     debug(F101,"ttgspd spd_flags","",spd_flags);
8108 #endif /* OLINUXHISPEED */
8109     switch (s) {
8110 #ifdef B0
8111       case B0:    ss = 0L; break;
8112 #endif /* B0 */
8113 
8114 #ifndef MINIX
8115 /*
8116  MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
8117  etc, making for many "duplicate case in switch" errors, which are fatal.
8118 */
8119 #ifdef B50
8120       case B50:   ss = 50L; break;
8121 #endif /* B50 */
8122 #ifdef B75
8123       case B75:   ss = 75L; break;
8124 #endif /* B75 */
8125 #endif /* MINIX */
8126 
8127 #ifdef B110
8128       case B110:  ss = 110L; break;
8129 #endif /* B110 */
8130 
8131 #ifndef MINIX
8132 #ifdef B134
8133       case B134:  ss = 134L; break;
8134 #endif /* B134 */
8135 #ifdef B150
8136       case B150:  ss = 150L; break;
8137 #endif /* B150 */
8138 #endif /* MINIX */
8139 
8140 #ifdef B200
8141       case B200:  ss = 200L; break;
8142 #endif /* B200 */
8143 
8144 #ifdef B300
8145       case B300:  ss = 300L; break;
8146 #endif /* B300 */
8147 
8148 #ifdef B600
8149       case B600:  ss = 600L; break;
8150 #endif /* B600 */
8151 
8152 #ifdef B1200
8153       case B1200: ss = 1200L; break;
8154 #endif /* B1200 */
8155 
8156 #ifdef B1800
8157       case B1800: ss = 1800L; break;
8158 #endif /* B1800 */
8159 
8160 #ifdef B2400
8161       case B2400: ss = 2400L; break;
8162 #endif /* B2400 */
8163 
8164 #ifdef B4800
8165       case B4800: ss = 4800L; break;
8166 #endif /* B4800 */
8167 
8168 #ifdef B7200
8169       case B7200: ss = 7200L; break;
8170 #endif /* B7200 */
8171 
8172 #ifdef B9600
8173       case B9600: ss = 9600L; break;
8174 #endif /* B9600 */
8175 
8176 #ifdef B19200
8177       case B19200: ss = 19200L; break;
8178 #else
8179 #ifdef EXTA
8180       case EXTA: ss = 19200L; break;
8181 #endif /* EXTA */
8182 #endif /* B19200 */
8183 
8184 #ifndef MINIX
8185 #ifdef B38400
8186       case B38400:
8187         ss = 38400L;
8188 #ifdef OLINUXHISPEED
8189         switch(spd_flags) {
8190           case ASYNC_SPD_HI:  ss =  57600L; break;
8191           case ASYNC_SPD_VHI: ss = 115200L; break;
8192 	}
8193 #endif /* OLINUXHISPEED */
8194         break;
8195 #else
8196 #ifdef EXTB
8197       case EXTB: ss = 38400L; break;
8198 #endif /* EXTB */
8199 #endif /* B38400 */
8200 #endif /* MINIX */
8201 
8202 #ifdef HPUX
8203 #ifdef _B57600
8204       case _B57600: ss = 57600L; break;
8205 #endif /* _B57600 */
8206 #ifdef _B115200
8207       case _B115200: ss = 115200L; break;
8208 #endif /* _B115200 */
8209 #else
8210 #ifdef B57600
8211       case B57600: ss = 57600L; break;
8212 #endif /* B57600 */
8213 #ifdef B76800
8214       case B76800: ss = 76800L; break;
8215 #endif /* B76800 */
8216 #ifdef B115200
8217       case B115200: ss = 115200L; break;
8218 #endif /* B115200 */
8219 #ifdef B153600
8220       case B153600: ss = 153600L; break;
8221 #endif /* B153600 */
8222 #ifdef B230400
8223       case B230400: ss = 230400L; break;
8224 #endif /* B230400 */
8225 #ifdef B307200
8226       case B307200: ss = 307200L; break;
8227 #endif /* B307200 */
8228 #ifdef B460800
8229       case B460800: ss = 460800L; break;
8230 #endif /* B460800 */
8231 #endif /* HPUX */
8232 #ifdef B921600
8233       case B921600: ss = 921600L; break;
8234 #endif /* B921600 */
8235       default:
8236 	ss = -1; break;
8237     }
8238 #endif /* Plan9 */
8239     debug(F101,"ttgspd speed","",ss);
8240     return(ss);
8241 
8242 #endif /* USETCSETSPEED */
8243 #endif /* NOLOCAL */
8244 }
8245 #ifdef MINIX2				/* Another hack alert */
8246 #define MINIX
8247 #endif /* MINIX2 */
8248 
8249 /*
8250   FIONREAD data type...  This has been defined as "long" for many, many
8251   years, and it worked OK until 64-bit platforms appeared.  Thus we use
8252   int for 64-bit platforms, but keep long for the others.  If we changed
8253   the default PEEKTYPE to int, this would probably break 16-bit builds
8254   (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
8255   of which we have no way of testing any more.  Therefore, do not change
8256   the default definition of PEEKTYPE -- only add exceptions to it as needed.
8257 */
8258 #ifdef COHERENT
8259 #ifdef FIONREAD
8260 #undef FIONREAD
8261 #endif /* FIONREAD */
8262 /* #define FIONREAD TIOCQUERY */
8263 /* #define PEEKTYPE int */
8264 #else  /* Not COHERENT... */
8265 
8266 #ifdef OSF32				/* Digital UNIX 3.2 or higher */
8267 #define PEEKTYPE int
8268 #else
8269 #define PEEKTYPE long			/* Elsewhere (see notes above) */
8270 #endif /* OSF32 */
8271 #endif /* COHERENT */
8272 
8273 /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
8274 
8275 #ifdef MYREAD
8276 
8277 /* Private buffer for myread() and its companions.  Not for use by anything
8278  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
8279  * allowed to read my_count.
8280  *
8281  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
8282  *
8283  * A global parity mask variable could be useful too.  We could use it to
8284  * let myread() strip the parity on its own, instead of stripping sign
8285  * bits as it does now.
8286  */
8287 #ifdef BIGBUFOK
8288 #define MYBUFLEN 32768
8289 #else
8290 #ifdef pdp11
8291 #define MYBUFLEN 256
8292 #else
8293 #define MYBUFLEN 1024
8294 #endif /* pdp11 */
8295 #endif /* BIGBUFOK */
8296 
8297 #ifdef ANYX25
8298 #undef MYBUFLEN
8299 #define MYBUFLEN 256
8300 /*
8301   On X.25 connections, there is an extra control byte at the beginning.
8302 */
8303 static CHAR x25buf[MYBUFLEN+1];		/* Communication device input buffer */
8304 static CHAR  *mybuf = x25buf+1;
8305 #else
8306 static CHAR mybuf[MYBUFLEN];
8307 #endif /* ANYX25 */
8308 
8309 static int my_count = 0;		/* Number of chars still in mybuf */
8310 static int my_item = -1;		/* Last index read from mybuf[]   */
8311 
8312 /*  T T P E E K  --  Peek into our internal communications input buffers. */
8313 
8314 /*
8315   NOTE: This routine is peculiar to UNIX, and is used only by the
8316   select()-based CONNECT module, ckucns.c.  It need not be replicated in
8317   the ck?tio.c of other platforms.
8318 */
8319 int
ttpeek()8320 ttpeek() {
8321 #ifdef TTLEBUF
8322     int rc = 0;
8323     if (ttpush >= 0)
8324       rc++;
8325     rc += le_inbuf();
8326     if (rc > 0)
8327       return(rc);
8328     else
8329 #endif /* TTLEBUF */
8330 
8331 #ifdef MYREAD
8332     return(my_count);
8333 #else
8334     return(0);
8335 #endif /* MYREAD */
8336 }
8337 
8338 /* myread() -- Efficient read of one character from communications line.
8339  *
8340  * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw
8341  * bytes from connection, so when the connection is encrypted, these bytes
8342  * must be decrypted.
8343  *
8344  * Uses a private buffer to minimize the number of expensive read() system
8345  * calls.  Essentially performs the equivalent of read() of 1 character, which
8346  * is then returned.  By reading all available input from the system buffers
8347  * to the private buffer in one chunk, and then working from this buffer, the
8348  * number of system calls is reduced in any case where more than one character
8349  * arrives during the processing of the previous chunk, for instance high
8350  * baud rates or network type connections where input arrives in packets.
8351  * If the time needed for a read() system call approaches the time for more
8352  * than one character to arrive, then this mechanism automatically compensates
8353  * for that by performing bigger read()s less frequently.  If the system load
8354  * is high, the same mechanism compensates for that too.
8355  *
8356  * myread() is a macro that returns the next character from the buffer.  If the
8357  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
8358  * returns.
8359  *
8360  * This should be efficient enough for any one-character-at-a-time loops.
8361  * For even better efficiency you might use memcpy()/bcopy() or such between
8362  * buffers (since they are often better optimized for copying), but it may not
8363  * be worth it if you have to take an extra pass over the buffer to strip
8364  * parity and check for CTRL-C anyway.
8365  *
8366  * Note that if you have been using myread() from another program module, you
8367  * may have some trouble accessing this macro version and the private variables
8368  * it uses.  In that case, just add a function in this module, that invokes the
8369  * macro.
8370  */
8371 #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
8372 
8373 /* Specification: Push back up to one character onto myread()'s queue.
8374  *
8375  * This implementation: Push back characters into mybuf. At least one character
8376  * must have been read through myread() before myunrd() may be used.  After
8377  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
8378  * one character can be pushed back, but only one character is guaranteed.
8379  * Since a previous myread() must have read its character out of mybuf[],
8380  * that guarantees that there is space for at least one character.  If push
8381  * back was really needed after EOF, a small addition could provide that.
8382  *
8383  * As of 02/2007 myunrd() is used by ttinl().
8384  */
8385 VOID
8386 #ifdef CK_ANSIC
myunrd(CHAR ch)8387 myunrd(CHAR ch)
8388 #else
8389 myunrd(ch) CHAR ch;
8390 #endif	/* CK_ANSIC */
8391 {
8392     if (my_item >= 0) {
8393 	mybuf[my_item--] = ch;
8394 	++my_count;
8395     }
8396 }
8397 
8398 /*  T T P U S H B A C K  --  Put n bytes back into the myread buffer */
8399 
8400 static CHAR * pushbuf = NULL;
8401 /* static int pushed = 0; */
8402 
8403 int
ttpushback(s,n)8404 ttpushback(s,n) CHAR * s; int n; {
8405     debug(F101,"ttpushback n","",n);
8406     if (pushbuf || n > MYBUFLEN || n < 1)
8407       return(-1);
8408     debug(F101,"ttpushback my_count","",my_count);
8409     if (my_count > 0) {
8410 	if (!(pushbuf = (CHAR *)malloc(n+1)))
8411 	  return(-1);
8412 	memcpy(pushbuf,mybuf,my_count);
8413 	/* pushed = my_count; */ /* (set but never used) */
8414     }
8415     memcpy(mybuf,s,n);
8416     my_count = n;
8417     my_item = -1;
8418     return(0);
8419 }
8420 
8421 /* mygetbuf() -- Fill buffer for myread() and return first character.
8422  *
8423  * This function is what myread() uses when it can't get the next character
8424  * directly from its buffer.  First, it calls a system dependent myfillbuf()
8425  * to read at least one new character into the buffer, and then it returns
8426  * the first character just as myread() would have done.  This function also
8427  * is responsible for all error conditions that myread() can indicate.
8428  *
8429  * Returns: When OK	=> a positive character, 0 or greater.
8430  *	    When EOF	=> -2.
8431  *	    When error	=> -3, error code in errno.
8432  *
8433  * Older myread()s additionally returned -1 to indicate that there was nothing
8434  * to read, upon which the caller would call myread() again until it got
8435  * something.  The new myread()/mygetbuf() always gets something.  If it
8436  * doesn't, then make it do so!  Any program that actually depends on the old
8437  * behaviour will break.
8438  *
8439  * The older version also used to return -2 both for EOF and other errors,
8440  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
8441  * other errors now return different results, although Kermit currently never
8442  * checks to see which it was.  It just disconnects in both cases.
8443  *
8444  * Kermit lets the user use the quit key to perform some special commands
8445  * during file transfer.  This causes read(), and thus also mygetbuf(), to
8446  * finish without reading anything and return the EINTR error.  This should
8447  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
8448  * but if there is nothing to read, this could delay Kermit's reaction to
8449  * the command, and make Kermit appear unresponsive.
8450  *
8451  * The debug() call should be removed for optimum performance.
8452  */
8453 int
mygetbuf()8454 mygetbuf() {
8455     int x;
8456     errno = 0;
8457 #ifdef DEBUG
8458     if (deblog && my_count > 0)
8459       debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
8460 #endif /* DEBUG */
8461     if (my_count <= 0)
8462       my_count = myfillbuf();
8463 
8464 #ifdef DEBUG
8465 #ifdef COMMENT
8466     if (deblog) debug(F101, "mygetbuf read", "", my_count);
8467 #else /* COMMENT */
8468     ckhexdump("mygetbuf read", mybuf, my_count);
8469 #endif /* COMMENT */
8470 #endif /* DEBUG */
8471     x = my_count;
8472     if (my_count <= 0) {
8473 	my_count = 0;
8474 	my_item = -1;
8475 	debug(F101,"mygetbuf errno","",errno);
8476 #ifdef TCPSOCKET
8477 	if (netconn && ttnet == NET_TCPB && errno != 0) {
8478 	    if (errno != EINTR) {
8479 		debug(F101,"mygetbuf TCP error","",errno);
8480 		ttclos(0);		/* Close the connection. */
8481 	    }
8482 	    return(-3);
8483 	}
8484 #endif /* TCPSOCKET */
8485 	if (!netconn && xlocal && errno) {
8486 	    if (errno != EINTR) {
8487 		debug(F101,"mygetbuf SERIAL error","",errno);
8488 		x = -3;
8489 		ttclos(0);		/* Close the connection. */
8490 	    }
8491 	}
8492 	return((x < 0) ? -3 : -2);
8493     }
8494     --my_count;
8495     return((unsigned)(0xff & mybuf[my_item = 0]));
8496 }
8497 
8498 /* myfillbuf():
8499  * System-dependent read() into mybuf[], as many characters as possible.
8500  *
8501  * Returns: OK => number of characters read, always more than zero.
8502  *          EOF => 0
8503  *          Error => -1, error code in errno.
8504  *
8505  * If there is input available in the system's buffers, all of it should be
8506  * read into mybuf[] and the function return immediately.  If no input is
8507  * available, it should wait for a character to arrive, and return with that
8508  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
8509  * character, but be aware that any such delay lengthens the packet turnaround
8510  * time during kermit file transfers.  Should never return with zero characters
8511  * unless EOF or irrecoverable read error.
8512  *
8513  * Correct functioning depends on the correct tty parameters being used.
8514  * Better control of current parameters is required than may have been the
8515  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
8516  * no longer be sometimes off and sometimes on like it used to, unless a
8517  * special myfillbuf() is written to handle that.  Otherwise the ordinary
8518  * myfillbuf()s may think they have come to EOF.
8519  *
8520  * If your system has a facility to directly perform the functioning of
8521  * myfillbuf(), then use it.  If the system can tell you how many characters
8522  * are available in its buffers, then read that amount (but not less than 1).
8523  * If the system can return a special indication when you try to read without
8524  * anything to read, while allowing you to read all there is when there is
8525  * something, you may loop until there is something to read, but probably that
8526  * is not good for the system load.
8527  */
8528 
8529 #ifdef SVORPOSIX
8530 	/* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
8531 	 * and CLOCAL set any way you like.  This way, read() will do exactly
8532 	 * what is required by myfillbuf(): If there is data in the buffers
8533 	 * of the O.S., all available data is read into mybuf, up to the size
8534 	 * of mybuf.  If there is none, the first character to arrive is
8535 	 * awaited and returned.
8536 	 */
8537 int
myfillbuf()8538 myfillbuf() {
8539     int fd, n;
8540 #ifdef NETCMD
8541     if (ttpipe)
8542       fd = fdin;
8543     else
8544 #endif /* NETCMD */
8545       fd = ttyfd;
8546 
8547 #ifdef sxaE50
8548     /* From S. Dezawa at Fujifilm in Japan.  I don't know why this is */
8549     /* necessary for the sxa E50, but it is. */
8550     return read(fd, mybuf, 255);
8551 #else
8552 #ifdef BEOSORBEBOX
8553     while (1) {
8554 #ifdef NETCONN
8555         if (netconn) {
8556             n = netxin(sizeof(mybuf), (char *)mybuf);
8557             debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
8558 	}
8559         else
8560 #endif /* NETCONN */
8561 	  n = read(fd, mybuf, sizeof(mybuf));
8562 	debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
8563         if (n > 0)
8564 	  return(n);
8565         snooze(1000.0);
8566     }
8567 #else /* BEOSORBEBOX */
8568     errno = 0;
8569     /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */
8570 #ifdef IBMX25
8571     if (netconn && (nettype == NET_IX25)) {
8572 	/* can't use sizeof because mybuf is a pointer, and not an array! */
8573 	n = x25xin( MYBUFLEN, mybuf );
8574     } else
8575 #endif /* IBMX25 */
8576 
8577 #ifdef CK_SSL
8578       if (ssl_active_flag || tls_active_flag) {
8579 	  int error, n = 0;
8580 	  debug(F100,"myfillbuf calling SSL_read() fd","",0);
8581 	  while (n == 0) {
8582 	      if (ssl_active_flag)
8583                 n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8584 	      else if (tls_active_flag)
8585                 n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8586               else
8587 		break;
8588 	      switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8589 		case SSL_ERROR_NONE:
8590 		  if (n > 0)
8591                     return(n);
8592 		  if (n < 0)
8593                     return(-2);
8594 		  msleep(50);
8595 		  break;
8596 		case SSL_ERROR_WANT_WRITE:
8597 		case SSL_ERROR_WANT_READ:
8598 		  return(-1);
8599 		case SSL_ERROR_SYSCALL:
8600 		  if (n != 0)
8601 		    return(-1);
8602 		case SSL_ERROR_WANT_X509_LOOKUP:
8603 		case SSL_ERROR_SSL:
8604 		case SSL_ERROR_ZERO_RETURN:
8605 		default:
8606 		  ttclos(0);
8607 		  return(-3);
8608             }
8609         }
8610     }
8611 #endif /* CK_SSL */
8612 #ifdef CK_KERBEROS
8613 #ifdef KRB4
8614 #ifdef RLOGCODE
8615     if (ttnproto == NP_EK4LOGIN) {
8616 	debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd);
8617         if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8618 	  return(-3);
8619         else
8620 	  return(n);
8621     }
8622 #endif /* RLOGCODE */
8623 #endif /* KRB4 */
8624 #ifdef KRB5
8625 #ifdef RLOGCODE
8626     if (ttnproto == NP_EK5LOGIN) {
8627 	debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd);
8628         if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0)
8629 	  return(-3);
8630         else
8631 	  return(n);
8632     }
8633 #endif /* RLOGCODE */
8634 #ifdef KRB5_U2U
8635     if (ttnproto == NP_K5U2U) {
8636 	debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd);
8637         if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8638 	  return(-3);
8639         else
8640 	  return(n);
8641     }
8642 #endif /* KRB5_U2U */
8643 #endif /* KRB5 */
8644 #endif /* CK_KERBEROS */
8645 
8646 #ifdef NETPTY
8647 #ifdef HAVE_PTYTRAP
8648     /* Special handling for HP-UX pty i/o */
8649   ptyread:
8650     if (ttpty && pty_trap_pending(ttyfd) > 0) {
8651 	debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd);
8652         if (pty_trap_handler(ttyfd) > 0) {
8653             ttclos(0);
8654             return(-3);
8655         }
8656     }
8657 #endif /* HAVE_PTYTRAP */
8658 #endif /* NETPTY */
8659     debug(F101,"myfillbuf calling read() fd","",ttyfd);
8660     n = read(fd, mybuf, sizeof(mybuf));
8661     debug(F101,"SVORPOSIX myfillbuf read","",n);
8662     debug(F101,"SVORPOSIX myfillbuf errno","",errno);
8663     debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
8664     if (n < 1) {
8665 #ifdef NETPTY
8666 #ifdef HAVE_PTYTRAP
8667         /* When we have a PTY trap in place the connection cannot */
8668         /* be closed until the trap receives a close indication.  */
8669         if (n == 0 && ttpty)
8670             goto ptyread;
8671 #endif /* HAVE_PTYTRAP */
8672 #endif /* NETPTY */
8673         return(-3);
8674     }
8675     return(n);
8676 #endif /* BEOSORBEBOX */
8677 #endif /* sxaE50 */
8678 }
8679 
8680 #else /* not AT&T or POSIX */
8681 
8682 #ifdef aegis
8683 	/* This is quoted from the old myread().  The semantics seem to be
8684 	 * alright, but maybe errno would not need to be set even when
8685 	 * there is no error?  I don't know aegis.
8686 	 */
8687 int
myfillbuf()8688 myfillbuf() {
8689     int count;
8690 #ifdef NETCMD
8691     if (ttpipe)
8692       fd = fdin;
8693     else
8694 #endif /* NETCMD */
8695       fd = ttyfd;
8696 
8697     count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
8698     errno = EIO;
8699     if (st.all == ios_$get_conditional_failed) /* get at least one */
8700       count = ios_$get((short)fd, 0, mybuf, 1L, st);
8701     if (st.all == ios_$end_of_file)
8702       return(-3);
8703     else if (st.all != status_$ok) {
8704 	errno = EIO;
8705 	return(-1);
8706     }
8707     return(count > 0 ? count : -3);
8708 }
8709 #else /* !aegis */
8710 
8711 #ifdef FIONREAD
8712 	/* This is for systems with FIONREAD.  FIONREAD returns the number
8713 	 * of characters available for reading. If none are available, wait
8714 	 * until something arrives, otherwise return all there is.
8715 	 */
8716 int
myfillbuf()8717 myfillbuf() {
8718     PEEKTYPE avail = 0;
8719     int x, fd;
8720 #ifdef NETCMD
8721     if (ttpipe)
8722       fd = fdin;
8723     else
8724 #endif /* NETCMD */
8725       fd = ttyfd;
8726 
8727 #ifdef SUNX25
8728 /*
8729   SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
8730   Depends on SunOS having FIONREAD, not because we use it, but just so this
8731   code is grouped correctly within the #ifdefs.  Let's hope Solaris keeps it.
8732 
8733   We call x25xin() instead of read() so that Q-Bit packets, which contain
8734   X.25 service-level information (e.g. PAD parameter changes), can be processed
8735   transparently to the upper-level code.  This is a blocking read, and so
8736   we depend on higher-level code (such as ttinc()) to set any necessary alarms.
8737 */
8738     extern int nettype;
8739     if (netconn && nettype == NET_SX25) {
8740 	while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
8741 	return(x - 1);	        /* "-1" compensates for extra status byte */
8742     }
8743 #endif /* SUNX25 */
8744 
8745 #ifdef CK_SSL
8746     if (ssl_active_flag || tls_active_flag) {
8747         int error, n = 0;
8748         while (n == 0) {
8749             if (ssl_active_flag)
8750 	      n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8751             else
8752 	      n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8753             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8754 	      case SSL_ERROR_NONE:
8755                 if (n > 0)
8756 		  return(n);
8757                 if (n < 0)
8758 		  return(-2);
8759                 msleep(50);
8760                 break;
8761 	      case SSL_ERROR_WANT_WRITE:
8762 	      case SSL_ERROR_WANT_READ:
8763                 return(-1);
8764 	      case SSL_ERROR_SYSCALL:
8765 		if (n != 0)
8766 		  return(-1);
8767 	      case SSL_ERROR_WANT_X509_LOOKUP:
8768 	      case SSL_ERROR_SSL:
8769 	      case SSL_ERROR_ZERO_RETURN:
8770 	      default:
8771                 ttclos(0);
8772                 return(-2);
8773             }
8774         }
8775     }
8776 #endif /* CK_SSL */
8777 #ifdef CK_KERBEROS
8778 #ifdef KRB4
8779 #ifdef RLOGCODE
8780     if (ttnproto == NP_EK4LOGIN) {
8781         if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8782 	  return(-1);
8783         else
8784 	  return(x);
8785     }
8786 #endif /* RLOGCODE */
8787 #endif /* KRB4 */
8788 #ifdef KRB5
8789 #ifdef RLOGCODE
8790     if (ttnproto == NP_EK5LOGIN) {
8791         if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8792 	  return(-1);
8793         else
8794 	  return(x);
8795     }
8796 #endif /* RLOGCODE */
8797 #ifdef KRB5_U2U
8798     if (ttnproto == NP_K5U2U) {
8799         if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8800 	  return(-1);
8801         else
8802 	  return(x);
8803     }
8804 #endif /* KRB5_U2U */
8805 #endif /* KRB5 */
8806 #endif /* CK_KERBEROS */
8807 
8808     errno = 0;
8809     debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
8810     x = ioctl(fd, FIONREAD, &avail);
8811 #ifdef DEBUG
8812     if (deblog) {
8813 	debug(F101,"myfillbuf FIONREAD","",x);
8814 	debug(F101,"myfillbuf FIONREAD avail","",avail);
8815 	debug(F101,"myfillbuf FIONREAD errno","",errno);
8816     }
8817 #endif /* DEBUG */
8818     if (x < 0 || avail == 0)
8819       avail = 1;
8820 
8821     if (avail > MYBUFLEN)
8822       avail = MYBUFLEN;
8823 
8824     errno = 0;
8825 
8826     x = read(fd, mybuf, (int) avail);
8827 #ifdef DEBUG
8828     if (deblog) {
8829 	debug(F101,"myfillbuf avail","",avail);
8830 	debug(F101,"myfillbuf read","",x);
8831 	debug(F101,"myfillbuf read errno","",errno);
8832         if (x > 0)
8833 	  ckhexdump("myfillbuf mybuf",mybuf,x);
8834     }
8835 #endif /* DEBUG */
8836     if (x < 1) x = -3;			/* read 0 == connection loss */
8837     return(x);
8838 }
8839 
8840 #else /* !FIONREAD */
8841 /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
8842 /* When there is no other possibility, read 1 character at a time. */
8843 int
myfillbuf()8844 myfillbuf() {
8845     int x;
8846 
8847 #ifdef CK_SSL
8848     if (ssl_active_flag || tls_active_flag) {
8849         int error, n = 0;
8850         while (n == 0) {
8851             if (ssl_active_flag)
8852 	      n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8853             else
8854 	      count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8855             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8856 	      case SSL_ERROR_NONE:
8857                 if (n > 0)
8858 		  return(n);
8859                 if (n < 0)
8860 		  return(-2);
8861                 msleep(50);
8862                 break;
8863 	      case SSL_ERROR_WANT_WRITE:
8864 	      case SSL_ERROR_WANT_READ:
8865                 return(-1);
8866 	      case SSL_ERROR_SYSCALL:
8867 		if (n != 0)
8868 		  return(-1);
8869 	      case SSL_ERROR_WANT_X509_LOOKUP:
8870 	      case SSL_ERROR_SSL:
8871 	      case SSL_ERROR_ZERO_RETURN:
8872 	      default:
8873                 ttclos(0);
8874                 return(-2);
8875             }
8876         }
8877     }
8878 #endif /* CK_SSL */
8879 #ifdef CK_KERBEROS
8880 #ifdef KRB4
8881 #ifdef RLOGCODE
8882     if (ttnproto == NP_EK4LOGIN) {
8883         if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8884 	  return(-1);
8885         else
8886 	  return(len);
8887     }
8888 #endif /* RLOGCODE */
8889 #endif /* KRB4 */
8890 #ifdef KRB5
8891 #ifdef RLOGCODE
8892     if (ttnproto == NP_EK5LOGIN) {
8893         if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8894 	  return(-1);
8895         else
8896 	  return(len);
8897     }
8898 #endif /* RLOGCODE */
8899 #ifdef KRB5_U2U
8900     if (ttnproto == NP_K5U2U) {
8901         if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8902 	  return(-1);
8903         else
8904 	  return(len);
8905     }
8906 #endif /* KRB5_U2U */
8907 #endif /* KRB5 */
8908 #endif /* CK_KERBEROS */
8909 
8910 #ifdef NETCMD
8911     if (ttpipe)
8912       fd = fdin;
8913     else
8914 #endif /* NETCMD */
8915       fd = ttyfd;
8916     x = read(fd, mybuf, 1);
8917     return(x > 0 ? x : -3);
8918 }
8919 
8920 #endif /* !FIONREAD */
8921 #endif /* !aegis */
8922 #endif /* !ATTSV */
8923 
8924 #endif /* MYREAD */
8925 
8926 /*  T T _ T N O P T  --  Handle Telnet negotions in incoming data */
8927 /*
8928   Call with the IAC that was encountered.
8929   Returns:
8930    -3: If connection has dropped or gone bad.
8931    -2: On Telnet protocol error resulting in inconsistent states.
8932     0: If negotiation OK and caller has nothing to do.
8933     1: If packet start character has changed (new value is in global stchr).
8934   255: If there was a quoted IAC as data.
8935    or: Not at all if we got a legitimate Telnet Logout request.
8936 */
8937 #ifdef TCPSOCKET
8938 static int
tt_tnopt(n)8939 tt_tnopt(n) int n; {			/* Handle Telnet options */
8940     /* In case caller did not already check these conditions...  */
8941     if (n == IAC &&
8942 	((xlocal && netconn && IS_TELNET()) ||
8943 	 (!xlocal && sstelnet))) {
8944 	extern int server;
8945 	int tx = 0;
8946 	debug(F100,"ttinl calling tn_doop()","",0);
8947 	tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
8948 	debug(F111,"ttinl tn_doop() returned","tx",tx);
8949 	switch (tx) {
8950 	  case 0:
8951 	    return(0);
8952 	  case -1:			/* I/O error */
8953 	    ttimoff();			/* Turn off timer */
8954 	    return(-3);
8955           case -2:			/* Connection failed. */
8956           case -3:
8957 	    ttimoff();			/* Turn off timer */
8958 	    ttclos(0);
8959 	    return(-3);
8960 	  case 1:			/* ECHO change */
8961 	    duplex = 1;
8962 	    return(0);
8963 	  case 2:			/* ECHO change */
8964 	    duplex = 0;
8965 	    return(0);
8966 	  case 3:			/* Quoted IAC */
8967 	    n = 255;
8968 	    return((unsigned)255);
8969 #ifdef IKS_OPTION
8970 	  case 4: {
8971 	      if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
8972 #ifdef IKSD
8973 		  && !inserver
8974 #endif /* IKSD */
8975 		  ) {			/* Remote in Server mode */
8976 		  ttimoff();		/* Turn off timer */
8977 		  debug(F100,"u_start and !inserver","",0);
8978 		  return(-2);		/* End server mode */
8979 	      } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
8980 			 server
8981 			 ) {		/* I'm no longer in Server Mode */
8982 		  debug(F100,"me_start and server","",0);
8983 		  ttimoff();
8984 		  return(-2);
8985 	      }
8986 	      return(0);
8987 	  }
8988 	  case 5: {			/* Start character change */
8989 	      /* extern CHAR stchr; */
8990 	      /* start = stchr; */
8991 	      return(1);
8992 	  }
8993 #endif /* IKS_OPTION */
8994 	  case 6:			/* Remote Logout */
8995 	    ttimoff();
8996 	    ttclos(0);
8997 #ifdef IKSD
8998 	    if (inserver && !local)
8999 	      doexit(GOOD_EXIT,0);
9000 	    else
9001 #endif /* IKSD */
9002 	      return(-2);
9003 	  default:
9004 	    return(0);
9005 	}
9006     } else
9007       return(0);
9008 }
9009 #endif /* TCPSOCKET */
9010 
9011 /*  T T F L U I  --  Flush tty input buffer */
9012 
9013 void
ttflux()9014 ttflux() {				/* But first... */
9015 #ifdef MYREAD
9016 /*
9017   Flush internal MYREAD buffer.
9018 */
9019 #ifdef TCPSOCKET
9020     int dotnopts, x;
9021     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
9022 		 (!xlocal && sstelnet)));
9023 #endif /* TCPSOCKET */
9024     debug(F101,"ttflux my_count","",my_count);
9025 #ifdef TCPSOCKET
9026     if (dotnopts) {
9027 	CHAR ch = '\0';
9028         while (my_count > 0) {
9029 	    ch = myread();
9030 #ifdef CK_ENCRYPTION
9031             if (TELOPT_U(TELOPT_ENCRYPTION))
9032 	      ck_tn_decrypt((char *)&ch,1);
9033 #endif /* CK_ENCRYPTION */
9034             if (ch == IAC)
9035 	      x = tt_tnopt(ch);
9036         }
9037     } else
9038 #endif /* TCPSOCKET */
9039 #ifdef COMMENT
9040 #ifdef CK_ENCRYPTION
9041     if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
9042       ck_tn_decrypt(&mybuf[my_item+1],my_count);
9043 #endif /* CK_ENCRYPTION */
9044 #endif /* COMMENT */
9045     my_count = 0;			/* Reset count to zero */
9046     my_item = -1;			/* And buffer index to -1 */
9047 #endif /* MYREAD */
9048 }
9049 
9050 int
ttflui()9051 ttflui() {
9052     int n, fd;
9053 #ifdef TCPSOCKET
9054     int dotnopts;
9055     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
9056 		 (!xlocal && sstelnet)));
9057 #endif /* TCPSOCKET */
9058 
9059 #ifdef NETCMD
9060     if (ttpipe)
9061       fd = fdin;
9062     else
9063 #endif /* NETCMD */
9064       fd = ttyfd;
9065 
9066 #ifdef TTLEBUF
9067     ttpush = -1;			/* Clear the peek-ahead char */
9068     while (le_data && (le_inbuf() > 0)) {
9069         CHAR ch = '\0';
9070         if (le_getchar(&ch) > 0) {	/* Clear any more... */
9071             debug(F101,"ttflui le_inbuf ch","",ch);
9072         }
9073     }
9074 #endif /* TTLEBUF */
9075     debug(F101,"ttflui ttpipe","",ttpipe);
9076 
9077 #ifdef MYREAD
9078 /*
9079   Flush internal MYREAD buffer *NEXT*, in all cases.
9080 */
9081     ttflux();
9082 #endif /* MYREAD */
9083 
9084 #ifdef NETCONN
9085 /* Network flush is done specially, in the network support module. */
9086     if ((netconn || sstelnet) && !ttpipe && !ttpty) {
9087 	debug(F100,"ttflui netflui","",0);
9088 #ifdef COMMENT
9089 #ifdef TN_COMPORT
9090 	if (istncomport())
9091             tnc_send_purge_data(TNC_PURGE_RECEIVE);
9092 #endif /* TN_COMPORT */
9093 #endif /* COMMENT */
9094 	return(netflui());
9095     }
9096 #endif /* NETCONN */
9097 
9098     debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
9099     if (ttyfd < 0)
9100       return(-1);
9101 
9102 #ifdef aegis
9103     sio_$control((short)yfd, sio_$flush_in, true, st);
9104     if (st.all != status_$ok) {
9105 	fprintf(stderr, "flush failed: "); error_$print(st);
9106     } else {      /* sometimes the flush doesn't work */
9107         for (;;) {
9108 	    char buf[256];
9109             /* eat all the characters that shouldn't be available */
9110             ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
9111             if (st.all == ios_$get_conditional_failed) break;
9112             fprintf(stderr, "flush failed(2): "); error_$print(st);
9113         }
9114     }
9115 #else
9116 #ifdef BSD44				/* 4.4 BSD */
9117     n = FREAD;                          /* Specify read queue */
9118     debug(F100,"ttflui BSD44","",0);
9119     ioctl(fd,TIOCFLUSH,&n);
9120 #else
9121 #ifdef Plan9
9122 #undef POSIX				/* Uh oh... */
9123 #endif /* Plan9 */
9124 #ifdef POSIX				/* POSIX */
9125     debug(F100,"ttflui POSIX","",0);
9126     tcflush(fd,TCIFLUSH);
9127 #else
9128 #ifdef ATTSV				/* System V */
9129 #ifndef VXVE
9130     debug(F100,"ttflui ATTSV","",0);
9131     ioctl(fd,TCFLSH,0);
9132 #endif /* VXVE */
9133 #else					/* Not BSD44, POSIX, or Sys V */
9134 #ifdef TIOCFLUSH			/* Those with TIOCFLUSH defined */
9135 #ifdef ANYBSD				/* Berkeley */
9136     n = FREAD;                          /* Specify read queue */
9137     debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
9138     ioctl(fd,TIOCFLUSH,&n);
9139 #else					/* Others (V7, etc) */
9140     debug(F100,"ttflui TIOCFLUSH","",0);
9141     ioctl(fd,TIOCFLUSH,0);
9142 #endif /* ANYBSD */
9143 #else					/* All others... */
9144 /*
9145   No system call (that we know about) for input buffer flushing.
9146   So see how many there are and read them in a loop, using ttinc().
9147   ttinc() is buffered, so we're not getting charged with a system call
9148   per character, just a function call.
9149 */
9150     if ((n = ttchk()) > 0) {
9151 	debug(F101,"ttflui read loop","",n);
9152 	while ((n--) && ttinc(0) > 0) ;
9153     }
9154 #endif /* TIOCFLUSH */
9155 #endif /* ATTSV */
9156 #endif /* POSIX */
9157 #ifdef Plan9
9158 #define POSIX
9159 #endif /* Plan9 */
9160 #endif /* BSD44 */
9161 #endif /* aegis */
9162     return(0);
9163 }
9164 
9165 int
ttfluo()9166 ttfluo() {				/* Flush output buffer */
9167     int fd;
9168 #ifdef NETCMD
9169     if (ttpipe)
9170       fd = fdout;
9171     else
9172 #endif /* NETCMD */
9173       fd = ttyfd;
9174 
9175 #ifdef Plan9
9176     return 0;
9177 #else
9178 #ifdef POSIX
9179     return(tcflush(fd,TCOFLUSH));
9180 #else
9181 #ifdef OXOS
9182     return(ioctl(fd,TCFLSH,1));
9183 #else
9184     return(0);				/* All others, nothing */
9185 #endif /* OXOS */
9186 #endif /* POSIX */
9187 #endif /* Plan9 */
9188 }
9189 
9190 /* Interrupt Functions */
9191 
9192 /* Set up terminal interrupts on console terminal */
9193 
9194 #ifndef FIONREAD			/* We don't need esctrp() */
9195 #ifndef SELECT				/* if we have any of these... */
9196 #ifndef CK_POLL
9197 #ifndef RDCHK
9198 
9199 #ifndef OXOS
9200 #ifdef SVORPOSIX
9201 SIGTYP
esctrp(foo)9202 esctrp(foo) int foo; {			/* trap console escapes (^\) */
9203     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9204     conesc = 1;
9205     debug(F101,"esctrp caught SIGQUIT","",conesc);
9206 }
9207 #endif /* SVORPOSIX */
9208 #endif /* OXOS */
9209 
9210 #ifdef V7
9211 #ifndef MINIX2
9212 SIGTYP
esctrp(foo)9213 esctrp(foo) int foo; {			/* trap console escapes (^\) */
9214     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9215     conesc = 1;
9216     debug(F101,"esctrp caught SIGQUIT","",conesc);
9217 }
9218 #endif /* MINIX2 */
9219 #endif /* V7 */
9220 
9221 #ifdef C70
9222 SIGTYP
esctrp(foo)9223 esctrp(foo) int foo; {			/* trap console escapes (^\) */
9224     conesc = 1;
9225     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9226 }
9227 #endif /* C70 */
9228 
9229 #endif /* RDCHK */
9230 #endif /* CK_POLL */
9231 #endif /* SELECT */
9232 #endif /* FIONREAD */
9233 
9234 /*  C O N B G T  --  Background Test  */
9235 
9236 static int jc = 0;			/* 0 = no job control */
9237 
9238 /*
9239   Call with flag == 1 to prevent signal test, which can not be expected
9240   to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
9241 
9242   Call with flag == 0 to use the signal test, but only if the process-group
9243   test fails, as it does on some UNIX systems, where getpgrp() is buggy,
9244   requires an argument when the man page says it doesn't, or vice versa.
9245 
9246   If flag == 0 and the process-group test fails, then we determine background
9247   status simply (but not necessarily reliably) from isatty().
9248 
9249   conbgt() sets the global backgrd = 1 if we appear to be in the background,
9250   and to 0 if we seem to be in the foreground.  conbgt() is highly prone to
9251   misbehavior.
9252 */
9253 VOID
conbgt(flag)9254 conbgt(flag) int flag; {
9255     int x = -1,				/* process group or SIGINT test */
9256         y = 0;				/* isatty() test */
9257 /*
9258   Check for background operation, even if not running on real tty, so that
9259   background flag can be set correctly.  If background status is detected,
9260   then Kermit will not issue its interactive prompt or most messages.
9261   If your prompt goes away, you can blame (and fix?) this function.
9262 */
9263 
9264 /* Use process-group test if possible. */
9265 
9266 #ifdef POSIX				/* We can do it in POSIX */
9267 #define PGROUP_T
9268 #else
9269 #ifdef BSD4				/* and in BSD 4.x. */
9270 #define PGROUP_T
9271 #else
9272 #ifdef HPUXJOBCTL			/* and in most HP-UX's */
9273 #define PGROUP_T
9274 #else
9275 #ifdef TIOCGPGRP			/* and anyplace that has this ioctl. */
9276 #define PGROUP_T
9277 #endif /* TIOCGPGRP */
9278 #endif /* HPUXJOBCTL */
9279 #endif /* BSD4 */
9280 #endif /* POSIX */
9281 
9282 #ifdef MIPS				/* Except if it doesn't work... */
9283 #undef PGROUP_T
9284 #endif /* MIPS */
9285 
9286 #ifdef MINIX
9287 #undef PGROUP_T
9288 #endif	/* MINIX */
9289 
9290 #ifdef PGROUP_T
9291 /*
9292   Semi-reliable process-group test.  Check whether this process's group is
9293   the same as the controlling terminal's process group.  This works if the
9294   getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
9295 */
9296     PID_T mypgrp = (PID_T)0;		/* Kermit's process group */
9297     PID_T ctpgrp = (PID_T)0;		/* The terminal's process group */
9298 #ifndef _POSIX_SOURCE
9299 /*
9300   The getpgrp() prototype is obtained from system header files for POSIX
9301   and Sys V R4 compilations.  Other systems, who knows.  Some complain about
9302   a duplicate declaration here, others don't, so it's safer to leave it in
9303   if we don't know for certain.
9304 */
9305 #ifndef SVR4
9306 #ifndef PS2AIX10
9307 #ifndef HPUX9
9308     extern PID_T getpgrp();
9309 #endif /* HPUX9 */
9310 #endif /* PS2AIX10 */
9311 #endif /* SVR4 */
9312 #endif /* _POSIX_SOURCE */
9313 
9314 /* Get my process group. */
9315 
9316 #ifdef SVR3 /* Maybe this should be ATTSV? */
9317 /* This function is not described in SVID R2 */
9318     mypgrp = getpgrp();
9319     /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
9320 #else
9321 #ifdef POSIX
9322     mypgrp = getpgrp();
9323     /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
9324 #else
9325 #ifdef OSFPC
9326     mypgrp = getpgrp();
9327     /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
9328 #else
9329 #ifdef QNX
9330     mypgrp = getpgrp();
9331     /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
9332 #else
9333 #ifdef OSF32				/* (was OSF40) */
9334     mypgrp = getpgrp();
9335     /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
9336 #else /* BSD, V7, etc */
9337 #ifdef MINIX2
9338     mypgrp = getpgrp();
9339 #else
9340     mypgrp = getpgrp(0);
9341 #endif /* MINIX2 */
9342     /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
9343 #endif /* OSF32 */
9344 #endif /* QNX */
9345 #endif /* OSFPC */
9346 #endif /* POSIX */
9347 #endif /* SVR3 */
9348 
9349 #ifdef MINIX
9350     /* MINIX does not support job control so Kermit is always in foreground */
9351     x = 0;
9352 
9353 #else  /* Not MINIX */
9354 
9355 /* Now get controlling tty's process group */
9356 #ifdef BSD44ORPOSIX
9357     ctpgrp = tcgetpgrp(1);		/* The POSIX way */
9358     /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
9359 #else
9360     ioctl(1, TIOCGPGRP, &ctpgrp);	/* Or the BSD way */
9361    /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
9362 #endif /* BSD44ORPOSIX */
9363 
9364     if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
9365       x = (mypgrp == ctpgrp) ? 0 : 1;	/* If they differ, then background. */
9366     else x = -1;			/* If error, remember. */
9367     debug(F101,"conbgt process group test","",x);
9368 #endif /* PGROUP_T */
9369 #endif	/* MINIX */
9370 
9371 /* Try to see if job control is available */
9372 
9373 #ifdef NOJC				/* User override */
9374     jc = 0;				/* No job control allowed */
9375     debug(F111,"NOJC","jc",jc);
9376 #else
9377 #ifdef BSD44
9378     jc = 1;
9379 #else
9380 #ifdef SVR4ORPOSIX			/* POSIX actually tells us */
9381     debug(F100,"SVR4ORPOSIX jc test...","",0);
9382 #ifdef _SC_JOB_CONTROL
9383 #ifdef __bsdi__
9384     jc = 1;
9385 #else
9386 #ifdef __386BSD__
9387     jc = 1;
9388 #else
9389     jc = sysconf(_SC_JOB_CONTROL);	/* Whatever system says */
9390     if (jc < 0) {
9391 	debug(F101,"sysconf fails, jcshell","",jcshell);
9392 	jc = (jchdlr == SIG_DFL) ? 1 : 0;
9393     } else
9394       debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
9395 #endif /* __386BSD__ */
9396 #endif /* __bsdi__ */
9397 #else
9398 #ifdef _POSIX_JOB_CONTROL
9399     jc = 1;				/* By definition */
9400     debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
9401 #else
9402     jc = 0;				/* Assume job control not allowed */
9403     debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
9404 #endif /* _POSIX_JOB_CONTROL */
9405 #endif /* _SC_JOB_CONTROL */
9406 #else
9407 #ifdef BSD4
9408     jc = 1;				/* Job control allowed */
9409     debug(F111,"BSD job control","jc",jc);
9410 #else
9411 #ifdef SVR3JC
9412     jc = 1;				/* JC allowed */
9413     debug(F111,"SVR3 job control","jc",jc);
9414 #else
9415 #ifdef OXOS
9416     jc = 1;				/* JC allowed */
9417     debug(F111,"X/OS job control","jc",jc);
9418 #else
9419 #ifdef HPUX9
9420     jc = 1;				/* JC allowed */
9421     debug(F111,"HP-UX 9.0 job control","jc",jc);
9422 #else
9423 #ifdef HPUX10
9424     jc = 1;				/* JC allowed */
9425     debug(F111,"HP-UX 10.0 job control","jc",jc);
9426 #else
9427     jc = 0;				/* JC not allowed */
9428     debug(F111,"job control catch-all","jc",jc);
9429 #endif /* HPUX10 */
9430 #endif /* HPUX9 */
9431 #endif /* OXOS */
9432 #endif /* SVR3JC */
9433 #endif /* BSD4 */
9434 #endif /* SVR4ORPOSIX */
9435 #endif /* BSD44 */
9436 #endif /* NOJC */
9437     debug(F101,"conbgt jc","",jc);
9438 #ifndef NOJC
9439     debug(F101,"conbgt jcshell","",jcshell);
9440 /*
9441   At this point, if jc == 1 but jcshell == 0, it means that the OS supports
9442   job control, but the shell or other process we are running under does not
9443   (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
9444   will come of it.  So...
9445 */
9446     if (jc < 0) jc = 0;
9447     if (jc > 0 && jcshell == 0) jc = 0;
9448 #endif /* NOJC */
9449 
9450 /*
9451   Another background test.
9452   Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
9453   which is done by the shell (sh) if the program is started with '&'.
9454   Unfortunately, this is NOT done by csh or ksh so watch out!
9455   Note, it's safe to set SIGINT to SIG_IGN here, because further down
9456   we always set it to something else.
9457   Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
9458   SIG_IGN ourselves.
9459 */
9460     if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
9461 
9462 	SIGTYP (*osigint)();
9463 
9464 	osigint = signal(SIGINT,SIG_IGN);	/* What is SIGINT set to? */
9465 	sigint_ign = 1;
9466 	x = (osigint == SIG_IGN) ? 1 : 0;	/* SIG_IGN? */
9467 	/* debug(F101,"conbgt osigint","",osigint); */
9468 	/* debug(F101,"conbgt signal test","",x); */
9469     }
9470 
9471 /* Also check to see if we're running with redirected stdio. */
9472 /* This is not really background operation, but we want to act as though */
9473 /* it were. */
9474 
9475 #ifdef IKSD
9476     if (inserver) {			/* Internet Kermit Server */
9477 	backgrd = 0;			/* is not in the background */
9478 	return;
9479     }
9480 #endif /* IKSD */
9481 
9482     y = (isatty(0) && isatty(1)) ? 1 : 0;
9483     debug(F101,"conbgt isatty test","",y);
9484 
9485 #ifdef BSD29
9486 /* The process group and/or signal test doesn't work under these... */
9487     backgrd = !y;
9488 #else
9489 #ifdef sxaE50
9490     backgrd = !y;
9491 #else
9492 #ifdef MINIX
9493     backgrd = !y;
9494 #else
9495 #ifdef MINIX2
9496     backgrd = !y;
9497 #else
9498     if (x > -1)
9499       backgrd = (x || !y) ? 1 : 0;
9500     else backgrd = !y;
9501 #endif /* BSD29 */
9502 #endif /* sxaE50 */
9503 #endif /* MINIX */
9504 #endif /* MINIX2 */
9505     debug(F101,"conbgt backgrd","",backgrd);
9506 }
9507 
9508 /*  C O N I N T  --  Console Interrupt setter  */
9509 
9510 /*
9511   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
9512   Second arg is pointer to function to handle SIGTSTP (suspend).
9513 */
9514 
9515 VOID					/* Set terminal interrupt traps. */
9516 #ifdef CK_ANSIC
9517 #ifdef apollo
9518 conint(f,s) SIGTYP (*f)(), (*s)();
9519 #else
9520 conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
9521 #endif /* apollo */
9522 #else
9523 conint(f,s) SIGTYP (*f)(), (*s)();
9524 #endif /* CK_ANSIC */
9525 /* conint */ {
9526 
9527     debug(F101,"conint conistate","",conistate);
9528 
9529     conbgt(0);				/* Do background test. */
9530 
9531 /* Set the desired handlers for hangup and software termination. */
9532 
9533 #ifdef SIGTERM
9534     signal(SIGTERM,f);                  /* Software termination */
9535 #endif /* SIGTERM */
9536 
9537 /*
9538   Prior to July 1999 we used to call sighup() here but now it's called in
9539   sysinit() so SIGHUP can be caught during execution of the init file or
9540   a kerbang script.
9541 */
9542 
9543 /* Now handle keyboard stop, quit, and interrupt signals. */
9544 /* Check if invoked in background -- if so signals set to be ignored. */
9545 /* However, if running under a job control shell, don't ignore them. */
9546 /* We won't be getting any, as we aren't in the terminal's process group. */
9547 
9548     debug(F101,"conint backgrd","",backgrd);
9549     debug(F101,"conint jc","",jc);
9550 
9551     if (backgrd && !jc) {		/* In background, ignore signals */
9552 	debug(F101,"conint background ignoring signals, jc","",jc);
9553 #ifdef SIGTSTP
9554         signal(SIGTSTP,SIG_IGN);        /* Keyboard stop */
9555 #endif /* SIGTSTP */
9556         signal(SIGQUIT,SIG_IGN);        /* Keyboard quit */
9557         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
9558 	sigint_ign = 1;
9559 	conistate = CONI_NOI;
9560     } else {				/* Else in foreground or suspended */
9561 	debug(F101,"conint foreground catching signals, jc","",jc);
9562         signal(SIGINT,f);               /* Catch terminal interrupt */
9563 	sigint_ign = (f == SIG_IGN) ? 1 : 0;
9564 
9565 #ifdef SIGTSTP				/* Keyboard stop (suspend) */
9566 	/* debug(F101,"conint SIGSTSTP","",s); */
9567 	if (s == NULL) s = SIG_DFL;
9568 #ifdef NOJC				/* No job control allowed. */
9569 	signal(SIGTSTP,SIG_IGN);
9570 #else					/* Job control allowed */
9571 	if (jc)				/* if available. */
9572 	  signal(SIGTSTP,s);
9573 	else
9574 	  signal(SIGTSTP,SIG_IGN);
9575 #endif /* NOJC */
9576 #endif /* SIGTSTP */
9577 
9578 #ifndef OXOS
9579 #ifdef SVORPOSIX
9580 #ifndef FIONREAD			/* Watch out, we don't know this... */
9581 #ifndef SELECT
9582 #ifndef CK_POLL
9583 #ifndef RDCHK
9584         signal(SIGQUIT,esctrp);         /* Quit signal, Sys III/V. */
9585 #endif /* RDCHK */
9586 #endif /* CK_POLL */
9587 #endif /* SELECT */
9588 #endif /* FIONREAD */
9589         if (conesc) conesc = 0;         /* Clear out pending escapes */
9590 #else
9591 #ifdef V7
9592         signal(SIGQUIT,esctrp);         /* V7 like Sys III/V */
9593         if (conesc) conesc = 0;
9594 #else
9595 #ifdef aegis
9596         signal(SIGQUIT,f);              /* Apollo, catch it like others. */
9597 #else
9598         signal(SIGQUIT,SIG_IGN);        /* Others, ignore like 4D & earlier. */
9599 #endif /* aegis */
9600 #endif /* V7 */
9601 #endif /* SVORPOSIX */
9602 #endif /* OXOS */
9603 	conistate = CONI_INT;
9604     }
9605 }
9606 
9607 
9608 /*  C O N N O I  --  Reset console terminal interrupts */
9609 
9610 VOID
connoi()9611 connoi() {                              /* Console-no-interrupts */
9612 
9613     debug(F101,"connoi conistate","",conistate);
9614 #ifdef SIGTSTP
9615     signal(SIGTSTP,SIG_IGN);		/* Suspend */
9616 #endif /* SIGTSTP */
9617     conint(SIG_IGN,SIG_IGN);		/* Interrupt */
9618     sigint_ign = 1;			/* Remember we did this ourselves */
9619 #ifdef SIGQUIT
9620     signal(SIGQUIT,SIG_IGN);		/* Quit */
9621 #endif /* SIGQUIT */
9622 #ifdef SIGTERM
9623     signal(SIGTERM,SIG_IGN);		/* Term */
9624 #endif /* SIGTERM */
9625     conistate = CONI_NOI;
9626 }
9627 
9628 /*  I N I T R A W Q  --  Set up to read /dev/kmem for character count.  */
9629 
9630 #ifdef  V7
9631 /*
9632  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
9633  eliminates blocking on a read, because we can read /dev/kmem to get the
9634  number of characters available for raw input.  If your system can't
9635  or you won't let the world read /dev/kmem then you must figure out a
9636  different way to do the counting of characters available, or else replace
9637  this by a dummy function that always returns 0.
9638 */
9639 /*
9640  * Call this routine as: initrawq(tty)
9641  * where tty is the file descriptor of a terminal.  It will return
9642  * (as a char *) the kernel-mode memory address of the rawq character
9643  * count, which may then be read.  It has the side-effect of flushing
9644  * input on the terminal.
9645  */
9646 /*
9647  * John Mackin, Physiology Dept., University of Sydney (Australia)
9648  * ...!decvax!mulga!physiol.su.oz!john
9649  *
9650  * Permission is hereby granted to do anything with this code, as
9651  * long as this comment is retained unmodified and no commercial
9652  * advantage is gained.
9653  */
9654 #ifndef MINIX
9655 #ifndef MINIX2
9656 #ifndef COHERENT
9657 #include <a.out.h>
9658 #include <sys/proc.h>
9659 #endif /* COHERENT */
9660 #endif /* MINIX2 */
9661 #endif /* MINIX */
9662 
9663 #ifdef COHERENT
9664 #include <l.out.h>
9665 #include <sys/proc.h>
9666 #endif /* COHERENT */
9667 
9668 char *
initrawq(tty)9669 initrawq(tty) int tty; {
9670 #ifdef MINIX
9671     return(0);
9672 #else
9673 #ifdef MINIX2
9674     return(0);
9675 #else
9676 #ifdef UTS24
9677     return(0);
9678 #else
9679 #ifdef BSD29
9680     return(0);
9681 #else
9682     long lseek();
9683     static struct nlist nl[] = {
9684         {PROCNAME},
9685         {NPROCNAME},
9686         {""}
9687     };
9688     static struct proc *pp;
9689     char *qaddr, *p, c;
9690     int m;
9691     PID_T pid, me;
9692     NPTYPE xproc;                       /* Its type is defined in makefile. */
9693     int catch();
9694 
9695     me = getpid();
9696     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
9697     nlist(BOOTNAME, nl);
9698     if (nl[0].n_type == 0) err("proc array");
9699 
9700     if (nl[1].n_type == 0) err("nproc");
9701 
9702     lseek(m, (long)(nl[1].n_value), 0);
9703     read (m, &xproc, sizeof(xproc));
9704     saval = signal(SIGALRM, catch);
9705     if ((pid = fork()) == 0) {
9706         while(1)
9707             read(tty, &c, 1);
9708     }
9709     alarm(2);
9710 
9711     if(setjmp(jjbuf) == 0) {
9712         while(1)
9713 	  read(tty, &c, 1);
9714     }
9715     signal(SIGALRM, SIG_DFL);
9716 
9717 #ifdef DIRECT
9718     pp = (struct proc *) nl[0].n_value;
9719 #else
9720     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
9721     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
9722 #endif
9723     lseek(m, (long)(nl[1].n_value), 0);
9724     read(m, &xproc, sizeof(xproc));
9725 
9726     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
9727     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
9728     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
9729         err("read proc table");
9730     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
9731         if (pp -> p_pid == (short) pid) goto iout;
9732     }
9733     err("no such proc");
9734 
9735 iout:
9736     close(m);
9737     qaddr = (char *)(pp -> p_wchan);
9738     free (p);
9739     kill(pid, SIGKILL);
9740     wait((WAIT_T *)0);
9741     return (qaddr);
9742 #endif
9743 #endif
9744 #endif
9745 #endif
9746 }
9747 
9748 /*  More V7-support functions...  */
9749 
9750 static VOID
err(s)9751 err(s) char *s; {
9752     char buf[200];
9753 
9754     ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
9755     perror(buf);
9756     doexit(1,-1);
9757 }
9758 
9759 static VOID
catch(foo)9760 catch(foo) int foo; {
9761     longjmp(jjbuf, -1);
9762 }
9763 
9764 
9765 /*  G E N B R K  --  Simulate a modem break.  */
9766 
9767 #ifdef MINIX
9768 #define BSPEED B110
9769 #else
9770 #ifdef MINIX2
9771 #define BSPEED B110
9772 #else
9773 #define BSPEED B150
9774 #endif /* MINIX2 */
9775 #endif /* MINIX */
9776 
9777 #ifndef MINIX2
9778 VOID
genbrk(fn,msec)9779 genbrk(fn,msec) int fn, msec; {
9780     struct sgttyb ttbuf;
9781     int ret, sospeed, x, y;
9782 
9783     ret = ioctl(fn, TIOCGETP, &ttbuf);
9784     sospeed = ttbuf.sg_ospeed;
9785     ttbuf.sg_ospeed = BSPEED;
9786     ret = ioctl(fn, TIOCSETP, &ttbuf);
9787     y = (int)strlen(brnuls);
9788     x = ( BSPEED * 100 ) / msec;
9789     if (x > y) x = y;
9790     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9791     ttbuf.sg_ospeed = sospeed;
9792     ret = ioctl(fn, TIOCSETP, &ttbuf);
9793     ret = write(fn, "@", 1);
9794     return;
9795 }
9796 #endif /* MINIX2 */
9797 
9798 #ifdef MINIX2
9799 int
genbrk(fn,msec)9800 genbrk(fn,msec) int fn, msec; {
9801     struct termios ttbuf;
9802     int ret, x, y;
9803     speed_t sospeed;
9804 
9805     ret = tcgetattr(fn, &ttbuf);
9806     sospeed = ttbuf.c_ospeed;
9807     ttbuf.c_ospeed = BSPEED;
9808     ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
9809     y = (int)strlen(brnuls);
9810     x = ( BSPEED * 100 ) / msec;
9811     if (x > y) x = y;
9812     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9813     ttbuf.c_ospeed = sospeed;
9814     ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
9815     ret = write(fn, "@", 1);
9816     return ret;
9817 }
9818 #endif /* MINIX2 */
9819 #endif /* V7 */
9820 
9821 /*
9822   I N C H K  --  Check if chars waiting to be read on given file descriptor.
9823 
9824   This routine is a merger of ttchk() and conchk().
9825   Call with:
9826     channel == 0 to check console.
9827     channel == 1 to check communications connection.
9828   and:
9829     fd = file descriptor.
9830   Returns:
9831    >= 0: number of characters waiting, 0 or greater,
9832      -1: on any kind of error,
9833      -2: if there is (definitely) no connection.
9834   Note: In UNIX we don't have to call nettchk() because a socket
9835   file descriptor works just like in serial i/o, ioctls and all.
9836   (But this will change if we add non-file-descriptor channels,
9837   such as IBM X.25 for AIX...)
9838 */
9839 static int
in_chk(channel,fd)9840 in_chk(channel, fd) int channel, fd; {
9841     int x, n = 0;			/* Workers, n = return value */
9842     extern int clsondisc;		/* Close on disconnect */
9843 /*
9844   The first section checks to make sure we have a connection,
9845   but only if we're in local mode.
9846 */
9847 #ifdef DEBUG
9848     if (deblog) {
9849 	debug(F111,"in_chk entry",ckitoa(fd),channel);
9850 	debug(F101,"in_chk ttyfd","",ttyfd);
9851 	debug(F101,"in_chk ttpty","",ttpty);
9852     }
9853 #endif /* DEBUG */
9854 /*
9855   But don't say connection is gone if we have any buffered-stuff.
9856 */
9857 #ifdef TTLEBUF
9858     debug(F101,"in_chk ttpush","",ttpush);
9859     if (channel == 1) {
9860 	if (ttpush >= 0)
9861 	  n++;
9862 	n += le_inbuf();
9863 	if (n > 0)
9864 	  return(n);
9865     }
9866 #endif /* TTLEBUF */
9867 
9868 #ifdef NETPTY
9869 #ifdef HAVE_PTYTRAP
9870     /* Special handling for HP-UX pty i/o */
9871     if (ttpty && pty_trap_pending(ttyfd) > 0) {
9872         if (pty_trap_handler(ttyfd) > 0) {
9873             ttclos(0);
9874             return(-2);
9875         }
9876     }
9877 #endif /* HAVE_PTYTRAP */
9878 #endif /* NETPTY */
9879 
9880     if (channel) {			/* Checking communications channel */
9881 	if (ttyfd < 0) {		/* No connection */
9882 	  return(-2);			/* That's what this means */
9883 	} else if (xlocal &&		/* In local mode */
9884 		   (!netconn		/* Serial connection or */
9885 #ifdef TN_COMPORT
9886 		    || istncomport()    /* Telnet Com Port */
9887 #endif /* TN_COMPORT */
9888 		   ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
9889 #ifdef COMMENT
9890 #ifdef MYREAD
9891 /*
9892   Seems like this would be a good idea but it prevents C-Kermit from
9893   popping back to the prompt automatically when carrier drops.  However,
9894   commenting this out prevents us from seeing the NO CARRIER message.
9895   Needs more work...
9896 */
9897 		   && my_count < 1	/* Nothing in our internal buffer */
9898 #endif /* MYREAD */
9899 #endif /* COMMENT */
9900 		   ) {
9901 	    int x;
9902 	    x = ttgmdm();		/* So get modem signals */
9903 	    debug(F101,"in_chk close-on-disconnect","",clsondisc);
9904 	    if (x > -1) {		/* Check for carrier */
9905 		if (!(x & BM_DCD)) {	/* No carrier */
9906 		    debug(F101,"in_chk carrier lost","",x);
9907 		    if (clsondisc)	/* If "close-on-disconnect" */
9908 		      ttclos(0);	/* close device & release lock. */
9909 		    return(-2);		/* This means "disconnected" */
9910 		}
9911 	    /* In case I/O to device after CD dropped always fails */
9912 	    /* as in Debian Linux 2.1 and Unixware 2.1... */
9913 	    } else {
9914 	        debug(F101,"in_chk ttgmdm I/O error","",errno);
9915 	        debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
9916 	        if (gotsigs) {		/* If we got signals before... */
9917 		    if (errno == 5 || errno == 6) { /* I/O error etc */
9918 		        if (clsondisc)	/* like when modem hangs up */
9919 			  ttclos(0);
9920 			return(-2);
9921 		    }
9922 		}
9923 		/* If we never got modem signals successfully on this */
9924 		/* connection before, we can't conclude that THIS failure */
9925 		/* means the connection was lost. */
9926 		return(0);
9927 	    }
9928 	}
9929     }
9930 
9931 /* We seem to have a connection so now see if any bytes are waiting on it */
9932 
9933 #ifdef CK_SSL
9934     if (ssl_active_flag || tls_active_flag) {
9935         n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
9936         debug(F101,"in_chk SSL_pending","",n);
9937         if (n < 0) {
9938             ttclos(0);
9939             return(-1);
9940         } else if (n > 0) {
9941             return(n);
9942         }
9943     }
9944 #endif /* CK_SSL */
9945 #ifdef RLOGCODE
9946 #ifdef CK_KERBEROS
9947     /* It is not safe to read any data when using encrypted Klogin */
9948     if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
9949 #ifdef KRB4
9950         if (ttnproto == NP_EK4LOGIN) {
9951             n += krb4_des_avail(ttyfd);
9952             debug(F101,"in_chk krb4_des_avail","",n);
9953         }
9954 #endif /* KRB4 */
9955 #ifdef KRB5
9956         if (ttnproto == NP_EK5LOGIN) {
9957             n += krb5_des_avail(ttyfd);
9958             debug(F101,"in_chk krb5_des_avail","",n);
9959         }
9960 #ifdef KRB5_U2U
9961         if (ttnproto == NP_K5U2U) {
9962             n += krb5_u2u_avail(ttyfd);
9963             debug(F101,"in_chk krb5_des_avail","",n);
9964         }
9965 #endif /* KRB5_U2U */
9966 #endif /* KRB5 */
9967         if (n < 0)			/* Is this right? */
9968 	  return(-1);
9969         else
9970 	  return(n);
9971     }
9972 #endif /* CK_KERBEROS */
9973 #endif /* RLOGCODE */
9974 
9975     errno = 0;				/* Reset this so we log good info */
9976 #ifdef FIONREAD
9977     x = ioctl(fd, FIONREAD, &n);	/* BSD and lots of others */
9978 #ifdef DEBUG				/* (the more the better) */
9979     if (deblog) {
9980 	debug(F101,"in_chk FIONREAD return code","",x);
9981 	debug(F101,"in_chk FIONREAD count","",n);
9982 	debug(F101,"in_chk FIONREAD errno","",errno);
9983     }
9984 #endif /* DEBUG */
9985 #else /* FIONREAD not defined */
9986 /*
9987   Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
9988   with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
9989   portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
9990   that I looked at, but it is needed to prevent the call from blocking), and
9991   the msghdr struct differs from place to place, so we would need another
9992   avalanche of ifdefs.  Still, when FIONREAD is not available, this is the
9993   only other known method of asking the OS for the *number* of characters
9994   available for reading.
9995 */
9996 #ifdef V7				/* UNIX V7: look in kernel memory */
9997 #ifdef MINIX
9998     n = 0;				/* But not in MINIX */
9999 #else
10000 #ifdef MINIX2
10001     n = 0;
10002 #else
10003     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
10004     x = read(kmem[TTY], &n, sizeof(int));
10005     if (x != sizeof(int))
10006       n = 0;
10007 #endif /* MINIX2 */
10008 #endif /* MINIX */
10009 #else /* Not V7 */
10010 #ifdef PROVX1
10011     x = ioctl(fd, TIOCQCNT, &ttbuf);	/* DEC Pro/3xx Venix V.1 */
10012     n = ttbuf.sg_ispeed & 0377;		/* Circa 1984 */
10013     if (x < 0) n = 0;
10014 #else
10015 #ifdef MYREAD
10016 /*
10017   Here we skip all the undependable and expensive calls below if we
10018   already have something in our internal buffer.  This tends to work quite
10019   nicely, so the only really bad case remaining is the one in which neither
10020   FIONREAD or MYREAD are defined, which is increasingly rare these days.
10021 */
10022     if (channel != 0 && my_count > 0) {
10023 	debug(F101,"in_chk buf my_count","",my_count);
10024 	n = my_count;			/* n was 0 before we got here */
10025 	return(n);
10026     }
10027 #endif /* MYREAD */
10028 /*
10029   rdchk(), select(), and poll() tell us *if* data is available to be read, but
10030   not how much, so these should be used only as a final resort.  Especially
10031   since these calls tend to add a lot overhead.
10032 */
10033 #ifdef RDCHK				/* This mostly SCO-specific */
10034     n = rdchk(fd);
10035     debug(F101,"in_chk rdchk","",n);
10036 #else /* No RDCHK */
10037 #ifdef SELECT
10038 #ifdef Plan9
10039     /* Only allows select on the console ... don't ask */
10040     if (channel == 0)
10041 #endif /* Plan9 */
10042       {
10043 	fd_set rfds;			/* Read file descriptors */
10044 #ifdef BELLV10
10045 	FD_ZERO(rfds);			/* Initialize them */
10046 	FD_SET(fd,rfds);		/* We want to look at this fd */
10047 #else
10048 	FD_ZERO(&rfds);			/* Initialize them */
10049 	FD_SET(fd,&rfds);		/* We want to look at this fd */
10050 	tv.tv_sec = tv.tv_usec = 0L;	/* A 0-valued timeval structure */
10051 #endif /* BELLV10 */
10052 #ifdef Plan9
10053 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10054 	debug(F101,"in_chk Plan 9 select","",n);
10055 #else
10056 #ifdef BELLV10
10057 	n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
10058 	debug(F101,"in_chk BELLV10 select","",n);
10059 #else
10060 #ifdef BSD44
10061 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10062 	debug(F101,"in_chk BSD44 select","",n);
10063 #else
10064 #ifdef BSD43
10065 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10066 	debug(F101,"in_chk BSD43 select","",n);
10067 #else
10068 #ifdef SOLARIS
10069 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10070 	debug(F101,"in_chk SOLARIS select","",n);
10071 #else
10072 #ifdef QNX6
10073 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10074 	debug(F101,"in_chk QNX6 select","",n);
10075 #else
10076 #ifdef QNX
10077 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10078 	debug(F101,"in_chk QNX select","",n);
10079 #else
10080 #ifdef COHERENT
10081 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10082 	debug(F101,"in_chk COHERENT select","",n);
10083 #else
10084 #ifdef SVR4
10085 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10086 	debug(F101,"in_chk SVR4 select","",n);
10087 #else
10088 #ifdef __linux__
10089 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10090 	debug(F101,"in_chk LINUX select","",n);
10091 #ifdef OSF
10092 	n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10093 	debug(F101,"in_chk OSF select","",n);
10094 #else
10095 	n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
10096 	debug(F101,"in_chk catchall select","",n);
10097 #endif /* OSF */
10098 #endif /* __linux__ */
10099 #endif /* SVR4 */
10100 #endif /* COHERENT */
10101 #endif /* QNX */
10102 #endif /* QNX6 */
10103 #endif /* SOLARIS */
10104 #endif /* BSD43 */
10105 #endif /* BSD44 */
10106 #endif /* BELLV10 */
10107 #endif /* Plan9 */
10108     }
10109 #else  /* Not SELECT */
10110 #ifdef CK_POLL
10111     {
10112       struct pollfd pfd;
10113 
10114       pfd.fd = fd;
10115       pfd.events = POLLIN;
10116       pfd.revents = 0;
10117       n = poll(&pfd, 1, 0);
10118       debug(F101,"in_chk poll","",n);
10119       if ((n > 0) && (pfd.revents & POLLIN))
10120 	n = 1;
10121     }
10122 #endif /* CK_POLL */
10123 #endif /* SELECT */
10124 #endif /* RDCHK */
10125 #endif /* PROVX1 */
10126 #endif /* V7 */
10127 #endif /* FIONREAD */
10128 
10129 /* From here down, treat console and communication device differently... */
10130 
10131     if (channel == 0) {			/* Console */
10132 
10133 #ifdef SVORPOSIX
10134 #ifndef FIONREAD
10135 #ifndef SELECT
10136 #ifndef CK_POLL
10137 #ifndef RDCHK
10138 /*
10139   This is the hideous hack used in System V and POSIX systems that don't
10140   support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
10141   CONNECT-mode escape character is attached to SIGQUIT.  Used, obviously,
10142   only on the console.
10143 */
10144 	if (conesc) {			/* Escape character typed == SIGQUIT */
10145 	    debug(F100,"in_chk conesc","",conesc);
10146 	    conesc = 0;
10147 	    signal(SIGQUIT,esctrp);	/* Restore signal */
10148 	    n += 1;
10149 	}
10150 #endif /* RDCHK */
10151 #endif /* CK_POLL */
10152 #endif /* SELECT */
10153 #endif /* FIONREAD */
10154 #endif /* SVORPOSIX */
10155 
10156 	return(n);			/* Done with console */
10157     }
10158 
10159     if (channel != 0) {			/* Communications connection */
10160 
10161 #ifdef MYREAD
10162 #ifndef FIONREAD
10163 /*
10164   select() or rdchk(), etc, has told us that something is waiting, but we
10165   don't know how much.  So we do a read to get it and then we know.  Note:
10166   This read is NOT nonblocking if nothing is there (because of VMIN=1), but
10167   it should be safe in this case since the OS tells us at least one byte is
10168   waiting to be read, and MYREAD reads return as much as is there without
10169   waiting for any more.  Controlled tests on Solaris and Unixware (with
10170   FIONREAD deliberately undefined) show this to be true.
10171 */
10172 	debug(F101,"in_chk read my_count","",my_count);
10173 	debug(F101,"in_chk read n","",n);
10174 	if (n > 0 && my_count == 0) {
10175 	    /* This also catches disconnects etc */
10176 	    /* Do what mygetbuf does except don't grab a character */
10177 	    my_count = myfillbuf();
10178 	    my_item = -1;		/* ^^^ */
10179 	    debug(F101,"in_chk myfillbuf my_count","",my_count);
10180 	    if (my_count < 0)
10181 	      return(-1);
10182 	    else
10183 	      n = 0;			/* NB: n is replaced by my_count */
10184 	}
10185 #endif /* FIONREAD */
10186 /*
10187   Here we add whatever we think is unread to what is still in our
10188   our internal buffer.  Thus the importance of setting n to 0 just above.
10189 */
10190 	debug(F101,"in_chk my_count","",my_count);
10191 	debug(F101,"in_chk n","",n);
10192 	if (my_count > 0)
10193 	  n += my_count;
10194 #endif /* MYREAD */
10195     }
10196     debug(F101,"in_chk result","",n);
10197 
10198     /* Errors here don't prove the connection has dropped so just say 0 */
10199 
10200     return(n < 0 ? 0 : n);
10201 }
10202 
10203 
10204 /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
10205 
10206 int
ttchk()10207 ttchk() {
10208     int fd;
10209 #ifdef NETCMD
10210     if (ttpipe)
10211       fd = fdin;
10212     else
10213 #endif /* NETCMD */
10214       fd = ttyfd;
10215     return(in_chk(1,fd));
10216 }
10217 
10218 /*  T T X I N  --  Get n characters from tty input buffer  */
10219 
10220 /*  Returns number of characters actually gotten, or -1 on failure  */
10221 
10222 /*  Intended for use only when it is known that n characters are actually */
10223 /*  Available in the input buffer.  */
10224 
10225 int
ttxin(n,buf)10226 ttxin(n,buf) int n; CHAR *buf; {
10227     register int x = 0, c = -2;
10228 #ifdef TTLEBUF
10229     register int i = 0;
10230 #endif /* TTLEBUF */
10231     int fd;
10232 
10233     if (n < 1)				/* Nothing to do */
10234       return(0);
10235 
10236 #ifdef TTLEBUF
10237     if (ttpush >= 0) {
10238         buf[0] = ttpush;		/* Put pushed char in buffer*/
10239         ttpush = -1;			/* Clear the push buffer */
10240         if (ttchk() > 0)
10241 	  return(ttxin(n-1, &buf[1]) + 1);
10242         else
10243 	  return(1);
10244     }
10245     if (le_data) {
10246         while (le_inbuf() > 0) {
10247 	    if (le_getchar(&buf[i])) {
10248                 i++;
10249                 n--;
10250             }
10251         }
10252         if (ttchk() > 0)
10253 	  return(ttxin(n,&buf[i])+i);
10254         else
10255 	  return(i);
10256     }
10257 #endif /* TTLEBUF */
10258 
10259 #ifdef NETCMD
10260     if (ttpipe)
10261       fd = fdin;
10262     else
10263 #endif /* NETCMD */
10264       fd = ttyfd;
10265 
10266 #ifdef SUNX25
10267     if (netconn && (ttnet == NET_SX25))	/* X.25 connection */
10268       return(x25xin(n,buf));
10269 #endif /* SUNX25 */
10270 
10271 #ifdef IBMX25
10272     /* riehm: possibly not needed. Test worked with normal reads and writes */
10273     if (netconn && (ttnet == NET_IX25))	{ /* X.25 connection */
10274 	x = x25xin(n,buf);
10275 	if (x > 0) buf[x] = '\0';
10276 	return(x);
10277     }
10278 #endif /* IBMX25 */
10279 
10280 #ifdef MYREAD
10281     debug(F101,"ttxin MYREAD","",n);
10282     while (x < n) {
10283 	c = myread();
10284 	if (c < 0) {
10285 	    debug(F101,"ttxin myread returns","",c);
10286 	    if (c == -3) x = -1;
10287 	    break;
10288         }
10289 	buf[x++] = c & ttpmsk;
10290 #ifdef RLOGCODE
10291 #ifdef CK_KERBEROS
10292         /* It is impossible to know how many characters are waiting */
10293         /* to be read when you are using Encrypted Rlogin or SSL    */
10294         /* as the transport since the number of real data bytes     */
10295         /* can be greater or less than the number of bytes on the   */
10296         /* wire which is what ttchk() returns.                      */
10297         if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
10298 	  if (ttchk() <= 0)
10299 	    break;
10300 #endif /* CK_KERBEROS */
10301 #endif /* RLOGCODE */
10302 #ifdef CK_SSL
10303         if (ssl_active_flag || tls_active_flag)
10304 	  if (ttchk() <= 0)
10305 	    break;
10306 #endif /* CK_SSL */
10307     }
10308 #else
10309     debug(F101,"ttxin READ","",n);
10310     x = read(fd,buf,n);
10311     for (c = 0; c < n; c++)		/* Strip any parity */
10312       buf[c] &= ttpmsk;
10313 #endif /* MYREAD */
10314 
10315     debug(F101,"ttxin x","",x);		/* Done */
10316     if (x > 0) buf[x] = '\0';
10317     if (x < 0) x = -1;
10318     return(x);
10319 }
10320 
10321 /*  T T O L  --  Write string s, length n, to communication device.  */
10322 /*
10323   Returns:
10324    >= 0 on success, number of characters actually written.
10325    -1 on failure.
10326 */
10327 #ifdef CK_ENCRYPTION
10328 CHAR * xpacket = NULL;
10329 int nxpacket = 0;
10330 #endif /* CK_ENCRYPTION */
10331 
10332 #define TTOLMAXT 5
10333 int
ttol(s,n)10334 ttol(s,n) int n; CHAR *s; {
10335     int x, len, tries, fd;
10336 #ifdef CKXXCHAR
10337     extern int dblflag;			/* For SET SEND DOUBLE-CHARACTER */
10338     extern short dblt[];
10339     CHAR *p = NULL, *p2, *s2, c;
10340     int n2 = 0;
10341 #endif /* CKXXCHAR */
10342 
10343     if (ttyfd < 0)			/* Not open? */
10344       return(-3);
10345 #ifdef DEBUG
10346     if (deblog) {
10347 	/* debug(F101,"ttol ttyfd","",ttyfd); */
10348 	ckhexdump("ttol s",s,n);
10349     }
10350 #endif /* DEBUG */
10351 
10352 #ifdef NETCMD
10353     if (ttpipe)
10354       fd = fdout;
10355     else
10356 #endif /* NETCMD */
10357       fd = ttyfd;
10358 
10359 #ifdef CKXXCHAR
10360 /*  Double any characters that must be doubled.  */
10361     debug(F101,"ttol dblflag","",dblflag);
10362     if (dblflag) {
10363 	p = (CHAR *) malloc(n + n + 1);
10364 	if (p) {
10365 	    s2 = s;
10366 	    p2 = p;
10367 	    n2 = 0;
10368 	    while (*s2) {
10369 		c = *s2++;
10370 		*p2++ = c;
10371 		n2++;
10372 		if (dblt[(unsigned) c] & 2) {
10373 		    *p2++ = c;
10374 		    n2++;
10375 		}
10376 	    }
10377 	    s = p;
10378 	    n = n2;
10379 	    s[n] = '\0';
10380 	}
10381 #ifdef DEBUG
10382         ckhexdump("ttol doubled s",s,n);
10383 #endif /* DEBUG */
10384     }
10385 #endif /* CKXXCHAR */
10386 
10387     tries = TTOLMAXT;			/* Allow up to this many tries */
10388     len = n;				/* Remember original length */
10389 
10390 #ifdef CK_ENCRYPTION
10391 /*
10392   This is to avoid encrypting a packet that is already encrypted, e.g.
10393   when we resend a packet directly out of the packet buffer, and also to
10394   avoid encrypting a constant (literal) string, which can cause a memory
10395   fault.
10396 */
10397     if (TELOPT_ME(TELOPT_ENCRYPTION)) {
10398 	int x;
10399 	if (nxpacket < n) {
10400 	    if (xpacket) {
10401 		free(xpacket);
10402 		xpacket = NULL;
10403 		nxpacket = 0;
10404 	    }
10405 	    x = n > 10240 ? n : 10240;
10406 	    xpacket = (CHAR *)malloc(x);
10407 	    if (!xpacket) {
10408 		fprintf(stderr,"ttol malloc failure\n");
10409 		return(-1);
10410 	    } else
10411 	      nxpacket = x;
10412 	}
10413 	memcpy((char *)xpacket,(char *)s,n);
10414 	s = xpacket;
10415 	ck_tn_encrypt((char *)s,n);
10416     }
10417 #endif /* CK_ENCRYPTION */
10418 
10419     while (n > 0 &&
10420 	   (tries-- > 0
10421 #ifdef CK_ENCRYPTION
10422 	    /* keep trying if we are encrypting */
10423 	    || TELOPT_ME(TELOPT_ENCRYPTION)
10424 #endif /* CK_ENCRYPTION */
10425             )) {			/* Be persistent */
10426 	debug(F101,"ttol try","",TTOLMAXT - tries);
10427 #ifdef BEOSORBEBOX
10428         if (netconn && !ttpipe && !ttpty)
10429 	  x = nettol((char *)s,n);	/* Write string to device */
10430         else
10431 #endif /* BEOSORBEBOX */
10432 #ifdef IBMX25
10433 	  if (ttnet == NET_IX25)
10434 	    /*
10435 	     * this is a more controlled way of writing to X25
10436 	     * STREAMS, however write should also work!
10437 	     */
10438 	    x = x25write(ttyfd, s, n);
10439 	  else
10440 #endif /* IBMX25 */
10441 #ifdef CK_SSL
10442 	    if (ssl_active_flag || tls_active_flag) {
10443 		int error;
10444 		/* Write using SSL */
10445                 ssl_retry:
10446 		if (ssl_active_flag)
10447                   x = SSL_write(ssl_con, s, n);
10448 		else
10449                   x = SSL_write(tls_con, s, n);
10450 		switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
10451                 case SSL_ERROR_NONE:
10452                     if (x == n)
10453 		      return(len);
10454                     s += x;
10455                     n -= x;
10456                     goto ssl_retry;
10457 		  case SSL_ERROR_WANT_WRITE:
10458 		  case SSL_ERROR_WANT_READ:
10459 		    x = 0;
10460 		    break;
10461 		  case SSL_ERROR_SYSCALL:
10462                     if (x != 0)
10463 		      return(-1);
10464 		  case SSL_ERROR_WANT_X509_LOOKUP:
10465 		  case SSL_ERROR_SSL:
10466 		  case SSL_ERROR_ZERO_RETURN:
10467 		  default:
10468 		    ttclos(0);
10469 		    return(-3);
10470 		}
10471 	    } else
10472 #endif /* CK_SSL */
10473 #ifdef CK_KERBEROS
10474 #ifdef KRB4
10475 #ifdef RLOGCODE
10476 	    if (ttnproto == NP_EK4LOGIN) {
10477 		return(krb4_des_write(ttyfd,s,n));
10478 	    } else
10479 #endif /* RLOGCODE */
10480 #endif /* KRB4 */
10481 #ifdef KRB5
10482 #ifdef RLOGCODE
10483             if (ttnproto == NP_EK5LOGIN) {
10484                 return(krb5_des_write(ttyfd,(char *)s,n,0));
10485             } else
10486 #endif /* RLOGCODE */
10487 #ifdef KRB5_U2U
10488             if (ttnproto == NP_K5U2U) {
10489                 return(krb5_u2u_write(ttyfd,(char *)s,n));
10490             } else
10491 #endif /* KRB5_U2U */
10492 #endif /* KRB5 */
10493 #endif /* CK_KERBEROS */
10494 	      x = write(fd,s,n);	/* Write string to device */
10495 
10496 	if (x == n) {			/* Worked? */
10497 	    debug(F101,"ttol ok","",x);	/* OK */
10498 #ifdef CKXXCHAR
10499 	    if (p) free(p);
10500 #endif /* CKXXCHAR */
10501 	    return(len);		/* Done */
10502 	} else if (x < 0) {		/* No, got error? */
10503 	    debug(F101,"ttol write error","",errno);
10504 #ifdef EWOULDBLOCK
10505 	    if (errno == EWOULDBLOCK) {
10506 		msleep(10);
10507 		continue;
10508 	    } else
10509 #endif /* EWOULDBLOCK */
10510 #ifdef TCPSOCKET
10511 	    if (netconn && ttnet == NET_TCPB) {
10512 		debug(F101,"ttol TCP error","",errno);
10513 		ttclos(0);		/* Close the connection. */
10514 		x = -3;
10515 	    }
10516 #endif /* TCPSOCKET */
10517 #ifdef CKXXCHAR
10518 	    if (p) free(p);
10519 #endif /* CKXXCHAR */
10520 	    return(x);
10521 	} else {			/* No error, so partial success */
10522 	    debug(F101,"ttol partial","",x); /* This never happens */
10523 	    s += x;			/* Point to part not written yet */
10524 	    n -= x;			/* Adjust length */
10525 	    if (x > 0) msleep(10);	/* Wait 10 msec */
10526 	}				/* Go back and try again */
10527     }
10528 #ifdef CKXXCHAR
10529     if (p) free(p);
10530 #endif /* CKXXCHAR */
10531     return(n < 1 ? len : -1);		/* Return the results */
10532 }
10533 
10534 /*  T T O C  --  Output a character to the communication line  */
10535 
10536 /*
10537  This function should only be used for interactive, character-mode operations,
10538  like terminal connection, script execution, dialer i/o, where the overhead
10539  of the signals and alarms does not create a bottleneck.
10540 */
10541 int
10542 #ifdef CK_ANSIC
ttoc(char c)10543 ttoc(char c)
10544 #else
10545 ttoc(c) char c;
10546 #endif /* CK_ANSIC */
10547 /* ttoc */ {
10548 #define TTOC_TMO 15			/* Timeout in case we get stuck */
10549     int xx, fd;
10550 
10551     if (ttyfd < 0)			/* Check for not open. */
10552       return(-1);
10553 
10554 #ifdef NETCMD
10555     if (ttpipe)
10556       fd = fdout;
10557     else
10558 #endif /* NETCMD */
10559       fd = ttyfd;
10560 
10561     c &= 0xff;
10562     /* debug(F101,"ttoc","",(CHAR) c); */
10563     saval = signal(SIGALRM,timerh);	/* Enable timer interrupt */
10564     xx = alarm(TTOC_TMO);		/* for this many seconds. */
10565     if (xx < 0) xx = 0;			/* Save old alarm value. */
10566     /* debug(F101,"ttoc alarm","",xx); */
10567     if (
10568 #ifdef CK_POSIX_SIG
10569 	sigsetjmp(sjbuf,1)
10570 #else
10571 	setjmp(sjbuf)
10572 #endif /* CK_POSIX_SIG */
10573 	) {		/* Timer went off? */
10574 	ttimoff();			/* Yes, cancel this alarm. */
10575 	if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
10576         /* debug(F100,"ttoc timeout","",0); */
10577 #ifdef NETCONN
10578 	if (!netconn) {
10579 #endif /* NETCONN */
10580 	    debug(F101,"ttoc timeout","",c);
10581 	    if (ttflow == FLO_XONX) {
10582 		debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
10583 #ifndef Plan9
10584 #ifdef POSIX
10585 		/* POSIX way to unstick. */
10586 		debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
10587 #else
10588 #ifdef BSD4				/* Berkeley way to do it. */
10589 #ifdef TIOCSTART
10590 /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);".  Who knows? */
10591 		{
10592 		  int x = 0;
10593 		  debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
10594 		}
10595 #endif /* TIOCSTART */
10596 #endif /* BSD4 */
10597 					/* Is there a Sys V way to do this? */
10598 #endif /* POSIX */
10599 #endif /* Plan9 */
10600 	    }
10601 #ifdef NETCONN
10602         }
10603 #endif /* NETCONN */
10604 	return(-1);			/* Return failure code. */
10605     } else {
10606         int rc;
10607 #ifdef BEOSORBEBOX
10608 #ifdef NETCONN
10609         if (netconn && !ttpipe && !ttpty)
10610 	  rc = nettoc(c);
10611         else
10612 #endif /*  BEOSORBEBOX */
10613 #endif /* NETCONN */
10614 #ifdef CK_ENCRYPTION
10615 	  if (TELOPT_ME(TELOPT_ENCRYPTION))
10616 	    ck_tn_encrypt(&c,1);
10617 #endif /* CK_ENCRYPTION */
10618 #ifdef IBMX25
10619 	/* riehm: maybe this isn't necessary after all. Test program
10620 	 * worked fine with data being sent and retrieved with normal
10621 	 * read's and writes!
10622 	 */
10623 	if (ttnet == NET_IX25)
10624 	  rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
10625 	else
10626 #endif /* IBMX25 */
10627 #ifdef CK_SSL
10628 	  if (ssl_active_flag || tls_active_flag) {
10629 	      int error;
10630 	      /* Write using SSL */
10631 	      if (ssl_active_flag)
10632                 rc = SSL_write(ssl_con, &c, 1);
10633 	      else
10634                 rc = SSL_write(tls_con, &c, 1);
10635 	      switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
10636 		case SSL_ERROR_NONE:
10637 		  break;
10638 		case SSL_ERROR_WANT_WRITE:
10639 		case SSL_ERROR_WANT_READ:
10640 		  rc = 0;
10641 		  break;
10642 		case SSL_ERROR_SYSCALL:
10643 		  if (rc != 0)
10644 		    return(-1);
10645 		case SSL_ERROR_WANT_X509_LOOKUP:
10646 		case SSL_ERROR_SSL:
10647 		case SSL_ERROR_ZERO_RETURN:
10648 		default:
10649 		  ttclos(0);
10650 		  return(-1);
10651 	      }
10652 	  } else
10653 #endif /* CK_SSL */
10654 #ifdef CK_KERBEROS
10655 #ifdef KRB4
10656 #ifdef RLOGCODE
10657 	  if (ttnproto == NP_EK4LOGIN) {
10658 	      rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1);
10659 	  } else
10660 #endif /* RLOGCODE */
10661 #endif /* KRB4 */
10662 #ifdef KRB5
10663 #ifdef RLOGCODE
10664           if (ttnproto == NP_EK5LOGIN) {
10665               rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
10666           } else
10667 #endif /* RLOGCODE */
10668 #ifdef KRB5_U2U
10669           if (ttnproto == NP_K5U2U) {
10670               rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
10671           } else
10672 #endif /* KRB5_U2U */
10673 #endif /* KRB5 */
10674 #endif /* CK_KERBEROS */
10675 	    rc = write(fd,&c,1);	/* Try to write the character. */
10676 	if (rc < 1) {			/* Failed */
10677 	    ttimoff();			/* Turn off the alarm. */
10678 	    alarm(xx);			/* Restore previous alarm. */
10679 	    debug(F101,"ttoc errno","",errno); /* Log the error, */
10680 	    return(-1);			/* and return the error code. */
10681 	}
10682     }
10683     ttimoff();				/* Success, turn off the alarm. */
10684     alarm(xx);				/* Restore previous alarm. */
10685     return(0);				/* Return good code. */
10686 }
10687 
10688 /*  T T I N L  --  Read a record (up to break character) from comm line.  */
10689 /*
10690   Reads up to "max" characters from the connection, terminating on:
10691     (a) the packet length field if the "turn" argument is zero, or
10692     (b) on the packet-end character (eol) if the "turn" argument is nonzero
10693     (c) a certain number of Ctrl-C's in a row
10694 
10695   Returns:
10696     >= 0, the number of characters read upon success;
10697     -1 if "max" exceeded, timeout, or other correctable error;
10698     -2 on user interruption (c);
10699     -3 on fatal error like connection lost.
10700 
10701   The name of this routine dates from the early days when Kermit packets
10702   were, indeed, always lines of text.  That was before control-character
10703   unprefixing and length-driven packet framing were introduced, which this
10704   version handle.  NB: this routine is ONLY for reading incoming Kermit
10705   packets, nothing else.  To read other kinds of incoming material, use
10706   ttinc() or ttxin().
10707 
10708   The bytes that were input are copied into "dest" with their parity bits
10709   stripped if parity was selected.  Returns the number of bytes read.
10710   Bytes after the eol are available upon the next call to this function.
10711 
10712   The idea is to minimize the number of system calls per packet, and also to
10713   minimize timeouts.  This function is the inner loop of the protocol and must
10714   be as efficient as possible.  The current strategy is to use myread(), a
10715   macro to manage buffered (and generally nonblocking) reads.
10716 
10717   WARNING: This function calls parchk(), which is defined in another module.
10718   Normally, ckutio.c does not depend on code from any other module, but there
10719   is an exception in this case because all the other ck?tio.c modules also
10720   need to call parchk(), so it's better to have it defined in a common place.
10721 */
10722 #ifdef CTRLC
10723 #undef CTRLC
10724 #endif /* CTRLC */
10725 #define CTRLC '\03'
10726 /*
10727   We have four different declarations here because:
10728   (a) to allow Kermit to be built without the automatic parity sensing feature
10729   (b) one of each type for ANSI C, one for non-ANSI.
10730 */
10731 #ifndef NOXFER
10732 
10733 static int pushedback = 0;
10734 
10735 int
10736 #ifdef PARSENSE
10737 #ifdef CK_ANSIC
ttinl(CHAR * dest,int max,int timo,CHAR eol,CHAR start,int turn)10738 ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
10739 #else
10740 ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
10741 #endif /* CK_ANSIC */
10742 #else /* not PARSENSE */
10743 #ifdef CK_ANSIC
10744 ttinl(CHAR *dest, int max,int timo, CHAR eol)
10745 #else
10746 ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
10747 #endif /* CK_ANSIC */
10748 #endif /* PARSENSE */
10749 /* ttinl */ {
10750 
10751 #ifndef MYREAD
10752     CHAR ch, dum;
10753 #endif /* MYREAD */
10754 #ifdef PARSENSE
10755     int pktlen = -1;
10756     int lplen = 0;
10757     int havelen = 0;
10758 #endif /* PARSENSE */
10759     int fd;
10760     int sopmask = 0xff;			/* Start-Of-Packet mask */
10761 #ifdef CKXXCHAR
10762     extern short dblt[];		/* Ignore-character table */
10763     extern int ignflag;
10764 #endif /* CKXXCHAR */
10765 #ifdef TCPSOCKET
10766     extern CHAR stchr;
10767 #endif /* TCPSOCKET */
10768     int x;
10769 #ifdef STREAMING
10770     extern int streaming;
10771     extern int sndtyp;
10772 #endif /* STREAMING */
10773 
10774     if (ttyfd < 0) return(-3);          /* Not open. */
10775 /*
10776   In February 2007 I fixed ttinl() to work better under the truly awful
10777   conditions encountered by the AM-APEX oceanographic floats that gather
10778   hurricane data and phone home using Iridium satellite modems, which under
10779   certain conditions, can send two packets back to back after a long pause.
10780   In this case the second packet would be ignored because the SOH was skipped
10781   due to the ttflui() call.  But the reworked lookahead/pushback logic broke
10782   Kermit transfers on encrypted connections.  This was fixed 12-13 August
10783   2007.  All of this happened after 8.0.212 Dev.27 was released and before
10784   Dev.28, so no harm done other than the delay.
10785 */
10786     debug(F101,"ttinl max","",max);
10787     debug(F101,"ttinl timo","",timo);
10788 
10789 #ifdef NETCMD
10790     if (ttpipe)
10791       fd = fdin;
10792     else
10793 #endif /* NETCMD */
10794       fd = ttyfd;
10795 
10796 #ifdef COMMENT
10797     if (xlocal && conchk() > 0)		/* Allow for console interruptions */
10798       return(-1);
10799 #endif /* COMMENT */
10800 
10801     *dest = '\0';                       /* Clear destination buffer */
10802     if (timo < 0) timo = 0;		/* Safety */
10803     if (timo) {				/* Don't time out if timo == 0 */
10804 	int xx;
10805 	saval = signal(SIGALRM,timerh);	/* Enable timer interrupt */
10806 	xx = alarm(timo);		/* Set it. */
10807 	debug(F101,"ttinl alarm","",xx);
10808     }
10809     if (
10810 #ifdef CK_POSIX_SIG
10811 	sigsetjmp(sjbuf,1)
10812 #else
10813 	setjmp(sjbuf)
10814 #endif /* CK_POSIX_SIG */
10815 	) {				/* Timer went off? */
10816 	debug(F100,"ttinl timout","",0); /* Get here on timeout. */
10817 	/* debug(F110," with",(char *) dest,0); */
10818 	ttimoff();			/* Turn off timer */
10819 	return(-1);			/* and return error code. */
10820     } else {
10821 	register int i, n = -1;		/* local variables */
10822 	int ccn = 0;
10823 #ifdef PARSENSE
10824 	register int flag = 0;
10825 	debug(F000,"ttinl start","",start);
10826 #endif /* PARSENSE */
10827 
10828 	ttpmsk = ttprty ? 0177 : 0377;	/* Set parity stripping mask. */
10829 	sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
10830 
10831 /* Now read into destination, stripping parity and looking for the */
10832 /* the packet terminator, and also for several Ctrl-C's typed in a row. */
10833 
10834 	i = 0;				/* Destination index */
10835 	debug(F101,"ttinl eol","",eol);
10836 
10837 	while (i < max-1) {
10838 #ifdef MYREAD
10839 	    errno = 0;
10840 	    /* On encrypted connections myread returns encrypted bytes */
10841 	    n = myread();
10842 	    debug(F000,"TTINL myread char","",n);
10843 	    if (n < 0) {	/* Timeout or i/o error? */
10844 #ifdef DEBUG
10845 		if (deblog) {
10846 		    debug(F101,"ttinl myread failure, n","",n);
10847 		    debug(F101,"ttinl myread errno","",errno);
10848 		}
10849 #endif /* DEBUG */
10850 		/* Don't let EINTR break packets. */
10851 		if (n == -3) {
10852 		    if (errno == EINTR && i > 0) {
10853 			debug(F111,"ttinl EINTR myread i","continuing",i);
10854 			continue;
10855 		    } else {
10856 			debug(F110,"ttinl non-EINTR -3","closing",0);
10857 			wasclosed = 1;
10858 			ttimoff();	/* Turn off timer */
10859 			ttclos(0);
10860 			return(n);
10861 		    }
10862 		} else if (n == -2 && netconn /* && timo == 0 */ ) {
10863 		    /* Here we try to catch broken network connections */
10864 		    /* even when ioctl() and read() do not catch them */
10865 		    debug(F111,"ttinl network myread failure","closing",n);
10866 		    wasclosed = 1;
10867 		    ttimoff();
10868 		    ttclos(0);
10869 		    return(-3);
10870 		}
10871 #ifdef STREAMING
10872 		/* Streaming and no data to read */
10873 		else if (n == 0 && streaming && sndtyp == 'D')
10874 		  return(0);
10875 #endif /* STREAMING */
10876 		break;			/* Break out of while loop */
10877 	    }
10878 
10879 #else /* not MYREAD (is this code used anywhere any more?) */
10880 /*
10881   The non-MYREAD code dates from the 1980s and was needed on certain platforms
10882   where there were no nonblocking reads.  -fdc, 2007/02/22.
10883 */
10884 	    if ((n = read(fd, &n, 1)) < 1)
10885 	      break;			/* Error - break out of while loop */
10886 
10887 #endif /* MYREAD */
10888 
10889 	    /* Get here with char in n */
10890 
10891 #ifdef CK_ENCRYPTION
10892 	    if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) {
10893 		CHAR ch = n;
10894 		ck_tn_decrypt((char *)&ch,1);
10895 		n = ch;
10896 		debug(F000,"TTINL decryp char","",n);
10897 	    }
10898 	    pushedback = 0;
10899 #endif /* CK_ENCRYPTION */
10900 
10901 #ifdef TCPSOCKET
10902 	    if (n == IAC &&		/* Handle Telnet options */
10903 		((xlocal && netconn && IS_TELNET()) ||
10904 		(!xlocal && sstelnet))) {
10905 		n = tt_tnopt(n);
10906 		if (n < 0)
10907 		  return(n);
10908 #ifndef NOPARSEN
10909 		else if (n == 1)
10910 		  start = stchr;
10911 #endif /* NOPARSEN */
10912 		if (n != 255)		/* No data - go back for next char */
10913 		  continue;
10914 	    }				/* Quoted IAC - keep going */
10915 #endif /* TCPSOCKET */
10916 
10917 #ifdef CKXXCHAR
10918 	    if (ignflag)
10919 	      if (dblt[(unsigned) n] & 1) /* Character to ignore? */
10920 		continue;
10921 #endif /* CKXXCHAR */
10922 /*
10923   Use parity mask, rather than always stripping parity, to check for
10924   cancellation.  Otherwise, runs like \x03\x83\x03 in a packet could cancel
10925   the transfer when parity is NONE.  (Note that \x03\x03\x03 is extremely
10926   unlikely due to run-length encoding.)
10927 */
10928 	    /* Check cancellation */
10929 	    if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
10930 		if (++ccn >= xfrnum) {	/* If xfrnum in a row, bail out. */
10931 		    if (timo) {		/* Clear timer. */
10932 			ttimoff();
10933 		    }
10934 		    if (xfrchr < 32)
10935 		      printf("^%c...\r\n",(char)(xfrchr+64));
10936 		    else
10937 		      printf("Canceled...\r\n");
10938 		    return(-2);
10939 		}
10940 	    } else ccn = 0;		/* No cancellation, reset counter, */
10941 
10942 #ifdef PARSENSE
10943 /*
10944   Restructured code allows for a new packet to appear somewhere in the
10945   middle of a previous one.  -fdc, 24 Feb 2007.
10946 */
10947 	    if ((n & sopmask) == start) { /* Start of Packet */
10948 		debug(F101,"ttinl SOP i","",i);
10949 		flag = 1;		/* Flag that we are in a packet */
10950 		havelen = 0;		/* Invalidate previous length */
10951 		pktlen = -1;		/* (if any) in case we were */
10952 		lplen = 0;		/* alread processand a packet */
10953 		i = 0;			/* and reset the dest buffer pointer */
10954 	    }
10955 	    if (flag == 0) {		/* No SOP yet... */
10956 		debug(F000,"ttinl skipping","",n);
10957 		continue;
10958 	    }
10959 	    dest[i++] = n & ttpmsk;
10960 /*
10961   If we have not been instructed to wait for a turnaround character, we can go
10962   by the packet length field.  If turn != 0, we must wait for the end of line
10963   (eol) character before returning.  This is an egregious violation of all
10964   principles of layering...  (Less egregious in C-Kermit 9.0, in which we go
10965   by the length field but also look for the eol in case it arrives early,
10966   e.g. if the length field was corrupted upwards.)
10967 */
10968 	    if (!havelen) {
10969 		if (i == 2) {
10970 		    if ((dest[1] & 0x7f) < 32) /* Garbage in length field */
10971 		      return(-1);	/* fdc - 13 Apr 2010 */
10972 		    pktlen = xunchar(dest[1] & 0x7f);
10973                     if (pktlen > 94)	/* Rubout in length field */
10974 		      return(-1);	/* fdc - 13 Apr 2010 */
10975 		    if (pktlen > 1) {
10976 			havelen = 1;
10977 			debug(F101,"ttinl pktlen value","",pktlen);
10978 		    }
10979 		} else if (i == 5 && pktlen == 0) {
10980 		    lplen = xunchar(dest[4] & 0x7f);
10981 		} else if (i == 6 && pktlen == 0) {
10982 		    pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
10983 		    havelen = 1;
10984 		    debug(F101,"ttinl extended length","",pktlen);
10985 		}
10986 	    }
10987 
10988 /*
10989   Suppose we looked at the sequence number here and found it was out of
10990   range?  This would mean either (a) incoming packets had SOP unprefixed
10991   and we are out of sync, or (b) the packet is damaged.  Since (a) is bad
10992   practice, let's ignore it.  So what should we do here if we know the
10993   packet is damaged?
10994 
10995    1. Nothing -- keep trying to read the packet till we find what we think
10996       is the end, or we time out, and let the upper layer decide what to
10997       do.  But since either the packet is corrupt or we are out of sync,
10998       our criterion for finding the end does not apply and we are likely
10999       to time out (or swallow a piece of the next packet) if our assumed
11000       length is too long.  (This was the behavior prior to version 7.0.)
11001 
11002    2. set flag = 0 and continue?  This would force us to wait for the
11003       next packet to come in, and therefore (in the nonwindowing case),
11004       would force a timeout in the other Kermit.
11005 
11006    3. set flag = 0 and continue, but only if the window size is > 1 and
11007       the window is not blocked?  Talk about cheating!
11008 
11009    4. Return a failure code and let the upper layer decide what to do.
11010       This should be equivalent to 3, but without the cheating.  So let's
11011       do it that way...  But note that we must ignore the parity bit
11012       in case this is the first packet and we have not yet run parchk().
11013 */
11014 	    if (i == 3) {		/* Peek at sequence number */
11015 		x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
11016 		if (x < 0 || x > 63) {
11017 		    debug(F111,"ttinl bad seq",dest,x);
11018 		    if (timo) ttimoff();
11019 		    return(-1);		/* return a nonfatal error */
11020 		}
11021 	    }
11022 
11023 #else /* PARSENSE */
11024 	    dest[i++] = n & ttpmsk;
11025 #endif /* PARSENSE */
11026 
11027     /* Check for end of packet */
11028 
11029 	    if (
11030 		((n & ttpmsk) == eol)	/* Always break on the eol char */
11031 #ifdef PARSENSE
11032 		 ||			/* fdc - see notes of 13 Apr 2010 */
11033 /*
11034   Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
11035   This allows packet terminators and handshake characters to appear
11036   literally inside a packet data field.
11037 */
11038 		(havelen && (i > pktlen+1) &&
11039 		 (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
11040 
11041 #endif /* PARSENSE */
11042 		) {
11043 /*
11044   Here we have either read the last byte of the packet based on its length
11045   field, or else we have read the packet terminator (eol) or the half-duplex
11046   line-turnaround char (turn).
11047 */
11048 #ifndef PARSENSE
11049 		debug(F101,"ttinl got eol","",eol); /* (or turn) */
11050 		dest[i] = '\0';		/* Yes, terminate the string, */
11051 		/* debug(F101,"ttinl i","",i); */
11052 
11053 #else  /* PARSENSE */
11054 
11055 #ifdef DEBUG
11056 		if (deblog) {
11057 		    if ((n & ttpmsk) != eol) {
11058 			debug(F101,"ttinl EOP length","",pktlen);
11059 			debug(F000,"ttinl EOP current char","",n);
11060 			debug(F101,"ttinl EOP packet buf index","",i);
11061 		    } else debug(F101,"ttinl got eol","",eol);
11062 		}
11063 #endif /* DEBUG */
11064 
11065 #ifdef MYREAD
11066 /*
11067   The packet was read based on its length.  This leaves the packet terminator
11068   unread, and so ttchk() will always return at least 1 because of this,
11069   possibly giving a false positive to the "is there another packet waiting?"
11070   test.  But if we know the terminator (or any other interpacket junk) is
11071   there, we can safely get rid of it.
11072 
11073   NOTE: This code reworked to (a) execute even if the debug log isn't active;
11074   and (b) actually work.  -fdc, 2007/02/22.  And again 2007/08/12-13 to also
11075   work on encrypted connections.
11076 */
11077 		debug(F101,"TTINL my_count","",my_count);
11078 		if ((n & ttpmsk) != eol) { /* Not the packet terminator */
11079 		    int x;
11080 		    while (my_count > 0) {
11081 			x = myread();	   /* (was ttinc(0) */
11082 			debug(F000,"TTINL lkread char","",x);
11083 #ifdef CK_ENCRYPTION
11084 			if (TELOPT_U(TELOPT_ENCRYPTION)) {
11085 			    CHAR ch = x;
11086 			    ck_tn_decrypt((char *)&ch,1);
11087 			    x = ch;
11088 			    debug(F000,"TTINL lkdecr char","",x);
11089 			}
11090 #endif	/* CK_ENCRYPTION */
11091 			/*
11092 			  Note: while it might seem more elegant to simply
11093 			  push back the encrypted byte, that desynchronizes
11094 			  the decryption stream; the flag is necessary so we
11095 			  don't try to decrypt the same byte twice.
11096 			*/
11097 			if ((x & ttpmsk) == start) { /* Start of next packet */
11098 			    myunrd(x);	/* Push back the decrypted byte */
11099 			    pushedback = 1; /* And set flag */
11100 			    debug(F000,"TTINL lkpush char","",x);
11101 			    break;
11102 			}
11103 		    }
11104 		}
11105 #endif /* MYREAD */
11106 
11107 		dest[i] = '\0';		/* Terminate the string, */
11108 	        if (needpchk) {		/* Parity checked yet? */
11109 		    if (ttprty == 0) {	/* No, check. */
11110 			if ((ttprty = parchk(dest,start,i)) > 0) {
11111 			    int j;
11112 			    debug(F101,"ttinl senses parity","",ttprty);
11113 			    debug(F110,"ttinl packet before",dest,0);
11114 			    ttpmsk = 0x7f;
11115 			    for (j = 0; j < i; j++)
11116 			      dest[j] &= 0x7f;	/* Strip parity from packet */
11117 			    debug(F110,"ttinl packet after ",dest,0);
11118 			} else ttprty = 0; /* Restore if parchk error */
11119 		    }
11120 		    sopmask = ttpmsk;
11121 		    needpchk = 0;
11122 		}
11123 #endif /* PARSENSE */
11124 
11125 		if (timo)		/* Turn off timer if it was on */
11126 		  ttimoff();
11127                 ckhexdump("ttinl got",dest,i);
11128 
11129 #ifdef STREAMING
11130 		/* ttinl() was called because there was non-packet */
11131 		/* data sitting in the back channel.  Ignore it.   */
11132 		if (streaming && sndtyp == 'D')
11133 		  return(-1);
11134 #endif /* STREAMING */
11135 		return(i);
11136 	    }
11137 	} /* End of while() */
11138 	ttimoff();
11139 	return(n);
11140     }
11141 }
11142 #endif /* NOXFER */
11143 
11144 /*  T T I N C --  Read a character from the communication line  */
11145 /*
11146  On success, returns the character that was read, >= 0.
11147  On failure, returns -1 or other negative myread error code,
11148    or -2 if connection is broken or ttyfd < 0.
11149    or -3 if session limit has expired,
11150    or -4 if something or other...
11151  NOTE: The API does not provide for ttinc() returning a special code
11152  upon timeout, but we need it.  So for this we have a global variable,
11153  ttinctimo.
11154 */
11155 static int ttinctimo = 0;		/* Yuk */
11156 
11157 int
ttinc(timo)11158 ttinc(timo) int timo; {
11159 
11160     int n = 0, fd;
11161     int is_tn = 0;
11162     CHAR ch = 0;
11163 
11164     ttinctimo = 0;
11165 
11166     if (ttyfd < 0) return(-2);          /* Not open. */
11167 
11168     is_tn = (xlocal && netconn && IS_TELNET()) ||
11169 	    (!xlocal && sstelnet);
11170 
11171 #ifdef TTLEBUF
11172     if (ttpush >= 0) {
11173         debug(F111,"ttinc","ttpush",ttpush);
11174         ch = ttpush;
11175         ttpush = -1;
11176         return(ch);
11177     }
11178     if (le_data) {
11179         if (le_getchar(&ch) > 0) {
11180             debug(F111,"ttinc le_getchar","ch",ch);
11181             return(ch);
11182         }
11183     }
11184 #endif /* TTLEBUF */
11185 
11186 #ifdef NETCMD
11187     if (ttpipe)
11188       fd = fdin;
11189     else
11190 #endif /* NETCMD */
11191       fd = ttyfd;
11192 
11193     if ((timo <= 0)			/* Untimed. */
11194 #ifdef MYREAD
11195 	|| (my_count > 0)		/* Buffered char already waiting. */
11196 #endif /* MYREAD */
11197 	) {
11198 #ifdef MYREAD
11199         /* Comm line failure returns -1 thru myread, so no &= 0377 */
11200 	n = myread();			/* Wait for a character... */
11201 	/* debug(F000,"ttinc MYREAD n","",n); */
11202 #ifdef CK_ENCRYPTION
11203 	/* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
11204 	if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11205 	    ch = n;
11206 	    ck_tn_decrypt((char *)&ch,1);
11207 	    n = ch;
11208 	}
11209 #endif /* CK_ENCRYPTION */
11210 
11211 #ifdef NETPTY
11212 	if (ttpty && n < 0) {
11213 	    debug(F101,"ttinc error on pty","",n);
11214 	    ttclos(0);
11215 	    return(n);
11216 	}
11217 #endif /* NETPTY */
11218 
11219 #ifdef TNCODE
11220 	if ((n > -1) && is_tn)
11221 	  return((unsigned)(n & 0xff));
11222 	else
11223 #endif /* TNCODE */
11224 	  return(n < 0 ? n : (unsigned)(n & ttpmsk));
11225 
11226 #else  /* MYREAD */
11227 
11228         while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
11229         /* Shouldn't have to loop in ver 5A. */
11230 #ifdef NETCONN
11231 	  if (netconn) {		/* Special handling for net */
11232 	      netclos();		/* If read() returns 0 it means */
11233 	      netconn = 0;		/* the connection has dropped. */
11234 	      errno = ENOTCONN;
11235 	      return(-2);
11236 	  }
11237 #endif /* NETCONN */
11238 	  ;
11239 	/* debug(F101,"ttinc","",ch); */
11240 #ifdef TNCODE
11241 	if ((n > 0) && is_tn) {
11242 #ifdef CK_ENCRYPTION
11243 	    if (TELOPT_U(TELOPT_ENCRYPTION)) {
11244 		ck_tn_decrypt(&ch,1);
11245 		n = ch;
11246 	    }
11247 #endif /* CK_ENCRYPTION */
11248 	    return((unsigned)(ch & 0xff));
11249 	} else
11250 #endif /* TNCODE */
11251         return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
11252 #endif /* MYREAD */
11253 
11254     } else {				/* Timed read */
11255 
11256 	int oldalarm;
11257 	saval = signal(SIGALRM,timerh);	/* Set up handler, save old one. */
11258 	oldalarm = alarm(timo);		/* Set alarm, save old one. */
11259 	if (
11260 #ifdef CK_POSIX_SIG
11261 	    sigsetjmp(sjbuf,1)
11262 #else
11263 	    setjmp(sjbuf)
11264 #endif /* CK_POSIX_SIG */
11265 	    ) {				/* Timer expired */
11266 	    ttinctimo = 1;
11267 	    n = -1;			/* set flag */
11268 	} else {
11269 #ifdef MYREAD
11270 	    n = myread();		/* If managing own buffer... */
11271 	    debug(F101,"ttinc myread","",n);
11272 	    ch = n;
11273 #else
11274 	    n = read(fd,&ch,1);		/* Otherwise call the system. */
11275 	    if (n == 0) n = -1;
11276 	    debug(F101,"ttinc read","",n);
11277 #endif /* MYREAD */
11278 
11279 #ifdef CK_ENCRYPTION
11280 	    if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11281 		ck_tn_decrypt((char *)&ch,1);
11282 	    }
11283 #endif /* CK_ENCRYPTION */
11284 	    if (n >= 0)
11285 	      n = (unsigned) (ch & 0xff);
11286 	    else
11287 	      n = (n < 0) ? -4 : -2;	/* Special return codes. */
11288 	}
11289 	ttimoff();			/* Turn off the timer */
11290 	if (oldalarm > 0) {
11291 	    if (n == -1)		/* and restore any previous alarm */
11292 	      oldalarm -= timo;
11293 	    if (oldalarm < 0)		/* adjusted by our timeout interval */
11294 	      oldalarm = 0;
11295 	    if (oldalarm) {
11296 	        debug(F101,"ttinc restoring oldalarm","",oldalarm);
11297 		alarm(oldalarm);
11298 	    }
11299 	}
11300 #ifdef NETCONN
11301 	if (netconn) {
11302 	    if (n == -2) {		/* read() returns 0 */
11303 		netclos();		/* on network read failure */
11304 		netconn = 0;
11305 		errno = ENOTCONN;
11306 	    }
11307 	}
11308 #endif	/* NETCONN */
11309 #ifdef TNCODE
11310 	if ((n > -1) && is_tn)
11311 	  return((unsigned)(n & 0xff));
11312 	else
11313 #endif /* TNCODE */
11314 	  /* Return masked char or neg. */
11315 	  return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
11316     }
11317 }
11318 
11319 /*  S N D B R K  --  Send a BREAK signal of the given duration  */
11320 
11321 static int
11322 #ifdef CK_ANSIC
sndbrk(int msec)11323 sndbrk(int msec) {			/* Argument is milliseconds */
11324 #else
11325 sndbrk(msec) int msec; {
11326 #endif /* CK_ANSIC */
11327 #ifndef POSIX
11328     int x, n;
11329 #endif /* POSIX */
11330 
11331 #ifdef OXOS
11332 #define BSDBREAK
11333 #endif /* OXOS */
11334 
11335 #ifdef ANYBSD
11336 #define BSDBREAK
11337 #endif /* ANYBSD */
11338 
11339 #ifdef BSD44
11340 #define BSDBREAK
11341 #endif /* BSD44 */
11342 
11343 #ifdef COHERENT
11344 #ifdef BSDBREAK
11345 #undef BSDBREAK
11346 #endif /* BSDBREAK */
11347 #endif /* COHERENT */
11348 
11349 #ifdef BELLV10
11350 #ifdef BSDBREAK
11351 #undef BSDBREAK
11352 #endif /* BSDBREAK */
11353 #endif /* BELLV10 */
11354 
11355 #ifdef PROVX1
11356     char spd;
11357 #endif /* PROVX1 */
11358 
11359     debug(F101,"ttsndb ttyfd","",ttyfd);
11360     if (ttyfd < 0) return(-1);          /* Not open. */
11361 
11362 #ifdef Plan9
11363     return p9sndbrk(msec);
11364 #else
11365 #ifdef NETCONN
11366 #ifdef NETCMD
11367     if (ttpipe)				/* Pipe */
11368       return(ttoc('\0'));
11369 #endif /* NETCMD */
11370 #ifdef NETPTY
11371     if (ttpty)
11372       return(ttoc('\0'));
11373 #endif /* NETPTY */
11374     if (netconn) 			/* Send network BREAK */
11375       return(netbreak());
11376 #endif /* NETCONN */
11377 
11378     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
11379 
11380 #ifdef POSIX				/* Easy in POSIX */
11381     {
11382 	int x;
11383 	debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
11384 	errno = 0;
11385 	x = tcsendbreak(ttyfd,msec / 375);
11386 	debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
11387 	return(x);
11388     }
11389 #else
11390 #ifdef PROVX1
11391     gtty(ttyfd,&ttbuf);                 /* Get current tty flags */
11392     spd = ttbuf.sg_ospeed;              /* Save speed */
11393     ttbuf.sg_ospeed = B50;              /* Change to 50 baud */
11394     stty(ttyfd,&ttbuf);                 /*  ... */
11395     n = (int)strlen(brnuls);		/* Send the right number of nulls */
11396     x = msec / 91;
11397     if (x > n) x = n;
11398     write(ttyfd,brnuls,n);
11399     ttbuf.sg_ospeed = spd;              /* Restore speed */
11400     stty(ttyfd,&ttbuf);                 /*  ... */
11401     return(0);
11402 #else
11403 #ifdef aegis
11404     sio_$control((short)ttyfd, sio_$send_break, msec, st);
11405     return(0);
11406 #else
11407 #ifdef BSDBREAK
11408     n = FWRITE;                         /* Flush output queue. */
11409 /* Watch out for int vs long problems in &n arg! */
11410     debug(F101,"sndbrk BSDBREAK","",msec);
11411     ioctl(ttyfd,TIOCFLUSH,&n);          /* Ignore any errors.. */
11412     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {  /* Turn on BREAK */
11413         perror("Can't send BREAK");
11414         return(-1);
11415     }
11416     x = msleep(msec);                    /* Sleep for so many milliseconds */
11417     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {  /* Turn off BREAK */
11418         perror("BREAK stuck!!!");
11419         doexit(BAD_EXIT,-1);		/* Get out, closing the line. */
11420                                         /*   with bad exit status */
11421     }
11422     return(x);
11423 #else
11424 #ifdef ATTSV
11425 /*
11426   No way to send a long BREAK in Sys V, so send a bunch of regular ones.
11427   (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
11428   but there's no way for this code to know for sure.)
11429 */
11430     debug(F101,"sndbrk ATTSV","",msec);
11431     x = msec / 275;
11432     for (n = 0; n < x; n++) {
11433 	/* Reportedly the cast breaks this function on some systems */
11434 	/* But then why was it here in the first place? */
11435 	if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
11436 	    perror("Can't send BREAK");
11437 	    return(-1);
11438 	}
11439     }
11440     return(0);
11441 #else
11442 #ifdef  V7
11443     debug(F101,"sndbrk V7","",msec);
11444     return(genbrk(ttyfd,250));		/* Simulate a BREAK */
11445 #else
11446     debug(F101,"sndbrk catchall","",msec);
11447     ttoc(0);ttoc(0);ttoc(0);ttoc(0);
11448     return(0);
11449 #endif /* V7 */
11450 #endif /* BSDBREAK */
11451 #endif /* ATTSV */
11452 #endif /* aegis */
11453 #endif /* PROVX1 */
11454 #endif /* POSIX */
11455 #endif /* Plan9 */
11456 }
11457 
11458 /*  T T S N D B  --  Send a BREAK signal  */
11459 
11460 int
11461 ttsndb() {
11462 #ifdef TN_COMPORT
11463     if (netconn && istncomport())
11464       return((tnsndb(275L) >= 0) ? 0 : -1);
11465     else
11466 #endif /* TN_COMPORT */
11467       return(sndbrk(275));
11468 }
11469 
11470 /*  T T S N D L B  --  Send a Long BREAK signal  */
11471 
11472 int
11473 ttsndlb() {
11474 #ifdef TN_COMPORT
11475     if (netconn && istncomport())
11476       return((tnsndb(1800L) >= 0) ? 0 : -1);
11477     else
11478 #endif /* TN_COMPORT */
11479     return(sndbrk(1500));
11480 }
11481 
11482 /*  M S L E E P  --  Millisecond version of sleep().  */
11483 
11484 /*
11485   Call with number of milliseconds (thousandths of seconds) to sleep.
11486   Intended only for small intervals.  For big ones, just use sleep().
11487   Highly system-dependent.
11488   Returns 0 always, even if it didn't work.
11489 */
11490 
11491 /* Define MSLFTIME for systems that must use an ftime() loop. */
11492 #ifdef ANYBSD				/* For pre-4.2 BSD versions */
11493 #ifndef BSD4
11494 #define MSLFTIME
11495 #endif /* BSD4 */
11496 #endif /* ANYBSD */
11497 
11498 #ifdef TOWER1				/* NCR Tower OS 1.0 */
11499 #define MSLFTIME
11500 #endif /* TOWER1 */
11501 
11502 #ifdef COHERENT         /* Coherent... */
11503 #ifndef _I386           /* Maybe Coherent/386 should get this, too */
11504 #define MSLFTIME        /* Opinions are divided */
11505 #endif /* _I386 */
11506 #endif /* COHERENT */
11507 
11508 #ifdef COMMENT
11509 #ifdef GETMSEC
11510 
11511 /* Millisecond timer */
11512 
11513 static long msecbase = 0L;		/* Unsigned long not portable */
11514 
11515 long
11516 getmsec() {				/* Milliseconds since base time */
11517     struct timeval xv;
11518     struct timezone xz;
11519     long secs, msecs;
11520     if (
11521 #ifdef GTODONEARG
11522 	gettimeofday(&tv)
11523 #else
11524 #ifdef PTX
11525 	gettimeofday(&tv, NULL)
11526 #else
11527 	gettimeofday(&tv, &tz)
11528 #endif /* PTX */
11529 #endif /* GTODONEARG */
11530 	< 0)
11531       return(-1);
11532     if (msecbase == 0L) {		/* First call, set base time. */
11533 	msecbase = tv.tv_sec;
11534 	debug(F101,"getmsec base","",msecbase);
11535     }
11536     return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
11537 }
11538 #endif /* GETMSEC */
11539 #endif /* COMMENT */
11540 
11541 #ifdef SELECT
11542 int
11543 ttwait(fd, secs) int fd, secs; {
11544     int x;
11545     fd_set rfds;
11546     FD_ZERO(&rfds);
11547     FD_SET(fd,&rfds);
11548     tv.tv_sec = secs;
11549     tv.tv_usec = 0L;
11550     errno = 0;
11551     if ((x = select(FD_SETSIZE,
11552 #ifdef HPUX9
11553 		    (int *)
11554 #else
11555 #ifdef HPUX1000
11556 		    (int *)
11557 #endif /* HPUX1000 */
11558 #endif /* HPUX9 */
11559 		    &rfds,
11560 		    0, 0, &tv)) < 0) {
11561 	debug(F101,"ttwait select errno","",errno);
11562 	return(0);
11563     } else {
11564 	debug(F101,"ttwait OK","",errno);
11565 	x = FD_ISSET(fd, &rfds);
11566 	debug(F101,"ttwait select x","",x);
11567 	return(x ? 1 : 0);
11568     }
11569 }
11570 #endif /* SELECT */
11571 
11572 int
11573 msleep(m) int m; {
11574 /*
11575   Other possibilities here are:
11576    nanosleep(), reportedly defined in POSIX.4.
11577    sginap(), IRIX only (back to what IRIX version I don't know).
11578 */
11579 #ifdef Plan9
11580     return _SLEEP(m);
11581 #else
11582 #ifdef BEOSORBEBOX
11583     snooze(m*1000);
11584 #else /* BEOSORBEBOX */
11585 #ifdef SELECT
11586     int t1, x;
11587     debug(F101,"msleep SELECT 1","",m);
11588     if (m <= 0) return(0);
11589     if (m >= 1000) {			/* Catch big arguments. */
11590 	sleep(m/1000);
11591 	m = m % 1000;
11592 	if (m < 10) return(0);
11593     }
11594     debug(F101,"msleep SELECT 2","",m);
11595 #ifdef BELLV10
11596     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
11597     debug(F101,"msleep BELLV10 select","",x);
11598 #else /* BELLV10 */
11599 #ifdef HPUX9
11600     gettimeofday(&tv, &tz);
11601 #else
11602 
11603 #ifndef COHERENT
11604 #ifdef GTODONEARG
11605     if (gettimeofday(&tv) < 0)
11606 #else
11607 #ifdef PTX
11608     if (gettimeofday(&tv,NULL) < 0)
11609 #else
11610 #ifdef NOTIMEZONE
11611     if (gettimeofday(&tv, NULL) < 0)	/* wonder what this does... */
11612 #else
11613     if (gettimeofday(&tv, &tz) < 0)
11614 #endif /* NOTIMEZONE */
11615 #endif /* PTX */
11616 #endif /* GTODONEARG */
11617       return(-1);
11618     t1 = tv.tv_sec;                     /* Seconds */
11619 #endif /* COHERENT */
11620 #endif /* HPUX9 */
11621     tv.tv_sec = 0;                      /* Use select() */
11622     tv.tv_usec = m * 1000L;
11623 #ifdef BSD44
11624     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11625     debug(F101,"msleep BSD44 select","",x);
11626 #else /* BSD44 */
11627 #ifdef __linux__
11628     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11629     debug(F101,"msleep __linux__ select","",x);
11630 #else /* __linux__ */
11631 #ifdef BSD43
11632     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11633     debug(F101,"msleep BSD43 select","",x);
11634 #else /* BSD43 */
11635 #ifdef QNX6
11636     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11637     debug(F101,"msleep QNX6 select","",x);
11638 #else /* QNX6 */
11639 #ifdef QNX
11640     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11641     debug(F101,"msleep QNX select","",x);
11642 #else /* QNX */
11643 #ifdef COHERENT
11644     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11645     debug(F101,"msleep COHERENT select","",x);
11646 #else /* COHERENT */
11647 #ifdef HPUX1000				/* 10.00 only, not 10.10 or later */
11648     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11649     debug(F101,"msleep HP-UX 10.00 select","",x);
11650 #else /* HPUX1000 */
11651 #ifdef SVR4
11652     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11653     debug(F101,"msleep SVR4 select","",x);
11654 #else /* SVR4 */
11655 #ifdef OSF40
11656     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11657     debug(F101,"msleep OSF40 select","",x);
11658 #else /* OSF40 */
11659 #ifdef PTX
11660     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11661     debug(F101,"msleep OSF40 select","",x);
11662 #else
11663     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11664     debug(F101,"msleep catch-all select","",x);
11665 #endif /* PTX */
11666 #endif /* OSF40 */
11667 #endif /* HP1000 */
11668 #endif /* SVR4 */
11669 #endif /* COHERENT */
11670 #endif /* QNX */
11671 #endif /* QNX6 */
11672 #endif /* BSD43 */
11673 #endif /* __linux__ */
11674 #endif /* BSD44 */
11675 #endif /* BELLV10 */
11676     return(0);
11677 
11678 #else					/* Not SELECT */
11679 #ifdef CK_POLL				/* We have poll() */
11680     struct pollfd pfd;			/* Supply a valid address for poll() */
11681 
11682 #ifdef ODT30				/* But in SCO ODT 3.0 */
11683 #ifdef NAP				/* we should use nap() instead */
11684     debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
11685     nap((long)m);			   /* seems to break dialing. */
11686     return(0);
11687 #else
11688     debug(F101,"msleep ODT 3.0 POLL","",m);
11689     poll(&pfd, 0, m);
11690     return(0);
11691 #endif /* NAP */
11692 #else
11693     debug(F101,"msleep POLL","",m);
11694     poll(&pfd, 0, m);
11695     return(0);
11696 #endif /* ODT30 */
11697 
11698 /*
11699   We could handle the above more cleanly by just letting nap() always
11700   take precedence over poll() in this routine, but there is no way to know
11701   whether that would break something else.
11702 */
11703 
11704 #else					/* Not POLL */
11705 #ifdef USLEEP
11706 /*
11707   "This routine is implemented using setitimer(2); it requires eight
11708   system calls...".  In other words, it might take 5 minutes to sleep
11709   10 milliseconds...
11710 */
11711     debug(F101,"msleep USLEEP","",m);
11712     if (m >= 1000) {			/* Catch big arguments. */
11713 	sleep(m/1000);
11714 	m = m % 1000;
11715 	if (m < 10) return(0);
11716     }
11717     usleep((unsigned int)(m * 1000));
11718     return(0);
11719 #else
11720 #ifdef aegis
11721     time_$clock_t dur;
11722     debug(F101,"msleep aegis","",m);
11723     dur.c2.high16 = 0;
11724     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
11725     time_$wait(time_$relative, dur, st);
11726     return(0);
11727 #else
11728 #ifdef PROVX1
11729     debug(F101,"msleep Venix","",m);
11730     if (m <= 0) return(0);
11731     sleep(-((m * 60 + 500) / 1000));
11732     return(0);
11733 #else
11734 #ifdef NAP
11735     debug(F101,"msleep NAP","",m);
11736     nap((long)m);
11737     return(0);
11738 #else
11739 #ifdef ATTSV
11740 #ifndef BSD44
11741     extern long times();		/* Or #include <times.h> ? */
11742 #endif /* BSD44 */
11743     long t1, t2, tarray[4];
11744     int t3;
11745     char *cp = getenv("HZ");
11746     int CLOCK_TICK;
11747     int hertz;
11748 
11749     if (cp && (hertz = atoi(cp))) {
11750         CLOCK_TICK  = 1000 / hertz;
11751     } else {				/* probably single user mode */
11752 #ifdef HZ
11753         CLOCK_TICK  = 1000 / HZ;
11754 #else
11755 	static warned = 0;
11756 	/* HZ always exists in, for instance, SCO Xenix, so you don't have to
11757 	 * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
11758 	 * have Xenix, you have should have nap(), so the best is to use -DNAP
11759 	 * in the makefile. Most systems have HZ.
11760 	 */
11761 	CLOCK_TICK = 17;		/* 1/60 sec */
11762 	if (!warned) {
11763           printf("warning: environment variable HZ bad... using HZ=%d\r\n",
11764 		 1000 / CLOCK_TICK);
11765           warned = 1;
11766 	}
11767 #endif /* !HZ */
11768     }
11769     debug(F101,"msleep ATTSV","",m);
11770     if (m <= 0) return(0);
11771     if (m >= 1000) {			/* Catch big arguments. */
11772 	sleep(m/1000);
11773 	m = m % 1000;
11774 	if (m < 10) return(0);
11775     }
11776     if ((t1 = times(tarray)) < 0) return(-1);
11777     while (1) {
11778         if ((t2 = times(tarray)) < 0) return(-1);
11779         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
11780         if (t3 > m) return(t3);
11781     }
11782 #else /* Not ATTSV */
11783 #ifdef MSLFTIME				/* Use ftime() loop... */
11784     int t1, t3 = 0;
11785     debug(F101,"msleep MSLFTIME","",m);
11786     if (m <= 0) return(0);
11787     if (m >= 1000) {			/* Catch big arguments. */
11788 	sleep(m/1000);
11789 	m = m % 1000;
11790 	if (m < 10) return(0);
11791     }
11792 #ifdef QNX
11793     ftime(&ftp);			/* void ftime() in QNX */
11794 #else
11795     if (ftime(&ftp) < 0) return(-1);	/* Get base time. */
11796 #endif /* QNX */
11797     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
11798     while (1) {
11799         ftime(&ftp);			/* Get current time and compare. */
11800         t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
11801         if (t3 > m) return(0);
11802     }
11803 #else
11804 /* This includes true POSIX, which has no way to do this. */
11805     debug(F101,"msleep busy loop","",m);
11806     if (m >= 1000) {			/* Catch big arguments. */
11807 	sleep(m/1000);
11808 	m = m % 1000;
11809 	if (m < 10) return(0);
11810     }
11811     if (m > 0) while (m > 0) m--;	/* Just a dumb busy loop */
11812     return(0);
11813 #endif /* MSLFTIME */
11814 #endif /* ATTSV */
11815 #endif /* NAP */
11816 #endif /* PROVX1 */
11817 #endif /* aegis */
11818 #endif /* CK_POLL */
11819 #endif /* SELECT */
11820 #endif /* BEOSORBEBOX */
11821 #endif /* USLEEP */
11822 #endif /* Plan9 */
11823 }
11824 
11825 /*  R T I M E R --  Reset elapsed time counter  */
11826 
11827 VOID
11828 rtimer() {
11829     tcount = time( (time_t *) 0 );
11830 }
11831 
11832 
11833 /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
11834 
11835 int
11836 gtimer() {
11837     int x;
11838     x = (int) (time( (time_t *) 0 ) - tcount);
11839     debug(F101,"gtimer","",x);
11840     return( (x < 0) ? 0 : x );
11841 }
11842 
11843 #ifdef GFTIMER
11844 /*
11845   Floating-point timers.  Require not only floating point support, but
11846   also gettimeofday().
11847 */
11848 static struct timeval tzero;
11849 
11850 VOID
11851 rftimer() {
11852 #ifdef GTODONEARG			/* Account for Mot's definition */
11853     (VOID) gettimeofday(&tzero);
11854 #else
11855     (VOID) gettimeofday(&tzero, (struct timezone *)0);
11856 #endif /* GTODONEARG */
11857 }
11858 
11859 CKFLOAT
11860 gftimer() {
11861     struct timeval tnow, tdelta;
11862     CKFLOAT s;
11863 #ifdef DEBUG
11864     char fpbuf[64];
11865 #endif /* DEBUG */
11866 #ifdef GTODONEARG			/* Account for Mot's definition */
11867     (VOID) gettimeofday(&tnow);
11868 #else
11869     (VOID) gettimeofday(&tnow, (struct timezone *)0);
11870 #endif /* GTODONEARG */
11871 
11872     tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
11873     tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
11874 
11875     if (tdelta.tv_usec < 0) {
11876 	tdelta.tv_sec--;
11877 	tdelta.tv_usec += 1000000;
11878     }
11879     s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
11880     if (s < GFMINTIME)
11881       s = GFMINTIME;
11882 #ifdef DEBUG
11883     if (deblog) {
11884 	sprintf(fpbuf,"%f",s);
11885 	debug(F110,"gftimer",fpbuf,0);
11886     }
11887 #endif /* DEBUG */
11888     return(s);
11889 }
11890 #endif /* GFTIMER */
11891 
11892 /*  Z T I M E  --  Return asctime()-format date/time string  */
11893 /*
11894   NOTE: as a side effect of calling this routine, we can also set the
11895   following two variables, giving the micro- and milliseconds (fractions of
11896   seconds) of the clock time.  Currently this is done only in BSD-based builds
11897   that use gettimeofday().  When these variables are not filled in, they are
11898   left with a value of -1L.
11899 */
11900 static char asctmbuf[64];
11901 
11902 VOID
11903 ztime(s) char **s; {
11904 
11905 #ifdef GFTIMER
11906 /*
11907   The gettimeofday() method, which also sets ztmsec and ztusec, works for
11908   all GFTIMER builds.  NOTE: ztmsec and ztusec are defined in ckcmai.c,
11909   and extern declarations for them are in ckcdeb.h; thus they are
11910   declared in this file by inclusion of ckcdeb.h.
11911 */
11912     char *asctime();
11913     struct tm *localtime();
11914     struct tm *tp;
11915     ztmsec = -1L;
11916     ztusec = -1L;
11917 
11918     if (!s)
11919       debug(F100,"ztime s==NULL","",0);
11920 
11921 #ifdef GTODONEARG
11922     /* No 2nd arg in Motorola SV88 and some others */
11923     if (gettimeofday(&tv) > -1)
11924 #else
11925 #ifndef COHERENT
11926 #ifdef PTX
11927     if (gettimeofday(&tv,NULL) > -1)
11928 #else
11929 #ifdef NOTIMEZONE
11930     if (gettimeofday(&tv, NULL) > -1)	/* wonder what this does... */
11931 #else
11932     if (gettimeofday(&tv, &tz) > -1)
11933 #endif /* NOTIMEZONE */
11934 #endif /* PTX */
11935 #endif /* COHERENT */
11936 #endif /* GTODONEARG */
11937       {					/* Fill in tm struct */
11938 	ztusec = tv.tv_usec;		/* Microseconds */
11939 	ztmsec = ztusec / 1000L;	/* Milliseconds */
11940 #ifdef HPUX9
11941 	{
11942 	    time_t zz;
11943 	    zz = tv.tv_sec;
11944 	    tp = localtime(&zz);	/* Convert to local time */
11945 	}
11946 #else
11947 #ifdef HPUX1000
11948 	{
11949 	    time_t zz;
11950 	    zz = tv.tv_sec;
11951 	    tp = localtime(&zz);
11952 	}
11953 #else
11954 #ifdef LINUX
11955 	{   /* avoid unaligned access trap on 64-bit platforms */
11956 	    time_t zz;
11957 	    zz = tv.tv_sec;
11958 	    tp = localtime(&zz);
11959 	}
11960 #else
11961 #ifdef MACOSX
11962 	tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
11963 #else
11964 	tp = localtime(&tv.tv_sec);
11965 #endif /* MACOSX */
11966 #endif /* LINUX */
11967 #endif /* HPUX1000 */
11968 #endif /* HPUX9 */
11969 	if (s) {
11970 	    char * s2;
11971 	    s2 = asctime(tp);		/* Convert result to ASCII string */
11972 	    asctmbuf[0] = '\0';
11973 	    if (s2) ckstrncpy(asctmbuf,s2,64);
11974 	    *s = asctmbuf;
11975 	    debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
11976 	}
11977     }
11978 #else  /* Not GFTIMER */
11979 
11980 #undef ZTIMEV7				/* Which systems need to use */
11981 #ifdef COHERENT				/* old UNIX Version 7 way... */
11982 #define ZTIMEV7
11983 #endif /* COHERENT */
11984 #ifdef TOWER1
11985 #define ZTIMEV7
11986 #endif /* TOWER1 */
11987 #ifdef ANYBSD
11988 #ifndef BSD42
11989 #define ZTIMEV7
11990 #endif /* BSD42 */
11991 #endif /* ANYBSD */
11992 #ifdef V7
11993 #ifndef MINIX
11994 #define ZTIMEV7
11995 #endif /* MINIX */
11996 #endif /* V7 */
11997 #ifdef POSIX
11998 #define ZTIMEV7
11999 #endif /* POSIX */
12000 
12001 #ifdef HPUX1020
12002 /*
12003   Prototypes are in <time.h>, included above.
12004 */
12005     time_t clock_storage;
12006     clock_storage = time((void *) 0);
12007     if (s) {
12008 	*s = ctime(&clock_storage);
12009 	debug(F110,"ztime: HPUX 10.20",*s,0);
12010     }
12011 #else
12012 #ifdef ATTSV				/* AT&T way */
12013 /*  extern long time(); */		/* Theoretically these should */
12014     char *ctime();			/* already been dcl'd in <time.h> */
12015     time_t clock_storage;
12016     clock_storage = time(
12017 #ifdef IRIX60
12018 			 (time_t *)
12019 #else
12020 #ifdef BSD44
12021 			 (time_t *)
12022 #else
12023 			 (long *)
12024 #endif /* BSD44 */
12025 #endif /* IRIX60 */
12026 			 0 );
12027     if (s) {
12028 	*s = ctime( &clock_storage );
12029 	debug(F110,"ztime: ATTSV",*s,0);
12030     }
12031 #else
12032 #ifdef PROVX1				/* Venix 1.0 way */
12033     int utime[2];
12034     time(utime);
12035     if (s) {
12036 	*s = ctime(utime);
12037 	debug(F110,"ztime: PROVX1",*s,0);
12038     }
12039 #else
12040 #ifdef BSD42				/* 4.2BSD way */
12041     char *asctime();
12042     struct tm *localtime();
12043     struct tm *tp;
12044     gettimeofday(&tv, &tz);
12045     ztusec = tv.tv_usec;
12046     ztmsec = tv.tv_usec / 1000L;
12047     tp = localtime(&tv.tv_sec);
12048     if (s) {
12049 	*s = asctime(tp);
12050 	debug(F111,"ztime: BSD42",*s,ztusec);
12051     }
12052 #else
12053 #ifdef MINIX				/* MINIX way */
12054 #ifdef COMMENT
12055     extern long time();			/* Already got these from <time.h> */
12056     extern char *ctime();
12057 #endif /* COMMENT */
12058     time_t utime[2];
12059     time(utime);
12060     if (s) {
12061 	*s = ctime(utime);
12062 	debug(F110,"ztime: MINIX",*s,0);
12063     }
12064 #else
12065 #ifdef ZTIMEV7				/* The regular way */
12066     char *asctime();
12067     struct tm *localtime();
12068     struct tm *tp;
12069     long xclock;			/* or unsigned long for BeBox? */
12070     time(&xclock);
12071     tp = localtime(&xclock);
12072     if (s) {
12073 	*s = asctime(tp);
12074 	debug(F110,"ztime: ZTIMEV7",*s,0);
12075     }
12076 #else					/* Catch-all for others... */
12077     if (s) {
12078 	*s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
12079 	debug(F110,"ztime: catch-all",*s,0);
12080     }
12081 #endif /* ZTIMEV7 */
12082 #endif /* MINIX */
12083 #endif /* BSD42 */
12084 #endif /* PROVX1 */
12085 #endif /* ATTSV */
12086 #endif /* HPUX1020 */
12087 #endif /* GFTIMER */
12088 }
12089 
12090 /*  C O N G M  --  Get console terminal modes.  */
12091 
12092 /*
12093   Saves initial console mode, and establishes variables for switching
12094   between current (presumably normal) mode and other modes.
12095   Should be called when program starts, but only after establishing
12096   whether program is in the foreground or background.
12097   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
12098 */
12099 int
12100 congm() {
12101     int fd;
12102     if (backgrd || !isatty(0)) {	/* If in background. */
12103 	cgmf = -1;			/* Don't bother, modes are garbage. */
12104 	return(-1);
12105     }
12106     if (cgmf > 0) return(0);		/* Already did this. */
12107     debug(F100,"congm getting modes","",0); /* Need to do it. */
12108 #ifdef aegis
12109     ios_$inq_type_uid(ios_$stdin, conuid, st);
12110     if (st.all != status_$ok) {
12111 	fprintf(stderr, "problem getting stdin objtype: ");
12112 	error_$print(st);
12113     }
12114     concrp = (conuid == mbx_$uid);
12115     conbufn = 0;
12116 #endif /* aegis */
12117 
12118 #ifndef BEBOX
12119     if ((fd = open(CTTNAM,2)) < 0) {	/* Open controlling terminal */
12120 #ifdef COMMENT
12121 	fprintf(stderr,"Error opening %s\n", CTTNAM);
12122 	perror("congm");
12123 	return(-1);
12124 #else
12125 	fd = 0;
12126 #endif /* COMMENT */
12127     }
12128 #else
12129     fd = 0;
12130 #endif /* !BEBOX */
12131 #ifdef BSD44ORPOSIX
12132     if (tcgetattr(fd,&ccold) < 0) return(-1);
12133     if (tcgetattr(fd,&cccbrk) < 0) return(-1);
12134     if (tcgetattr(fd,&ccraw) < 0) return(-1);
12135 #else
12136 #ifdef ATTSV
12137     if (ioctl(fd,TCGETA,&ccold)  < 0) return(-1);
12138     if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
12139     if (ioctl(fd,TCGETA,&ccraw)  < 0) return(-1);
12140 #ifdef VXVE
12141     cccbrk.c_line = 0;			/* STTY line 0 for CDC VX/VE */
12142     if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
12143     ccraw.c_line = 0;			/* STTY line 0 for CDC VX/VE */
12144     if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
12145 #endif /* VXVE */
12146 #else
12147 #ifdef BELLV10
12148     if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
12149     if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
12150     if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
12151     debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
12152 #else
12153     if (gtty(fd,&ccold) < 0) return(-1);
12154     if (gtty(fd,&cccbrk) < 0) return(-1);
12155     if (gtty(fd,&ccraw) < 0) return(-1);
12156 #endif /* BELLV10 */
12157 #endif /* ATTSV */
12158 #endif /* BSD44ORPOSIX */
12159 #ifdef sony_news			/* Sony NEWS */
12160     if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
12161 	perror("congm error getting Kanji mode");
12162 	debug(F101,"congm error getting Kanji mode","",0);
12163 	km_con = -1;			/* Make sure this stays undefined. */
12164 	return(-1);
12165     }
12166 #endif /* sony_news */
12167     if (fd > 0)
12168       close(fd);
12169     cgmf = 1;				/* Flag that we got them. */
12170     return(1);
12171 }
12172 
12173 
12174 static VOID
12175 congetbuf(x) int x; {
12176     int n;
12177     n = CONBUFSIZ - (conbufp - conbuf);	/* How much room left in buffer? */
12178     if (x > n) {
12179 	debug(F101,"congetbuf char loss","",x-n);
12180 	x = n;
12181     }
12182     x = read(0,conbufp,x);
12183     conbufn += x;
12184     debug(F111,"congetbuf readahead",conbuf,x);
12185 }
12186 
12187 
12188 /*  C O N C B --  Put console in cbreak mode.  */
12189 
12190 /*  Returns 0 if ok, -1 if not  */
12191 
12192 int
12193 #ifdef CK_ANSIC
12194 concb(char esc)
12195 #else
12196 concb(esc) char esc;
12197 #endif /* CK_ANSIC */
12198 /* concb */ {
12199     int x, y = 0;
12200     debug(F101,"concb constate","",constate);
12201     debug(F101,"concb cgmf","",cgmf);
12202     debug(F101,"concb backgrd","",backgrd);
12203 
12204     if (constate == CON_CB)
12205       return(0);
12206 
12207     if (cgmf < 1)			/* Did we get console modes yet? */
12208       if (!backgrd)			/* No, in background? */
12209 	congm();			/* No, try to get them now. */
12210     if (cgmf < 1)			/* Still don't have them? */
12211       return(0);			/* Give up. */
12212     debug(F101,"concb ttyfd","",ttyfd);
12213     debug(F101,"concb ttfdflg","",ttfdflg);
12214 #ifdef COMMENT
12215     /* This breaks returning to prompt after protocol with "-l 0" */
12216     /* Commented out July 1998 */
12217     if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
12218       return(0);
12219 #endif /* COMMENT */
12220     x = isatty(0);
12221     debug(F101,"concb isatty","",x);
12222     if (!x) return(0);			/* Only when running on real ttys */
12223     debug(F101,"concb xsuspend","",xsuspend);
12224     if (backgrd)			/* Do nothing if in background. */
12225       return(0);
12226     escchr = esc;                       /* Make this available to other fns */
12227     ckxech = 1;                         /* Program can echo characters */
12228 #ifdef aegis
12229     conbufn = 0;
12230     if (concrp) return(write(1, "\035\002", 2));
12231     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
12232 #endif /* aegis */
12233 
12234 #ifdef COHERENT
12235 #define SVORPOSIX
12236 #endif /* COHERENT */
12237 
12238 #ifdef Plan9
12239     x = p9concb();
12240 #else
12241 #ifndef SVORPOSIX			/* BSD, V7, etc */
12242     debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
12243     debug(F101,"concb stty CBREAK","",0);
12244     cccbrk.sg_flags |= (CBREAK|CRMOD);	/* Set to character wakeup, */
12245     cccbrk.sg_flags &= ~ECHO;           /* no echo. */
12246     debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
12247     errno = 0;
12248 /*
12249   BSD stty() clears the console buffer.  So if anything is waiting in it,
12250   we have to read it now to avoid losing it.
12251 */
12252     x = conchk();
12253     if (x > 0)
12254       congetbuf(x);
12255 
12256 #ifdef BELLV10
12257     x = ioctl(0,TIOCSETP,&cccbrk);
12258 #else
12259     x = stty(0,&cccbrk);
12260     debug(F101,"cccbrk.sg_flags concb x","", x);
12261 #endif /* BELLV10 */
12262 #else					/* Sys V and POSIX */
12263 #ifndef OXOS
12264     debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
12265 #ifdef QNX
12266     /* Don't mess with IEXTEN */
12267     cccbrk.c_lflag &= ~(ICANON|ECHO);
12268 #else
12269 #ifdef COHERENT
12270     cccbrk.c_lflag &= ~(ICANON|ECHO);
12271 #else
12272     cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
12273 #endif /* COHERENT */
12274 #endif /* QNX */
12275     cccbrk.c_lflag |= ISIG;		/* Allow signals in command mode. */
12276     cccbrk.c_iflag |= IGNBRK;		/* But ignore BREAK signal */
12277     cccbrk.c_iflag &= ~BRKINT;
12278 
12279 #else /* OXOS */
12280     debug(F100,"concb OXOS is defined","",0);
12281     cccbrk.c_lflag &= ~(ICANON|ECHO);
12282     cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
12283 #endif /* OXOS */
12284 #ifdef COMMENT
12285 /*
12286   Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
12287   array reference is out of bounds.  It's only a debug() call so who needs it.
12288 */
12289 #ifdef VSUSP
12290     debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
12291 #endif /* VSUSP */
12292 #endif /* COMMENT */
12293 #ifndef VINTR
12294     debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
12295     cccbrk.c_cc[0] = 003;               /* Interrupt char is Control-C */
12296 #else
12297     debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
12298     cccbrk.c_cc[VINTR] = 003;
12299 #endif /* VINTR */
12300 #ifndef VQUIT
12301     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
12302 #else
12303     cccbrk.c_cc[VQUIT] = escchr;
12304 #endif /* VQUIT */
12305 #ifndef VEOF
12306     cccbrk.c_cc[4] = 1;
12307 #else
12308 #ifndef OXOS
12309 #ifdef VMIN
12310     cccbrk.c_cc[VMIN] = 1;
12311 #endif /* VMIN */
12312 #else /* OXOS */
12313     cccbrk.c_min = 1;
12314 #endif /* OXOS */
12315 #endif /* VEOF */
12316 #ifdef ZILOG
12317     cccbrk.c_cc[5] = 0;
12318 #else
12319 #ifndef VEOL
12320     cccbrk.c_cc[5] = 1;
12321 #else
12322 #ifndef OXOS
12323 #ifdef VTIME
12324     cccbrk.c_cc[VTIME] = 1;
12325 #endif /* VTIME */
12326 #else /* OXOS */
12327     cccbrk.c_time = 1;
12328 #endif /* OXOS */
12329 #endif /* VEOL */
12330 #endif /* ZILOG */
12331     errno = 0;
12332 #ifdef BSD44ORPOSIX			/* Set new modes */
12333     x = tcsetattr(0,TCSADRAIN,&cccbrk);
12334 #else /* ATTSV */      			/* or the POSIX way */
12335     x = ioctl(0,TCSETAW,&cccbrk);	/* the Sys V way */
12336 #endif /* BSD44ORPOSIX */
12337 #endif /* SVORPOSIX */
12338 
12339 #ifdef COHERENT
12340 #undef SVORPOSIX
12341 #endif /* COHERENT */
12342 
12343     debug(F101,"concb x","",x);
12344     debug(F101,"concb errno","",errno);
12345 
12346 #ifdef  V7
12347 #ifndef MINIX
12348     if (kmem[CON] < 0) {
12349         qaddr[CON] = initrawq(0);
12350         if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
12351             fprintf(stderr, "Can't read /dev/kmem in concb.\n");
12352             perror("/dev/kmem");
12353             exit(1);
12354         }
12355     }
12356 #endif /* MINIX */
12357 #endif /* V7 */
12358 #endif /* Plan9 */
12359 
12360     if (x > -1)
12361       constate = CON_CB;
12362 
12363     debug(F101,"concb returns","",x);
12364     return(x);
12365 }
12366 
12367 /*  C O N B I N  --  Put console in binary mode  */
12368 
12369 /*  Returns 0 if ok, -1 if not  */
12370 
12371 int
12372 #ifdef CK_ANSIC
12373 conbin(char esc)
12374 #else
12375 conbin(esc) char esc;
12376 #endif /* CK_ANSIC */
12377 /* conbin */  {
12378 
12379     int x;
12380 
12381     debug(F101,"conbin constate","",constate);
12382 
12383     if (constate == CON_BIN)
12384       return(0);
12385 
12386     if (!isatty(0)) return(0);          /* only for real ttys */
12387     congm();				/* Get modes if necessary. */
12388     debug(F100,"conbin","",0);
12389     escchr = esc;                       /* Make this available to other fns */
12390     ckxech = 1;                         /* Program can echo characters */
12391 #ifdef aegis
12392     conbufn = 0;
12393     if (concrp) return(write(1, "\035\002", 2));
12394     if (conuid == input_pad_$uid) {
12395 	pad_$raw(ios_$stdin, st);
12396 	return(0);
12397       }
12398 #endif /* aegis */
12399 
12400 #ifdef COHERENT
12401 #define SVORPOSIX
12402 #endif /* COHERENT */
12403 
12404 #ifdef Plan9
12405     return p9conbin();
12406 #else
12407 #ifdef SVORPOSIX
12408 #ifndef OXOS
12409 #ifdef QNX
12410     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12411 #else
12412 #ifdef COHERENT
12413     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12414 #else
12415     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
12416 #endif /* COHERENT */
12417 #endif /* QNX */
12418 #else /* OXOS */
12419     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12420     ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
12421 #endif /* OXOS */
12422     ccraw.c_iflag |= IGNPAR;
12423 /*
12424   Note that for terminal sessions we disable Xon/Xoff flow control to allow
12425   the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
12426   transfers to work when C-Kermit is in the middle, etc.  Hardware flow
12427   control, if in use, is not affected.
12428 */
12429 #ifdef ATTSV
12430 #ifdef BSD44
12431     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
12432                         |INPCK|ISTRIP);
12433 #else
12434     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
12435                         |INPCK|ISTRIP);
12436 #endif /* BSD44 */
12437 #else /* POSIX */
12438     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
12439 #endif /* ATTSV */
12440     ccraw.c_oflag &= ~OPOST;
12441 #ifdef COMMENT
12442 /*
12443   WHAT THE HECK WAS THIS FOR?
12444   The B9600 setting (obviously) prevents CONNECT from working at any
12445   speed other than 9600 when you are logged in to the 7300 on a serial
12446   line.  Maybe some of the other flags are necessary -- if so, put back
12447   the ones that are needed.  This code is supposed to work the same, no
12448   matter whether you are logged in to the 7300 on the real console device,
12449   or through a serial port.
12450 */
12451 #ifdef ATT7300
12452     ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
12453 #endif /* ATT7300 */
12454 #endif /* COMMENT */
12455 
12456 /*** Kermit used to put the console in 8-bit raw mode, but some users have
12457  *** pointed out that this should not be done, since some sites actually
12458  *** use terminals with parity settings on their Unix systems, and if we
12459  *** override the current settings and stop doing parity, then their terminals
12460  *** will display blotches for characters whose parity is wrong.  Therefore,
12461  *** the following two lines are commented out (Larry Afrin, Clemson U):
12462  ***
12463  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
12464  ***   ccraw.c_cflag |= (CS8|CREAD);
12465  ***
12466  *** Sys III/V sites that have trouble with this can restore these lines.
12467  ***/
12468 #ifndef VINTR
12469     ccraw.c_cc[0] = 003;		/* Interrupt char is Ctrl-C */
12470 #else
12471     ccraw.c_cc[VINTR] = 003;
12472 #endif /* VINTR */
12473 #ifndef VQUIT
12474     ccraw.c_cc[1] = escchr;		/* Escape during packet mode */
12475 #else
12476     ccraw.c_cc[VQUIT] = escchr;
12477 #endif /* VQUIT */
12478 #ifndef VEOF
12479     ccraw.c_cc[4] = 1;
12480 #else
12481 #ifndef OXOS
12482 #ifdef VMIN
12483     ccraw.c_cc[VMIN] = 1;
12484 #endif /* VMIN */
12485 #else /* OXOS */
12486     ccraw.c_min = 1;
12487 #endif /* OXOS */
12488 #endif /* VEOF */
12489 
12490 #ifdef ZILOG
12491     ccraw.c_cc[5] = 0;
12492 #else
12493 #ifndef VEOL
12494     ccraw.c_cc[5] = 1;
12495 #else
12496 #ifndef OXOS
12497 #ifdef VTIME
12498     ccraw.c_cc[VTIME] = 1;
12499 #endif /* VTIME */
12500 #else /* OXOS */
12501     ccraw.c_time = 1;
12502 #endif /* OXOS */
12503 #endif /* VEOL */
12504 #endif /* ZILOG */
12505 
12506 #ifdef BSD44ORPOSIX
12507     x = tcsetattr(0,TCSADRAIN,&ccraw);	/* Set new modes. */
12508 #else
12509     x = ioctl(0,TCSETAW,&ccraw);
12510 #endif /* BSD44ORPOSIX */
12511 #else /* Berkeley, etc. */
12512     x = conchk();			/* Because stty() is destructive */
12513     if (x > 0)
12514       congetbuf(x);
12515     ccraw.sg_flags |= (RAW|TANDEM);     /* Set rawmode, XON/XOFF (ha) */
12516     ccraw.sg_flags &= ~(ECHO|CRMOD);    /* Set char wakeup, no echo */
12517 #ifdef BELLV10
12518     x = ioctl(0,TIOCSETP,&ccraw);
12519 #else
12520     x = stty(0,&ccraw);
12521 #endif /* BELLV10 */
12522 #endif /* SVORPOSIX */
12523 #endif /* Plan9 */
12524 
12525     if (x > -1)
12526       constate = CON_BIN;
12527 
12528     debug(F101,"conbin returns","",x);
12529     return(x);
12530 
12531 #ifdef COHERENT
12532 #undef SVORPOSIX
12533 #endif /* COHERENT */
12534 
12535 }
12536 
12537 
12538 /*  C O N R E S  --  Restore the console terminal  */
12539 
12540 int
12541 conres() {
12542     int x;
12543     debug(F101,"conres cgmf","",cgmf);
12544     debug(F101,"conres constate","",constate);
12545 
12546     if (cgmf < 1)			/* Do nothing if modes unchanged */
12547       return(0);
12548     if (constate == CON_RES)
12549       return(0);
12550 
12551     if (!isatty(0)) return(0);          /* only for real ttys */
12552     debug(F100,"conres isatty ok","",0);
12553     ckxech = 0;                         /* System should echo chars */
12554 
12555 #ifdef aegis
12556     conbufn = 0;
12557     if (concrp) return(write(1, "\035\001", 2));
12558     if (conuid == input_pad_$uid) {
12559 	pad_$cooked(ios_$stdin, st);
12560 	constate = CON_RES;
12561 	return(0);
12562     }
12563 #endif /* aegis */
12564 
12565 #ifdef Plan9
12566     p9conres();
12567 #else
12568 #ifdef BSD44ORPOSIX
12569     debug(F100,"conres restoring tcsetattr","",0);
12570     x = tcsetattr(0,TCSADRAIN,&ccold);
12571 #else
12572 #ifdef ATTSV
12573     debug(F100,"conres restoring ioctl","",0);
12574     x = ioctl(0,TCSETAW,&ccold);
12575 #else /* BSD, V7, and friends */
12576 #ifdef sony_news			/* Sony NEWS */
12577     if (km_con != -1)
12578       ioctl(0,TIOCKSET,&km_con);	/* Restore console Kanji mode */
12579 #endif /* sony_news */
12580     msleep(100);
12581     debug(F100,"conres restoring stty","",0);
12582     x = conchk();			/* Because stty() is destructive */
12583     if (x > 0)
12584       congetbuf(x);
12585 #ifdef BELLV10
12586     x = ioctl(0,TIOCSETP,&ccold);
12587 #else
12588     x = stty(0,&ccold);
12589 #endif /* BELLV10 */
12590 #endif /* ATTSV */
12591 #endif /* BSD44ORPOSIX */
12592 #endif /* Plan9 */
12593     if (x > -1)
12594       constate = CON_RES;
12595 
12596     debug(F101,"conres returns","",x);
12597     return(x);
12598 }
12599 
12600 /*  C O N O C  --  Output a character to the console terminal  */
12601 
12602 int
12603 #ifdef CK_ANSIC
12604 conoc(char c)
12605 #else
12606 conoc(c) char c;
12607 #endif /* CK_ANSIC */
12608 /* conoc */ {
12609 
12610 #ifdef IKSD
12611     if (inserver && !local)
12612       return(ttoc(c));
12613 
12614 #ifdef CK_ENCRYPTION
12615     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12616         ck_tn_encrypt(&c,1);
12617 #endif /* CK_ENCRYPTION */
12618 #endif /* IKSD */
12619 
12620 #ifdef Plan9
12621     return conwrite(&c,1);
12622 #else
12623     return(write(1,&c,1));
12624 #endif /* Plan9 */
12625 }
12626 
12627 /*  C O N X O  --  Write x characters to the console terminal  */
12628 
12629 int
12630 conxo(x,s) int x; char *s; {
12631 
12632 #ifdef IKSD
12633     if (inserver && !local)
12634       return(ttol((CHAR *)s,x));
12635 
12636 #ifdef CK_ENCRYPTION
12637     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12638         ck_tn_encrypt(s,x);
12639 #endif /* CK_ENCRYPTION */
12640 #endif /* IKSD */
12641 
12642 #ifdef Plan9
12643     return(conwrite(s,x));
12644 #else
12645     return(write(1,s,x));
12646 #endif /* Plan9 */
12647 }
12648 
12649 /*  C O N O L  --  Write a line to the console terminal  */
12650 
12651 int
12652 conol(s) char *s; {
12653     int len;
12654     if (!s) s = "";			/* Always do this! */
12655     len = strlen(s);
12656     if (len == 0)
12657       return(0);
12658 
12659 #ifdef IKSD
12660     if (inserver && !local)
12661       return(ttol((CHAR *)s,len));
12662 
12663 #ifdef CK_ENCRYPTION
12664     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
12665 	if (nxpacket < len) {
12666 	    if (xpacket) {
12667 		free(xpacket);
12668 		xpacket = NULL;
12669 		nxpacket = 0;
12670 	    }
12671 	    len = len > 10240 ? len : 10240;
12672 	    xpacket = (CHAR *)malloc(len);
12673 	    if (!xpacket) {
12674 		fprintf(stderr,"ttol malloc failure\n");
12675 		return(-1);
12676 	    } else
12677 	      nxpacket = len;
12678 	}
12679 	memcpy(xpacket,s,len);
12680 	s = (char *)xpacket;
12681 	ck_tn_encrypt(s,len);
12682     }
12683 #endif /* CK_ENCRYPTION */
12684 #endif /* IKSD */
12685 
12686 #ifdef Plan9
12687     return(conwrite(s,len));
12688 #else
12689     return(write(1,s,len));
12690 #endif /* Plan9 */
12691 }
12692 
12693 /*  C O N O L A  --  Write an array of lines to the console terminal */
12694 
12695 int
12696 conola(s) char *s[]; {
12697     char * p;
12698     int i, x;
12699 
12700 
12701     if (!s) return(0);
12702     for (i = 0; ; i++) {
12703 	p = s[i];
12704 	if (!p) p = "";			/* Let's not dump core shall we? */
12705 	if (!*p)
12706 	  break;
12707 #ifdef IKSD
12708 	if (inserver && !local)
12709 	  x = ttol((CHAR *)p,(int)strlen(p));
12710 	else
12711 #endif /* IKSD */
12712 	  x = conol(p);
12713 	if (x < 0)
12714 	  return(-1);
12715     }
12716     return(0);
12717 }
12718 
12719 /*  C O N O L L  --  Output a string followed by CRLF  */
12720 
12721 int
12722 conoll(s) char *s; {
12723     CHAR buf[3];
12724     buf[0] = '\r';
12725     buf[1] = '\n';
12726     buf[2] = '\0';
12727     if (!s) s = "";
12728 
12729 #ifdef IKSD
12730     if (inserver && !local) {
12731 	if (*s) ttol((CHAR *)s,(int)strlen(s));
12732 	return(ttol(buf,2));
12733     }
12734 #endif /* IKSD */
12735 
12736     if (*s) conol(s);
12737 #ifdef IKSD
12738 #ifdef CK_ENCRYPTION
12739     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12740       ck_tn_encrypt((char *)buf,2);
12741 #endif /* CK_ENCRYPTION */
12742 #endif /* IKSD */
12743 
12744 #ifdef Plan9
12745     return(conwrite(buf, 2));
12746 #else
12747     return(write(1,buf,2));
12748 #endif /* Plan9 */
12749 }
12750 
12751 /*  C O N C H K  --  Return how many characters available at console  */
12752 /*
12753   We could also use select() here to cover a few more systems that are not
12754   covered by any of the following, e.g. HP-UX 9.0x on the model 800.
12755 */
12756 int
12757 conchk() {
12758     static int contyp = 0;		/* +1 for isatty, -1 otherwise */
12759 
12760     if (contyp == 0)			/* This prevents unnecessary */
12761       contyp = (isatty(0) ? 1 : -1);	/* duplicated calls to isatty() */
12762     debug(F101,"conchk contyp","",contyp);
12763     if (backgrd || (contyp < 0))
12764       return(0);
12765 
12766 #ifdef aegis
12767     if (conbufn > 0) return(conbufn);   /* use old count if nonzero */
12768 
12769     /* read in more characters */
12770     conbufn = ios_$get(ios_$stdin,
12771               ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
12772     if (st.all != status_$ok) conbufn = 0;
12773     conbufp = conbuf;
12774     return(conbufn);
12775 #else
12776 #ifdef IKSD
12777     if (inserver && !local)
12778       return(in_chk(1,ttyfd));
12779     else
12780 #endif /* IKSD */
12781       return(in_chk(0,0));
12782 #endif /* aegis */
12783 }
12784 
12785 /*  C O N I N C  --  Get a character from the console  */
12786 /*
12787   Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
12788   read.  Upon success, returns the character.  Upon failure, returns -1.
12789   A timed read that does not complete within the timeout period returns -2.
12790 */
12791 int
12792 coninc(timo) int timo; {
12793     int n = 0; CHAR ch;
12794     int xx;
12795 
12796     if (conbufn > 0) {			/* If something already buffered */
12797 	--conbufn;
12798 	return((unsigned)(*conbufp++ & 0xff));
12799     }
12800 
12801     errno = 0;				/* Clear this */
12802 #ifdef IKSD
12803     if (inserver && !local) {
12804 	xx = ttinc(timo);
12805 	if (xx < 0)
12806 	  return(ttinctimo ? -2 : -1);
12807 	else
12808 	  return(xx);
12809     }
12810 #endif /* IKSD */
12811 
12812 #ifdef aegis				/* Apollo Aegis only... */
12813     debug(F101,"coninc timo","",timo);
12814     fflush(stdout);
12815     if (conchk() > 0) {
12816 	--conbufn;
12817 	return((unsigned)(*conbufp++ & 0xff));
12818     }
12819 #endif /* aegis */
12820 
12821 #ifdef TTLEBUF
12822     if (
12823 #ifdef IKSD
12824 	inserver &&
12825 #endif /* IKSD */
12826 	!xlocal
12827 	) {
12828 	if (ttpush >= 0) {
12829 	    debug(F111,"ttinc","ttpush",ttpush);
12830 	    ch = ttpush;
12831 	    ttpush = -1;
12832 	    return(ch);
12833 	}
12834 	if (le_data) {
12835 	    if (le_getchar(&ch) > 0) {
12836 		debug(F111,"ttinc LocalEchoInBuf","ch",ch);
12837 		return(ch);
12838 	    }
12839 	}
12840     }
12841 #endif /* TTLEBUF */
12842 
12843     if (timo <= 0) {			/* Untimed, blocking read. */
12844 	while (1) {			/* Keep trying till we get one. */
12845 	    n = read(0, &ch, 1);	/* Read a character. */
12846 	    if (n == 0) continue;	/* Shouldn't happen. */
12847 	    if (n > 0) {		/* If read was successful, */
12848 #ifdef IKSD
12849 #ifdef CK_ENCRYPTION
12850                 debug(F100,"coninc decrypt 1","",0);
12851                 if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12852 		  ck_tn_decrypt((char *)&ch,1);
12853 #endif /* CK_ENCRYPTION */
12854 #endif /* IKSD */
12855 		return((unsigned)(ch & 0xff)); /* return the character. */
12856             }
12857 
12858 /* Come here if read() returned an error. */
12859 
12860 	    debug(F101, "coninc(0) errno","",errno); /* Log the error. */
12861 #ifndef OXOS
12862 #ifdef SVORPOSIX
12863 #ifdef CIE                             /* CIE Regulus has no EINTR symbol? */
12864 #ifndef EINTR
12865 #define EINTR 4
12866 #endif /* EINTR */
12867 #endif /* CIE */
12868 /*
12869   This routine is used for several different purposes.  In CONNECT mode, it is
12870   used to do an untimed, blocking read from the keyboard in the lower CONNECT
12871   fork.  During local-mode file transfer, it reads a character from the
12872   console to interrupt the file transfer (like A for a status report, X to
12873   cancel a file, etc).  Obviously, we don't want the reads in the latter case
12874   to be blocking, or the file transfer would stop until the user typed
12875   something.  Unfortunately, System V does not allow the console device input
12876   buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
12877   used instead.  During local-mode file transfer, the SIGQUIT signal is armed
12878   and trapped by esctrp(), and this routine pretends to have read the quit
12879   character from the keyboard normally.  But, kludge or no kludge, the read()
12880   issued by this command, under System V only, can fail if a signal -- ANY
12881   signal -- is caught while the read is pending.  This can occur not only when
12882   the user types the quit character, but also during telnet negotiations, when
12883   the lower CONNECT fork signals the upper one about an echoing mode change.
12884   When this happens, we have to post the read() again.  This is apparently not
12885   a problem in BSD-based UNIX versions.
12886 */
12887 	    if (errno == EINTR)		/* Read interrupted. */
12888 	      if (conesc)  {		/* If by SIGQUIT, */
12889  		 conesc = 0;		/* the conesc variable is set, */
12890  		 return(escchr);	/* so return the escape character. */
12891 	     } else continue;		/* By other signal, try again. */
12892 #else
12893 /*
12894   This might be dangerous, but let's do this on non-System V versions too,
12895   since at least one SunOS 4.1.2 user complains of immediate disconnections
12896   upon first making a TELNET connection.
12897 */
12898 	    if (errno == EINTR)		/* Read interrupted. */
12899 	      continue;
12900 #endif /* SVORPOSIX */
12901 #else /* OXOS */
12902 	    if (errno == EINTR)		/* Read interrupted. */
12903 	      continue;
12904 #endif /* OXOS */
12905 	    return(-1);			/* Error */
12906 	}
12907     }
12908 #ifdef DEBUG
12909     if (deblog && timo <= 0) {
12910 	debug(F100,"coninc timeout logic error","",0);
12911 	timo = 1;
12912     }
12913 #endif /* DEBUG */
12914 
12915 /* Timed read... */
12916 
12917     saval = signal(SIGALRM,timerh);	/* Set up timeout handler. */
12918     xx = alarm(timo);			/* Set the alarm. */
12919     debug(F101,"coninc alarm set","",timo);
12920     if (
12921 #ifdef CK_POSIX_SIG
12922 	sigsetjmp(sjbuf,1)
12923 #else
12924 	setjmp(sjbuf)
12925 #endif /* CK_POSIX_SIG */
12926 	)				/* The read() timed out. */
12927       n = -2;				/* Code for timeout. */
12928     else
12929       n = read(0, &ch, 1);
12930     ttimoff();				/* Turn off timer */
12931     if (n > 0) {			/* Got character OK. */
12932 #ifdef IKSD
12933 #ifdef CK_ENCRYPTION
12934         debug(F100,"coninc decrypt 2","",0);
12935         if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12936 	  ck_tn_decrypt((char *)&ch,1);
12937 #endif /* CK_ENCRYPTION */
12938 #endif /* IKSD */
12939 	return((unsigned)(ch & 0xff));	/* Return it. */
12940     }
12941 /*
12942   read() returned an error.  Same deal as above, but without the loop.
12943 */
12944     debug(F101, "coninc(timo) n","",n);
12945     debug(F101, "coninc(timo) errno","",errno);
12946 #ifndef OXOS
12947 #ifdef SVORPOSIX
12948     if (n == -1 && errno == EINTR && conesc != 0) {
12949 	conesc = 0;
12950 	return(escchr);			/* User entered escape character. */
12951     }
12952 #endif /* SVORPOSIX */
12953     if (n == 0 && errno > 0) {		/* It's an error */
12954 	return(-1);
12955     }
12956 #endif /* ! OXOS */
12957     return(n);
12958 }
12959 
12960 /*  C O N G K S  --  Console Get Keyboard Scancode  */
12961 
12962 #ifndef congks
12963 /*
12964   This function needs to be filled in with the various system-dependent
12965   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
12966   keyboard scan code.  Unfortunately there aren't any.
12967 */
12968 int
12969 congks(timo) int timo; {
12970 
12971 #ifdef IKSD
12972     if (inserver && !local)
12973       return(ttinc(timo));
12974 #endif /* IKSD */
12975 
12976     return(coninc(timo));
12977 }
12978 #endif /* congks */
12979 
12980 #ifdef ATT7300
12981 
12982 /*  A T T D I A L  --  Dial up the remote system using internal modem
12983  * Purpose: to open and dial a number on the internal modem available on the
12984  * ATT7300 UNIX PC.  Written by Joe Doupnik. Superceeds version written by
12985  * Richard E. Hill, Dickinson, TX. which employed dial(3c).
12986  * Uses information in <sys/phone.h> and our status int attmodem.
12987  */
12988 attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
12989     char *telnum;
12990 
12991     attmodem &= ~ISMODEM;                       /* modem not in use yet */
12992                     /* Ensure O_NDELAY is set, else i/o traffic hangs */
12993                     /* We turn this flag off once the dial is complete */
12994     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
12995 
12996     /* Condition line, check availability & DATA mode, turn on speaker */
12997     if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
12998         printf("cannot access phone\n");
12999         ttclos(0);
13000         return (-2);
13001     }
13002     ioctl(ttyfd,PIOCGETP,&dialer);      /* get phone dialer parameters */
13003 
13004     if (dialer.c_lineparam & VOICE) {	/* phone must be in DATA mode */
13005         printf(" Should not dial with modem in VOICE mode.\n");
13006         printf(" Exit Kermit, switch to DATA and retry call.\n");
13007         ttclos(0);
13008         return (-2);
13009     }
13010 #ifdef ATTTONED				/* Old way, tone dialing only. */
13011     dialer.c_lineparam = DATA | DTMF;	/* Dial with tones, */
13012     dialer.c_lineparam &= ~PULSE;	/* not with pulses. */
13013 #else
13014     /* Leave current pulse/tone state alone. */
13015     /* But what about DATA?  Add it back if you have trouble. */
13016     /* sys/phone says you get DATA automatically by opening device RDWR */
13017 #endif
13018     dialer.c_waitdialtone = 5;                  /* wait 5 sec for dialtone */
13019 #ifdef COMMENT
13020     dialer.c_feedback = SPEAKERON|NORMSPK|RINGON;  /* control speaker */
13021 #else
13022     /* sys/phone says RINGON used only for incoming voice calls */
13023     dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
13024     dialer.c_feedback |= SPEAKERON|NORMSPK;
13025 #endif
13026     dialer.c_waitflash = 500;                   /* 0.5 sec flash hook */
13027     if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) {   /* set phone parameters */
13028         printf("Cannot set modem characteristics\n");
13029         ttclos(0);
13030         return (-2);
13031     }
13032     ioctl(ttyfd,PIOCRECONN,0);		/* Turns on speaker for pulse */
13033 
13034 #ifdef COMMENT
13035     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
13036 line_status:%o feedback:%o\n",
13037     dialer.c_lineparam, dialer.c_waitdialtone,
13038     dialer.c_linestatus, dialer.c_feedback);
13039 #endif
13040 
13041     attmodem |= ISMODEM;                        /* modem is now in-use */
13042     sleep(1);
13043     for (telnum = telnbr; *telnum != '\0'; telnum++)    /* dial number */
13044 #ifdef ATTTONED
13045       /* Tone dialing only */
13046       if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13047 	  perror("Error in dialing");
13048 	  ttclos(0);
13049 	  return(-2);
13050       }
13051 #else /* Allow Pulse or Tone dialing */
13052     switch (*telnum) {
13053       case 't': case 'T': case '%':	/* Tone dialing requested */
13054 	dialer.c_lineparam |= DTMF;
13055 	dialer.c_lineparam &= ~PULSE;
13056 	if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13057 	    printf("Cannot set modem to tone dialing\n");
13058 	    ttclos(0);
13059 	    return(-2);
13060 	}
13061 	break;
13062       case 'd': case 'D': case 'p': case 'P': case '^':
13063 	dialer.c_lineparam |= PULSE;
13064 	dialer.c_lineparam &= ~DTMF;
13065 	if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13066 	    printf("Cannot set modem to pulse dialing\n");
13067 	    ttclos(0);
13068 	    return(-2);
13069 	}
13070 	break;
13071       default:
13072         if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13073 	    perror("Dialing error");
13074 	    ttclos(0);
13075 	    return(-2);
13076 	}
13077 	break;
13078     }
13079 #endif
13080 
13081     ioctl(ttyfd,PIOCDIAL,"@");		/* terminator for data call */
13082     do {				/* wait for modems to Connect */
13083         if (ioctl(ttyfd,PIOCGETP,&dialer) != 0)	{ /* get params */
13084 	    perror("Cannot get modems to connect");
13085 	    ttclos(0);
13086 	    return(-2);
13087 	}
13088     } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
13089     /* Turn off O_NDELAY flag now. */
13090     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
13091     signal(SIGHUP, sighup);             /* hangup on loss of carrier */
13092     return(0);                          /* return success */
13093 }
13094 
13095 /*
13096   Offgetty, ongetty functions. These function get the 'getty(1m)' off
13097   and restore it to the indicated line.  Shell's return codes are:
13098     0: Can't do it.  Probably a user logged on.
13099     1: No need.  No getty on that line.
13100     2: Done, you should restore the getty when you're done.
13101   DOGETY System(3), however, returns them as 0, 256, 512, respectively.
13102   Thanks to Kevin O'Gorman, Anarm Software Systems.
13103 
13104    getoff.sh looks like:   geton.sh looks like:
13105      setgetty $1 0           setgetty $1 1
13106      err=$?                  exit $?
13107      sleep 2
13108      exit $err
13109 */
13110 
13111 /*  O F F G E T T Y  --  Turn off getty(1m) for the communications tty line
13112  * and get status so it can be restarted after the line is hung up.
13113  */
13114 int
13115 offgetty(ttname) char *ttname; {
13116     char temp[30];
13117     while (*ttname != '\0') ttname++;       /* seek terminator of path */
13118     ttname -= 3;                            /* get last 3 chars of name */
13119     sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
13120     return(zsyscmd(temp));
13121 }
13122 
13123 /*  O N G E T T Y  --  Turn on getty(1m) for the communications tty line */
13124 
13125 int
13126 ongetty(ttname) char *ttname; {
13127     char temp[30];
13128     while (*ttname != '\0') ttname++;       /* comms tty path name */
13129     ttname -= 3;
13130     sprintf(temp,"/usr/bin/geton.sh %s",ttname);
13131     return(zsyscmd(temp));
13132 }
13133 #endif /* ATT7300 */
13134 
13135 /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
13136  *
13137  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
13138  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
13139  *  2 = Auto: For "modem direct": The same as "Off".
13140  *            For real modem types: Heed carrier during connect, but ignore
13141  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
13142  *
13143  * As you can see, this setting does not affect dialing, which always ignores
13144  * carrier (unless there is some special exception for some modem type).  It
13145  * does affect ttopen() if it is set before ttopen() is used.  This setting
13146  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
13147  * (or should be) always called before any communications is tried, which
13148  * means that, practically speaking, the effect is immediate.
13149  *
13150  * Of course, nothing of this applies to remote mode (xlocal = 0).
13151  *
13152  * Someone has yet to uncover how to manipulate the carrier in the BSD
13153  * environment (or any non-termio using environment).  Until that time, this
13154  * will simply be a no-op for BSD.
13155  *
13156  * Note that in previous versions, the carrier was most often left unchanged
13157  * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX.  This
13158  * has changed.  Now it is controlled by ttcarr in conjunction with these
13159  * modes.
13160  */
13161 int
13162 ttscarr(carrier) int carrier; {
13163     ttcarr = carrier;
13164     debug(F101, "ttscarr","",ttcarr);
13165     return(ttcarr);
13166 }
13167 
13168 /* C A R R C T L  --  Set tty modes for carrier treatment.
13169  *
13170  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
13171  * (actually, there are no bits in sgttyb for that), or performs any other
13172  * operations needed to control this on the current system.  The function does
13173  * not do the actual TCSETA or stty, since often we want to set other bits too
13174  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
13175  *
13176  * We don't know how to do anything like carrier control on non-ATTSV systems,
13177  * except, apparently, ultrix.  See above.  It is also known that this doesn't
13178  * have much effect on a Xenix system.  For Xenix, one should switch back and
13179  * forth between the upper and lower case device files.  Maybe later.
13180  * Presently, Xenix will stick to the mode it was opened with.
13181  *
13182  * carrier: 0 = ignore carrier, 1 = require carrier.
13183  * The current state is saved in curcarr, and checked to save labour.
13184  */
13185 #ifdef SVORPOSIX
13186 int
13187 #ifdef BSD44ORPOSIX
13188 carrctl(ttpar, carrier)	struct termios *ttpar; int carrier;
13189 #else /* ATTSV */
13190 carrctl(ttpar, carrier)	struct termio *ttpar; int carrier;
13191 #endif /* BSD44ORPOSIX */
13192 /* carrctl */ {
13193     debug(F101, "carrctl","",carrier);
13194     if (carrier)
13195       ttpar->c_cflag &= ~CLOCAL;
13196     else
13197       ttpar->c_cflag |= CLOCAL;
13198     return(0);
13199 }
13200 #else /* Berkeley, V7, et al... */
13201 int
13202 carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
13203     debug(F101, "carrctl","",carrier);
13204     if (carrier == curcarr)
13205       return(0);
13206     curcarr = carrier;
13207 #ifdef ultrix
13208 #ifdef COMMENT
13209 /*
13210   Old code from somebody at DEC that tends to get stuck, time out, etc.
13211 */
13212     if (carrier) {
13213 	ioctl(ttyfd, TIOCMODEM, &temp);
13214 	ioctl(ttyfd, TIOCHPCL, 0);
13215     } else {
13216 	/* (According to the manuals, TIOCNCAR should be preferred */
13217 	/* over TIOCNMODEM...) */
13218 	ioctl(ttyfd, TIOCNMODEM, &temp);
13219     }
13220 #else
13221 /*
13222   New code from Jamie Watson that, he says, eliminates the problems.
13223 */
13224     if (carrier) {
13225 	ioctl(ttyfd, TIOCCAR);
13226 	ioctl(ttyfd, TIOCHPCL);
13227     } else {
13228 	ioctl(ttyfd, TIOCNCAR);
13229     }
13230 #endif /* COMMENT */
13231 #endif /* ultrix */
13232     return(0);
13233 }
13234 #endif /* SVORPOSIX */
13235 
13236 
13237 /*  T T G M D M  --  Get modem signals  */
13238 /*
13239  Looks for RS-232 modem signals, and returns those that are on in as its
13240  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
13241  Returns:
13242  -3 Not implemented
13243  -2 if the communication device does not have modem control (e.g. telnet)
13244  -1 on error.
13245  >= 0 on success, with a bit mask containing the modem signals that are on.
13246 */
13247 
13248 /*
13249   Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
13250   modem control, namely the TIOCMGET ioctl.
13251 */
13252 
13253 #ifdef BSD43
13254 #define K_MDMCTL
13255 #endif /* BSD43 */
13256 
13257 #ifdef SUNOS4
13258 #define K_MDMCTL
13259 #endif /* SUNOS4 */
13260 
13261 /*
13262   SCO OpenServer R5.0.4.  The TIOCMGET definition is hardwired in because it
13263   is skipped in termio.h when _POSIX_SOURCE is defined.  But _POSIX_SOURCE
13264   must be defined in order to get the high serial speeds that are new to
13265   5.0.4.  However, the regular SCO drivers do not implement TIOCMGET, so the
13266   ioctl() returns -1 with errno 22 (invalid function).  But third-party
13267   drivers, e.g. for Digiboard, do implement it, and so it should work on ports
13268   driven by those drivers.
13269 */
13270 #ifdef SCO_OSR504
13271 #ifndef TIOCMGET
13272 #define TIOCMGET (('t'<<8)|29)
13273 #endif /* TIOCMGET */
13274 #endif /* SCO_OSR504 */
13275 
13276 #ifdef CK_SCOV5
13277 /* Because POSIX strictness in <sys/termio.h> won't let us see these. */
13278 #ifndef TIOCM_DTR
13279 #define TIOCM_DTR	0x0002		/* data terminal ready */
13280 #define TIOCM_RTS	0x0004		/* request to send */
13281 #define TIOCM_CTS	0x0020		/* clear to send */
13282 #define TIOCM_CAR	0x0040		/* carrier detect */
13283 #define TIOCM_RNG	0x0080		/* ring */
13284 #define TIOCM_DSR	0x0100		/* data set ready */
13285 #define TIOCM_CD	TIOCM_CAR
13286 #define TIOCM_RI	TIOCM_RNG
13287 #endif /* TIOCM_DTR */
13288 #endif /* CK_SCOV5 */
13289 
13290 #ifdef QNX
13291 #define K_MDMCTL
13292 #else
13293 #ifdef TIOCMGET
13294 #define K_MDMCTL
13295 #endif /* TIOCMGET */
13296 #endif /* QNX */
13297 /*
13298   "A serial communication program that can't read modem signals
13299    is like a car without windows."
13300 */
13301 int
13302 ttgmdm() {
13303 
13304 #ifdef QNX
13305 #include <sys/qioctl.h>
13306 
13307     unsigned long y, mdmbits[2];
13308     int x, z = 0;
13309 
13310     if (xlocal && ttyfd < 0)
13311       return(-1);
13312 
13313 #ifdef NETCONN
13314     if (netconn) {			/* Network connection */
13315 #ifdef TN_COMPORT
13316         if (istncomport()) {
13317 	    gotsigs = 1;
13318 	    return(tngmdm());
13319 	} else
13320 #endif /* TN_COMPORT */
13321 	  return(-2);			/* No modem signals */
13322     }
13323 #endif /* NETCONN */
13324 
13325 #ifdef NETCMD
13326     if (ttpipe) return(-2);
13327 #endif /* NETCMD */
13328 #ifdef NETPTY
13329     if (ttpty) return(-2);
13330 #endif /* NETPTY */
13331 
13332     mdmbits[0] = 0L;
13333     mdmbits[1] = 0L;
13334 /*
13335  * From <sys/qioctl.h>:
13336  *
13337  * SERIAL devices   (all Dev.ser versions)
13338  * 0 : DTR           8 = Data Bits 0  16 - reserved     24 - reserved
13339  * 1 : RTS           9 = Data Bits 1  17 - reserved     25 - reserved
13340  * 2 = Out 1        10 = Stop Bits    18 - reserved     26 - reserved
13341  * 3 = Int Enable   11 = Par Enable   19 - reserved     27 - reserved
13342  * 4 = Loop         12 = Par Even     20 = CTS          28 - reserved
13343  * 5 - reserved     13 = Par Stick    21 = DSR          29 - reserved
13344  * 6 - reserved     14 : Break        22 = RI           30 - reserved
13345  * 7 - reserved     15 = 0            23 = CD           31 - reserved
13346  */
13347     errno = 0;
13348     x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
13349     debug(F101,"ttgmdm qnx_ioctl","",x);
13350     debug(F101,"ttgmdm qnx_ioctl errno","",errno);
13351     if (!x) {
13352 	debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
13353 	debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
13354 	y = mdmbits[0];
13355 	if (y & 0x000001L) z |= BM_DTR;	/* Bit  0 */
13356 	if (y & 0x000002L) z |= BM_RTS;	/* Bit  1 */
13357 	if (y & 0x100000L) z |= BM_CTS;	/* Bit 20 */
13358 	if (y & 0x200000L) z |= BM_DSR;	/* Bit 21 */
13359 	if (y & 0x400000L) z |= BM_RNG;	/* Bit 22 */
13360 	if (y & 0x800000L) z |= BM_DCD;	/* Bit 23 */
13361 	debug(F101,"ttgmdm qnx result","",z);
13362 	debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
13363 	gotsigs = 1;
13364 	return(z);
13365     } else return(-1);
13366 #else /* QNX */
13367 #ifdef HPUX				/* HPUX has its own way */
13368     int x, z;
13369 
13370 #ifdef HPUX10				/* Modem flag word */
13371     mflag y;				/* mflag typedef'd in <sys/modem.h> */
13372 #else
13373 #ifdef HPUX9
13374     mflag y;
13375 #else
13376 #ifdef HPUX8
13377     mflag y;
13378 #else
13379     unsigned long y;			/* Not sure about pre-8.0... */
13380 #endif /* HPUX8 */
13381 #endif /* HPUX9 */
13382 #endif /* HPUX10 */
13383 
13384     if (xlocal && ttyfd < 0)
13385       return(-1);
13386 
13387 #ifdef NETCONN
13388     if (netconn) {			/* Network connection */
13389 #ifdef TN_COMPORT
13390         if (istncomport()) {
13391 	    gotsigs = 1;
13392 	    return(tngmdm());
13393 	} else
13394 #endif /* TN_COMPORT */
13395 	  return(-2);			/* No modem signals */
13396     }
13397 #endif /* NETCONN */
13398 
13399 #ifdef NETCMD
13400     if (ttpipe) return(-2);
13401 #endif /* NETCMD */
13402 #ifdef NETPTY
13403     if (ttpty) return(-2);
13404 #endif /* NETPTY */
13405 
13406     if (xlocal)				/* Get modem signals */
13407       x = ioctl(ttyfd,MCGETA,&y);
13408     else
13409       x = ioctl(0,MCGETA,&y);
13410     if (x < 0) return(-1);
13411     debug(F101,"ttgmdm","",y);
13412 
13413     z = 0;				/* Initialize return value */
13414 
13415 /* Now set bits for each modem signal that is reported to be on. */
13416 
13417 #ifdef MCTS
13418     /* Clear To Send */
13419     debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
13420     if (y & MCTS) z |= BM_CTS;
13421 #endif
13422 #ifdef MDSR
13423     /* Data Set Ready */
13424     debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
13425     if (y & MDSR) z |= BM_DSR;
13426 #endif
13427 #ifdef MDCD
13428     /* Carrier */
13429     debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
13430     if (y & MDCD) z |= BM_DCD;
13431 #endif
13432 #ifdef MRI
13433     /* Ring Indicate */
13434     debug(F101,"ttgmdm HPUX RI","",y & MRI);
13435     if (y & MRI) z |= BM_RNG;
13436 #endif
13437 #ifdef MDTR
13438     /* Data Terminal Ready */
13439     debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
13440     if (y & MDTR) z |= BM_DTR;
13441 #endif
13442 #ifdef MRTS
13443     /* Request To Send */
13444     debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
13445     if (y & MRTS) z |= BM_RTS;
13446 #endif
13447     gotsigs = 1;
13448     return(z);
13449 
13450 #else /* ! HPUX */
13451 
13452 #ifdef K_MDMCTL
13453 /*
13454   Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
13455   If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
13456   are needed.
13457 */
13458 #ifndef TIOCMGET
13459 #include <sys/ttycom.h>
13460 #endif /* TIOCMGET */
13461 
13462     int x, y, z;
13463 
13464     debug(F100,"ttgmdm K_MDMCTL defined","",0);
13465 
13466 #ifdef NETCONN
13467     if (netconn) {			/* Network connection */
13468 #ifdef TN_COMPORT
13469         if (istncomport()) {
13470 	    gotsigs = 1;
13471 	    return(tngmdm());
13472 	} else
13473 #endif /* TN_COMPORT */
13474 	  return(-2);			/* No modem signals */
13475     }
13476 #endif /* NETCONN */
13477 
13478 #ifdef NETCMD
13479     if (ttpipe) return(-2);
13480 #endif /* NETCMD */
13481 #ifdef NETPTY
13482     if (ttpty) return(-2);
13483 #endif /* NETPTY */
13484 
13485     if (xlocal && ttyfd < 0)
13486       return(-1);
13487 
13488     if (xlocal)
13489       x = ioctl(ttyfd,TIOCMGET,&y);	/* Get modem signals. */
13490     else
13491       x = ioctl(0,TIOCMGET,&y);
13492     debug(F101,"ttgmdm TIOCMGET ioctl","",x);
13493     if (x < 0) {
13494 	debug(F101,"ttgmdm errno","",errno);
13495 	return(-1);
13496     }
13497     debug(F101,"ttgmdm bits","",y);
13498 
13499     z = 0;				/* Initialize return value. */
13500 #ifdef TIOCM_CTS
13501     /* Clear To Send */
13502     if (y & TIOCM_CTS) z |= BM_CTS;
13503     debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS);
13504 #else
13505     debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
13506 #endif
13507 #ifdef TIOCM_DSR
13508     /* Data Set Ready */
13509     if (y & TIOCM_DSR) z |= BM_DSR;
13510     debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR);
13511 #else
13512     debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
13513 #endif
13514 #ifdef TIOCM_CAR
13515     /* Carrier */
13516     if (y & TIOCM_CAR) z |= BM_DCD;
13517     debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR);
13518 #else
13519     debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
13520 #endif
13521 #ifdef TIOCM_RNG
13522     /* Ring Indicate */
13523     if (y & TIOCM_RNG) z |= BM_RNG;
13524     debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG);
13525 #else
13526     debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
13527 #endif
13528 #ifdef TIOCM_DTR
13529     /* Data Terminal Ready */
13530     if (y & TIOCM_DTR) z |= BM_DTR;
13531     debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR);
13532 #else
13533     debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
13534 #endif
13535 #ifdef TIOCM_RTS
13536     /* Request To Send */
13537     if (y & TIOCM_RTS) z |= BM_RTS;
13538     debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS);
13539 #else
13540     debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
13541 #endif
13542     gotsigs = 1;
13543     return(z);
13544 
13545 #else /* !K_MDMCTL catch-All */
13546 
13547     debug(F100,"ttgmdm K_MDMCTL not defined","",0);
13548 #ifdef TIOCMGET
13549     debug(F100,"ttgmdm TIOCMGET defined","",0);
13550 #else
13551     debug(F100,"ttgmdm TIOCMGET not defined","",0);
13552 #endif /* TIOCMGET */
13553 #ifdef _SVID3
13554     debug(F100,"ttgmdm _SVID3 defined","",0);
13555 #else
13556     debug(F100,"ttgmdm _SVID3 not defined","",0);
13557 #endif /* _SVID3 */
13558 
13559 #ifdef NETCONN
13560     if (netconn) {			/* Network connection */
13561 #ifdef TN_COMPORT
13562         if (istncomport()) {
13563 	    gotsigs = 1;
13564 	    return(tngmdm());
13565 	} else
13566 #endif /* TN_COMPORT */
13567 	  return(-2);			/* No modem signals */
13568     }
13569 #endif /* NETCONN */
13570 
13571 #ifdef NETCMD
13572     if (ttpipe) return(-2);
13573 #endif /* NETCMD */
13574 #ifdef NETPTY
13575     if (ttpty) return(-2);
13576 #endif /* NETPTY */
13577 
13578     return(-3);				/* Sorry, I don't know how... */
13579 
13580 #endif /* K_MDMCTL */
13581 #endif /* HPUX */
13582 #endif /* QNX */
13583 }
13584 
13585 /*  P S U S P E N D  --  Put this process in the background.  */
13586 
13587 /*
13588   Call with flag nonzero if suspending is allowed, zero if not allowed.
13589   Returns 0 on apparent success, -1 on failure (flag was zero, or
13590   kill() returned an error code.
13591 */
13592 int
13593 psuspend(flag) int flag; {
13594 
13595 #ifdef RTU
13596     extern int rtu_bug;
13597 #endif /* RTU */
13598 
13599     if (flag == 0) return(-1);
13600 
13601 #ifdef NOJC
13602     return(-1);
13603 #else
13604 #ifdef SIGTSTP
13605 /*
13606   The big question here is whether job control is *really* supported.
13607   There's no way Kermit can know for sure.  The fact that SIGTSTP is
13608   defined does not guarantee the Unix kernel supports it, and the fact
13609   that the Unix kernel supports it doesn't guarantee that the user's
13610   shell (or other process that invoked Kermit) supports it.
13611 */
13612 #ifdef RTU
13613     rtu_bug = 1;
13614 #endif /* RTU */
13615     if (kill(0,SIGSTOP) < 0
13616 #ifdef MIPS
13617 /* Let's try this for MIPS too. */
13618 	&& kill(getpid(),SIGSTOP) < 0
13619 #endif /* MIPS */
13620 	) {				/* If job control, suspend the job */
13621 	perror("suspend");
13622 	debug(F101,"psuspend error","",errno);
13623 	return(-1);
13624     }
13625     debug(F100,"psuspend ok","",0);
13626     return(0);
13627 #else
13628     return(-1);
13629 #endif /* SIGTSTP */
13630 #endif /* NOJC */
13631 }
13632 
13633 /*
13634   setuid package, by Kristoffer Eriksson, with contributions from Dean
13635   Long and fdc.
13636 */
13637 
13638 /* The following is for SCO when CK_ANSILIBS is defined... */
13639 #ifdef M_UNIX
13640 #ifdef CK_ANSILIBS
13641 #ifndef NOGETID_PROTOS
13642 #define NOGETID_PROTOS
13643 #endif /* NOGETID_PROTOS */
13644 #endif /* CK_ANSILIBS */
13645 #endif /* M_UNIX */
13646 
13647 #ifndef _POSIX_SOURCE
13648 #ifndef SUNOS4
13649 #ifndef NEXT
13650 #ifndef PS2AIX10
13651 #ifndef sequent
13652 #ifndef HPUX9
13653 #ifndef HPUX10
13654 #ifndef COHERENT
13655 #ifndef NOGETID_PROTOS
13656 _PROTOTYP( UID_T getuid, (void) );
13657 _PROTOTYP( UID_T geteuid, (void) );
13658 _PROTOTYP( UID_T getreuid, (void) );
13659 _PROTOTYP( UID_T getgid, (void) );
13660 _PROTOTYP( UID_T getegid, (void) );
13661 _PROTOTYP( UID_T getregid, (void) );
13662 #endif /* NOGETID_PROTOS */
13663 #else
13664 _PROTOTYP( UID_T getreuid, (void) );
13665 _PROTOTYP( UID_T getregid, (void) );
13666 #endif /* COHERENT */
13667 #endif /* HPUX10 */
13668 #endif /* HPUX9 */
13669 #endif /* sequent */
13670 #endif /* PS2AIX10 */
13671 #endif /* NEXT */
13672 #endif /* SUNOS4 */
13673 #endif /* _POSIX_SOURCE */
13674 
13675 /*
13676 Subject: Set-user-id
13677 To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
13678 Date: Sat, 21 Apr 90 4:48:25 MES
13679 From: Kristoffer Eriksson <ske@pkmab.se>
13680 
13681 This is a set of functions to be used in programs that may be run set-user-id
13682 and/or set-group-id. They handle both the case where the program is not run
13683 with such privileges (nothing special happens then), and the case where one
13684 or both of these set-id modes are used.  The program is made to run with the
13685 user's real user and group ids most of the time, except for when more
13686 privileges are needed.  Don't set-user-id to "root".
13687 
13688 This works on System V and POSIX.  In BSD, it depends on the
13689 "saved-set-user-id" feature.
13690 */
13691 
13692 #define UID_ROOT 0			/* Root user and group ids */
13693 #define GID_ROOT 0
13694 
13695 /*
13696   The following code defines the symbol SETEUID for UNIX systems based
13697   on BSD4.4 (either -Encumbered or -Lite).  This program will then use
13698   seteuid() and setegid() instead of setuid() and setgid(), which still
13699   don't allow arbitrary switching.  It also avoids setreuid() and
13700   setregid(), which are included in BSD4.4 for compatibility only, are
13701   insecure, and print warnings to stderr under at least one system (NetBSD
13702   1.0).  Note that POSIX systems should still use setuid() and setgid();
13703   the seteuid() and setegid() functions are BSD4.4 extensions to the
13704   POSIX model.  Mike Long <mike.long@analog.com>, 8/94.
13705 */
13706 #ifdef BSD44
13707 #define SETEUID
13708 #endif /* BSD44 */
13709 
13710 /*
13711   The following construction automatically defines the symbol SETREUID for
13712   UNIX versions based on Berkeley Unix 4.2 and 4.3.  If this symbol is
13713   defined, then this program will use getreuid() and getregid() calls in
13714   preference to getuid() and getgid(), which in Berkeley-based Unixes do
13715   not allow arbitrary switching back and forth of real & effective uid.
13716   This construction also allows -DSETREUID to be put on the cc command line
13717   for any system that has and wants to use setre[ug]id().  It also prevents
13718   automatic definition of SETREUID if -DNOSETREU is included on the cc
13719   command line (or otherwise defined).
13720 */
13721 #ifdef FT18				/* None of this for Fortune. */
13722 #define NOSETREU
13723 #endif /* FT18 */
13724 
13725 #ifdef ANYBSD
13726 #ifndef BSD29
13727 #ifndef BSD41
13728 #ifndef SETREUID
13729 #ifndef NOSETREU
13730 #ifndef SETEUID
13731 #define SETREUID
13732 #endif /* SETEUID */
13733 #endif /* NOSETREU */
13734 #endif /* SETREUID */
13735 #endif /* !BSD41 */
13736 #endif /* !BSD29 */
13737 #endif /* ANYBSD */
13738 
13739 /* Variables for user and group IDs. */
13740 
13741 static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
13742 static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
13743 
13744 
13745 /* P R I V _ I N I  --  Initialize privileges package  */
13746 
13747 /* Called as early as possible in a set-uid or set-gid program to store the
13748  * set-to uid and/or gid and step down to the users real uid and gid. The
13749  * stored id's can be temporarily restored (allowed in System V) during
13750  * operations that require the privilege.  Most of the time, the program
13751  * should execute in unpriviliged state, to not impose any security threat.
13752  *
13753  * Note: Don't forget that access() always uses the real id:s to determine
13754  * file access, even with privileges restored.
13755  *
13756  * Returns an error mask, with error values or:ed together:
13757  *   1 if setuid() fails,
13758  *   2 if setgid() fails, and
13759  *   4 if the program is set-user-id to "root", which can't be handled.
13760  *
13761  * Only the return value 0 indicates real success. In case of failure,
13762  * those privileges that could be reduced have been, at least, but the
13763  * program should be aborted none-the-less.
13764  *
13765  * Also note that these functions do not expect the uid or gid to change
13766  * without their knowing. It may work if it is only done temporarily, but
13767  * you're on your own.
13768  */
13769 int
13770 priv_ini() {
13771     int err = 0;
13772 
13773 #ifndef HAVE_LOCKDEV
13774 
13775     /* Save real ID:s. */
13776     realuid = getuid();
13777     realgid = getgid();
13778 
13779     /* Save current effective ID:s, those set to at program exec. */
13780     privuid = geteuid();
13781     privgid = getegid();
13782 
13783     /* If running set-uid, go down to real uid, otherwise remember that
13784      * no privileged uid is available.
13785      *
13786      * Exceptions:
13787      *
13788      * 1) If the real uid is already "root" and the set-uid uid (the
13789      * initial effective uid) is not "root", then we would have trouble
13790      * if we went "down" to "root" here, and then temporarily back to the
13791      * set-uid uid (not "root") and then again tried to become "root". I
13792      * think the "saved set-uid" is lost when changing uid from effective
13793      * uid "root", which changes all uid, not only the effective uid. But
13794      * in this situation, we can simply go to "root" and stay there all
13795      * the time. That should give sufficient privilege (understatement!),
13796      * and give the right uids for subprocesses.
13797      *
13798      * 2) If the set-uid (the initial effective uid) is "root", and we
13799      * change uid to the real uid, we can't change it back to "root" when
13800      * we need the privilege, for the same reason as in 1). Thus, we can't
13801      * handle programs that are set-user-id to "root" at all. The program
13802      * should be stopped.  Use some other uid.  "root" is probably too
13803      * privileged for such things, anyway. (The uid is reverted to the
13804      * real uid until termination.)
13805      *
13806      * These two exceptions have the effect that the "root" uid will never
13807      * be one of the two uids that are being switched between, which also
13808      * means we don't have to check for such cases in the switching
13809      * functions.
13810      *
13811      * Note that exception 1) is handled by these routines (by constantly
13812      * running with uid "root", while exception 2) is a serious error, and
13813      * is not provided for at all in the switching functions.
13814      */
13815     if (realuid == privuid)
13816 	privuid = (UID_T) -1;		/* Not running set-user-id. */
13817 
13818     /* If running set-gid, go down to real gid, otherwise remember that
13819      * no privileged gid is available.
13820      *
13821      * There are no exception like there is for the user id, since there
13822      * is no group id that is privileged in the manner of uid "root".
13823      * There could be equivalent problems for group changing if the
13824      * program sometimes ran with uid "root" and sometimes not, but
13825      * that is already avoided as explained above.
13826      *
13827      * Thus we can expect always to be able to switch to the "saved set-
13828      * gid" when we want, and back to the real gid again. You may also
13829      * draw the conclusion that set-gid provides for fewer hassles than
13830      * set-uid.
13831      */
13832 
13833 #ifdef SUIDDEBUG
13834     fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
13835     fprintf(stderr,"realuid=%d\n",realuid);
13836     fprintf(stderr,"privuid=%d\n",privuid);
13837 #endif /* SUIDDEBUG */
13838 
13839     if (realgid == privgid)		/* If not running set-user-id, */
13840       privgid = (GID_T) -1;		/*  remember it this way. */
13841 
13842     err = priv_off();			/* Turn off setuid privilege. */
13843 
13844     if (privuid == UID_ROOT)		/* If setuid to root, */
13845       err |= 4;				/* return this error. */
13846 
13847     if (realuid == UID_ROOT) {		/* If real id is root, */
13848 	privuid = (UID_T) -1;		/* stay root at all times. */
13849 #ifdef ATT7300
13850 	/* If Kermit installed SUID uucp and user is running as root */
13851 	err &= ~1;			/* System V R0 does not save UID */
13852 #endif /* ATT7300 */
13853     }
13854 #endif /* HAVE_LOCKDEV */
13855     return(err);
13856 }
13857 
13858 
13859 /* Macros for hiding the differences in UID/GID setting between various Unix
13860  * systems. These macros should always be called with both the privileged ID
13861  * and the non-privileged ID. The one in the second argument, will become the
13862  * effective ID. The one in the first argument will be retained for later
13863  * retrieval.
13864  */
13865 #ifdef SETREUID
13866 #ifdef SAVEDUID
13867 /* On BSD systems with the saved-UID feature, we just juggle the effective
13868  * UID back and forth, and leave the real UID at its true value.  The kernel
13869  * allows switching to both the current real UID, the effective UID, and the
13870  * UID which the program is set-UID to.  The saved set-UID always holds the
13871  * privileged UID for us, and the real UID will always be the non-privileged,
13872  * and we can freely choose one of them for the effective UID at any time.
13873  */
13874 #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
13875 #define switchgid(hidden,active) setregid( (GID_T) -1, active)
13876 
13877 #else   /* SETREUID,!SAVEDUID */
13878 
13879 /* On systems with setreXid() but without the saved-UID feature, notably
13880  * BSD 4.2, we swap the real and effective UIDs each time.  It's
13881  * the effective UID that we are interested in, but we have to retain the
13882  * unused UID somewhere to enable us to restore it later, and we do this
13883  * in the real UID.  The kernel only allows switching to either the current
13884  * real or the effective UID, unless you're "root".
13885  */
13886 #define switchuid(hidden,active)	setreuid(hidden,active)
13887 #define switchgid(hidden,active)	setregid(hidden,active)
13888 #endif
13889 
13890 #else /* !SETREUID, !SAVEDUID */
13891 
13892 #ifdef SETEUID
13893 /*
13894   BSD 4.4 works similarly to System V and POSIX (see below), but uses
13895   seteXid() instead of setXid() to change effective IDs.  In addition, the
13896   seteXid() functions work the same for "root" as for other users.
13897 */
13898 #define switchuid(hidden,active)	seteuid(active)
13899 #define switchgid(hidden,active)	setegid(active)
13900 
13901 #else /* !SETEUID */
13902 
13903 /* On System V and POSIX, the only thing we can change is the effective UID
13904  * (unless the current effective UID is "root", but initsuid() avoids that for
13905  * us).  The kernel allows switching to the current real UID or to the saved
13906  * set-UID.  These are always set to the non-privileged UID and the privileged
13907  * UID, respectively, and we only change the effective UID.  This breaks if
13908  * the current effective UID is "root", though, because for "root" setuid/gid
13909  * becomes more powerful, which is why initsuid() treats "root" specially.
13910  * Note: That special treatment maybe could be ignored for BSD?  Note: For
13911  * systems that don't fit any of these four cases, we simply can't support
13912  * set-UID.
13913  */
13914 
13915 #define switchuid(hidden,active)	setuid(active)
13916 #define switchgid(hidden,active)	setgid(active)
13917 
13918 #endif /* SETEUID */
13919 #endif /* SETREUID */
13920 
13921 /* P R I V _ O N  --  Turn on the setuid and/or setgid */
13922 
13923 /* Go to the privileged uid (gid) that the program is set-user-id
13924  * (set-group-id) to, unless the program is running unprivileged.
13925  * If setuid() fails, return value will be 1. If getuid() fails it
13926  * will be 2.  Return immediately after first failure, and the function
13927  * tries to restore any partial work done.  Returns 0 on success.
13928  * Group id is changed first, since it is less serious than user id.
13929  */
13930 int
13931 priv_on() {
13932 #ifndef HAVE_LOCKDEV
13933     if (privgid != (GID_T) -1)
13934       if (switchgid(realgid,privgid))
13935         return(2);
13936 
13937     if (privuid != (UID_T) -1)
13938       if (switchuid(realuid,privuid)) {
13939 	  if (privgid != (GID_T) -1)
13940 	    if (switchgid(privgid,realgid))
13941               return(2);
13942 	  return(1);
13943       }
13944 #endif /* HAVE_LOCKDEV */
13945     return(0);
13946 }
13947 
13948 /* P R I V _ O F F  --  Turn on the real uid and gid */
13949 
13950 /* Return to the unprivileged uid (gid) after an temporary visit to
13951  * privileged status, unless the program is running without set-user-id
13952  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
13953  * in setgid() or:ed together. The functions tries to return both uid
13954  * and gid to unprivileged state, regardless of errors. Returns 0 on
13955  * success.
13956  */
13957 int
13958 priv_off() {
13959     int err = 0;
13960 #ifndef HAVE_LOCKDEV
13961     if (privuid != (UID_T) -1)
13962        if (switchuid(privuid,realuid))
13963 	  err |= 1;
13964 
13965     if (privgid != (GID_T) -1)
13966        if (switchgid(privgid,realgid))
13967 	err |= 2;
13968 #endif /* HAVE_LOCKDEV */
13969     return(err);
13970 }
13971 
13972 /* Turn off privilege permanently.  No going back.  This is necessary before
13973  * a fork() on BSD43 machines that don't save the setUID or setGID, because
13974  * we swap the real and effective ids, and we don't want to let the forked
13975  * process swap them again and get the privilege back. It will work on other
13976  * machines too, such that you can rely on its effect always being the same,
13977  * for instance, even when you're in priv_on() state when this is called.
13978  * (Well, that part about "permanent" is on System V only true if you follow
13979  * this with a call to exec(), but that's what we want it for anyway.)
13980  * Added by Dean Long -- dlong@midgard.ucsc.edu
13981  */
13982 int
13983 priv_can() {
13984 #ifndef HAVE_LOCKDEV
13985 #ifdef SETREUID
13986     int err = 0;
13987     if (privuid != (UID_T) -1)
13988        if (setreuid(realuid,realuid))
13989 	  err |= 1;
13990 
13991     if (privgid != (GID_T) -1)
13992         if (setregid(realgid,realgid))
13993  	  err |= 2;
13994 
13995     return(err);
13996 
13997 #else
13998 #ifdef SETEUID
13999     int err = 0;
14000     if (privuid != (UID_T) -1)
14001 	if (setuid(realuid)) {
14002 	    debug(F101,"setuid failed","",errno);
14003 	    err |= 1;
14004 	    debug(F101,"ruid","",getuid());
14005 	    debug(F101,"euid","",geteuid());
14006 	}
14007     debug(F101,"setuid","",realuid);
14008     if (privgid != (GID_T) -1)
14009         if (setgid(realgid)) {
14010 	    debug(F101,"setgid failed","",errno);
14011 	    err |= 2;
14012 	    debug(F101,"rgid","",getgid());
14013 	    debug(F101,"egid","",getegid());
14014 	}
14015     debug(F101,"setgid","",realgid);
14016     return(err);
14017 #else
14018     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
14019     return(priv_off());
14020 #endif /* SETEUID */
14021 #endif /* SETREUID */
14022 #else
14023     return(0);
14024 #endif /* HAVE_LOCKDEV */
14025 }
14026 
14027 /* P R I V _ O P N  --  For opening protected files or devices. */
14028 
14029 int
14030 priv_opn(name, modes) char *name; int modes; {
14031     int x;
14032     priv_on();				/* Turn privileges on */
14033     debug(F111,"priv_opn",name,modes);
14034     errno = 0;
14035     x = open(name, modes);		/* Try to open the device */
14036     debug(F101,"priv_opn result","",x);
14037     debug(F101,"priv_opn errno","",errno);
14038     priv_off();				/* Turn privileges off */
14039     return(x);				/* Return open's return code */
14040 }
14041 
14042 /*  P R I V _ C H K  --  Check privileges.  */
14043 
14044 /*  Try to turn them off.  If turning them off did not succeed, cancel them */
14045 
14046 int
14047 priv_chk() {
14048     int x, y = 0;
14049     x = priv_off();			/* Turn off privs. */
14050     if (x != 0 || getuid() == privuid || geteuid() == privuid)
14051       y = priv_can();
14052     if (x != 0 || getgid() == privgid || getegid() == privgid)
14053       y = y | priv_can();
14054     return(y);
14055 }
14056 
14057 UID_T
14058 real_uid() {
14059     return(realuid);
14060 }
14061 
14062 VOID
14063 ttimoff() {				/* Turn off any timer interrupts */
14064     /* int xx; */
14065 /*
14066   As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
14067   SIG_DFL (to catch alarms, or if there is no handler, to exit).  This is to
14068   cure (mask, really) a deeper problem with stray alarms that occurs on some
14069   systems, possibly having to do with sleep(), that caused core dumps.  It
14070   should be OK to do this, because no code in this module uses nested alarms.
14071   (But we still have to watch out for SCRIPT and DIAL...)
14072 */
14073     /* xx = */ alarm(0);
14074     /* debug(F101,"ttimoff alarm","",xx); */
14075     if (saval) {			/* Restore any previous */
14076 	signal(SIGALRM,saval);		/* alarm handler. */
14077 	/* debug(F101,"ttimoff alarm restoring saval","",saval); */
14078 	saval = NULL;
14079     } else {
14080 	signal(SIGALRM,SIG_IGN);	/* Used to be SIG_DFL */
14081 	/* debug(F100,"ttimoff alarm SIG_IGN","",0); */
14082     }
14083 }
14084 
14085 
14086 int
14087 tt_is_secure() {	  /* Tells whether the current connection is secure */
14088 
14089     if (ttyfd == -1)
14090       return(0);
14091 
14092     if (0
14093 #ifdef SSHBUILTIN
14094 	|| IS_SSH()
14095 #endif /* SSHBUILTIN */
14096 #ifdef CK_ENCRYPTION
14097 	|| ck_tn_encrypting() && ck_tn_decrypting()
14098 #endif /* CK_ENCRYPTION */
14099 #ifdef CK_SSL
14100 	|| tls_active_flag || ssl_active_flag
14101 #endif /* CK_SSL */
14102 #ifdef RLOGCODE
14103 #ifdef CK_KERBEROS
14104 #ifdef CK_ENCRYPTION
14105 	|| ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
14106 #endif /* CK_ENCRYPTION */
14107 #endif /* CK_KERBEROS */
14108 #endif /* RLOGCODE */
14109 	)
14110       return(1);
14111     return(0);
14112 }
14113 
14114 #ifdef CK_REDIR
14115 
14116 /* External protocol handler parameters from ckuus3.c */
14117 extern int exp_handler, exp_stderr, exp_timo;
14118 
14119 #ifdef SELECT
14120 #ifdef NETPTY
14121 
14122 /* The right size is 24576 */
14123 
14124 #ifndef PTY_PBUF_SIZE			/* Size of buffer to read from pty */
14125 #define PTY_PBUF_SIZE 24576		/* and write to net. */
14126 #endif	/* PTY_PBUF_SIZE */
14127 
14128 #ifndef PTY_TBUF_SIZE			/* Size of buffer to read from net */
14129 #define PTY_TBUF_SIZE 24576		/* and write to pty. */
14130 #endif	/* PTY_TBUF_SIZE */
14131 
14132 #ifdef O_NDELAY				/* Whether to use nonblocking */
14133 #ifndef PTY_NO_NDELAY			/* reads on the pseudoterminal */
14134 #ifndef PTY_USE_NDELAY
14135 #define PTY_USE_NDELAY
14136 #endif	/* PTY_USE_NDELAY */
14137 #endif	/* PTY_NO_NDELAY */
14138 #endif	/* O_NDELAY */
14139 
14140 #ifndef HAVE_OPENPTY
14141 #ifndef USE_CKUPTY_C
14142 #define USE_CKUPTY_C
14143 #endif /* USE_CKUPTY_C */
14144 #endif /* HAVE_OPENPTY */
14145 
14146 VOID
14147 pty_make_raw(fd) int fd; {
14148     int x = -23, i;
14149 
14150 #ifdef BSD44ORPOSIX			/* POSIX */
14151     struct termios tp;
14152 #else
14153 #ifdef ATTSV				/* AT&T UNIX */
14154 #ifdef CK_ANSIC
14155     struct termio tp = {0};
14156 #else
14157     struct termio tp;
14158 #endif	/* CK_ANSIC */
14159 #else
14160     struct sgttyb tp;			/* Traditional */
14161 #endif /* ATTSV */
14162 #endif /* BSD44ORPOSIX */
14163 
14164     debug(F101,"pty_make_raw fd","",fd);
14165     errno = 0;
14166 
14167 #ifdef BSD44ORPOSIX			/* POSIX */
14168     x = tcgetattr(fd,&tp);
14169     debug(F101,"pty_make_raw tcgetattr","",x);
14170 #else
14171 #ifdef ATTSV				/* AT&T UNIX */
14172     x = ioctl(fd,TCGETA,&tp);
14173     debug(F101,"pty_make_raw TCGETA ioctl","",x);
14174 #else
14175     x = gtty(fd,&tp);
14176     debug(F101,"pty_make_raw ttty","",x);
14177 #endif /* ATTSV */
14178 #endif /* BSD44ORPOSIX */
14179     debug(F101,"pty_make_raw GET errno","",errno);
14180 
14181 #ifdef USE_CFMAKERAW
14182     errno = 0;
14183     cfmakeraw(&tp);
14184     debug(F101,"pty_make_raw cfmakeraw errno","",errno);
14185 #else  /* USE_CFMAKERAW */
14186 
14187 #ifdef COMMENT
14188 
14189 /* This very simple version recommended by Serg Iakolev doesn't work */
14190 
14191     tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
14192     tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
14193     tp.c_cflag &= ~(CSIZE|PARENB);
14194     tp.c_cflag |= CS8;
14195     tp.c_oflag &= ~(OPOST);
14196     tp.c_cc[VMIN] = 1;
14197     tp.c_cc[VTIME] = 0;
14198 
14199     debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS);
14200     debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag);
14201     debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag);
14202     debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag);
14203     debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag);
14204 
14205 #else
14206 #ifdef COMMENT
14207 /*
14208   In this version we unset everything and then set only the
14209   bits we know we need.
14210 */
14211     /* iflags */
14212     tp.c_iflag = 0L;
14213     tp.c_iflag |= IGNBRK;
14214 #ifdef IMAXBEL
14215     tp.c_iflag |= IMAXBEL;
14216 #endif /* IMAXBEL */
14217 
14218     /* oflags */
14219     tp.c_oflag = 0L;
14220 
14221     /* lflags */
14222     tp.c_lflag = 0L;
14223 #ifdef NOKERNINFO
14224     tp.c_lflag |= NOKERNINFO;
14225 #endif	/* NOKERNINFO */
14226 
14227     /* cflags */
14228     tp.c_cflag = 0L;
14229     tp.c_cflag |= CS8|CREAD;
14230 
14231     for (i = 0; i < NCCS; i++) {	/* No special characters */
14232 	tp.c_cc[i] = 0;
14233     }
14234 #ifdef VMIN
14235     tp.c_cc[VMIN] = 1;			/* But always wait for input */
14236 #endif	/* VMIN */
14237     debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS);
14238     debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag);
14239     debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag);
14240     debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag);
14241     debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag);
14242 
14243 #else  /* COMMENT */
14244 /*
14245   In this version we set or unset every single flag explicitly.  It works a
14246   bit better than the simple version just above, but it's still far from
14247   adequate.
14248 */
14249     /* iflags */
14250     tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
14251     tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF);
14252     tp.c_iflag |= IGNBRK;
14253 #ifdef IMAXBEL
14254 #ifdef COMMENT
14255     tp.c_iflag |= IMAXBEL;
14256 #else
14257     tp.c_iflag &= ~IMAXBEL;
14258 #endif /* COMMENT */
14259 #endif /* IMAXBEL */
14260 #ifdef IUCLC
14261     tp.c_iflag &= ~IUCLC;
14262 #endif /* IUCLC */
14263 
14264     /* oflags */
14265 #ifdef BSDLY
14266     tp.c_oflag &= ~BSDLY;
14267 #endif /* BSDLY */
14268 #ifdef CRDLY
14269     tp.c_oflag &= ~CRDLY;
14270 #endif /* CRDLY */
14271 #ifdef FFDLY
14272     tp.c_oflag &= ~FFDLY;
14273 #endif /* FFDLY */
14274 #ifdef NLDLY
14275     tp.c_oflag &= ~NLDLY;
14276 #endif /* NLDLY */
14277 #ifdef TABDLY
14278     tp.c_oflag &= ~TABDLY;
14279 #endif /* TABDLY */
14280 #ifdef VTDLY
14281     tp.c_oflag &= ~VTDLY;
14282 #endif /* VTDLY */
14283 #ifdef OFDEL
14284     tp.c_oflag &= ~OFDEL;
14285 #endif /* OFDEL */
14286 #ifdef OFILL
14287     tp.c_oflag &= ~OFILL;
14288 #endif /* OFILL */
14289 #ifdef OLCUC
14290     tp.c_oflag &= ~OLCUC;
14291 #endif /* OLCUC */
14292 #ifdef CMSPAR
14293     tp.c_oflag &= ~CMSPAR;
14294 #endif /* CMSPAR */
14295     tp.c_oflag &= ~OPOST;
14296 #ifdef OXTABS
14297     tp.c_oflag &= ~OXTABS;
14298 #endif /* OXTABS */
14299 #ifdef COMMENT
14300 #ifdef ONOCR
14301     tp.c_oflag &= ~ONOCR;		/* Maybe should be |=? */
14302     tp.c_oflag |= ONOCR;		/* makes no difference either way */
14303 #endif /* ONOCR */
14304 #endif /* COMMENT */
14305 #ifdef ONOEOT
14306     tp.c_oflag &= ~ONOEOT;
14307 #endif /* ONOEOT */
14308 #ifdef ONLRET
14309     tp.c_oflag &= ~ONLRET;
14310 #endif /* ONLRET */
14311 #ifdef ONLCR
14312     tp.c_oflag &= ~ONLCR;
14313 #endif /* ONLCR */
14314 #ifdef OCRNL
14315     tp.c_oflag &= ~OCRNL;
14316 #endif /* OCRNL */
14317 
14318     /* lflags */
14319     tp.c_lflag &= ~ECHO;
14320 #ifdef ECHOE
14321     tp.c_lflag &= ~ECHOE;
14322 #endif /* ECHOE */
14323 #ifdef ECHONL
14324     tp.c_lflag &= ~ECHONL;
14325 #endif /* ECHONL */
14326 #ifdef ECHOPRT
14327     tp.c_lflag &= ~ECHOPRT;
14328 #endif /* ECHOPRT */
14329 #ifdef ECHOKE
14330     tp.c_lflag &= ~ECHOKE;
14331 #endif /* ECHOKE */
14332 #ifdef ECHOCTL
14333     tp.c_lflag &= ~ECHOCTL;
14334 #endif /* ECHOCTL */
14335 #ifdef XCASE
14336     tp.c_lflag &= ~XCASE;
14337 #endif /* XCASE */
14338 #ifdef ALTWERASE
14339     tp.c_lflag &= ~ALTWERASE;
14340 #endif /* ALTWERASE */
14341 #ifdef EXTPROC
14342     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC);
14343 #else
14344     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
14345 #endif	/* EXTPROC */
14346 #ifdef NOKERNINFO
14347     tp.c_lflag |= NOKERNINFO;
14348 #endif	/* NOKERNINFO */
14349 #ifndef COMMENT
14350     tp.c_lflag &= ~NOFLSH;		/* TRY IT THE OTHER WAY? */
14351 #else
14352     tp.c_lflag |= NOFLSH;		/* No, this way is worse */
14353 #endif /* COMMENT */
14354 
14355     /* cflags */
14356     tp.c_cflag &= ~(CSIZE|PARENB|PARODD);
14357     tp.c_cflag |= CS8|CREAD;
14358 
14359 #ifdef MDMBUF
14360     tp.c_cflag &= ~(MDMBUF);
14361 #else
14362 #ifdef CCAR_OFLOW
14363     tp.c_cflag &= ~(CCAR_OFLOW);	/* two names for the same thing */
14364 #endif /* CCAR_OFLOW */
14365 #endif /* MDMBUF */
14366 
14367 #ifdef CCTS_OFLOW
14368     tp.c_cflag &= ~(CCTS_OFLOW);
14369 #endif /* CCTS_OFLOW */
14370 #ifdef CDSR_OFLOW
14371     tp.c_cflag &= ~(CDSR_OFLOW);
14372 #endif /* CDSR_OFLOW */
14373 #ifdef CDTR_IFLOW
14374     tp.c_cflag &= ~(CDTR_IFLOW);
14375 #endif /* CDTR_IFLOW */
14376 #ifdef CRTS_IFLOW
14377     tp.c_cflag &= ~(CRTS_IFLOW);
14378 #endif /* CRTS_IFLOW */
14379 #ifdef CRTSXOFF
14380     tp.c_cflag &= ~(CRTSXOFF);
14381 #endif /* CRTSXOFF */
14382 #ifdef CRTSCTS
14383     tp.c_cflag &= ~(CRTSCTS);
14384 #endif /* CRTSCTS */
14385 #ifdef CLOCAL
14386     tp.c_cflag &= ~(CLOCAL);
14387 #endif /* CLOCAL */
14388 #ifdef CSTOPB
14389     tp.c_cflag &= ~(CSTOPB);
14390 #endif /* CSTOPB */
14391 #ifdef HUPCL
14392     tp.c_cflag &= ~(HUPCL);
14393 #endif /* HUPCL */
14394 
14395     for (i = 0; i < NCCS; i++) {	/* No special characters */
14396 	tp.c_cc[i] = 0;
14397     }
14398 #ifdef VMIN
14399     tp.c_cc[VMIN] = 1;			/* But always wait for input */
14400 #endif	/* VMIN */
14401     debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS);
14402     debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag);
14403     debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag);
14404     debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag);
14405     debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag);
14406 #endif /* COMMENT */
14407 #endif /* COMMENT */
14408 
14409     errno = 0;
14410 #ifdef BSD44ORPOSIX			/* POSIX */
14411     x = tcsetattr(fd,TCSANOW,&tp);
14412     debug(F101,"pty_make_raw tcsetattr","",x);
14413 #else
14414 #ifdef ATTSV				/* AT&T UNIX */
14415     x = ioctl(fd,TCSETA,&tp);
14416     debug(F101,"pty_make_raw ioctl","",x);
14417 #else
14418     x = stty(fd,&tp);			/* Traditional */
14419     debug(F101,"pty_make_raw stty","",x);
14420 #endif /* ATTSV */
14421 #endif /* BSD44ORPOSIX */
14422     debug(F101,"pty_make_raw errno","",errno);
14423 
14424 #endif /* __NetBSD__ */
14425 }
14426 
14427 static int
14428 pty_chk(fd) int fd; {
14429     int x, n = 0;
14430     errno = 0;
14431 #ifdef FIONREAD
14432     x = ioctl(fd, FIONREAD, &n);	/* BSD and most others */
14433     ckmakmsg(msgbuf,500,
14434 	     "pty_chk ioctl FIONREAD errno=",
14435 	     ckitoa(errno),
14436 	     " count=",
14437 	     ckitoa(n));
14438     debug(F100,msgbuf,"",0);
14439 #else
14440 #ifdef RDCHK
14441     n = rdchk(fd);
14442     debug(F101,"pty_chk rdchk","",n);
14443 #else
14444     n = 1;
14445 #endif	/* RDCHK */
14446 #endif	/* FIONREAD */
14447     return((n > -1) ? n : 0);
14448 }
14449 
14450 static int
14451 pty_get_status(fd,pid) int fd; PID_T pid; {
14452     int x, status = -1;
14453     PID_T w;
14454 
14455     debug(F101,"pty_get_status fd","",fd);
14456     debug(F101,"pty_get_status pid","",pid);
14457 
14458     if (pexitstat > -1)
14459       return(pexitstat);
14460 
14461 #ifdef COMMENT
14462     /* Not only unnecessary but harmful */
14463     errno = 0;
14464     x = kill(pty_fork_pid,0);
14465     debug(F101,"pty_get_status kill value","",x);
14466     debug(F101,"pty_get_status kill errno","",errno);
14467     if (x > -1 && errno != ESRCH)
14468       return(-1);			/* Fork still there */
14469     /* Fork seems to be gone */
14470 #endif	/* COMMENT */
14471 
14472     errno = 0;
14473     x = waitpid(pty_fork_pid,&status,WNOHANG);
14474     debug(F111,"pty_get_status waitpid",ckitoa(errno),x);
14475     if (x <= 0 && errno == 0) {
14476 	debug(F101,"pty_get_status waitpid return","",-1);
14477 	return(-1);
14478     }
14479     if (x > 0) {
14480 	if (x != pty_fork_pid)
14481 	  debug(F101,
14482 		"pty_get_status waitpid pid doesn't match","",pty_fork_pid);
14483 	debug(F101,"pty_get_status waitpid status","",status);
14484 	debug(F101,"pty_get_status waitpid errno","",errno);
14485 	if (WIFEXITED(status)) {
14486 	    debug(F100,"pty_get_status WIFEXITED","",0);
14487 	    status = WEXITSTATUS(status);
14488 	    debug(F101,"pty_get_status fork exit status","",status);
14489 #ifdef COMMENT
14490 	    end_pty();
14491 #endif	/* COMMENT */
14492 	    close(fd);
14493 	    pexitstat = status;
14494 	} else {
14495 	    debug(F100,"pty_get_status waitpid unexpected status","",0);
14496 	}
14497     }
14498     debug(F101,"pty_get_status return status","",status);
14499     return(status);
14500 }
14501 
14502 /* t t p t y c m d  --  Run command on pty and forward to net */
14503 
14504 /*
14505   Needed for running external protocols on secure connections.
14506   For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet
14507   connection, and then needs to transfer a file with Zmodem, which is
14508   an external program, this routine reads Zmodem's output, encrypts it,
14509   and then forwards it out the connection, and reads the encrypted data
14510   stream coming in from the connection, decrypts it, and forwards it to
14511   Zmodem.
14512 
14513   Works like a TCP/IP port forwarder except one end is a pty rather
14514   than a socket, which introduces some complications:
14515 
14516    . On most platforms, select() always indicates the output side of
14517      the pty has characters waiting to be read, even when it doesn't,
14518      even when the pty process has already exited.
14519 
14520    . Nonblocking reads must be used on the pty, because there is no
14521      way on certain platforms (e.g. NetBSD) to find out how many characters
14522      are available to be read (the FIONREAD ioctl always says 0).  The code
14523      also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not
14524      defined, or if PTY_NO_NDELAY is defined), but on some platforms this can
14525      result in single-byte reads and writes (NetBSD again).
14526 
14527    . Testing for "EOF" on the pty is problematic.  select() never gives
14528      any indication.  After the pty process has exited and the fork has
14529      disappeared, read() can still return with 0 bytes read but without an
14530      error (NetBSD); no known test on the pty file descriptor will indicate
14531      that it is no longer valid.  The process ID of the pty fork can be
14532      tested on some platforms (NetBSD, luckily) but not others (Solaris,
14533      Linux).
14534 
14535   On the network side, we use ttinc() and ttoc(), which, for network
14536   connections, handle any active security methods.
14537 
14538   Call with s = command.
14539   Returns 0 on failure, 1 on success.
14540   fdc - December 2006 - August 2007.
14541 
14542   NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are
14543   defined in the header files, which should be true of every recent Unix
14544   platform.  If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when
14545   building C-Kermit:
14546 
14547     touch ckutio.c
14548     make platformname KFLAGS=-DPTY_NO_NODELAY
14549 */
14550 static int have_pty = 0;		/* Do we have a pty? */
14551 
14552 static SIGTYP (*save_sigchld)() = NULL;	/* For catching SIGCHLD */
14553 
14554 static VOID
14555 sigchld_handler(sig) int sig; {
14556     have_pty = 0;			/* We don't have a pty */
14557 #ifdef DEBUG
14558     if (save_sigchld) {
14559 	(VOID) signal(SIGCHLD,save_sigchld);
14560 	save_sigchld = NULL;
14561     }
14562     if (deblog) {
14563 	debug(F100,"**************","",0);
14564 	debug(F100,"SIGCHLD caught","",0);
14565 	debug(F100,"**************","",0);
14566     }
14567 #endif	/* DEBUG */
14568 }
14569 #define HAVE_IAC 1
14570 #define HAVE_CR  2
14571 
14572 int
14573 ttptycmd(s) char *s; {
14574     CHAR tbuf[PTY_TBUF_SIZE];		/* Read from net, write to pty */
14575     int tbuf_avail = 0;			/* Pointers for tbuf */
14576     int tbuf_written = 0;
14577     static int in_state = 0;		/* For TELNET IAC and NVT in */
14578     static int out_prev = 0;		/* Simpler scheme for out */
14579 
14580     CHAR pbuf[PTY_PBUF_SIZE];		/* Read from pty, write to net */
14581     CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */
14582     int pbuf_avail = 0;			/* Pointers for pbuf */
14583     int pbuf_written = 0;
14584 
14585     int ptyfd = -1;			/* Pty file descriptor */
14586     int have_net = 0;			/* We have a network connection */
14587     int pty_err = 0;			/* Got error on pty */
14588     int net_err = 0;			/* Got error on net */
14589     int status = -1;			/* Pty process exit status */
14590     int rc = 0;				/* Our return code */
14591 
14592     int x1 = 0, x2 = 0;			/* Workers... */
14593     int c, n, m, t, x;			/* Workers */
14594 
14595     long seconds_to_wait = 0L;		/* select() timeout */
14596     struct timeval tv, *tv2;		/* For select() */
14597 #ifdef INTSELECT
14598     int in, out, err;			/* For select() */
14599 #else
14600     fd_set in, out, err;
14601 #endif /* INTSELECT */
14602     int nfds = 0;			/* For select() */
14603 
14604     int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */
14605     int read_net_bytes = 0;		/* Stats */
14606     int write_net_bytes = 0;		/* Stats */
14607     int read_pty_bytes = 0;		/* Stats */
14608     int write_pty_bytes = 0;		/* Stats */
14609     int is_tn = 0;			/* TELNET protocol is active */
14610 
14611     int masterfd = -1;
14612     int slavefd = -1;
14613 #ifndef USE_CKUPTY_C
14614     struct termios term;
14615     struct winsize twin;
14616     struct stringarray * q;
14617     char ** args = NULL;
14618 #endif /* USE_CKUPTY_C */
14619 
14620     in_state = 0;			/* No previous character yet */
14621 
14622     if (ttyfd == -1) {
14623 	printf("?Sorry, communication channel is not open\n");
14624 	return(0);
14625     } else {
14626 	have_net = 1;
14627     }
14628     if (nopush) {
14629 	debug(F100,"ttptycmd fail: nopush","",0);
14630 	return(0);
14631     }
14632     if (!s) s = "";			/* Defense de bogus arguments */
14633     if (!*s) return(0);
14634     pexitstat = -1;			/* Fork process exit status */
14635 
14636 #ifdef TNCODE
14637     is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */
14638 	    (!xlocal && sstelnet);
14639 #endif /* TNCODE */
14640 
14641     debug(F110,"ttptycmd command",s,0);
14642     debug(F101,"ttptycmd ttyfd","",ttyfd);
14643     debug(F101,"ttptycmd is_tn","",is_tn);
14644     debug(F101,"ttptycmd ckermit pid","",getpid());
14645 
14646 #ifdef USE_CKUPTY_C
14647     /* Call ckupty.c module to get and set up the pty fork */
14648     /* fc 1 == "run an external protocol" */
14649     debug(F100,"ttptycmd using ckupty.c","",0);
14650     if (do_pty(&ptyfd,s,1) < 0) {	/* Start the command on a pty */
14651 	debug(F100,"ttptycmd do_pty fails","",0);
14652 	return(0);
14653     }
14654     masterfd = ptyfd;
14655     pty_master_fd = ptyfd;
14656 #ifdef COMMENT
14657     slavefd = pty_slave_fd;		/* This is not visible to us */
14658 #endif /* COMMENT */
14659     debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd);
14660     debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd);
14661     debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid);
14662 #ifndef SOLARIS
14663     /* "ioctl inappropriate on device" for pty master */
14664     pty_make_raw(masterfd);
14665 #endif /* SOLARIS */
14666 
14667 #else /* USE_CKUPTY_C */
14668 
14669     debug(F100,"ttptycmd OPENPTY","",0);
14670     if (tcgetattr(0, &term) == -1) {	/* Get controlling terminal's modes */
14671 	perror("tcgetattr");
14672 	return(0);
14673     }
14674     if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */
14675 	perror("ioctl TIOCGWINSZ");
14676 	return(0);
14677     }
14678     if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) {
14679 	debug(F101,"ttptycmd openpty failed errno","",errno);
14680 	perror("opentpy");
14681 	return(0);
14682     }
14683     debug(F101,"ttptycmd openpty masterfd","",masterfd);
14684     debug(F101,"ttptycmd openpty slavefd","",slavefd);
14685     pty_master_fd = masterfd;
14686     pty_slave_fd = slavefd;
14687     debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd);
14688 
14689     /* Put pty master in raw mode but let forked app control the slave */
14690     pty_make_raw(masterfd);
14691 
14692 #ifdef COMMENT
14693 #ifdef TIOCREMOTE
14694     /* TIOCREMOTE,0 = disable all termio processing */
14695     x = ioctl(masterfd, TIOCREMOTE, 1);
14696     debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno);
14697 #endif	/* TIOCREMOTE */
14698 #ifdef TIOCTTY
14699     /* TIOCTTY,0 = disable all termio processing */
14700     x = ioctl(masterfd, TIOCTTY, 0);
14701     debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno);
14702 #endif	/* TIOCTTY */
14703 #endif /* COMMENT */
14704 
14705     have_pty = 1;			/* We have an open pty */
14706     save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */
14707 
14708     pty_fork_pid = fork();		/* Make fork for external protocol */
14709     debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid);
14710     if (pty_fork_pid == -1) {
14711 	perror("fork");
14712 	return(0);
14713     } else if (pty_fork_pid == 0) {	/* In new fork */
14714 	int x;
14715 	debug(F101,"ttptycmd new fork pid","",getpid());
14716 	close(masterfd);		/* Slave quarters no masters allowed */
14717 	x = setsid();
14718 	debug(F101,"ttptycmd new fork setsid","",x);
14719 	if (x == -1) {
14720 	    perror("ttptycmd setsid");
14721 	    exit(1);
14722 	}
14723 	signal(SIGINT,SIG_IGN);		/* Let upper fork catch this */
14724 
14725 #ifdef COMMENT
14726 #ifdef TIOCSCTTY
14727 	/* Make pty the controlling terminal for the process */
14728 	/* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */
14729 	x = ioctl(slavefd, TIOCSCTTY, NULL);
14730 	debug(F101,"ttptycmd TIOCSCTTY","",x);
14731 #endif	/* TIOCSCTTY */
14732 #endif	/* COMMENT */
14733 
14734 	/* Initialize slave pty modes and size to those of our terminal */
14735 	if (tcsetattr(slavefd, TCSANOW, &term) == -1) {
14736 	    perror("ttptycmd tcsetattr");
14737 	    exit(1);
14738 	}
14739 	if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) {
14740 	    perror("ttptycmd ioctl");
14741 	    exit(1);
14742 	}
14743 #ifdef COMMENT
14744 #ifdef TIOCNOTTY
14745 	/* Disassociate this process from its terminal */
14746 	/* THIS HAS NO EFFECT */
14747 	x = ioctl(slavefd, TIOCNOTTY, NULL);
14748 	debug(F101,"ttptycmd TIOCNOTTY","",x);
14749 #endif	/* TIOCNOTTY */
14750 #endif	/* COMMENT */
14751 
14752 #ifdef COMMENT
14753 #ifdef SIGTTOU
14754 	/* Ignore terminal output interrupts */
14755 	/* THIS HAS NO EFFECT */
14756 	debug(F100,"ttptycmd ignoring SIGTTOU","",0);
14757 	signal(SIGTTOU, SIG_IGN);
14758 #endif	/* SIGTTOU */
14759 #ifdef SIGTSTP
14760 	/* Ignore terminal output interrupts */
14761 	/* THIS HAS NO EFFECT */
14762 	debug(F100,"ttptycmd ignoring SIGTSTP","",0);
14763 	signal(SIGTSTP, SIG_IGN);
14764 #endif	/* SIGTSTP */
14765 #endif	/* COMMENT */
14766 
14767 	pty_make_raw(slavefd);		/* Put it in rawmode */
14768 
14769 	errno = 0;
14770 	if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO ||
14771 	    dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) {
14772 	    debug(F101,"ttptycmd new fork dup2 error","",errno);
14773 	    perror("ttptycmd dup2");
14774 	    exit(1);
14775 	}
14776 	debug(F100,"ttptycmd new fork dup2 ok","",0);
14777 
14778 	/* Parse external protocol command line */
14779 	q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0,0);
14780 	if (!q) {
14781 	    debug(F100,"ttptycmd cksplit failed","",0);
14782 	    exit(1);
14783 	} else {
14784 	    int i, n;
14785 	    debug(F100,"ttptycmd cksplit ok","",0);
14786 	    n = q->a_size;
14787 	    args = q->a_head + 1;
14788 	    for (i = 0; i <= n; i++) {
14789 		if (!args[i]) {
14790 		    break;
14791 		} else {
14792 		    /* sometimes cksplit() doesn't terminate the list */
14793 		    if ((i == n) && args[i]) {
14794 			if ((int)strlen(args[i]) == 0)
14795 			  makestr(&(args[i]),NULL);
14796 		    }
14797 		}
14798 	    }
14799 	}
14800 #ifdef COMMENT
14801 /*
14802   Putting the slave pty in rawmode should not be necessary because the
14803   external protocol program is supposed to do that itself.  Yet doing this
14804   here cuts down on Zmodem binary-file transmission errors by 30-50% but
14805   still doesn't eliminate them.
14806 */
14807 	pty_make_raw(STDIN_FILENO);
14808 	pty_make_raw(STDOUT_FILENO);
14809 #endif /* COMMENT */
14810 
14811 	debug(F100,"ttptycmd execvp'ing external protocol","",0);
14812 	execvp(args[0],args);
14813 	perror("execvp failed");
14814 	debug(F101,"ttptycmd execvp failed","",errno);
14815 	close(slavefd);
14816 	exit(1);
14817     }
14818     /* (there are better ways to do this...) */
14819     msleep(1000);		  /* Make parent wait for child to be ready */
14820     ptyfd = masterfd;			/* We talk to the master */
14821 
14822 #endif /* USE_CKUPTY_C */
14823 
14824     debug(F101,"ttptycmd ptyfd","",ptyfd);
14825     if (ptyfd < 0) {
14826 	printf("?Failure to get pty\n");
14827 	return(-9);
14828     }
14829     have_pty = 1;	      /* We have an open pty or we wouldn't he here */
14830 
14831     debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE);
14832     debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE);
14833 
14834 #ifdef PTY_USE_NDELAY
14835     /*
14836        NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications
14837        on the pty, we don't need nonblocking reads.  Performance of either
14838        method seems to be about the same, so use whatever works.
14839     */
14840     errno = 0;
14841     x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY);
14842     ckmakmsg(msgbuf,500,
14843 	     "ttptycmd set O_NDELAY errno=",
14844 	     ckitoa(errno),
14845 	     " fcntl=",
14846 	     ckitoa(x));
14847     debug(F100,msgbuf,"",0);
14848 #endif /* PTY_USE_NDELAY */
14849 
14850 #ifdef COMMENT
14851 /* Not necessary, the protocol module already did this */
14852 
14853 #ifdef USE_CFMAKERAW
14854     if (tcgetattr(ttyfd, &term) > -1) {
14855 	cfmakeraw(&term);
14856 	debug(F101,"ttptycmd net cfmakeraw errno","",errno);
14857 	x tcsetattr(ttyfd, TCSANOW, &term);
14858 	debug(F101,"ttptycmd net tcsetattr","",x);
14859 	debug(F101,"ttptycmd net tcsetattr","",errno);
14860     }
14861 #else
14862     if (local)				/* Put network connection in */
14863       ttpkt(ttspeed,ttflow,ttprty);	/* "packet mode". */
14864     else
14865       conbin((char)escchr);		/* OR... pty_make_raw(0) */
14866 #endif /* USE_CFMAKERAW */
14867 #endif /* COMMENT */
14868 
14869 #ifdef TNCODE
14870     if (is_tn) {
14871       debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY));
14872       debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY));
14873     }
14874 #endif /* TNCODE */
14875 
14876     debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait);
14877 
14878     while (have_pty || have_net) {
14879 	FD_ZERO(&in);			/* Initialize select() structs */
14880 	FD_ZERO(&out);
14881 	FD_ZERO(&err);			/* (not used because useless) */
14882 	nfds = -1;
14883 
14884 	debug(F101,"ttptycmd loop top have_pty","",have_pty);
14885 	debug(F101,"ttptycmd loop top have_net","",have_net);
14886 
14887 	/* Pty is open and we have room to read from it? */
14888 	if (have_pty && pbuf_avail < PTY_PBUF_SIZE) {
14889 	    debug(F100,"ttptycmd FD_SET ptyfd in","",0);
14890             FD_SET(ptyfd, &in);
14891 	    nfds = ptyfd;
14892         }
14893 	/* Network is open and we have room to read from it? */
14894         if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) {
14895 	    debug(F100,"ttptycmd FD_SET ttyfd in","",0);
14896             FD_SET(ttyfd, &in);
14897 	    if (ttyfd > nfds) nfds = ttyfd;
14898         }
14899 	/* Pty is open and we have stuff to write to it? */
14900         if (have_pty && tbuf_avail - tbuf_written > 0) {
14901 	    debug(F100,"ttptycmd FD_SET ptyfd out","",0);
14902             FD_SET (ptyfd, &out);
14903 	    if (ptyfd > nfds) nfds = ptyfd;
14904         }
14905 	/* Net is open and we have stuff to write to it? */
14906 	debug(F101,"ttptycmd pbuf_avail-pbuf_written","",
14907 	      pbuf_avail - pbuf_written);
14908         if (have_net && pbuf_avail - pbuf_written > 0) {
14909 	    debug(F100,"ttptycmd FD_SET ttyfd out","",0);
14910             FD_SET (ttyfd, &out);
14911 	    if (ttyfd > nfds) nfds = ttyfd;
14912         }
14913 	/* We don't use err because it's not really for errors, */
14914 	/* but for out of band data on the TCP socket, which, if it is */
14915 	/* to be handled at all, is handled in the tt*() routines */
14916 
14917 	nfds++;				/* 0-based to 1-based */
14918 	debug(F101,"ttptycmd nfds","",nfds);
14919 	if (!nfds) {
14920 	    debug(F100,"ttptycmd NO FDs set for select","",0);
14921 	    if (have_pty) {
14922 		/* This is not right -- sleeping won't accomplish anything */
14923 		debug(F101,"ttptycmd msleep","",100);
14924 		msleep(100);
14925 	    } else {
14926 		debug(F100,"ttptycmd no pty - quitting loop","",0);
14927 		break;
14928 	    }
14929 	}
14930 	errno = 0;
14931 
14932 	if (seconds_to_wait > 0L) {	/* Timeout in case nothing happens */
14933 	    tv.tv_sec = seconds_to_wait; /* for a long time */
14934 	    tv.tv_usec = 0L;
14935 	    tv2 = &tv;
14936         } else {
14937             tv2 = NULL;
14938 	}
14939 	x = select(nfds, &in, &out, NULL, tv2);
14940 	debug(F101,"ttptycmd select","",x);
14941 	if (x < 0) {
14942 	    if (errno == EINTR)
14943 	      continue;
14944 	    debug(F101,"ttptycmd select error","",errno);
14945 	    break;
14946 	}
14947 	if (x == 0) {
14948 	    debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait);
14949 	    if (have_pty) {
14950 		status = pty_get_status(ptyfd,pty_fork_pid);
14951 		debug(F101,"ttptycmd pty_get_status A","",status);
14952 		if (status > -1) pexitstat = status;
14953 		have_pty = 0;
14954 	    }
14955 	    break;
14956 	}
14957 	/* We want to handle any pending writes first to make room */
14958 	/* for new incoming. */
14959 
14960 	if (FD_ISSET(ttyfd, &out)) {	/* Can write to net? */
14961 	    CHAR * s;
14962 	    s = pbuf + pbuf_written;	/* Current spot for sending */
14963 #ifdef TNCODE
14964 	    if (is_tn) {		/* ttol() doesn't double IACs */
14965 		CHAR c;			/* Rewrite string with IACs doubled */
14966 		int i;
14967 		s = pbuf + pbuf_written; /* Source */
14968 		x = 0;		 	 /* Count */
14969 		for (i = 0; i < pbuf_avail - pbuf_written; i++) {
14970 		    c = s[i];		/* Next character */
14971 		    if (c == IAC) {	/* If it's IAC */
14972 			dbuf[x++] = c;	/* put another one */
14973 			debug(F000,">>> QUOTED IAC","",c);
14974 		    } else if (c != 0x0a && out_prev == 0x0d) {	/* Bare CR */
14975 			if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */
14976 			    c = 0x00;
14977 			    dbuf[x++] = c;
14978 			    debug(F000,">>> CR-NUL","",c);
14979 			}
14980 		    }
14981 		    dbuf[x++] = c;	/* Copy and count it */
14982 		    debug(F000,">>> char",ckitoa(in_state),c);
14983 		    out_prev = c;
14984 		}
14985 		s = dbuf;		/* New source */
14986 	    } else
14987 #endif /* TNCODE */
14988 	      x = pbuf_avail - pbuf_written; /* How much to send */
14989 
14990 	    debug(F101,"ttptycmd bytes to send","",x);
14991 	    x = ttol(s, x);
14992 	    debug(F101,">>> ttol","",x);
14993 	    if (x < 0) {
14994 		net_err++;
14995 		debug(F111,"ttptycmd ttol error",ckitoa(x),errno);
14996 		x = 0;
14997 	    }
14998 	    write_net_bytes += x;
14999 	    pbuf_written += x;
15000 	}
15001 	if (FD_ISSET(ptyfd, &out)) {	/* Can write to pty? */
15002 	    debug(F100,"ttptycmd FD_ISSET ptyfd out","",0);
15003 	    errno = 0;
15004 #ifndef COMMENT
15005 	    x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written);
15006 #else
15007 	    /* Byte loop to rule out data overruns in the pty */
15008 	    /* (it makes no difference) */
15009 	    {
15010 		char *p = tbuf+tbuf_written;
15011 		int n = tbuf_avail - tbuf_written;
15012 		for (x = 0; x < n; x++) {
15013 		    msleep(10);
15014 		    if (write(ptyfd,&(p[x]),1) < 0)
15015 		      break;
15016 		}
15017 	    }
15018 #endif /* COMMENT */
15019 	    debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x);
15020 	    if (x > 0) {
15021 		tbuf_written += x;
15022 		write_pty_bytes += x;
15023 	    } else {
15024 		x = 0;
15025 		pty_err++;
15026 		if (pexitstat < 0) {
15027 		    status = pty_get_status(ptyfd,pty_fork_pid);
15028 		    debug(F101,"ttptycmd pty_get_status B","",status);
15029 		    if (status > -1) pexitstat = status;
15030 		    have_pty = 0;
15031 		}
15032 		debug(F100,"ttptycmd +++ ptyfd write error","",0);
15033 	    }
15034 	}
15035 	if (FD_ISSET(ttyfd, &in)) {	/* Can read from net? */
15036 	    tset++;
15037 	    debug(F100,"ttptycmd FD_ISSET ttyfd in","",0);
15038 	    n = in_chk(1,ttyfd);
15039 	    debug(F101,"ttptycmd in_chk(ttyfd)","",n);
15040 	    if (n < 0 || ttyfd == -1) {
15041 		debug(F101,"ttptycmd +++ ttyfd errno","",errno);
15042 		net_err++;
15043 	    } else if (n > 0) {
15044 		if (n > PTY_TBUF_SIZE - tbuf_avail)
15045 		  n = PTY_TBUF_SIZE - tbuf_avail;
15046 		debug(F101,"ttptycmd net read size adjusted","",n);
15047 		if (xlocal && netconn) {
15048 		    /*
15049 		      We have to use a byte loop here because ttxin()
15050 		      does not decrypt or, for that matter, handle Telnet.
15051 		    */
15052 		    int c;
15053 		    CHAR * p;
15054 		    p = tbuf + tbuf_avail;
15055 		    for (x = 0; x < n; x++) {
15056 			if ((c = ttinc(0)) < 0)
15057 			  break;
15058 			if (!is_tn) {	/* Not Telnet - keep all bytes */
15059 			    *p++ = (CHAR)c;
15060 			    debug(F000,"<<< char","",c);
15061 #ifdef TNCODE
15062 			} else {	/* Telnet - must handle IAC and NVT */
15063 			    debug(F000,"<<< char",ckitoa(in_state),c);
15064 			    switch (c) {
15065 			      case 0x00: /* NUL */
15066 				if (in_state == HAVE_CR) {
15067 				    debug(F000,"<<< SKIP","",c);
15068 				} else {
15069 				    *p++ = c;
15070 				    debug(F000,"<<< Keep","",c);
15071 				}
15072 				in_state = 0;
15073 				break;
15074 			      case 0x0d: /* CR */
15075 				if (!TELOPT_U(TELOPT_BINARY))
15076 				  in_state = HAVE_CR;
15077 				*p++ = c;
15078 				debug(F000,"<<< Keep","",c);
15079 				break;
15080 #ifdef COMMENT
15081 			      case 0x0f: /* Ctrl-O */
15082 			      case 0x16: /* Ctrl-V */
15083 				*p++ = 0x16;
15084 				*p++ = c;
15085 				debug(F000,"<<< QUOT","",c);
15086 				break;
15087 #endif /* COMMENT */
15088 			      case 0xff: /* IAC */
15089 				if (in_state == HAVE_IAC) {
15090 				    debug(F000,"<<< KEEP","",c);
15091 				    *p++ = c;
15092 				    in_state = 0;
15093 				} else {
15094 				    debug(F000,"<<< SKIP","",c);
15095 				    in_state = HAVE_IAC;
15096 				}
15097 				break;
15098 			      default:	/* All others */
15099 				if (in_state == HAVE_IAC) {
15100 #ifdef COMMENT
15101 /*
15102   tn_doop() will consume an unknown number of bytes and we'll overshoot
15103   the for-loop.  The only Telnet command I've ever seen arrive here is
15104   a Data Mark, which comes when the remote protocol exits and the remote
15105   job returns to its shell prompt.  On the assumption it's a 1-byte command,
15106   we don't write out the IAC or the command, and we clear the state.  If
15107   we called tn_doop() we'd have no way of knowing how many bytes it took
15108   from the input stream.
15109 */
15110 				    int xx;
15111 				    xx = tn_doop((CHAR)c,duplex,ttinc);
15112 				    debug(F111,"<<< DOOP",ckctoa(c),xx);
15113 #else
15114 				    debug(F101,"<<< DOOP","",c);
15115 #endif	/* COMMENT */
15116 				    in_state = 0;
15117 				} else {
15118 				    *p++ = c;
15119 				    debug(F000,"<<< keep","",c);
15120 				    in_state = 0;
15121 				}
15122 			    }
15123 #endif	/* TNCODE */
15124 			}
15125 		    }
15126 		    ckmakmsg(msgbuf,500,
15127 			     "ttptycmd read net [ttinc loop] errno=",
15128 			     ckitoa(errno),
15129 			     " count=",
15130 			     ckitoa(x));
15131 		    debug(F100,msgbuf,"",0);
15132 		} else {
15133 		    x = ttxin(n,tbuf+tbuf_avail);
15134 		    debug(F101,"ttptycmd ttxin x","",x);
15135 		}
15136 
15137 		if (x < 0) {
15138 		    debug(F101,"ttptycmd read net error","",x);
15139 		    net_err++;
15140 		}
15141 		tbuf_avail += x;
15142 		read_net_bytes += x;
15143 	    }
15144 
15145 	} else
15146 	  tnotset++;
15147 
15148 	if (FD_ISSET(ptyfd, &in)) {	/* Read from pty? */
15149 	    pset++;
15150 	    debug(F100,"ttptycmd FD_ISSET ptyfd in","",0);
15151 #ifdef PTY_USE_NDELAY
15152 	    n = PTY_PBUF_SIZE;
15153 #else
15154 	    /*
15155 	      This does not work on nonblocking channels
15156 	      on certain platforms such as NetBSD.
15157 	    */
15158 	    n = pty_chk(ptyfd);
15159 #endif /* PTY_USE_NDELAY */
15160 	    debug(F101,"ttptycmd pty_chk() n","",n);
15161 
15162 	    if (n < 0)
15163 	      n = 0;
15164 	    if (n > 0) {
15165 		if (n > PTY_PBUF_SIZE - pbuf_avail)
15166 		  n = PTY_PBUF_SIZE - pbuf_avail;
15167 		debug(F101,"ttptycmd pty read size adjusted","",n);
15168 		errno = 0;
15169 		x = read(ptyfd,pbuf+pbuf_avail,n);
15170 #ifdef DEBUG
15171 		if (deblog) {
15172 		    ckmakmsg(msgbuf,500,
15173 			     "ttptycmd read pty errno=",
15174 			     ckitoa(errno),
15175 			     " count=",
15176 			     ckitoa(x));
15177 		    debug(F100,msgbuf,"",0);
15178 		}
15179 #endif	/* DEBUG */
15180 
15181 		if (x < 0 && errno == EAGAIN)
15182 		  x = 0;
15183 
15184 		if (x < 0) {		/* This works on Solaris and Linux */
15185 		    pty_err++;		/* but not NetBSD */
15186 		    debug(F100,"TERMINATION TEST A","",0);
15187 #ifdef COMMENT
15188 		    if (errno == EIO)
15189 		      rc = 1;
15190 #endif	/* COMMENT */
15191 		    if (pexitstat < 0) {
15192 			status = pty_get_status(ptyfd,pty_fork_pid);
15193 			debug(F101,"ttptycmd pty_get_status C","",status);
15194 			if (status > -1) pexitstat = status;
15195 		    }
15196 		    have_pty = 0;
15197 		    x = 0;
15198 		}
15199 		if (x == 0 && !pty_err) { /* This works on NetBSD but */
15200 		    debug(F100,"TERMINATION TEST B","",0);
15201 		    status = pexitstat > -1 ? pexitstat :
15202 			pty_get_status(ptyfd,pty_fork_pid);
15203 		    debug(F101,"ttptycmd pty_get_status D","",status);
15204 		    if (status > -1) {
15205 			pexitstat = status;
15206 			pty_err++;
15207 			have_pty = 0;
15208 		    } else {		/* Select() lied */
15209 			pty_err = 0;	/* pty still there but has nothing */
15210 			msleep(100);	/* sleep a bit */
15211 		    }
15212 		    x = 0;
15213 		}
15214 		/* Hopefully the next two are no longer needed... */
15215 		if (!pty_err && (
15216 #ifndef PTY_USE_NDELAY
15217 		    x < 1 || errno
15218 #else
15219 		    errno != 0 && errno != EAGAIN
15220 #endif /* PTY_USE_NDELAY */
15221 		    )) {
15222 		    debug(F100,"TERMINATION TEST C","",0);
15223 		    pty_err++;
15224 		    debug(F101,"ttptycmd SET pty_err","",pty_err);
15225 		    if (errno == EIO)	/* errno == EIO is like EOF */
15226 		      rc = 1;
15227 		    if (x < 0)
15228 		      x = 0;
15229 		}
15230 #ifdef COMMENT
15231 #ifdef DEBUG
15232 		if (deblog) {
15233 		    pbuf[pbuf_avail + x] = '\0';
15234 		    debug(F111,"ttptycmd added to pty buffer",
15235 			  pbuf+pbuf_avail,x);
15236 		}
15237 #endif	/* DEBUG */
15238 #endif	/* COMMENT */
15239 		pbuf_avail += x;
15240 		read_pty_bytes += x;
15241 	    } else {			/* n == 0 with blocking reads */
15242 		debug(F100,
15243 		      "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN",
15244 		      "",0);
15245 	    }
15246 	} else
15247 	  pnotset++;
15248 
15249 	/* If writes have caught up to reads, reset the buffers */
15250 
15251 	if (pbuf_written == pbuf_avail)
15252 	  pbuf_written = pbuf_avail = 0;
15253 	if (tbuf_written == tbuf_avail)
15254 	  tbuf_written = tbuf_avail = 0;
15255 
15256 	/* See if we can exit */
15257 
15258 	x1 = pbuf_avail - pbuf_written;
15259 	x2 = tbuf_avail - tbuf_written;
15260 
15261 	debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err);
15262 	debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1);
15263 	debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2);
15264 	debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc);
15265 	debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status);
15266 	debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat);
15267 
15268 	if (net_err) {			/* Net error? */
15269 	    debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err);
15270 	    if (have_net) {
15271 		if (local) {
15272 		    ttclos(0);
15273 		    printf("?Connection closed\n");
15274 		}
15275 		have_net = 0;
15276 	    }
15277 	    debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1);
15278 	    if (x1 == 0)
15279 	      break;
15280 	}
15281 	if (pty_err) {			/* Pty error? */
15282 	    if (have_pty) {
15283 		if (pexitstat < 0) {
15284 		    status = pty_get_status(ptyfd,pty_fork_pid);
15285 		    debug(F101,"ttptycmd pty_get_status E","",status);
15286 		    if (status > -1) pexitstat = status;
15287 		}
15288 		have_pty = 0;
15289 	    }
15290 	    if (x1 == 0 && x2 == 0) {	/* If buffers are caught up */
15291 		rc = 1;			/* set preliminary return to success */
15292 		debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc);
15293 		break;			/* and exit the loop */
15294 	    }
15295 	}
15296     }
15297     debug(F101,"ttptycmd +++ have_pty","",have_pty);
15298     if (have_pty) {			/* In case select() failed */
15299 #ifdef USE_CKUPTY_C
15300 	end_pty();
15301 	close(ptyfd);
15302 #else
15303 	close(slavefd);
15304 	close(masterfd);
15305 #endif /* USE_CKUPTY_C */
15306     }
15307     pty_master_fd = -1;
15308     debug(F101,"ttptycmd +++ pexitstat","",pexitstat);
15309     if (pexitstat < 0) {		/* Try one last time to get status */
15310 	status = pty_get_status(ptyfd,pty_fork_pid);
15311 	debug(F101,"ttptycmd pty_get_status F","",status);
15312 	if (status > -1) pexitstat = status;
15313     }
15314     debug(F101,"ttptycmd +++ final pexitstat","",pexitstat);
15315     if (deblog) {			/* Stats for debug log */
15316 	debug(F101,"ttptycmd +++ pset	","",pset);
15317 	debug(F101,"ttptycmd +++ pnotset","",pnotset);
15318 	debug(F101,"ttptycmd +++ tset	","",tset);
15319 	debug(F101,"ttptycmd +++ tnotset","",tnotset);
15320 
15321 	debug(F101,"ttptycmd +++  read_pty_bytes","",read_pty_bytes);
15322 	debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes);
15323 	debug(F101,"ttptycmd +++  read_net_bytes","",read_net_bytes);
15324 	debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes);
15325     }
15326 /*
15327   If we got the external protocol's exit status from waitpid(), we use that
15328   to set our return code.  If not, we fall back on whatever rc was previously
15329   set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise.
15330 */
15331     if (save_sigchld) {			/* Restore this if we changed it */
15332 	(VOID) signal(SIGCHLD,save_sigchld);
15333 	save_sigchld = NULL;
15334     }
15335     msleep(500);
15336     x = kill(pty_fork_pid,SIGHUP);	/* In case it's still there */
15337     pty_fork_pid = -1;
15338     debug(F101,"ttptycmd fork kill SIGHUP","",x);
15339     if (pexitstat > -1)
15340       rc = (pexitstat == 0 ? 1 : 0);
15341     debug(F101,"ttptycmd +++ rc","",rc);
15342     if (!local) {			/* If in remote mode */
15343 	conres();			/* restore console to CBREAK mode */
15344 	concb((char)escchr);
15345     }
15346     return(rc);
15347 }
15348 #endif	/* NETPTY */
15349 #endif	/* SELECT */
15350 
15351 /* T T R U N C M D  --  Redirect an external command over the connection. */
15352 
15353 /*
15354   TTRUNCMD is the routine that was originally used for running external
15355   protocols.  It is very simple and works fine provided (a) the connection
15356   is not encrypted, and (b) the external protocol uses standard i/o
15357   (file descriptors 0 and 1) for file transfer.
15358 */
15359 
15360 int
15361 ttruncmd(s) char *s; {
15362     PID_T pid;				/* pid of lower fork */
15363     int wstat;				/* for wait() */
15364     int x;
15365     int statusp;
15366 
15367     if (ttyfd == -1) {
15368 	printf("?Sorry, device is not open\n");
15369 	return(0);
15370     }
15371     if (nopush) {
15372 	debug(F100,"ttruncmd fail: nopush","",0);
15373 	return(0);
15374     }
15375 
15376 #ifdef NETPTY
15377 /***************
15378   It might also be necessary to use the pty routine for other reasons,
15379   e.g. because the external program does not use stdio.
15380 */
15381 #ifdef NETCONN
15382 /*
15383   If we have a network connection we use a different routine because
15384   (a) if the connection is encrypted, the mechanism used here can't deal
15385   with it; and (b) it won't handle any network protocols either, e.g.
15386   Telnet, Rlogin, K5 U-to-U, etc.  However, this routine works much
15387   better (faster, more transparent) on serial connections and when
15388   C-Kermit is in remote mode (i.e. is on the far end).
15389 */
15390     /* For testing always use this */
15391     if (netconn)
15392       return(ttptycmd(s));
15393 #endif /* NETCONN */
15394 
15395 /***************/
15396 #else  /* NETPTY */
15397     if (tt_is_secure()) {
15398 	printf("?Sorry, \
15399 external protocols over secure connections not supported in this OS.\n"
15400               );
15401         return(0);
15402     }
15403 #endif	/* NETPTY */
15404 
15405     conres();				/* Make console normal  */
15406     pexitstat = -4;
15407     if ((pid = fork()) == 0) {		/* Make a child fork */
15408 	if (priv_can())			/* Child: turn off privs. */
15409 	  exit(1);
15410 	dup2(ttyfd, 0);			/* Give stdin/out to the line */
15411 	dup2(ttyfd, 1);
15412 	x = system(s);
15413 	debug(F101,"ttruncmd system",s,x);
15414 	_exit(x ? BAD_EXIT : 0);
15415     } else {
15416 	SIGTYP (*istat)(), (*qstat)();
15417 	if (pid == (PID_T) -1)		/* fork() failed? */
15418 	  return(0);
15419 	istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
15420 	qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
15421 
15422 #ifdef COMMENT
15423     	while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
15424 #else  /* Not COMMENT */
15425     	while (1) {
15426 	    wstat = wait(&statusp);
15427 	    debug(F101,"ttruncmd wait","",wstat);
15428 	    if (wstat == pid || wstat == -1)
15429 	      break;
15430 	}
15431 #endif /* COMMENT */
15432 
15433 	pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
15434 	debug(F101,"ttruncmd wait statusp","",statusp);
15435 	debug(F101,"ttruncmd wait pexitstat","",pexitstat);
15436 	signal(SIGINT,istat);		/* Restore interrupts */
15437 	signal(SIGQUIT,qstat);
15438     }
15439     concb((char)escchr);		/* Restore console to CBREAK mode */
15440     return(statusp == 0 ? 1 : 0);
15441 }
15442 #endif	/* CK_REDIR */
15443 
15444 struct tm *
15445 #ifdef CK_ANSIC
15446 cmdate2tm(char * date, int gmt)         /* date as "yyyymmdd hh:mm:ss" */
15447 #else
15448 cmdate2tm(date,gmt) char * date; int gmt;
15449 #endif
15450 {
15451     /* date as "yyyymmdd hh:mm:ss" */
15452     static struct tm _tm;
15453     time_t now;
15454 
15455     if (strlen(date) != 17 ||
15456 	date[8] != ' ' ||
15457 	date[11] != ':' ||
15458 	date[14] != ':')
15459       return(NULL);
15460 
15461     time(&now);
15462     if (gmt)
15463       _tm = *gmtime(&now);
15464     else
15465       _tm = *localtime(&now);
15466     _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
15467                   (date[2]-'0')*10   + (date[3]-'0')-1900;
15468     _tm.tm_mon  = (date[4]-'0')*10   + (date[5]-'0')-1;
15469     _tm.tm_mday = (date[6]-'0')*10   + (date[7]-'0');
15470     _tm.tm_hour = (date[9]-'0')*10   + (date[10]-'0');
15471     _tm.tm_min  = (date[12]-'0')*10  + (date[13]-'0');
15472     _tm.tm_sec  = (date[15]-'0')*10  + (date[16]-'0');
15473 
15474     /* Should we set _tm.tm_isdst to -1 here? */
15475 
15476     _tm.tm_wday = 0;
15477     _tm.tm_yday = 0;
15478 
15479     return(&_tm);
15480 }
15481 
15482 #ifdef HAVE_LOCALE
15483 #include <langinfo.h>
15484 #define DAYNAMERESULT 128
15485 static char daynameresult[DAYNAMERESULT];
15486 /*
15487   day = day-of-week number, 0-6 (0=Su, 1=Mo, 2=Tu, ..., 6=Sa).
15488   fc = 0 for full name, 1 for standard abbreviation, e.g. Mon, Tue.
15489   Returns: Day name according to current locale on success; NULL on failure.
15490   Note: nl_langinfo() items are indexed by numbers that vary from
15491   platform to platform (e.g. NetBSD and Solaris are totally different).
15492 */
15493 char *
15494 locale_dayname(day,fc) int day, fc; {
15495     /* date as "yyyymmdd hh:mm:ss" */
15496     int n = 0;
15497     int x = DAY_1;
15498     char * date;
15499     char buf[20];
15500 
15501     if (day < 0 || day > 6) return(NULL);
15502     n = day + 1;
15503     if (n > 6) n = 0;			/* 2013-10-15 */
15504     if (fc) x = ABDAY_1;
15505     ckstrncpy(daynameresult,nl_langinfo(((nl_item)(n+x))),DAYNAMERESULT);
15506     return((char *)daynameresult);
15507 }
15508 #define MONTHNAMERESULT 128
15509 static char monthnameresult[MONTHNAMERESULT];
15510 /*
15511   month = month-of-year number, 0-11 (0=Jan, 1=Feb, 2=Mar, ..., 11=Dec).
15512   fc = 0 for full name, 1 for standard abbreviation, e.g. Jan, Feb.
15513   Returns: Month name according to current locale on success; NULL on failure.
15514 */
15515 char *
15516 locale_monthname(month,fc) int month, fc; {
15517     int n = 0;
15518     int x = MON_1;
15519     char * date;
15520     char buf[20];
15521     char mbuf[4];
15522 
15523     if (month < 0 || month > 11) return(NULL);
15524     n = month;				/* 0-based calendar month number */
15525     if (fc) x = ABMON_1;
15526     ckstrncpy(monthnameresult,nl_langinfo(((nl_item)(n+x))),MONTHNAMERESULT);
15527     return((char *)monthnameresult);
15528 }
15529 #endif /* HAVE_LOCALE */
15530 
15531 #ifdef OXOS
15532 #undef kill
15533 #endif /* OXOS */
15534 
15535 #ifdef OXOS
15536 int
15537 priv_kill(pid, sig) int pid, sig; {
15538     int	i;
15539 
15540     if (priv_on())
15541 	debug(F100,"priv_kill priv_on failed","",0);
15542     i = kill(pid, sig);
15543     if (priv_off())
15544 	debug(F100,"priv_kill priv_off failed","",0);
15545     return(i);
15546 }
15547 #endif /* OXOS */
15548 
15549 #ifdef BEOSORBEBOX
15550 /* #ifdef BE_DR_7 */
15551 /*
15552   alarm() function not supplied with Be OS DR7 - this one contributed by
15553   Neal P. Murphy.
15554 */
15555 
15556 /*
15557   This should mimic the UNIX/POSIX alarm() function well enough, with the
15558   caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
15559   and wait for the alarm thread to finish.
15560 */
15561 unsigned int
15562 alarm(unsigned int seconds) {
15563     long time_left = 0;
15564 
15565 /* If an alarm is active, turn it off, saving the unused time */
15566     if (alarm_thread != -1) {
15567         /* We'll be generous and count partial seconds as whole seconds. */
15568         time_left = alarm_struct.time -
15569 	  ((system_time() - time_started) / 1000000.0);
15570 
15571         /* Kill the alarm thread */
15572         kill_thread (alarm_thread);
15573 
15574         /* We need to clean up as though the alarm occured. */
15575         time_started = 0;
15576         alarm_struct.thread = -1;
15577         alarm_struct.time = 0;
15578         alarm_expired();
15579     }
15580 
15581 /* Set a new alarm clock, if requested. */
15582     if (seconds > 0) {
15583         alarm_struct.thread = find_thread(NULL);
15584         alarm_struct.time = seconds;
15585         time_started = system_time();
15586         alarm_thread = spawn_thread (do_alarm,
15587                                      "alarm_thread",
15588                                      B_NORMAL_PRIORITY,
15589                                      (void *) &alarm_struct
15590 				     );
15591         resume_thread (alarm_thread);
15592     }
15593 
15594 /* Now return [unused time | 0] */
15595     return ((unsigned int) time_left);
15596 }
15597 
15598 /*
15599   This function is the departure from UNIX/POSIX alarm handling. In the case
15600   of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
15601   handler. When Be implements alarm(), this function call can be eliminated
15602   from user's SIGALRM signal handlers.
15603 */
15604 
15605 void
15606 alarm_expired(void) {
15607     long ret_val;
15608 
15609     if (alarm_thread != -1) {
15610         wait_for_thread (alarm_thread, &ret_val);
15611         alarm_thread = -1;
15612     }
15613 }
15614 
15615 /*
15616   This is the function that snoozes the requisite number of seconds and then
15617   SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
15618   uses thread_id; currently they are both typdef'ed as long, but I'll do the
15619   cast anyway. This function is run in a separate thread.
15620 */
15621 
15622 long
15623 do_alarm (void *alarm_struct) {
15624     snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
15625     kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
15626     time_started = 0;
15627     ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
15628     ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
15629 }
15630 /* #endif */ /* BE_DR_7 */
15631 #endif /* BEOSORBEBOX */
15632 
15633 #ifdef Plan9
15634 
15635 int
15636 p9ttyctl(char letter, int num, int param) {
15637     char cmd[20];
15638     int len;
15639 
15640     if (ttyctlfd < 0)
15641       return -1;
15642 
15643     cmd[0] = letter;
15644     if (num)
15645       len = sprintf(cmd + 1, "%d", param) + 1;
15646     else {
15647 	cmd[1] = param;
15648 	len = 2;
15649     }
15650     if (write(ttyctlfd, cmd, len) == len) {
15651 	cmd[len] = 0;
15652 	/* fprintf(stdout, "wrote '%s'\n", cmd); */
15653 	return 0;
15654     }
15655     return -1;
15656 }
15657 
15658 int
15659 p9ttyparity(char l) {
15660     return p9ttyctl('p', 0, l);
15661 }
15662 
15663 int
15664 p9tthflow(int flow, int status) {
15665     return p9ttyctl('m', 1, status);
15666 }
15667 
15668 int
15669 p9ttsspd(int cps) {
15670     if (p9ttyctl('b', 1, cps * 10) < 0)
15671       return -1;
15672     ttylastspeed = cps * 10;
15673     return 0;
15674 }
15675 
15676 int
15677 p9openttyctl(char *ttname) {
15678     char name[100];
15679 
15680     if (ttyctlfd >= 0) {
15681 	close(ttyctlfd);
15682 	ttyctlfd = -1;
15683 	ttylastspeed = -1;
15684     }
15685     sprintf(name, "%sctl", ttname);
15686     ttyctlfd = open(name, 1);
15687     return ttyctlfd;
15688 }
15689 
15690 int
15691 p9concb() {
15692     if (consctlfd >= 0) {
15693 	if (write(consctlfd, "rawon", 5) == 5)
15694 	  return 0;
15695     }
15696     return -1;
15697 }
15698 
15699 int
15700 p9conbin() {
15701     return p9concb();
15702 }
15703 
15704 int
15705 p9conres() {
15706     if (consctlfd >= 0) {
15707 	if (write(consctlfd, "rawoff", 6) == 6)
15708 	  return 0;
15709     }
15710     return -1;
15711 }
15712 
15713 int
15714 p9sndbrk(int msec) {
15715     if (ttyctlfd >= 0) {
15716 	char cmd[20];
15717 	int i = sprintf(cmd, "k%d", msec);
15718 	if (write(ttyctlfd, cmd, i) == i)
15719 	  return 0;
15720     }
15721     return -1;
15722 }
15723 
15724 int
15725 conwrite(char *buf, int n) {
15726     int x;
15727     static int length = 0;
15728     static int holdingcr = 0;
15729     int normal = 0;
15730     for (x = 0; x < n; x++) {
15731 	char c = buf[x];
15732 	if (c == 007) {
15733 	    if (normal) {
15734 		write(1, buf + (x - normal), normal);
15735 		length += normal;
15736 		normal = 0;
15737 	    }
15738 	    /* write(noisefd, "1000 300", 8); */
15739 	    holdingcr = 0;
15740 	} else if (c == '\r') {
15741 	    if (normal) {
15742 		write(1, buf + (x - normal), normal);
15743 		length += normal;
15744 		normal = 0;
15745 	    }
15746 	    holdingcr = 1;
15747 	} else if (c == '\n') {
15748 	    write(1, buf + (x - normal), normal + 1);
15749 	    normal = 0;
15750 	    length = 0;
15751 	    holdingcr = 0;
15752 	} else if (c == '\b') {
15753 	    if (normal) {
15754 		write(1, buf + (x - normal), normal);
15755 		length += normal;
15756 		normal = 0;
15757 	    }
15758 	    if (length) {
15759 		write(1, &c, 1);
15760 		length--;
15761 	    }
15762 	    holdingcr = 0;
15763 	} else {
15764 	    if (holdingcr) {
15765 		char b = '\b';
15766 		while (length-- > 0)
15767 		  write(1, &b, 1);
15768 		length = 0;	/* compiler bug */
15769 	    }
15770 	    holdingcr = 0;
15771 	    normal++;
15772 	}
15773     }
15774     if (normal) {
15775 	write(1, buf + (x - normal), normal);
15776 	length += normal;
15777     }
15778     return n;
15779 }
15780 
15781 void
15782 conprint(char *fmt, ...) {
15783     static char buf[1000];		/* not safe if on the stack */
15784 
15785     va_list ap;
15786     int i;
15787 
15788     va_start(ap, fmt);
15789     i = vsprintf(buf, fmt, ap);
15790     conwrite(buf, i);
15791 }
15792 #endif /* Plan9 */
15793 
15794 /* fprintf, printf, perror replacements... */
15795 
15796 /* f p r i n t f */
15797 
15798 #ifdef UNIX
15799 #ifdef CK_ANSIC
15800 #include <stdarg.h>
15801 #else /* CK_ANSIC */
15802 #ifdef __GNUC__
15803 #include <stdarg.h>
15804 #else
15805 #include <varargs.h>
15806 #endif	/* __GNUC__ */
15807 #endif /* CK_ANSIC */
15808 #ifdef fprintf
15809 #undef fprintf
15810 static char str1[4096];
15811 static char str2[4096];
15812 int
15813 #ifdef CK_ANSIC
15814 ckxfprintf(FILE * file, const char * format, ...)
15815 #else /* CK_ANSIC */
15816 ckxfprintf(va_alist) va_dcl
15817 #endif /* CK_ANSIC */
15818 /* ckxfprintf */ {
15819     int i, j, len, got_cr;
15820     va_list args;
15821     int rc = 0;
15822 
15823 #ifdef CK_ANSIC
15824     va_start(args, format);
15825 #else /* CK_ANSIC */
15826     char * format;
15827     FILE * file;
15828     va_start(args);
15829     file = va_arg(args,FILE *);
15830     format = va_arg(args,char *);
15831 #endif /* CK_ANSIC */
15832 
15833     if (!inserver || (file != stdout && file != stderr && file != stdin)) {
15834 	rc = vfprintf(file,format,args);
15835     } else {
15836 	unsigned int c;
15837         rc = vsprintf(str1, format, args);
15838         len = strlen(str1);
15839         if (len >= sizeof(str1)) {
15840             debug(F101,"ckxfprintf() buffer overflow","",len);
15841             doexit(BAD_EXIT,1);
15842         }
15843         for (i = 0, j = 0, got_cr = 0;
15844 	     i < len && j < sizeof(str1)-2;
15845 	     i++, j++ ) {
15846 	    /* We can't use 255 as a case label because of signed chars */
15847 	    c = (unsigned)(str1[i] & 0xff);
15848 #ifdef TNCODE
15849 	    if (c == 255) {
15850 		if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15851 		  str2[j++] = '\0';
15852 		str2[j++] = IAC;
15853 		str2[j] = IAC;
15854 		got_cr = 0;
15855 	    } else
15856 #endif /* TNCODE */
15857 	    switch (c) {
15858 	      case '\r':
15859                 if (got_cr
15860 #ifdef TNCODE
15861 		    && !TELOPT_ME(TELOPT_BINARY)
15862 #endif /* TNCODE */
15863 		    )
15864 		  str2[j++] = '\0';
15865                 str2[j] = str1[i];
15866                 got_cr = 1;
15867                 break;
15868 	      case '\n':
15869                 if (!got_cr)
15870 		  str2[j++] = '\r';
15871                 str2[j] = str1[i];
15872                 got_cr = 0;
15873                 break;
15874 	      default:
15875                 if (got_cr
15876 #ifdef TNCODE
15877 		    && !TELOPT_ME(TELOPT_BINARY)
15878 #endif /* TNCODE */
15879 		    )
15880 		  str2[j++] = '\0';
15881                 str2[j] = str1[i];
15882                 got_cr = 0;
15883             }
15884         }
15885         if (got_cr
15886 #ifdef TNCODE
15887              && !TELOPT_ME(TELOPT_BINARY)
15888 #endif /* TNCODE */
15889              )
15890             str2[j++] = '\0';
15891 #ifdef CK_ENCRYPTION
15892 #ifdef TNCODE
15893         if (TELOPT_ME(TELOPT_ENCRYPTION))
15894 	  ck_tn_encrypt(str2,j);
15895 #endif /* TNCODE */
15896 #endif /* CK_ENCRYPTION */
15897 #ifdef CK_SSL
15898 	if (inserver && (ssl_active_flag || tls_active_flag)) {
15899 	    /* Write using SSL */
15900             char * p = str2;
15901           ssl_retry:
15902             if (ssl_active_flag)
15903 	      rc = SSL_write(ssl_con, p, j);
15904             else
15905 	      rc = SSL_write(tls_con, p, j);
15906 	    debug(F111,"ckxfprintf","SSL_write",rc);
15907             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
15908 	      case SSL_ERROR_NONE:
15909                 if (rc == j)
15910 		  break;
15911                 p += rc;
15912                 j -= rc;
15913                 goto ssl_retry;
15914 	      case SSL_ERROR_WANT_WRITE:
15915 	      case SSL_ERROR_WANT_READ:
15916 	      case SSL_ERROR_SYSCALL:
15917                 if (rc != 0)
15918 		  return(-1);
15919 	      case SSL_ERROR_WANT_X509_LOOKUP:
15920 	      case SSL_ERROR_SSL:
15921 	      case SSL_ERROR_ZERO_RETURN:
15922 	      default:
15923                 rc = 0;
15924             }
15925 	} else
15926 #endif /* CK_SSL */
15927         fwrite(str2,sizeof(char),j,stdout);
15928     }
15929     va_end(args);
15930     return(rc);
15931 }
15932 #endif /* fprintf */
15933 
15934 /* p r i n t f */
15935 
15936 #ifdef printf
15937 #undef printf
15938 int
15939 #ifdef CK_ANSIC
15940 ckxprintf(const char * format, ...)
15941 #else /* CK_ANSIC */
15942 ckxprintf(va_alist) va_dcl
15943 #endif /* CK_ANSIC */
15944 /* ckxprintf */ {
15945     int i, j, len, got_cr;
15946     va_list args;
15947     int rc = 0;
15948 
15949 #ifdef CK_ANSIC
15950     va_start(args, format);
15951 #else /* CK_ANSIC */
15952     char * format;
15953     va_start(args);
15954     format = va_arg(args,char *);
15955 #endif /* CK_ANSIC */
15956 
15957     if (!inserver) {
15958 	rc = vprintf(format, args);
15959     } else {
15960 	unsigned int c;
15961         rc = vsprintf(str1, format, args);
15962         len = strlen(str1);
15963         if (len >= sizeof(str1)) {
15964             debug(F101,"ckxprintf() buffer overflow","",len);
15965             doexit(BAD_EXIT,1);
15966         }
15967         for (i = 0, j = 0, got_cr=0;
15968 	     i < len && j < sizeof(str1)-2;
15969 	     i++, j++ ) {
15970 	    c = (unsigned)(str1[i] & 0xff);
15971 #ifdef TNCODE
15972 	    if (c == 255) {
15973 		if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15974 		  str2[j++] = '\0';
15975 		str2[j++] = IAC;
15976 		str2[j] = IAC;
15977 		got_cr = 0;
15978 	    } else
15979 #endif /* TNCODE */
15980 	    switch (c) {
15981 	      case '\r':
15982                 if (got_cr
15983 #ifdef TNCODE
15984 		    && !TELOPT_ME(TELOPT_BINARY)
15985 #endif /* TNCODE */
15986 		    )
15987 		  str2[j++] = '\0';
15988                 str2[j] = str1[i];
15989                 got_cr = 1;
15990                 break;
15991 	      case '\n':
15992                 if (!got_cr)
15993 		  str2[j++] = '\r';
15994                 str2[j] = str1[i];
15995                 got_cr = 0;
15996                 break;
15997 	      default:
15998                 if (got_cr
15999 #ifdef TNCODE
16000 		    && !TELOPT_ME(TELOPT_BINARY)
16001 #endif /* TNCODE */
16002 		    )
16003 		  str2[j++] = '\0';
16004                 str2[j] = str1[i];
16005                 got_cr = 0;
16006                 break;
16007 	    }
16008         }
16009         if (got_cr
16010 #ifdef TNCODE
16011              && !TELOPT_ME(TELOPT_BINARY)
16012 #endif /* TNCODE */
16013              )
16014             str2[j++] = '\0';
16015 #ifdef CK_ENCRYPTION
16016 #ifdef TNCODE
16017         if (TELOPT_ME(TELOPT_ENCRYPTION))
16018 	  ck_tn_encrypt(str2,j);
16019 #endif /* TNCODE */
16020 #endif /* CK_ENCRYPTION */
16021 #ifdef CK_SSL
16022 	if (inserver && (ssl_active_flag || tls_active_flag)) {
16023             char * p = str2;
16024 	    /* Write using SSL */
16025           ssl_retry:
16026             if (ssl_active_flag)
16027 	      rc = SSL_write(ssl_con, p, j);
16028             else
16029 	      rc = SSL_write(tls_con, p, j);
16030 	    debug(F111,"ckxprintf","SSL_write",rc);
16031             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
16032 	      case SSL_ERROR_NONE:
16033                 if (rc == j)
16034 		  break;
16035                 p += rc;
16036                 j -= rc;
16037                 goto ssl_retry;
16038 	      case SSL_ERROR_WANT_WRITE:
16039 	      case SSL_ERROR_WANT_READ:
16040 	      case SSL_ERROR_SYSCALL:
16041                 if (rc != 0)
16042 		  return(-1);
16043 	      case SSL_ERROR_WANT_X509_LOOKUP:
16044 	      case SSL_ERROR_SSL:
16045 	      case SSL_ERROR_ZERO_RETURN:
16046 	      default:
16047                 rc = 0;
16048             }
16049 	} else
16050 #endif /* CK_SSL */
16051 	  rc = fwrite(str2,sizeof(char),j,stdout);
16052     }
16053     va_end(args);
16054     return(rc);
16055 }
16056 #endif /* printf */
16057 
16058 /*  p e r r o r  */
16059 
16060 #ifdef perror
16061 #undef perror
16062 _PROTOTYP(char * ck_errstr,(VOID));
16063 #ifdef NEXT
16064 void
16065 #else
16066 #ifdef CK_SCOV5
16067 void
16068 #else
16069 int
16070 #endif /* CK_SCOV5 */
16071 #endif /* NEXT */
16072 #ifdef CK_ANSIC
16073 ckxperror(const char * str)
16074 #else /* CK_ANSIC */
16075 ckxperror(str) char * str;
16076 #endif /* CK_ANSIC */
16077 /* ckxperror */ {
16078     char * errstr = ck_errstr();
16079 #ifndef NEXT
16080 #ifndef CK_SCOV5
16081     return
16082 #endif /* CK_SCOV5 */
16083 #endif /* NEXT */
16084       ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
16085 }
16086 #endif /* perror */
16087 #endif /* UNIX */
16088 
16089 #ifdef MINIX2
16090 
16091 /* Minix doesn't have a gettimeofday call (but MINIX3 does).
16092  * We fake one here using time(2)
16093  */
16094 
16095 #ifndef MINIX3
16096 int
16097 gettimeofday(struct timeval *tp, struct timezone *tzp) {
16098     tp->tv_usec = 0L;			/* Close enough for horseshoes */
16099     if(time(&(tp->tv_sec))==-1)
16100       return(-1);
16101     return(0);
16102 }
16103 #endif	/* MINIX3 */
16104 
16105 #ifndef MINIX3
16106 int
16107 readlink(const char *path, void *buf, size_t bufsiz) {
16108     errno = ENOSYS;
16109     return(-1);
16110 }
16111 #endif	/* MINIX3 */
16112 
16113 #endif /* MINIX2 */
16114