Imported Upstream version 302
[ckermit.git] / ckutio.c
1 #define CKUTIO_C
2
3 #ifdef aegis
4 char *ckxv = "Aegis Communications support, 9.0.326, 20 August 2011";
5 #else
6 #ifdef Plan9
7 char *ckxv = "Plan 9 Communications support, 9.0.326, 20 August 2011";
8 #else
9 char *ckxv = "UNIX Communications support, 9.0.326, 20 August 2011";
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   Columbia University Academic Information Systems, New York City.
20
21   Copyright (C) 1985, 2011,
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
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  */
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 *
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
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
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
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
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
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
1706 le_clean() {                            /* LocalEchoCleanup() */
1707     le_init();
1708     return;
1709 }
1710
1711 int
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
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
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
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
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
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
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
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
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
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
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     if (!cttnam[0])
2178       ctermid(cttnam);
2179 #endif /* SVORPOSIX */
2180     if (!cttnam[0])
2181       ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
2182     debug(F110,"sysinit CTTNAM",CTTNAM,0);
2183     debug(F110,"sysinit cttnam",cttnam,0);
2184
2185     ttgwsiz();                          /* Get window (screen) dimensions. */
2186
2187 #ifndef NOSYSCONF
2188 #ifdef _SC_OPEN_MAX
2189     ckmaxfiles = sysconf(_SC_OPEN_MAX);
2190 #endif /* _SC_OPEN_MAX */
2191 #endif /* NOSYSCONF */
2192
2193 #ifdef Plan9
2194     if (!backgrd) {
2195         consctlfd = open("/dev/consctl", O_WRONLY);
2196         /*noisefd = open("/dev/noise", O_WRONLY)*/
2197     }
2198     ckxech = 1;
2199 #endif /* Plan9 */
2200
2201 #ifdef CK_UTSNAME
2202     if (uname(&name) > -1) {
2203         ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
2204         ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
2205         ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
2206         ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
2207 #ifdef DEBUG
2208         if (deblog) {
2209             debug(F110,"sysinit uname machine",unm_mch,0);
2210             debug(F110,"sysinit uname sysname",unm_nam,0);
2211             debug(F110,"sysinit uname release",unm_rel,0);
2212             debug(F110,"sysinit uname version",unm_ver,0);
2213         }
2214 #endif /* DEBUG */
2215
2216 #ifdef HPUX9PLUS
2217         if (name.machine[5] == '8')
2218           hpis800 = 1;
2219         else
2220           hpis800 = 0;
2221         debug(F101,"sysinit hpis800","",hpis800);
2222 #endif /* HPUX9PLUS */
2223 #ifdef TRU64
2224         getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
2225         debug(F110,"sysinit getsysinfo model",unm_mod,0);
2226 #endif /* TRU64 */
2227 #ifdef SOLARIS25
2228         sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
2229         debug(F110,"sysinit sysinfo model",unm_mod,0);
2230 #endif /* SOLARIS25 */
2231     }
2232 #endif /* CK_UTSNAME */
2233
2234 #ifdef CK_ENVIRONMENT
2235     {
2236 #ifdef TNCODE
2237         extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
2238         tn_env_prnt[], tn_env_sys[];
2239 #endif /* TNCODE */
2240         extern char uidbuf[];
2241         extern char * whoami();
2242         char *p;
2243 #ifdef CKSENDUID
2244         uidbuf[0] = '\0';
2245 #ifdef IKSD
2246         if (!inserver) {
2247 #endif /* IKSD */
2248             p = getenv("USER");
2249             debug(F110,"sysinit uidbuf from USER",uidbuf,0);
2250             if (!p) p = "";
2251             if (!*p) {
2252                 p = getenv("LOGNAME");
2253                 debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
2254             }
2255             if (!p) p = "";
2256             if (!*p) {
2257                 p = whoami();
2258                 debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
2259             }
2260             if (!p) p = "";
2261             ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
2262 #ifdef IKSD
2263         }
2264 #endif /* IKSD */
2265         debug(F110,"sysinit final uidbuf",uidbuf,0);
2266 #endif /* CKSENDUID */
2267
2268 #ifdef TNCODE
2269         if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
2270         if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
2271         if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
2272         if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
2273 #ifdef aegis
2274         ckstrncpy(tn_env_sys,"Aegis",64);
2275 #else
2276 #ifdef Plan9
2277         ckstrncpy(tn_env_sys,"Plan9",64);
2278 #else
2279         ckstrncpy(tn_env_sys,"UNIX",64);
2280 #endif /* Plan9 */
2281 #endif /* aegis */
2282 #endif /* TNCODE */
2283     }
2284 #endif /* CK_ENVIRONMENT */
2285 #ifdef CK_SNDLOC
2286     {
2287         extern char * tn_loc;
2288         char *p;
2289         if (p = getenv("LOCATION"))
2290           if (tn_loc = (char *)malloc((int)strlen(p)+1))
2291             strcpy(tn_loc,p);           /* safe */
2292     }
2293 #endif /* CK_SNDLOC */
2294
2295     ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
2296     startupdir[CKMAXPATH] = '\0';
2297     x = strlen(startupdir);
2298     if (x <= 0) {
2299         startupdir[0] = '/';
2300         startupdir[1] = '\0';
2301     } else if (startupdir[x-1] != '/') {
2302         startupdir[x] = '/';
2303         startupdir[x+1] = '\0';
2304     }
2305     debug(F110,"sysinit startupdir",startupdir,0);
2306 #ifdef TTLEBUF
2307     le_init();
2308 #endif /* TTLEBUF */
2309 #ifdef BSD44ORPOSIX
2310     /* This should catch the ncurses platforms */
2311     /* Some platforms don't have putenv(), like NeXTSTEP */
2312     putenv("NCURSES_NO_SETBUF=1");
2313 #endif /* BSD44ORPOSIX */
2314     return(0);
2315 }
2316
2317 /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
2318
2319 int
2320 syscleanup() {
2321 #ifdef F_SETFL
2322     if (iniflags > -1)
2323       fcntl(0,F_SETFL,iniflags);        /* Restore stdin flags */
2324 #endif /* F_SETFL */
2325 #ifdef ultrix
2326     stty(0,&vanilla);                   /* Get sgtty info */
2327 #endif /* ultrix */
2328 #ifdef NETCMD
2329     if (ttpid) kill(ttpid,9);
2330 #endif /* NETCMD */
2331     return(0);
2332 }
2333
2334 /*  T T O P E N  --  Open a tty for exclusive access.  */
2335
2336 /*
2337   Call with:
2338     ttname: character string - device name or network host name.
2339     lcl:
2340   If called with lcl < 0, sets value of lcl as follows:
2341   0: the terminal named by ttname is the job's controlling terminal.
2342   1: the terminal named by ttname is not the job's controlling terminal.
2343   But watch out: if a line is already open, or if requested line can't
2344   be opened, then lcl remains (and is returned as) -1.
2345     modem:
2346   Less than zero: ttname is a network host name.
2347   Zero or greater: ttname is a terminal device name.
2348   Zero means a local connection (don't use modem signals).
2349   Positive means use modem signals.
2350    timo:
2351   0 = no timer.
2352   nonzero = number of seconds to wait for open() to return before timing out.
2353
2354   Returns:
2355     0 on success
2356    -5 if device is in use
2357    -4 if access to device is denied
2358    -3 if access to lock directory denied
2359    -2 upon timeout waiting for device to open
2360    -1 on other error
2361 */
2362 static int ttotmo = 0;                  /* Timeout flag */
2363 /* Flag kept here to avoid being clobbered by longjmp.  */
2364
2365 int
2366 ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
2367
2368 #ifdef BSD44
2369 #define ctermid(x) strcpy(x,"")
2370 #else
2371 #ifdef SVORPOSIX
2372 #ifndef CIE
2373     extern char *ctermid();             /* Wish they all had this! */
2374 #else                                   /* CIE Regulus */
2375 #define ctermid(x) strcpy(x,"")
2376 #endif /* CIE */
2377 #endif /* SVORPOSIX */
2378 #endif /* BSD44 */
2379
2380 #ifdef ultrix
2381     int temp = 0;
2382 #endif /* ultrix */
2383
2384 #ifndef OPENFIRST
2385     char fullname[DEVNAMLEN+1];
2386 #endif /* OPENFIRST */
2387
2388     char * fnam;                        /* Full name after expansion */
2389
2390     int y;
2391
2392 #ifndef pdp11
2393 #define NAMEFD   /* Feature to allow name to be an open file descriptor */
2394 #endif /* pdp11 */
2395
2396 #ifdef NAMEFD
2397     char *p;
2398     debug(F101,"ttopen telnetfd","",telnetfd);
2399 #endif /* NAMEFD */
2400
2401     debug(F110,"ttopen ttname",ttname,0);
2402     debug(F110,"ttopen ttnmsv",ttnmsv,0);
2403     debug(F101,"ttopen modem","",modem);
2404     debug(F101,"ttopen netconn","",netconn);
2405     debug(F101,"ttopen ttyfd","",ttyfd);
2406     debug(F101,"ttopen *lcl","",*lcl);
2407     debug(F101,"ttopen ttmdm","",ttmdm);
2408     debug(F101,"ttopen ttnet","",ttnet);
2409
2410     ttpmsk = 0xff;
2411     lockpid[0] = '\0';
2412
2413     if (ttyfd > -1) {                   /* If device already opened */
2414         if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
2415           return(0);                    /* Yes, nothing to do - just return */
2416         ttnmsv[0] = '\0';               /* No, clear out old name */
2417         ttclos(ttyfd);                  /* close old connection.  */
2418     }
2419     wasclosed = 0;                      /* New connection, not closed yet. */
2420     ttpipe = 0;                         /* Assume it's not a pipe */
2421     ttpty = 0;                          /* or a pty... */
2422
2423 #ifdef NETCONN
2424 /*
2425   This is a bit tricky...  Suppose that previously Kermit had dialed a telnet
2426   modem server ("set host xxx:2001, set modem type usr, dial ...").  Then the
2427   connection was closed (ttyfd = -1), and then a REDIAL command was given.  At
2428   this point we've obliterated the negative modem type hack, and so would
2429   treat the IP hostname as a device name, and would then fail because of "No
2430   such device or directory".  But the previous connection has left behind some
2431   clues, so let's use them...
2432 */
2433     if (ttyfd < 0) {                    /* Connection is not open */
2434         if (!strcmp(ttname,ttnmsv)) {   /* Old and new names the same? */
2435             if (((netconn > 0) && (ttmdm < 0)) ||
2436                 ((ttnet > 0) &&
2437                  (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
2438                 ) {
2439                 int x, rc;
2440                 x = (ttmdm < 0) ? -ttmdm : ttnet;
2441                 rc = netopen(ttname, lcl, x);
2442                 debug(F111,"ttopen REOPEN netopen",ttname,rc);
2443                 if (rc > -1) {
2444                     netconn = 1;
2445                     xlocal = *lcl = 1;
2446                 } else {
2447                     netconn = 0;
2448                 }
2449                 gotsigs = 0;
2450                 return(rc);
2451             }
2452         }
2453     }
2454 #endif /* NETCONN */
2455
2456 #ifdef MAXNAMLEN
2457     debug(F100,"ttopen MAXNAMLEN defined","",0);
2458 #else
2459     debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
2460 #endif
2461
2462 #ifdef BSD4
2463     debug(F100,"ttopen BSD4 defined","",0);
2464 #else
2465     debug(F100,"ttopen BSD4 *NOT* defined","",0);
2466 #endif /* BSD4 */
2467
2468 #ifdef BSD42
2469     debug(F100,"ttopen BSD42 defined","",0);
2470 #else
2471     debug(F100,"ttopen BSD42 *NOT* defined","",0);
2472 #endif /* BSD42 */
2473
2474 #ifdef MYREAD
2475     debug(F100,"ttopen MYREAD defined","",0);
2476 #else
2477     debug(F100,"ttopen MYREAD *NOT* defined","",0);
2478 #endif /* MYREAD */
2479
2480 #ifdef  NETCONN
2481     if (modem < 0) {                    /* modem < 0 = code for network */
2482         int x;
2483         ttmdm = modem;
2484         modem = -modem;                 /* Positive network type number */
2485         fdflag = 0;                     /* Stdio not redirected. */
2486         netconn = 1;                    /* And it's a network connection */
2487         debug(F111,"ttopen net",ttname,modem);
2488 #ifdef NAMEFD
2489         for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
2490         if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
2491             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2492             ttfdflg = 1;                /* We got an open file descriptor */
2493             debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
2494             debug(F101,"ttopen net ttyfd","",ttyfd);
2495             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2496             x = 1;                      /* Return code is "good". */
2497             if (telnetfd) {
2498                 ttnet = NET_TCPB;
2499                 if (ttnproto != NP_TCPRAW)
2500                   ttnproto = NP_TELNET;
2501 #ifdef SUNX25
2502             } else if (x25fd) {
2503                 ttnet = NET_SX25;
2504                 ttnproto = NP_NONE;
2505 #endif /* SUNX25 */
2506             }
2507         } else {                        /* Host name or address given */
2508 #ifdef NETPTY
2509             if (modem == NET_PTY) {
2510                 int x;
2511                 if (nopush) {
2512                     debug(F100,"ttopen PTY: nopush","",0);
2513                     return(-1);
2514                 }
2515                 ttnet = NET_PTY;
2516                 ttnproto = NP_NONE;
2517                 netconn = 1;            /* but we don't use network i/o */
2518                 ttpty = 1;
2519                 debug(F110,"ttopen PTY",ttname,0);
2520                 x = do_pty(&ttyfd,ttname,0);
2521                 if (x > -1) {
2522                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2523                     xlocal = *lcl = 1;  /* It's local */
2524                 } else {
2525                     ttpty = 0;
2526                     netconn = 0;
2527                 }
2528                 gotsigs = 0;
2529                 return(x);
2530             }
2531 #endif /* NETPTY */
2532 #ifdef NETCMD
2533 /*
2534   dup2() is not available on older System V platforms like AT&T 3Bx.  For
2535   those systems we punt by not defining NETCMD, but we might be able to do
2536   better -- see workarounds for this problem in ckufio.c (search for dup2).
2537 */
2538             if (modem == NET_CMD) {
2539                 if (nopush) {
2540                     debug(F100,"ttopen pipe: nopush","",0);
2541                     return(-1);
2542                 }
2543                 if (pipe(pipe0) || pipe(pipe1)) {
2544                     perror("Pipe error");
2545                     return(-1);
2546                 }
2547                 ttpid = fork();         /* Make a fork */
2548
2549                 switch (ttpid) {
2550                   case -1:              /* Error making fork */
2551                     close(pipe0[0]);
2552                     close(pipe0[1]);
2553                     close(pipe1[0]);
2554                     close(pipe1[1]);
2555                     perror("Fork error");
2556                     return(-1);
2557                   case 0:               /* Child. */
2558                     close(pipe0[0]);
2559                     close(pipe1[1]);
2560                     dup2(pipe0[1], 1);
2561                     close(pipe0[1]);
2562                     dup2(pipe1[0], 0);
2563                     close(pipe1[0]);
2564                     system(ttname);
2565                     _exit(0);
2566                   default:              /* Parent */
2567                     close(pipe0[1]);
2568                     close(pipe1[0]);
2569                     fdin = pipe0[0];    /* Read from pipe */
2570                     fdout = pipe1[1];   /* Write to pipe */
2571                     ttout = fdopen(fdout,"w"); /* Get stream so we can */
2572                     if (!ttout) {       /* make it unbuffered. */
2573                         perror("fdopen failure");
2574                         return(-1);
2575                     }
2576                     setbuf(ttout,NULL);
2577                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2578                     xlocal = *lcl = 1;  /* It's local */
2579                     netconn = 1;        /* Call it a network connection */
2580                     ttmdm = modem;      /* Remember network type */
2581                     ttyfd = fdin;
2582                     ttpipe = 1;
2583                     gotsigs = 0;
2584                     return(0);
2585                 }
2586             }
2587 #endif /* NETCMD */
2588 #endif /* NAMEFD */
2589             x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
2590             if (x > -1) {
2591                 ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2592             } else netconn = 0;
2593 #ifdef NAMEFD
2594         }
2595 #endif /* NAMEFD */
2596
2597 #ifdef sony_news                        /* Sony NEWS */
2598         if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
2599             perror("ttopen error getting Kanji mode (network)");
2600             debug(F111,"ttopen error getting Kanji mode","network",0);
2601             km_ext = -1;                /* Make sure this stays undefined. */
2602         }
2603 #endif /* sony_news */
2604
2605         xlocal = *lcl = 1;              /* Network connections are local. */
2606         debug(F101,"ttopen net x","",x);
2607 #ifdef COMMENT
2608 /* Let netopen() do this */
2609         if (x > -1 && !x25fd)
2610           x = tn_ini();                 /* Initialize TELNET protocol */
2611 #endif /* COMMENT */
2612         gotsigs = 0;
2613         return(x);
2614     } else {                            /* Terminal device */
2615 #endif  /* NETCONN */
2616
2617 #ifdef NAMEFD
2618 /*
2619   This code lets you give Kermit an open file descriptor for a serial
2620   communication device, rather than a device name.  Kermit assumes that the
2621   line is already open, locked, conditioned with the right parameters, etc.
2622 */
2623         for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
2624         if (*p == '\0') {
2625             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2626             debug(F111,"ttopen got open fd",ttname,ttyfd);
2627             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2628             if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
2629               xlocal = *lcl = 0;        /* we're in remote mode */
2630             else                        /* otherwise */
2631               xlocal = *lcl = 1;        /* local mode. */
2632             netconn = 0;                /* Assume it's not a network. */
2633             tvtflg = 0;                 /* Might need to initialize modes. */
2634             ttmdm = modem;              /* Remember modem type. */
2635             fdflag = 0;                 /* Stdio not redirected. */
2636             ttfdflg = 1;                /* Flag we were opened this way. */
2637             debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
2638             debug(F101,"ttopen non-net ttyfd","",ttyfd);
2639
2640 #ifdef sony_news                        /* Sony NEWS */
2641             /* Get device Kanji mode */
2642             if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
2643                 perror("ttopen error getting Kanji mode");
2644                 debug(F101,"ttopen error getting Kanji mode","",0);
2645                 km_ext = -1;            /* Make sure this stays undefined. */
2646             }
2647 #endif /* sony_news */
2648             gotsigs = 0;
2649             return(0);                  /* Return success */
2650         }
2651 #endif /* NAMEFD */
2652 #ifdef NETCONN
2653     }
2654 #endif /* NETCONN */
2655
2656 /* Here we have to open a serial device of the given name. */
2657
2658     netconn = 0;                        /* So it's not a network connection */
2659     occt = signal(SIGINT, cctrap);      /* Set Control-C trap, save old one */
2660     sigint_ign = 0;
2661
2662     tvtflg = 0;                 /* Flag for use by ttvt(). */
2663                                 /* 0 = ttvt not called yet for this device */
2664
2665     fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
2666     debug(F101,"ttopen fdflag","",fdflag);
2667
2668     ttmdm = modem;                      /* Make this available to other fns */
2669     xlocal = *lcl;                      /* Make this available to other fns */
2670
2671 /* Code for handling bidirectional tty lines goes here. */
2672 /* Use specified method for turning off logins and suppressing getty. */
2673
2674 #ifdef ACUCNTRL
2675     /* Should put call to priv_on() here, but that would be very risky! */
2676     acucntrl("disable",ttname);         /* acucntrl() program. */
2677     /* and priv_off() here... */
2678 #else
2679 #ifdef ATT7300
2680     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
2681       attmodem |= offgetty(ttname);     /* Remember response.  */
2682 #endif /* ATT7300 */
2683 #endif /* ACUCNTRL */
2684
2685 #ifdef OPENFIRST
2686 /*
2687  1985-2001: opens device first then gets lock; reason:
2688  Kermit usually has to run setuid or setgid in order to create a lockfile.
2689  If you give a SET LINE command for a device that happens to be your job's
2690  controlling terminal, Kermit doesn't have to create a lockfile, and in fact
2691  should not create one, and would fail if it tried to if it did not have the
2692  required privileges.  But you can't find out if two tty device names are
2693  equivalent until you have a file descriptor that you can give to ttyname().
2694  But this can cause a race condition between Kermit and [m]getty.  So see
2695  the [#]else part...
2696 */ 
2697
2698 /*
2699  In the following section, we open the tty device for read/write.
2700  If a modem has been specified via "set modem" prior to "set line"
2701  then the O_NDELAY parameter is used in the open, provided this symbol
2702  is defined (e.g. in fcntl.h), so that the program does not hang waiting
2703  for carrier (which in most cases won't be present because a connection
2704  has not been dialed yet).  O_NDELAY is removed later on in ttopen().  It
2705  would make more sense to first determine if the line is local before
2706  doing this, but because ttyname() requires a file descriptor, we have
2707  to open it first.  See do_open().
2708
2709  Now open the device using the desired treatment of carrier.
2710  If carrier is REQUIRED, then open could hang forever, so an optional
2711  timer is provided.  If carrier is not required, the timer should never
2712  go off, and should do no harm...
2713 */
2714     ttotmo = 0;                         /* Flag no timeout */
2715     debug(F101,"ttopen timo","",timo);
2716     debug(F101,"ttopen xlocal","",xlocal);
2717     if (timo > 0) {
2718         int xx;
2719         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2720         xx = alarm(timo);               /* Timed open() */
2721         debug(F101,"ttopen alarm","",xx);
2722         if (
2723 #ifdef CK_POSIX_SIG
2724             sigsetjmp(sjbuf,1)
2725 #else
2726             setjmp(sjbuf)
2727 #endif /* CK_POSIX_SIG */
2728             ) {
2729             ttotmo = 1;                 /* Flag timeout. */
2730         } else ttyfd = do_open(ttname);
2731         ttimoff();
2732         debug(F111,"ttopen","modem",modem);
2733         debug(F101,"ttopen ttyfd","",ttyfd);
2734         debug(F101,"ttopen alarm return","",ttotmo);
2735     } else {
2736         errno = 0;
2737         ttyfd = do_open(ttname);
2738     }
2739     debug(F111,"ttopen ttyfd",ttname,ttyfd);
2740     if (ttyfd < 0) {                    /* If couldn't open, fail. */
2741         debug(F101,"ttopen errno","",errno);
2742         if (errno > 0 && !quiet)
2743           perror(ttname);               /* Print message */
2744
2745 #ifdef ATT7300
2746         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
2747           ongetty(ttnmsv);              /* yes, restart on tty line */
2748         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
2749 #else
2750 #ifdef ACUCNTRL
2751         /* Should put call to priv_on() here, but that would be risky! */
2752         acucntrl("enable",ttname);      /* acucntrl() program. */
2753         /* and priv_off() here... */
2754 #endif /* ACUNTRL */
2755 #endif /* ATT7300 */
2756
2757         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
2758         if (errno == EACCES) {          /* Device is protected against user */
2759             debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
2760             return(-4);
2761         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
2762     }
2763
2764 #ifdef QNX
2765     {
2766         extern int qnxportlock;
2767         x = qnxopencount();
2768         debug(F101,"ttopen qnxopencount","",x);
2769         debug(F101,"ttopen qnxportlock","",qnxportlock);
2770         if (x < 0 && qnxportlock) {
2771             ttclos(0);
2772             printf("?Can't get port open count\n");
2773             printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
2774             return(-1);                 /* Indicate device is in use */
2775         }
2776         if (x > 1) {                    /* 1 == me */
2777             if (qnxportlock)
2778               ttclos(0);
2779               return(-2);               /* Indicate device is in use */
2780             else if (!quiet)
2781               printf("WARNING: \"%s\" looks busy...\n",ttdev);
2782         }
2783     }
2784 #endif /* QNX */
2785
2786 #ifdef Plan9
2787     /* take this opportunity to open the control channel */
2788     if (p9openttyctl(ttname) < 0)
2789 #else
2790     /* Make sure it's a real tty. */
2791     if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
2792 #endif /* Plan9 */
2793       {
2794         fprintf(stderr,"%s is not a terminal device\n",ttname);
2795         debug(F111,"ttopen not a tty",ttname,errno);
2796         close(ttyfd);
2797         ttyfd = -1;
2798         wasclosed = 1;
2799         signal(SIGINT,occt);
2800         return(-1);
2801     }
2802
2803 #ifdef aegis
2804         /* Apollo C runtime claims that console pads are tty devices, which
2805          * is reasonable, but they aren't any good for packet transfer. */
2806         ios_$inq_type_uid((short)ttyfd, ttyuid, st);
2807         if (st.all != status_$ok) {
2808             fprintf(stderr, "problem getting tty object type: ");
2809             error_$print(st);
2810         } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
2811             close(ttyfd); ttyfd = -1;
2812             wasclosed = 1;
2813             errno = ENOTTY; perror(ttname);
2814             signal(SIGINT,occt);
2815             return(-1);
2816         }
2817 #endif /* aegis */
2818
2819     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2820
2821     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
2822
2823 /* Caller wants us to figure out if line is controlling tty */
2824
2825     if (*lcl < 0) {
2826         if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
2827             xlocal = 0;
2828             debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
2829         } else if (strcmp(ttname,cttnam) == 0) {
2830             xlocal = 0;
2831             debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
2832         } else if (cttnam[0]) {
2833 #ifdef BEBOX_DR7
2834             x = ttnmsv;                 /* ttyname() is broken */
2835 #else
2836             x = ttyname(ttyfd);         /* Get real name of ttname. */
2837 #endif /* BEBOX_DR7 */
2838             if (!x) x = "";
2839             if (*x)
2840               xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
2841             else
2842               xlocal = 1;
2843             debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
2844         }
2845     }
2846
2847 #ifndef NOFDZERO
2848 /* Note, the following code was added so that Unix "idle-line" snoopers */
2849 /* would not think Kermit was idle when it was transferring files, and */
2850 /* maybe log people out. */
2851     if (xlocal == 0) {                  /* Remote mode */
2852         if (fdflag == 0) {              /* Standard i/o is not redirected */
2853             debug(F100,"ttopen setting ttyfd = 0","",0);
2854 #ifdef LYNXOS
2855             /* On Lynx OS, fd 0 is open for read only. */
2856             dup2(ttyfd,0);
2857 #endif /* LYNXOS */
2858             close(ttyfd);               /* Use file descriptor 0 */
2859             ttyfd = 0;
2860         } else {                        /* Standard i/o is redirected */
2861             debug(F101,"ttopen stdio redirected","",ttyfd);
2862         }
2863     }
2864 #endif /* NOFDZERO */
2865
2866 /* Now check if line is locked -- if so fail, else lock for ourselves */
2867 /* Note: After having done this, don't forget to delete the lock if you */
2868 /* leave ttopen() with an error condition. */
2869
2870     lkf = 0;                            /* Check lock */
2871     if (xlocal > 0) {
2872         int xx; int xpid;
2873         if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
2874             debug(F111,"ttopen ttlock fails",ttname,xx);
2875             /* WARNING - This close() can hang if tty is an empty socket... */
2876             close(ttyfd);               /* Close the device. */
2877             ttyfd = -1;                 /* Erase its file descriptor. */
2878             wasclosed = 1;
2879             signal(SIGINT,occt);        /* Put old SIGINT back. */
2880             sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2881             if (xx == -2) {             /* If lockfile says device in use, */
2882 #ifndef NOUUCP
2883                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2884                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2885                 if (xpid > -1) {        /* If we got a pid */
2886                     if (!quiet)
2887                       printf("Locked by process %d\n",xpid); /* tell them. */
2888                     sprintf(lockpid,"%d",xpid); /* Record it too */
2889                     debug(F110,"ttopen lockpid",lockpid,0);
2890                 } else if (*flfnam) {
2891                     extern char *DIRCMD;
2892                     char *p = NULL;
2893                     int x;
2894                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2895                     p = malloc(x);      /* Print a directory listing. */
2896 /*
2897   Note: priv_on() won't help here, because we do not pass privs along to
2898   to inferior processes, in this case ls.  So if the real user does not have
2899   directory-listing access to the lockfile directory, this will result in
2900   something like "not found".  That's why we try this only as a last resort.
2901 */
2902                     if (p) {            /* If we got the space... */
2903                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2904                         zsyscmd(p);     /* Get listing. */
2905                         if (p) {        /* free the space */
2906                             free(p);
2907                             p = NULL;
2908                         }
2909                     }
2910                 }
2911 #endif /* NOUUCP */
2912                 return(-5);             /* Code for device in use */
2913             } else return(-3);          /* Access denied */
2914         } else lkf = 1;
2915     }
2916 #else  /* OPENFIRST */
2917
2918 /*
2919   27 Oct 2001: New simpler code that gets the lock first and then opens the
2920   device, which eliminates the race condition.  The downside is you can no
2921   longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
2922   terminal, without trying to create a lockfile, which fails if C-Kermit lacks
2923   privs, and if it succeeds, it has created a lockfile where it didn't create
2924   one before.
2925 */
2926     xlocal = *lcl;                      /* Is the device my login terminal? */
2927     debug(F111,"ttopen xlocal","A",xlocal);
2928     fnam = ttname;
2929     if (strcmp(ttname,CTTNAM) && netconn == 0) {
2930         if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
2931             if ((int)strlen(fullname) > 0)
2932               fnam = fullname;
2933         }
2934     }
2935     debug(F110,"ttopen fnam",fnam,0);
2936     if (xlocal < 0) {
2937         xlocal = (strcmp(fnam,CTTNAM) != 0);
2938     }
2939     debug(F111,"ttopen xlocal","B",xlocal);
2940
2941     lkf = 0;                            /* No lock yet */
2942     if (xlocal > 0) {                   /* If not... */
2943         int xx; int xpid;
2944         xx = ttlock(fnam);              /* Try to lock it. */
2945         debug(F101,"ttopen ttlock","",xx);
2946         if (xx < 0) {                   /* Can't lock it. */
2947             debug(F111,"ttopen ttlock fails",fnam,xx);
2948             if (xx == -2) {             /* If lockfile says device in use, */
2949 #ifndef NOUUCP
2950                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2951                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2952                 if (xpid > -1) {        /* If we got a pid */
2953                     if (!quiet)
2954                       printf("Locked by process %d\n",xpid); /* tell them. */
2955                     ckstrncpy(lockpid,ckitoa(xpid),16);
2956                     debug(F110,"ttopen lockpid",lockpid,0);
2957 #ifndef NOPUSH
2958                 } else if (flfnam[0] && !nopush) {
2959                     extern char *DIRCMD;
2960                     char *p = NULL;
2961                     int x;
2962                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2963                     p = malloc(x);      /* Print a directory listing. */
2964 /*
2965   Note: priv_on() won't help here, because we do not pass privs along to
2966   to inferior processes, in this case ls.  So if the real user does not have
2967   directory-listing access to the lockfile directory, this will result in
2968   something like "not found".  That's why we try this only as a last resort.
2969 */
2970                     if (p) {            /* If we got the space... */
2971                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2972                         zsyscmd(p);     /* Get listing. */
2973                         if (p) {        /* free the space */
2974                             free(p);
2975                             p = NULL;
2976                         }
2977                     }
2978 #endif /* NOPUSH */
2979                 }
2980 #endif /* NOUUCP */
2981                 return(-5);             /* Code for device in use */
2982             } else return(-3);          /* Access denied */
2983         } else lkf = 1;
2984     }
2985     /* Have lock -- now it's safe to open the device */
2986
2987     debug(F101,"ttopen lkf","",lkf);
2988     debug(F101,"ttopen timo","",timo);
2989
2990     ttotmo = 0;                         /* Flag no timeout */
2991     if (timo > 0) {
2992         int xx;
2993         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2994         xx = alarm(timo);               /* Timed open() */
2995         debug(F101,"ttopen alarm","",xx);
2996         if (
2997 #ifdef CK_POSIX_SIG
2998             sigsetjmp(sjbuf,1)
2999 #else
3000             setjmp(sjbuf)
3001 #endif /* CK_POSIX_SIG */
3002             ) {
3003             ttotmo = 1;                 /* Flag timeout. */
3004         } else {
3005             ttyfd = do_open(fnam);
3006         }
3007         ttimoff();
3008         debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
3009     } else {
3010         errno = 0;
3011         ttyfd = do_open(fnam);
3012         debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
3013     }
3014     if (ttyfd < 0) {                    /* If couldn't open, fail. */
3015         debug(F111,"ttopen errno",fnam,errno);
3016         debug(F111,"ttopen xlocal","C",xlocal);
3017         if (xlocal == 0) {
3018             debug(F100,"ttopen substituting 0","",0);
3019             ttyfd = 0;
3020         } else {
3021             if (errno > 0 && !quiet) {
3022                 debug(F111,"ttopen perror",fnam,errno);
3023                 perror(fnam);           /* Print message */
3024             }
3025             if (ttunlck())                  /* Release the lock file */
3026               fprintf(stderr,"Warning, problem releasing lock\r\n");
3027         }
3028     }
3029
3030     if (ttyfd < 0) {                    /* ttyfd is still < 0? */
3031 #ifdef ATT7300
3032         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
3033           ongetty(ttnmsv);              /* yes, restart on tty line */
3034         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
3035 #else
3036 #ifdef ACUCNTRL
3037         /* Should put call to priv_on() here, but that would be risky! */
3038         acucntrl("enable",fnam);        /* acucntrl() program. */
3039         /* and priv_off() here... */
3040 #endif /* ACUNTRL */
3041 #endif /* ATT7300 */
3042
3043         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
3044         if (errno == EACCES) {          /* Device is protected against user */
3045             debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
3046             return(-4);
3047         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
3048     }
3049
3050 /* Make sure it's a real tty. */
3051
3052 #ifdef Plan9
3053     /* take this opportunity to open the control channel */
3054     if (p9openttyctl(fnam) < 0)       
3055 #else
3056       if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
3057 #endif /* Plan9 */
3058         {
3059             fprintf(stderr,"%s is not a terminal device\n",fnam);
3060             debug(F111,"ttopen not a tty",fnam,errno);
3061             if (ttunlck())              /* Release the lock file */
3062               fprintf(stderr,"Warning, problem releasing lock\r\n");
3063             close(ttyfd);
3064             ttyfd = -1;
3065             wasclosed = 1;
3066             signal(SIGINT,occt);
3067             return(-1);
3068         }
3069
3070 #ifdef aegis
3071     /*
3072       Apollo C runtime claims that console pads are tty devices, which
3073       is reasonable, but they aren't any good for packet transfer.
3074     */
3075     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
3076     if (st.all != status_$ok) {
3077         fprintf(stderr, "problem getting tty object type: ");
3078         error_$print(st);
3079     } else if (ttyuid != sio_$uid) {    /* Reject non-SIO lines */
3080         close(ttyfd); ttyfd = -1;
3081         wasclosed = 1;
3082         errno = ENOTTY; perror(fnam);
3083         signal(SIGINT,occt);
3084         return(-1);
3085     }
3086 #endif /* aegis */
3087
3088     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3089
3090     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
3091
3092 /* Caller wants us to figure out if line is controlling tty */
3093
3094     if (*lcl < 0) {
3095         char * s;
3096         if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
3097             xlocal = 0;
3098             debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
3099         } else if (strcmp(fnam,cttnam) == 0) {
3100             xlocal = 0;
3101             debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
3102         } else if (cttnam[0]) {
3103 #ifdef BEBOX_DR7
3104             s = ttnmsv;                 /* ttyname() is broken */
3105 #else
3106             s = ttyname(ttyfd);         /* Get real name of ttname. */
3107 #endif /* BEBOX_DR7 */
3108             if (!s) s = "";
3109             if (*s)
3110               xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
3111             else
3112               xlocal = 1;
3113             debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
3114         }
3115     }
3116
3117 #ifndef NOFDZERO
3118 /* Note, the following code was added so that Unix "idle-line" snoopers */
3119 /* would not think Kermit was idle when it was transferring files, and */
3120 /* maybe log people out. */
3121     if (xlocal == 0) {                  /* Remote mode */
3122         if (fdflag == 0) {              /* Standard i/o is not redirected */
3123             debug(F100,"ttopen setting ttyfd = 0","",0);
3124 #ifdef LYNXOS
3125             /* On Lynx OS, fd 0 is open for read only. */
3126             dup2(ttyfd,0);
3127 #endif /* LYNXOS */
3128             close(ttyfd);               /* Use file descriptor 0 */
3129             ttyfd = 0;
3130         } else {                        /* Standard i/o is redirected */
3131             debug(F101,"ttopen stdio redirected","",ttyfd);
3132         }
3133     }
3134 #endif /* NOFDZERO */
3135 #endif /* OPENFIRST */
3136
3137 /* Got the line, now set the desired value for local. */
3138
3139     if (*lcl != 0) *lcl = xlocal;
3140
3141 /* Some special stuff for v7... */
3142
3143 #ifdef  V7
3144 #ifndef MINIX
3145     if (kmem[TTY] < 0) {                /*  If open, then skip this.  */
3146         qaddr[TTY] = initrawq(ttyfd);   /* Init the queue. */
3147         if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
3148             fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
3149             perror("/dev/kmem");
3150             exit(1);
3151         }
3152     }
3153 #endif /* !MINIX */
3154 #endif /* V7 */
3155
3156 /* No failure returns after this point */
3157
3158 #ifdef ultrix
3159     ioctl(ttyfd, TIOCMODEM, &temp);
3160 #ifdef TIOCSINUSE
3161     if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
3162         if (!quiet)
3163           perror(fnam);
3164     }
3165 #endif /* TIOCSINUSE */
3166 #endif /* ultrix */
3167
3168 /* Get tty device settings  */
3169
3170 #ifdef BSD44ORPOSIX                     /* POSIX */
3171     tcgetattr(ttyfd,&ttold);
3172     debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
3173     tcgetattr(ttyfd,&ttraw);
3174     debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
3175     tcgetattr(ttyfd,&tttvt);
3176     debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
3177 #else                                   /* BSD, V7, and all others */
3178 #ifdef ATTSV                            /* AT&T UNIX */
3179     ioctl(ttyfd,TCGETA,&ttold);
3180     debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
3181     ioctl(ttyfd,TCGETA,&ttraw);
3182     ioctl(ttyfd,TCGETA,&tttvt);
3183 #else
3184 #ifdef BELLV10
3185     ioctl(ttyfd,TIOCGETP,&ttold);
3186     debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
3187     ioctl(ttyfd,TIOCGDEV,&tdold);
3188     debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
3189 #else
3190     gtty(ttyfd,&ttold);
3191     debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
3192 #endif /* BELLV10 */
3193
3194 #ifdef sony_news                        /* Sony NEWS */
3195     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
3196         perror("ttopen error getting Kanji mode");
3197         debug(F101,"ttopen error getting Kanji mode","",0);
3198         km_ext = -1;                    /* Make sure this stays undefined. */
3199     }
3200 #endif /* sony_news */
3201
3202 #ifdef TIOCGETC
3203     debug(F100,"ttopen TIOCGETC","",0);
3204     tcharf = 0;                         /* In remote mode, also get */
3205     if (xlocal == 0) {                  /* special characters */
3206         if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
3207             debug(F100,"ttopen TIOCGETC failed","",0);
3208         } else {
3209             tcharf = 1;                 /* It worked. */
3210             ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
3211             debug(F100,"ttopen TIOCGETC ok","",0);
3212         }
3213     }
3214 #else
3215     debug(F100,"ttopen TIOCGETC not defined","",0);
3216 #endif /* TIOCGETC */
3217
3218 #ifdef TIOCGLTC
3219     debug(F100,"ttopen TIOCGLTC","",0);
3220     ltcharf = 0;                        /* In remote mode, also get */
3221     if (xlocal == 0) {                  /* local special characters */
3222         if (ioctl(ttyfd,TIOCGLTC,&ltchold) < 0) {
3223             debug(F100,"ttopen TIOCGLTC failed","",0);
3224         } else {
3225             ltcharf = 1;                /* It worked. */
3226             ioctl(ttyfd,TIOCGLTC,&ltchnoi); /* Get another copy */
3227             debug(F100,"ttopen TIOCGLTC ok","",0);
3228         }
3229     }
3230 #else
3231     debug(F100,"ttopen TIOCGLTC not defined","",0);
3232 #endif /* TIOCGLTC */
3233
3234 #ifdef TIOCLGET
3235     debug(F100,"ttopen TIOCLGET","",0);
3236     lmodef = 0;
3237     if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
3238         debug(F100,"ttopen TIOCLGET failed","",0);
3239     } else {
3240         lmodef = 1;
3241         debug(F100,"ttopen TIOCLGET ok","",0);
3242     }
3243 #endif /* TIOCLGET */
3244
3245 #ifdef BELLV10
3246     ioctl(ttyfd,TIOCGETP,&ttraw);
3247     ioctl(ttyfd,TIOCGETP,&tttvt);
3248 #else
3249     gtty(ttyfd,&ttraw);                 /* And a copy of it for packets*/
3250     gtty(ttyfd,&tttvt);                 /* And one for virtual tty service */
3251 #endif /* BELLV10 */
3252
3253 #endif /* ATTSV */
3254 #endif /* BSD44ORPOSIX */
3255
3256 /* Section for changing line discipline.  It's restored in ttres(). */
3257
3258 #ifdef AIXRS
3259 #ifndef AIX41
3260     { union txname ld_name; int ld_idx = 0;
3261       ttld = 0;
3262         do {
3263           ld_name.tx_which = ld_idx++;
3264           ioctl(ttyfd, TXGETCD, &ld_name);
3265           if (!strncmp(ld_name.tx_name, "rts", 3))
3266             ttld |= 1;
3267         } while (*ld_name.tx_name);
3268         debug(F101,"AIX line discipline","",ttld);
3269       }
3270 #endif /* AIX41 */
3271 #endif /* AIXRS */
3272
3273 #ifdef BSD41
3274 /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
3275     { int k;
3276       ioctl(ttyfd, TIOCGETD, &ttld);    /* Get and save line discipline */
3277       debug(F101,"4.1bsd line discipline","",ttld);
3278       k = OTTYDISC;                     /* Switch to "old" discipline */
3279       k = ioctl(ttyfd, TIOCSETD, &k);
3280       debug(F101,"4.1bsd tiocsetd","",k);
3281     }
3282 #endif /* BSD41 */
3283
3284 #ifdef aegis
3285     /* This was previously done before the last two TCGETA or gtty above,
3286      * in both the ATTSV and not-ATTSV case.  If it is not okay to have only
3287      * one copy if it here instead, give us a shout!
3288      */
3289     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
3290     if (xlocal) {       /* ignore breaks from local line */
3291         sio_$control((short)ttyfd, sio_$int_enable, false, st);
3292         sio_$control((short)ttyfd, sio_$quit_enable, false, st);
3293     }
3294 #endif /* aegis */
3295
3296 #ifdef VXVE
3297     ttraw.c_line = 0;                   /* STTY line 0 for VX/VE */
3298     tttvt.c_line = 0;                   /* STTY line 0 for VX/VE */
3299     ioctl(ttyfd,TCSETA,&ttraw);
3300 #endif /* vxve */
3301
3302 /* If O_NDELAY was used during open(), then remove it now. */
3303
3304 #ifdef O_NDELAY
3305     debug(F100,"ttopen O_NDELAY","",0);
3306     if (xlocal > 0) {
3307       if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
3308         debug(F100,"ttopen fcntl O_NDELAY","",0);
3309 #ifndef aegis
3310         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
3311             debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
3312             perror("Can't unset O_NDELAY");
3313         }
3314 #endif /* aegis */
3315         /* Some systems, notably Xenix (don't know how common this is in
3316          * other systems), need special treatment to get rid of the O_NDELAY
3317          * behaviour on read() with respect to carrier presence (i.e. read()
3318          * returning 0 when carrier absent), even though the above fcntl()
3319          * is enough to make read() wait for input when carrier is present.
3320          * This magic, in turn, requires CLOCAL for working when the carrier
3321          * is absent. But if xlocal == 0, presumably you already have CLOCAL
3322          * or you have a carrier, otherwise you wouldn't be running this.
3323          */
3324         debug(F101,"ttopen xlocal","",xlocal);
3325 #ifdef ATTSV
3326 #ifdef BSD44ORPOSIX
3327 #ifdef COMMENT                          /* 12 Aug 1997 */
3328 #ifdef __bsdi__
3329         if (xlocal)
3330           ttraw.c_cflag |= CLOCAL;
3331 #else
3332 #ifdef __FreeBSD__
3333         if (xlocal)
3334           ttraw.c_cflag |= CLOCAL;
3335 #endif /* __FreeBSD__ */
3336 #endif /* __bsdi__ */
3337 #else /* Not COMMENT */
3338 #ifdef CLOCAL
3339         if (xlocal)                     /* Unset this if it's defined. */
3340           ttraw.c_cflag |= CLOCAL;
3341 #endif /* CLOCAL */
3342 #endif /* COMMENT */
3343         debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
3344         if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
3345             debug(F100,"ttopen POSIX tcseattr fails","",0);
3346             perror("tcsetattr");
3347         }
3348 #else /* !BSD44ORPOSIX */
3349         if (xlocal) {
3350             ttraw.c_cflag |= CLOCAL;
3351             debug(F100,"ttopen calling ioctl(TCSETA)","",0);
3352             errno = 0;
3353             if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
3354                 debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
3355                 perror("ioctl(TCSETA)");
3356             }
3357         }
3358 #endif /* BSD44ORPOSIX */
3359 #endif /* ATTSV */
3360 #ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
3361 /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
3362         debug(F100,"ttopen executing close/open","",0);
3363         close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
3364 #endif /* NOCOTFMC */
3365       }
3366     }
3367 #endif /* O_NDELAY */
3368
3369 /* Instruct the system how to treat the carrier, and set a few other tty
3370  * parameters.
3371  *
3372  * This also undoes the temporary setting of CLOCAL that may have been done
3373  * for the close(open()) above (except in Xenix).  Also throw in ~ECHO, to
3374  * prevent the other end of the line from sitting there talking to itself,
3375  * producing garbage when the user performs a connect.
3376  *
3377  * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
3378  * Now it thinks CLOCAL is always on. It seems the only real solution for
3379  * Xenix is to switch between the lower and upper case device names.
3380  *
3381  * This section may at some future time expand into setting a complete
3382  * collection of tty parameters, or call a function shared with ttpkt()/
3383  * ttvt() that does so.  On the other hand, the initial parameters are not
3384  * that important, since ttpkt() or ttvt() should always fix that before
3385  * any communication is done.  Well, we'll see...
3386  */
3387     if (xlocal) {
3388         curcarr = -2;
3389         debug(F100,"ttopen calling carrctl","",0);
3390         carrctl(&ttraw, ttcarr == CAR_ON);
3391         debug(F100,"ttopen carrctl ok","",0);
3392
3393 #ifdef COHERENT
3394 #define SVORPOSIX
3395 #endif /* COHERENT */
3396
3397 #ifdef SVORPOSIX
3398         ttraw.c_lflag &= ~ECHO;
3399         ttold.c_lflag &= ~ECHO;
3400 #ifdef BSD44ORPOSIX
3401         y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
3402         debug(F101,"ttopen tcsetattr","",y);
3403 #else
3404         y = ioctl(ttyfd, TCSETA, &ttraw);
3405         debug(F100,"ttopen ioctl","",y);
3406 #endif /* BSD44ORPOSIX */
3407
3408 #else /* BSD, etc */
3409         ttraw.sg_flags &= ~ECHO;
3410         ttold.sg_flags &= ~ECHO;
3411 #ifdef BELLV10
3412         y = ioctl(ttyfd,TIOCSETP,&ttraw);
3413         debug(F100,"ttopen ioctl","",y);
3414 #else
3415         y = stty(ttyfd,&ttraw);
3416         debug(F100,"ttopen stty","",y);
3417 #endif /* BELLV10 */
3418 #endif /* SVORPOSIX */
3419
3420 #ifdef COHERENT
3421 #undef SVORPOSIX
3422 #endif /* COHERENT */
3423
3424         /* ttflui(); */  /*  This fails for some reason.  */
3425     }
3426
3427     /* Get current speed */
3428
3429 #ifndef BEBOX
3430     ttspeed = ttgspd();
3431 #else
3432     ttspeed = 19200;
3433 #endif /* !BEBOX */
3434     debug(F101,"ttopen ttspeed","",ttspeed);
3435
3436     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
3437
3438     debug(F101,"ttopen ttyfd","",ttyfd);
3439     debug(F101,"ttopen *lcl","",*lcl);
3440     debug(F111,"ttopen lock file",flfnam,lkf);
3441     signal(SIGINT,occt);
3442     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3443     gotsigs = 0;
3444     return(0);
3445 }
3446
3447
3448 /*  D O _ O P E N  --  Do the right kind of open() call for the tty. */
3449
3450 int
3451 do_open(ttname) char *ttname; {
3452     int flags;
3453
3454 #ifdef QNX6
3455     /* O_NONBLOCK on /dev/tty makes open() fail */
3456     return(priv_opn(ttname, O_RDWR |
3457                     (
3458                      ((int)strcmp(ttname,"/dev/tty") == 0) ?
3459                      0 :
3460                      (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
3461                     )
3462            ); 
3463 #else  /* !QNX6 */
3464
3465 #ifndef O_NDELAY                        /* O_NDELAY not defined */
3466     return(priv_opn(ttname,2));
3467 #else                                   /* O_NDELAY defined */
3468
3469 #ifdef ATT7300
3470 /*
3471  Open comms line without waiting for carrier so initial call does not hang
3472  because state of "modem" is likely unknown at the initial call  -jrd.
3473  If this is needed for the getty stuff to work, and the open would not work
3474  without O_NDELAY when getty is still on, then this special case is ok.
3475  Otherwise, get rid of it. -ske
3476 */
3477     return(priv_opn(ttname, O_RDWR | O_NDELAY));
3478
3479 #else   /* !ATT7300 */
3480
3481     /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
3482     flags = O_RDWR;
3483     debug(F101,"do_open xlocal","",xlocal);
3484     debug(F111,"do_open flags A",ttname,flags);
3485     if (xlocal && (ttcarr != CAR_ON))
3486       flags |= O_NDELAY;
3487     debug(F111,"do_open flags B",ttname,flags);
3488     return(priv_opn(ttname, flags));
3489 #endif /* !ATT7300 */
3490 #endif /* O_NDELAY */
3491 #endif /* QNX6 */
3492 }
3493
3494 /*  T T C L O S  --  Close the TTY, releasing any lock.  */
3495
3496 static int ttc_state = 0;               /* ttclose() state */
3497 static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
3498
3499 int
3500 ttclos(foo) int foo; {                  /* Arg req'd for signal() prototype */
3501     int xx, x = 0;
3502     extern int exithangup;
3503
3504     debug(F101,"ttclos ttyfd","",ttyfd);
3505     debug(F101,"ttclos netconn","",netconn);
3506     debug(F101,"ttclos xlocal","",xlocal);
3507 #ifdef NOFDZERO
3508     debug(F100,"ttclos NOFDZERO","",0);
3509 #endif /* NOFDZERO */
3510
3511 #ifdef COMMENT
3512 #ifdef TTLEBUF
3513     le_init();                          /* No need for any of this */
3514 #endif /* TTLEBUF */
3515 #endif /* COMMENT */
3516
3517     if (ttyfd < 0)                      /* Wasn't open. */
3518       return(0);
3519
3520     if (ttfdflg)                        /* If we inherited ttyfd from */
3521       return(0);                        /* another process, don't close it. */
3522
3523     tvtflg = 0;                         /* (some day get rid of this...) */
3524     gotsigs = 0;
3525
3526 #ifdef IKSD
3527     if (inserver) {
3528 #ifdef TNCODE
3529           tn_push();                    /* Place any waiting data into input*/
3530           tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
3531           TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
3532           tn_reset();                   /* The Reset Telnet Option table.  */
3533 #endif /* TNCODE */
3534 #ifdef CK_SSL
3535           if (ssl_active_flag) {
3536               if (ssl_debug_flag)
3537                 BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
3538               SSL_shutdown(ssl_con);
3539               SSL_free(ssl_con);
3540               ssl_con = NULL;
3541               ssl_active_flag = 0;
3542           }
3543           if (tls_active_flag) {
3544               if (ssl_debug_flag)
3545                 BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
3546               SSL_shutdown(tls_con);
3547               SSL_free(tls_con);
3548               tls_con = NULL;
3549               tls_active_flag = 0;
3550           }
3551 #endif /* CK_SSL */
3552     }
3553 #endif /* IKSD */
3554 #ifdef NETCMD
3555     if (ttpipe) {                       /* We've been using a pipe */
3556         /* ttpipe = 0; */
3557         if (ttpid > 0) {
3558             int wstat;
3559             int statusp;
3560             close(fdin);                /* Close these. */
3561             close(fdout);
3562             fdin = fdout = -1;
3563             kill(ttpid,1);              /* Kill fork with SIGHUP */
3564             while (1) {
3565                 wstat = wait(&statusp);
3566                 if (wstat == ttpid || wstat == -1)
3567                   break;
3568                 pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
3569             }
3570             ttpid = 0;
3571         }
3572         netconn = 0;
3573         wasclosed = 1;
3574         ttyfd = -1;
3575         return(0);
3576     }
3577 #endif /* NETCMD */
3578 #ifdef NETPTY
3579     if (ttpty) {
3580 #ifndef NODOPTY
3581         end_pty();
3582 #endif /* NODOPTY */
3583         close(ttyfd);
3584         netconn = 0;
3585         wasclosed = 1;
3586         ttpty = 0;
3587         ttyfd = -1;
3588         return(0);
3589     }
3590 #endif /* NETPTY */
3591
3592 #ifdef  NETCONN
3593     if (netconn) {                      /* If it's a network connection. */
3594         debug(F100,"ttclos closing net","",0);
3595         netclos();                      /* Let the network module close it. */
3596         netconn = 0;                    /* No more network connection. */
3597         debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
3598         return(0);
3599     }
3600 #endif  /* NETCONN */
3601
3602     if (xlocal) {                       /* We're closing a SET LINE device */
3603 #ifdef FT21                             /* Fortune 2.1-specific items ... */
3604         ioctl(ttyfd,TIOCHPCL, NULL);
3605 #endif /* FT21 */
3606 #ifdef ultrix                           /* Ultrix-specific items ... */
3607 #ifdef TIOCSINUSE
3608         /* Unset the INUSE flag that we set in ttopen() */
3609         ioctl(ttyfd, TIOCSINUSE, NULL);
3610 #endif /* TIOCSINUSE */
3611         ioctl(ttyfd, TIOCNMODEM, &x);
3612 #ifdef COMMENT
3613         /* What was this? */
3614         ioctl(ttyfd, TIOCNCAR, NULL);
3615 #endif /* COMMENT */
3616 #endif /* ultrix */
3617     }
3618
3619     /* This is to prevent us from sticking in tthang() or close(). */
3620
3621 #ifdef O_NDELAY
3622 #ifndef aegis
3623     if (ttyfd > 0) {                    /* But skip it on stdin. */
3624         debug(F100,"ttclos setting O_NDELAY","",0);
3625         x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
3626 #ifdef DEBUG
3627         if (deblog && x == -1) {
3628             perror("Warning - Can't set O_NDELAY");
3629             debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
3630         }
3631 #endif /* DEBUG */
3632     }
3633 #endif /* aegis */
3634 #endif /* O_NDELAY */
3635
3636     x = 0;
3637     ttc_state = 0;
3638     if (xlocal
3639 #ifdef NOFDZERO
3640         || ttyfd > 0
3641 #endif /* NOFDZERO */
3642         ) {
3643         saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
3644         xx = alarm(8);                  /* Allow 8 seconds. */
3645         debug(F101,"ttclos alarm","",xx);
3646         if (
3647 #ifdef CK_POSIX_SIG
3648             sigsetjmp(sjbuf,1)
3649 #else
3650             setjmp(sjbuf)
3651 #endif /* CK_POSIX_SIG */
3652             ) {                         /* Timer went off? */
3653             x = -1;
3654 #ifdef DEBUG
3655             debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
3656             printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
3657 #endif /* DEBUG */
3658         }
3659         /* Hang up the device (drop DTR) */
3660
3661         errno = 0;
3662         debug(F111,"ttclos A",ckitoa(x),ttc_state);
3663         if (ttc_state < 1) {
3664             ttc_state = 1;
3665             debug(F101,"ttclos exithangup","",exithangup);
3666             if (exithangup) {
3667                 alarm(8);               /* Re-arm the timer */
3668                 debug(F101,"ttclos calling tthang()","",x);
3669                 x = tthang();           /* Hang up first, then... */
3670                 debug(F101,"ttclos tthang()","",x);
3671             }
3672 #ifndef CK_NOHUPCL
3673 /*
3674   Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF.
3675   Suggested by Soewono Effendi.
3676 */
3677 #ifdef HUPCL
3678             else {
3679                 ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */
3680 #ifdef BSD44ORPOSIX
3681                 tcsetattr(ttyfd,TCSANOW,&ttold);
3682 #else /* !BSD44ORPOSIX */
3683 #ifdef ATTSV
3684                 ioctl(ttyfd,TCSETAW,&ttold);            
3685 #else  /* !ATTSV */
3686                 stty(ttyfd,&ttold);
3687 #endif  /* ATTSV */
3688 #endif  /* BSD44ORPOSIX */
3689             }
3690 #endif  /* HUPCL */
3691 #endif  /* CK_NOHUPCL */
3692         }
3693         /* Put back device modes as we found them */
3694
3695         errno = 0;
3696         debug(F111,"ttclos B",ckitoa(x),ttc_state);
3697         if (ttc_state < 2) {
3698             ttc_state = 2;
3699             /* Don't try to mess with tty modes if tthang failed() */
3700             /* since it probably won't work. */
3701             if (x > -1) {
3702                 debug(F101,"ttclos calling ttres()","",x);
3703                 signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
3704                 alarm(8);               /* Re-arm the timer */
3705                 x = ttres();            /* Reset device modes. */
3706                 debug(F101,"ttclos ttres()","",x);
3707                 alarm(0);
3708             }
3709         }
3710         /* Close the device */
3711
3712         errno = 0;
3713         debug(F101,"ttclos C","",ttc_state);
3714         if (ttc_state < 3) {
3715             ttc_state = 3;
3716             errno = 0;
3717             debug(F101,"ttclos calling close","",x);
3718             signal(SIGALRM,xtimerh);    /* Re-enable alarm. */
3719             alarm(8);                   /* Re-arm the timer */
3720             x = close(ttyfd);           /* Close the device. */
3721             debug(F101,"ttclos close()","",x);
3722             if (x > -1)
3723               ttc_state = 3;
3724         }
3725         debug(F101,"ttclos D","",ttc_state);
3726         ttimoff();                      /* Turn off timer. */
3727         if (x < 0) {
3728             printf("?WARNING - close failed: %s\n",ttnmsv);
3729 #ifdef DEBUG
3730             if (deblog) {
3731                 printf("errno = %d\n", errno);
3732                 debug(F101,"ttclos failed","",errno);
3733             }
3734 #endif /* DEBUG */
3735         }
3736         /* Unlock after closing but before any getty mumbo jumbo */
3737
3738         debug(F100,"ttclos about to call ttunlck","",0);
3739         if (ttunlck())                  /* Release uucp-style lock */
3740           fprintf(stderr,"Warning, problem releasing lock\r\n");
3741     }
3742
3743 /* For bidirectional lines, restore getty if it was there before. */
3744
3745 #ifdef ACUCNTRL                         /* 4.3BSD acucntrl() method. */
3746     if (xlocal) {
3747         debug(F100,"ttclos ACUCNTRL","",0);
3748         acucntrl("enable",ttnmsv);      /* Enable getty on the device. */
3749     }
3750 #else
3751 #ifdef ATT7300                          /* ATT UNIX PC (3B1, 7300) method. */
3752     if (xlocal) {
3753         debug(F100,"ttclos ATT7300 ongetty","",0);
3754         if (attmodem & DOGETY)          /* Was getty(1m) running before us? */
3755           ongetty(ttnmsv);              /* Yes, restart getty on tty line */
3756         attmodem &= ~DOGETY;            /* No phone in use, getty restored */
3757     }
3758 #endif /* ATT7300 */
3759 #endif /* System-dependent getty-restoring methods */
3760
3761 #ifdef sony_news
3762     km_ext = -1;                        /* Invalidate device's Kanji-mode */
3763 #endif /* sony_news */
3764
3765     ttyfd = -1;                         /* Invalidate the file descriptor. */
3766     wasclosed = 1;
3767     debug(F100,"ttclos done","",0);
3768     return(0);
3769 }
3770
3771 /*  T T H A N G  --  Hangup phone line or network connection.  */
3772 /*
3773   Returns:
3774   0 if it does nothing.
3775   1 if it believes that it hung up successfully.
3776  -1 if it believes that the hangup attempt failed.
3777 */
3778
3779 #define HUPTIME 500                     /* Milliseconds for hangup */
3780
3781 #ifdef COMMENT
3782 /* The following didn't work but TIOCSDTR does work */
3783 #ifdef UNIXWARE
3784 /* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
3785 #ifndef POSIX                           /* Such as Unixware 1.x, 2.x */
3786 #ifndef HUP_POSIX
3787 #define HUP_POSIX
3788 #endif /* HUP_POSIX */
3789 #endif /* POSIX */
3790 #endif /* UNIXWARE */
3791 #endif /* COMMENT */
3792
3793 #ifndef USE_TIOCSDTR
3794 #ifdef __NetBSD__
3795 /* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
3796 #ifdef TIOCSDTR
3797 #ifdef TIOCCDTR
3798 #define USE_TIOCSDTR
3799 #endif /* TIOCCDTR */
3800 #endif /* TIOCSDTR */
3801 #endif /* __NetBSD__ */
3802 #endif /* USE_TIOCSDTR */
3803
3804 #ifndef HUP_CLOSE_POSIX
3805 #ifdef OU8
3806 #define HUP_CLOSE_POSIX
3807 #else
3808 #ifdef CK_SCOV5
3809 #define HUP_CLOSE_POSIX
3810 #endif /* CK_SCOV5 */
3811 #endif /* OU8 */
3812 #endif /* HUP_CLOSE_POSIX */
3813
3814 #ifdef NO_HUP_CLOSE_POSIX
3815 #ifdef HUP_CLOSE_POSIX
3816 #undef HUP_CLOSE_POSIX
3817 #endif /* HUP_CLOSE_POSIX */
3818 #endif /* NO_HUP_CLOSE_POSIX */
3819
3820 int
3821 tthang() {
3822 #ifdef NOLOCAL
3823     return(0);
3824 #else
3825     int x = 0;                          /* Sometimes used as return code. */
3826 #ifndef POSIX
3827     int z;                              /* worker */
3828 #endif /* POSIX */
3829
3830 #ifdef COHERENT
3831 #define SVORPOSIX
3832 #endif /* COHERENT */
3833
3834 #ifdef SVORPOSIX                        /* AT&T, POSIX, HPUX declarations. */
3835     int spdsav;                         /* for saving speed */
3836 #ifdef HUP_POSIX
3837     int spdsavi;
3838 #else
3839 #ifdef BSD44ORPOSIX
3840     int spdsavi;
3841 #endif /* BSD44ORPOSIX */
3842 #endif /* HUP_POSIX */
3843 #ifdef HPUX
3844 /*
3845   Early versions of HP-UX omitted the mflag typedef.  If you get complaints
3846   about it, just change it to long (or better still, unsigned long).
3847 */
3848     mflag
3849       dtr_down = 00000000000,
3850       modem_rtn,
3851       modem_sav;
3852     char modem_state[64];
3853 #endif /* HPUX */
3854     int flags;                          /* fcntl flags */
3855     unsigned short ttc_save;
3856 #endif /* SVORPOSIX */
3857
3858     if (ttyfd < 0) return(0);           /* Don't do this if not open  */
3859     if (xlocal < 1) return(0);          /* Don't do this if not local */
3860
3861 #ifdef NETCMD
3862     if (ttpipe)
3863       return((ttclos(0) < 0) ? -1 : 1);
3864 #endif /* NETCMD */
3865 #ifdef NETPTY
3866     if (ttpty)
3867       return((ttclos(0) < 0) ? -1 : 1);
3868 #endif /* NETPTY */
3869 #ifdef NETCONN
3870     if (netconn) {                      /* Network connection. */
3871 #ifdef TN_COMPORT
3872         if (istncomport()) {
3873             int rc = tnc_set_dtr_state(0);
3874             if (rc >= 0) {
3875                 msleep(HUPTIME);
3876                 rc = tnc_set_dtr_state(1);
3877             }
3878             return(rc >= 0 ? 1 : -1);
3879         } else
3880 #endif /* TN_COMPORT */
3881           return((netclos() < 0) ? -1 : 1); /* Just close it. */
3882   }
3883 #endif /* NETCONN */
3884
3885 /* From here down, we handle real tty devices. */
3886 #ifdef HUP_POSIX
3887 /*
3888   e.g. for Unixware 2, where we don't have a full POSIX build, we
3889   still have to use POSIX-style hangup.  Thus the duplication of this
3890   and the next case, the only difference being we use a local termios
3891   struct here, since a different model is used elsewhere.
3892
3893   NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
3894   even though it compiles and executes without error, doesn't actually
3895   work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
3896 */
3897     {
3898         struct termios ttcur;
3899         int x;
3900         debug(F100,"tthang HUP_POSIX style","",0);
3901         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3902         debug(F111,"tthang tcgetattr",ckitoa(errno),x);
3903         if (x < 0) return(-1);
3904         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
3905         debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
3906         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
3907         debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
3908         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
3909         debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
3910         if (x < 0) return(-1);
3911         x = cfsetispeed(&ttcur,B0);
3912         debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
3913         if (x < 0) return(-1);
3914         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3915         debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
3916         if (x < 0) return(-1);
3917         msleep(HUPTIME);                /* Sleep 0.5 sec */
3918         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
3919         if (x < 0) return(-1);
3920         debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
3921         x = cfsetispeed(&ttcur,spdsavi);
3922         debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
3923         if (x < 0) return(-1);
3924         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3925         debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
3926         if (x < 0) return(-1);
3927         return(1);
3928     }
3929 #else
3930 #ifdef BSD44ORPOSIX
3931 #ifdef QNX
3932     {
3933         int x;
3934         x = tcdropline(ttyfd,500);
3935         debug(F101,"tthang QNX tcdropline","",x);
3936         ttcur.c_cflag |= CLOCAL;
3937         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3938         debug(F101,"tthang QNX tcsetattr restore","",x);
3939         if (x < 0) {
3940             debug(F101,"tthang QNX tcsetattr restore errno","",errno);
3941             return(-1);
3942         }
3943         /* Fix flags - ensure O_NONBLOCK is off */
3944
3945         errno = 0;
3946         debug(F101,"tthang QNX iniflags","",iniflags);
3947         if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
3948             debug(F101,"tthang QNX F_SETFL errno","",errno);
3949             return(-1);
3950         }
3951         return(x);
3952     }
3953 #else  /* QNX */
3954     {
3955         int x;
3956 #ifdef USE_TIOCSDTR
3957         debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
3958         errno = 0;
3959         x = ioctl(ttyfd, TIOCCDTR, NULL);
3960         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
3961         if (x < 0) return(-1);
3962         msleep(HUPTIME);                /* Sleep 0.5 sec */
3963         errno = 0;
3964         x = ioctl(ttyfd, TIOCSDTR, NULL);
3965         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
3966         if (x < 0) return(-1);
3967 #else  /* USE_TIOCSDTR */
3968
3969 #ifdef HUP_CLOSE_POSIX
3970 /*
3971   In OSR5 versions where TIOCSDTR is not defined (up to and including at
3972   least 5.0.6a) the POSIX APIs in the "#else" part below are available but
3973   don't work, and no other APIs are available that do work.  In this case
3974   we have to drop DTR by brute force: close and reopen the port.  This
3975   code actually works, but all the steps are crucial: setting CLOCAL, the
3976   O_NDELAY manipulations, etc.
3977 */
3978         debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
3979         debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
3980         debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
3981         errno = 0;
3982         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3983         debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
3984         if (x < 0) {
3985             debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
3986             return(-1);
3987         }
3988         errno = 0;
3989
3990         x = close(ttyfd);               /* Close without releasing lock */
3991         if (x < 0) {
3992             debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
3993             return(-1);
3994         }
3995         errno = 0;
3996         x = msleep(500);                /* Pause half a second */
3997         if (x < 0) {                    /* Or if that doesn't work, 1 sec */
3998             debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
3999             sleep(1);
4000         }
4001         errno = 0;
4002         ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
4003         debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
4004         if (ttyfd < 0) {
4005             debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
4006             return(-1);
4007         }
4008         debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
4009
4010         /* Restore previous attributes */
4011
4012         errno = 0;
4013         tvtflg = 0;
4014         ttcur.c_cflag |= CLOCAL;
4015         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4016         debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
4017         if (x < 0) {
4018             debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
4019                   "",errno);
4020             return(-1);
4021         }
4022         /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
4023
4024         errno = 0;
4025         if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
4026             debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
4027             return(-1);
4028         }
4029         debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4030         errno = 0;
4031         x &= ~(O_NONBLOCK|O_NDELAY);
4032         debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
4033         debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
4034         if (fcntl(ttyfd, F_SETFL, x) == -1) {
4035             debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
4036             return(-1);
4037         }
4038 #ifdef DEBUG
4039         if (deblog) {
4040             if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
4041                 debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4042                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
4043                       "",x&O_NONBLOCK);
4044                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
4045                       "",x&O_NDELAY);
4046             }
4047         }
4048 #endif /* DEBUG */
4049
4050 #else  /* HUP_CLOSE_POSIX */
4051         
4052         /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
4053
4054         debug(F100,"tthang BSD44ORPOSIX B0","",0);
4055         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
4056         debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
4057         if (x < 0) return(-1);
4058         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
4059         debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
4060         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
4061         debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
4062         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
4063         debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
4064         if (x < 0) return(-1);
4065         x = cfsetispeed(&ttcur,B0);
4066         debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
4067         if (x < 0) return(-1);
4068         /* This gets EINVAL on NetBSD 1.4.1 because of B0... */
4069         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4070         debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
4071         if (x < 0) return(-1);
4072         msleep(HUPTIME);                /* Sleep 0.5 sec */
4073         debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
4074         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
4075         debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
4076         if (x < 0) return(-1);
4077         debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
4078         x = cfsetispeed(&ttcur,spdsavi);
4079         debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
4080         if (x < 0) return(-1);
4081         ttcur.c_cflag |= CLOCAL;        /* Don't expect CD after hangup */
4082         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4083         debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
4084         if (x < 0) return(-1);
4085
4086 #endif /* HUP_CLOSE_POSIX */
4087 #endif /* USE_TIOCSDTR */
4088
4089         return(1);
4090     }
4091
4092 #endif /* QNX */
4093 #else /* BSD44ORPOSIX */
4094
4095 #ifdef aegis                            /* Apollo Aegis */
4096     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
4097     msleep(HUPTIME);                                    /* pause */
4098     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
4099     return(1);
4100 #endif /* aegis */
4101
4102 #ifdef ANYBSD                           /* Any BSD version. */
4103 #ifdef TIOCCDTR                         /* Except those that don't have this */
4104     debug(F100,"tthang BSD style","",0);
4105     if (ioctl(ttyfd,TIOCCDTR,0) < 0) {  /* Clear DTR. */
4106         debug(F101,"tthang TIOCCDTR fails","",errno);
4107         return(-1);
4108     }
4109     msleep(HUPTIME);                    /* For about 1/2 sec */
4110     errno = 0;
4111     x = ioctl(ttyfd,TIOCSDTR,0);        /* Restore DTR */
4112     if (x < 0) {
4113         /*
4114           For some reason, this tends to fail with "no such device or address"
4115           but the operation still works, probably because of the close/open
4116           later on.  So let's not scare the user unnecessarily here.
4117         */
4118         debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
4119         x = 1;                          /* Pretend we succeeded */
4120     } else if (x == 0) x = 1;           /* Success */
4121 #ifdef COMMENT
4122 #ifdef FT21
4123     ioctl(ttyfd, TIOCSAVEMODES, 0);
4124     ioctl(ttyfd, TIOCHPCL, 0);
4125     close(ttyfd);                       /* Yes, must do this twice */
4126     if ((ttyfd = open(ttnmsv,2)) < 0)   /* on Fortune computers... */
4127       return(-1);                       /* (but why?) */
4128     else x = 1;
4129 #endif /* FT21 */
4130 #endif /* COMMENT */
4131 #endif /* TIOCCDTR */
4132     close(do_open(ttnmsv));             /* Clear i/o error condition */
4133     errno = 0;
4134 #ifdef COMMENT
4135 /* This is definitely dangerous.  Why was it here? */
4136     z = ttvt(ttspeed,ttflow);           /* Restore modes. */
4137     debug(F101,"tthang ttvt returns","",z);
4138     return(z < 0 ? -1 : 1);
4139 #else
4140     return(x);
4141 #endif /* COMMENT */
4142 #endif /* ANYBSD */
4143
4144 #ifdef ATTSV
4145 /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
4146
4147 #ifdef HPUX
4148 /* Hewlett Packard allows explicit manipulation of modem signals. */
4149
4150 #ifdef COMMENT
4151 /* Old way... */
4152     debug(F100,"tthang HP-UX style","",0);
4153     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0)        /* lower DTR */
4154       return(-1);                                  /* oops, can't. */
4155     msleep(HUPTIME);                               /* Pause half a second. */
4156     x = 1;                                         /* Set return code */
4157     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) {     /* Get line status. */
4158         if ((modem_rtn & MDCD) != 0)               /* Check if CD is low. */
4159           x = -1;                                  /* CD didn't drop, fail. */
4160     } else x = -1;
4161
4162     /* Even if above calls fail, RTS & DTR should be turned back on. */
4163     modem_rtn = MRTS | MDTR;
4164     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
4165     return(x);
4166 #else
4167 /* New way, from Hellmuth Michaelis */
4168     debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
4169     if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
4170         debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
4171         return(-1);
4172     }
4173     sprintf(modem_state,"%#lx",modem_rtn);
4174     debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
4175     modem_sav = modem_rtn;              /* Save current modem signals */
4176     modem_rtn &= ~MDTR;                 /* Turn DTR bit off */
4177     sprintf(modem_state,"%#lx",modem_rtn);
4178     debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
4179     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
4180         debug(F100,"tthang HP-UX: can't lower DTR!","",0);
4181         return(-1);                     /* oops, can't. */
4182     }
4183     msleep(HUPTIME);                    /* Pause half a second. */
4184     x = 1;                              /* Set return code */
4185     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
4186         sprintf(modem_state,"%#lx",modem_rtn);
4187         debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
4188         if ((modem_rtn & MDCD) != 0) {  /* Check if CD is low. */
4189             debug(F100,"tthang HP-UX: DCD not down","",0);
4190             x = -1;                     /* CD didn't drop, fail. */
4191         } else {
4192             debug(F100,"tthang HP-UX: DCD down","",0);
4193         }
4194     } else {
4195         x = -1;
4196         debug(F100,"tthang HP-UX: can't get DCD status !","",0);
4197     }
4198
4199     /* Even if above calls fail, DTR should be turned back on. */
4200
4201     modem_sav |= MDTR;
4202     if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
4203         x = -1;
4204         debug(F100,"tthang HP-UX: can't set saved state","",0);
4205     } else {
4206         sprintf(modem_state,"%#lx",modem_sav);
4207         debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
4208     }
4209     return(x);
4210 #endif /* COMMENT */
4211
4212 #else /* AT&T but not HP-UX */
4213
4214 /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
4215 /* It is not known how many, if any, systems actually implement them, */
4216 /* so we include them here in ifdef's. */
4217
4218 /*
4219   Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
4220   gives error 22 (invalid argument).
4221 */
4222 #ifndef _IBMR2
4223 /*
4224   No modem-signal twiddling for IBM RT PC or RS/6000.
4225   In AIX 3.1 and earlier, the ioctl() call is broken.
4226   This code could be activated for AIX 3.1 with PTF 2006 or later
4227   (e.g. AIX 3.2), but close/open does the job too, so why bother.
4228 */
4229 #ifdef TIOCMBIS                         /* Bit Set */
4230 #ifdef TIOCMBIC                         /* Bit Clear */
4231 #ifdef TIOCM_DTR                        /* DTR */
4232
4233 /* Clear DTR, sleep 300 msec, turn it back on. */
4234 /* If any of the ioctl's return failure, go on to the next section. */
4235
4236     z = TIOCM_DTR;                      /* Code for DTR. */
4237 #ifdef COMMENT
4238 /*
4239   This was the cause of the troubles with the Solaris Port Monitor.
4240   The problem is: RTS never comes back on.  Moral: Don't do it!
4241   (But why doesn't it come back on?  See the TIOCMBIS call...)
4242 */
4243 #ifdef TIOCM_RTS                        /* Lower RTS too if symbol is known. */
4244     z |= TIOCM_RTS;
4245 #endif /* TIOCM_RTS */
4246 #endif /* COMMENT */
4247
4248     debug(F101,"tthang TIOCM signal mask","",z);
4249     if (ioctl(ttyfd,TIOCMBIC,&z) > -1) {   /* Try to lower DTR. */
4250         debug(F100,"tthang TIOCMBIC ok","",0);
4251         msleep(HUPTIME);                   /* Pause half a second. */
4252         if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
4253             debug(F100,"tthang TIOCMBIS ok","",0);
4254 #ifndef CLSOPN
4255             return(1);                  /* Success, done. */
4256 #endif /* CLSOPN */
4257         } else {                        /* Couldn't raise, continue. */
4258             debug(F101,"tthang TIOCMBIS errno","",errno);
4259         }
4260     } else {                            /* Couldn't lower, continue. */
4261         debug(F101,"tthang TIOCMBIC errno","",errno);
4262     }
4263 #endif /* TIOCM_DTR */
4264 #endif /* TIOCMBIC */
4265 #endif /* TIOCMBIS */
4266 #endif /* _IBMR2 */
4267
4268 /*
4269   General AT&T UNIX case, not HPUX.  The following code is highly suspect.  No
4270   two AT&T-based systems seem to do this the same way.  The object is simply
4271   to turn off DTR and then turn it back on.  SVID says the universal method
4272   for turning off DTR is to set the speed to zero, and this does seem to do
4273   the trick in all cases.  But neither SVID nor any known man pages say how to
4274   turn DTR back on again.  Some variants, like most Xenix implementations,
4275   raise DTR again when the speed is restored to a nonzero value.  Others
4276   require the device to be closed and opened again, but this is risky because
4277   getty could seize the device during the instant it is closed.
4278 */
4279
4280 /* Return code for ioctl failures... */
4281 #ifdef ATT6300
4282     x = 1;                              /* ATT6300 doesn't want to fail... */
4283 #else
4284     x = -1;
4285 #endif /* ATT6300 */
4286
4287     debug(F100,"tthang get settings","",0);
4288     if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
4289       return(x);                        /* Fail if this doesn't work. */
4290     if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
4291       return(x);
4292     ttc_save = ttcur.c_cflag;           /* Remember current speed. */
4293     spdsav = ttc_save & CBAUD;
4294     debug(F101,"tthang speed","",spdsav);
4295
4296 #ifdef O_NDELAY
4297     debug(F100,"tthang turning O_NDELAY on","",0);
4298     fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
4299 #endif /* O_NDELAY */
4300
4301 #ifdef ATT7300 /* This is the way it is SUPPOSED to work */
4302     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4303 #else
4304 #ifdef RTAIX
4305     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4306 #else          /* This way really works but may be dangerous */
4307 #ifdef u3b2
4308     ttcur.c_cflag = ~(CBAUD|CLOCAL);    /* Special for AT&T 3B2s */
4309                                         /* (CLOCAL must be OFF) */
4310 #else
4311 #ifdef SCO3R2                           /* SCO UNIX 3.2 */
4312 /*
4313   This is complete nonsense, but an SCO user claimed this change made
4314   hanging up work.  Comments from other SCO UNIX 3.2 users would be
4315   appreciated.
4316 */
4317     ttcur.c_cflag = CBAUD|B0;
4318 #else
4319 #ifdef AIXRS                            /* AIX on RS/6000 */
4320 /*
4321   Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
4322   even though you can do it on the built-in port and the 8- and 16-port
4323   adapters.  (Untested on 128-port adapter.)
4324 */
4325     ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
4326 #else                                   /* None of the above */
4327 /*
4328   Set everything, including the speed, to zero, except for the CLOCAL
4329   and HUPCL bits.
4330 */
4331     ttcur.c_cflag = CLOCAL|HUPCL;
4332 #endif /* AIXRS */
4333 #endif /* SCO3R2 */
4334 #endif /* u3b2 */
4335 #endif /* RTAIX */
4336 #endif /* ATT7300 */
4337
4338 #ifdef COMMENT
4339     /* and if none of those work, try one of these... */
4340     ttcur.c_cflag = 0;
4341     ttcur.c_cflag = CLOCAL;
4342     ttcur.c_cflag &= ~(CBAUD|HUPCL);
4343     ttcur.c_cflag &= ~(CBAUD|CREAD);
4344     ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
4345     /* or other combinations */
4346 #endif /* COMMENT */
4347
4348 #ifdef TCXONC
4349     debug(F100,"tthang TCXONC","",0);
4350     if (ioctl(ttyfd, TCXONC, 1) < 0) {
4351         debug(F101,"tthang TCXONC failed","",errno);
4352     }
4353 #endif /* TCXONC */
4354
4355 #ifdef TIOCSTART
4356     debug(F100,"tthang TIOCSTART","",0);
4357     if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
4358         debug(F101,"tthang TIOCSTART failed","",errno);
4359     }
4360 #endif /* TIOCSTART */
4361
4362     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
4363         debug(F101,"tthang TCSETAF failed","",errno);
4364         fcntl(ttyfd, F_SETFL, flags);   /* Restore flags */
4365         return(-1);                     /* before returning. */
4366     }
4367     msleep(300);                        /* Give modem time to notice. */
4368
4369 #ifndef NOCOTFMC
4370
4371 /* Now, even though it doesn't say this in SVID or any man page, we have */
4372 /* to close and reopen the device.  This is not necessary for all systems, */
4373 /* but it's impossible to predict which ones need it and which ones don't. */
4374
4375 #ifdef ATT7300
4376 /*
4377   Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
4378   related ioctl's for their internal modems.  attmodem has getty status and
4379   modem-in-use bit.  Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
4380   but also ruins the file descriptor, and no other phone(7) ioctl call can fix
4381   it.  Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
4382   The only way to undo the damage is to close the fd and then reopen it.
4383 */
4384     if (attmodem & ISMODEM) {
4385         debug(F100,"tthang attmodem close/open","",0);
4386         ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
4387         ioctl(ttyfd,PIOCDISC,&dialer);  /* Disconnect phone. */
4388         close(ttyfd);                   /* Close and reopen the fd. */
4389         ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
4390         attmodem &= ~ISMODEM;           /* Phone no longer in use. */
4391     }
4392 #else /* !ATT7300 */
4393 /* It seems we have to close and open the device for other AT&T systems */
4394 /* too, and this is the place to do it.  The following code does the */
4395 /* famous close(open(...)) magic by default.  If that doesn't work for you, */
4396 /* then try uncommenting the following statement or putting -DCLSOPN in */
4397 /* the makefile CFLAGS. */
4398
4399 /* #define CLSOPN */
4400
4401 #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
4402
4403 #ifdef O_NDELAY
4404 #define OPENFLGS O_RDWR | O_NDELAY
4405 #else
4406 #define OPENFLGS O_RDWR
4407 #endif
4408
4409 #ifndef CLSOPN
4410 /* This method is used by default, i.e. unless CLSOPN is defined. */
4411 /* It is thought to be safer because there is no window where getty */
4412 /* can seize control of the device.  The drawback is that it might not work. */
4413
4414     debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
4415     close(priv_opn(ttnmsv, OPENFLGS));
4416
4417 #else
4418 /* This method is used if you #define CLSOPN.  It is more likely to work */
4419 /* than the previous method, but it's also more dangerous. */
4420
4421     debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
4422     close(ttyfd);
4423     msleep(10);
4424     ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */
4425 #endif /* CLSOPN */
4426 #undef OPENFLGS
4427
4428 #endif /* SCO32 */
4429 #endif /* ATT7300 */
4430
4431 #endif /* NOCOTFMC */
4432
4433 /* Now put all flags & modes back the way we found them. */
4434 /* (Does the order of ioctl & fcntl matter ? ) */
4435
4436     debug(F100,"tthang restore settings","",0);
4437     ttcur.c_cflag = ttc_save;           /* Get old speed back. */
4438     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
4439       return(-1);
4440 #ifdef O_NDELAY
4441 /*
4442   This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
4443   After closing a modem line, the modem will probably not be asserting
4444   carrier any more, so we should not require carrier any more.  If this
4445   causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
4446   than O_NDELAY.
4447 */
4448     flags &= ~O_NDELAY;                 /* Don't require carrier on reopen */
4449 #endif /* O_NDELAY */
4450     if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */
4451       return(-1);
4452
4453     return(1);
4454 #endif /* not HPUX */
4455 #endif /* ATTSV */
4456 #endif /* BSD44ORPOSIX */
4457 #endif /* HUP_POSIX */
4458 #endif /* NOLOCAL */
4459 }
4460
4461 /*
4462   Major change in 5A(174).  We used to use LPASS8, if it was defined, to
4463   allow 8-bit data and Xon/Xoff flow control at the same time.  But this
4464   LPASS8 business seems to have been causing trouble for everybody but me!
4465   For example, Annex terminal servers, commonly used with Encore computers,
4466   do not support LPASS8 even though the Encore itself does.  Ditto for many
4467   other terminal servers, TELNET connections, rlogin connections, etc etc.
4468   Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
4469   serial lines, even though LPASS8 is a feature of 4.3BSD.  So let's turn it
4470   off for everybody.  That means we goes back to using raw mode, with no
4471   flow control.  Phooey.
4472
4473   NOTE: This must be done before the first reference to LPASS8 in this file,
4474   and after the last #include statment.
4475 */
4476 #ifdef LPASS8
4477 #undef LPASS8
4478 #endif /* LPASS8 */
4479
4480 /*  T T R E S  --  Restore terminal to "normal" mode.  */
4481
4482 /* ske@pkmab.se: There are two choices for what this function should do.
4483  * (1) Restore the tty to current "normal" mode, with carrier treatment
4484  * according to ttcarr, to be used after every kermit command. (2) Restore
4485  * the tty to the state it was in before kermit opened it. These choices
4486  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
4487  * is currently being called as in choice (1), but ttold basically holds
4488  * the initial parameters, as in (2), and the description at the beginning
4489  * of this file says (2).
4490  *
4491  * I don't think restoring tty parameters after all kermit commands makes
4492  * much of a difference.  Restoring them upon exit from kermit may be of
4493  * some use in some cases (when the line is not restored automatically on
4494  * close, by the operating system).
4495  *
4496  * I can't choose which one it should be, so I haven't changed it. It
4497  * probably works as it is, too. It would probably even work even with
4498  * ttres() entirely deleted...
4499  *
4500  * (from fdc: Actually, this function operates in remote mode too, so
4501  * it restores the console (command) terminal to whatever mode it was
4502  * in before packet operations began, so that commands work right again.)
4503  */
4504 int
4505 ttres() {                               /* Restore the tty to normal. */
4506     int x;
4507
4508     if (ttyfd < 0) return(-1);          /* Not open. */
4509
4510     if (ttfdflg) return(0);             /* Don't mess with terminal modes if */
4511                                         /* we got ttyfd from another process */
4512 #ifdef  NETCONN
4513     if (netconn) {                      /* Network connection */
4514         tvtflg = 0;
4515 #ifdef TCPSOCKET
4516 #ifdef TCP_NODELAY
4517         {
4518             extern int tcp_nodelay;     /* Just put this back if necessary */
4519             if (ttnet == NET_TCPB) {
4520                 if (nodelay_sav > -1) {
4521                     no_delay(ttyfd,nodelay_sav);
4522                     nodelay_sav = -1;
4523                 }
4524             }
4525         }
4526 #endif /* TCP_NODELAY */
4527 #ifdef TN_COMPORT
4528         if (istncomport()) {
4529             int rc = -1;
4530             if ((rc = tnsetflow(ttflow)) < 0)
4531               return(rc);
4532             if (ttspeed <= 0) 
4533               ttspeed = tnc_get_baud();
4534             else if ((rc = tnc_set_baud(ttspeed)) < 0)
4535               return(rc);
4536             tnc_set_datasize(8);
4537             tnc_set_stopsize(stopbits);
4538
4539 #ifdef HWPARITY
4540             if (hwparity) {
4541                 switch (hwparity) {
4542                   case 'e':                     /* Even */
4543                     debug(F100,"ttres 8 bits + even parity","",0);
4544                     tnc_set_parity(3);
4545                     break;
4546                   case 'o':                     /* Odd */
4547                     debug(F100,"ttres 8 bits + odd parity","",0);
4548                     tnc_set_parity(2);
4549                     break;
4550                   case 'm':                     /* Mark */
4551                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
4552                     tnc_set_parity(4);
4553                     break;
4554                   case 's':                     /* Space */
4555                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
4556                     tnc_set_parity(5);
4557                     break;
4558                 }
4559             } else
4560 #endif /* HWPARITY */
4561             {
4562                 tnc_set_parity(1);              /* None */
4563             }
4564             tvtflg = 0;
4565             return(0);
4566         }
4567 #endif /* TN_COMPORT */
4568 #endif /* TCPSOCKET */
4569         return(0);
4570     }
4571 #endif  /* NETCONN */
4572 #ifdef NETCMD
4573     if (ttpipe) return(0);
4574 #endif /* NETCMD */
4575 #ifdef NETPTY
4576     if (ttpty) return(0);
4577 #endif /* NETPTY */
4578
4579 /* Real terminal device, so restore its original modes */
4580
4581 #ifdef BSD44ORPOSIX                     /* For POSIX like this */
4582     debug(F100,"ttres BSD44ORPOSIX","",0);
4583     x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
4584 #else                                   /* For all others... */
4585 #ifdef ATTSV                            /* For AT&T versions... */
4586     debug(F100,"ttres ATTSV","",0);
4587     x = ioctl(ttyfd,TCSETAW,&ttold);    /* Restore tty modes this way. */
4588 #else
4589 /* Here we restore the modes for BSD */
4590
4591 #ifdef LPASS8                           /* Undo "pass8" if it were done */
4592     if (lmodef) {
4593         if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4594           debug(F100,"ttres TIOCLSET failed","",0);
4595         else
4596           debug(F100,"ttres TIOCLSET ok","",0);
4597     }
4598 #endif /* LPASS8 */
4599
4600 #ifdef CK_DTRCTS                   /* Undo hardware flow 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 /* CK_DTRCTS */
4608
4609 #ifdef TIOCGETC                         /* Put back special characters */
4610     if (tcharf && (xlocal == 0)) {
4611         if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
4612           debug(F100,"ttres TIOCSETC failed","",0);
4613         else
4614           debug(F100,"ttres TIOCSETC ok","",0);
4615     }
4616 #endif /* TIOCGETC */
4617
4618 #ifdef TIOCGLTC                         /* Put back local special characters */
4619     if (ltcharf && (xlocal == 0)) {
4620         if (ioctl(ttyfd,TIOCSLTC,&ltchold) < 0)
4621           debug(F100,"ttres TIOCSLTC failed","",0);
4622         else
4623           debug(F100,"ttres TIOCSLTC ok","",0);
4624     }
4625 #endif /* TIOCGLTC */
4626
4627 #ifdef BELLV10
4628     debug(F100,"ttres BELLV10","",0);
4629     x = ioctl(ttyfd,TIOCSETP,&ttold);   /* Restore both structs */
4630     x = ioctl(ttyfd,TIOCSDEV,&tdold);
4631 #else
4632     debug(F100,"ttres stty","",0);
4633     x = stty(ttyfd,&ttold);             /* Restore tty modes the old way. */
4634 #endif /* BELLV10 */
4635
4636     if (!xlocal)
4637       msleep(100);                      /* This replaces sleep(1)... */
4638                                         /* Put back sleep(1) if tty is */
4639                                         /* messed up after close. */
4640 #endif /* ATTSV */
4641 #endif /* BSD44ORPOSIX */
4642
4643     debug(F101,"ttres result","",x);
4644 #ifndef QNX
4645     if (x < 0) debug(F101,"ttres errno","",errno);
4646 #endif /* QNX */
4647
4648 #ifdef AIXRS
4649 #ifndef AIX41
4650     x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
4651     debug(F101,"ttres AIX line discipline rts restore","",x);
4652 #endif /* AIX41 */
4653 #endif /* AIXRS */
4654
4655 #ifdef BSD41
4656     if (ttld > -1) {                    /* Put back line discipline */
4657         x = ioctl(ttyfd, TIOCSETD, &ttld);
4658         debug(F101,"ttres BSD41 line discipline restore","",x);
4659         if (x < 0) debug(F101,"...ioctl errno","",errno);
4660         ttld = -1;
4661     }
4662 #endif /* BSD41 */
4663
4664 #ifdef sony_news
4665     x = xlocal ? km_ext : km_con;       /* Restore Kanji mode. */
4666     if (x != -1) {                      /* Make sure we know original modes. */
4667         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
4668             perror("ttres can't set Kanji mode");
4669             debug(F101,"ttres error setting Kanji mode","",x);
4670             return(-1);
4671         }
4672     }
4673     debug(F100,"ttres set Kanji mode ok","",0);
4674 #endif /* sony_news */
4675
4676     tvtflg = 0;                         /* Invalidate terminal mode settings */
4677     debug(F101,"ttres return code","",x);
4678     return(x);
4679 }
4680
4681 #ifndef NOUUCP
4682
4683 /*  T T C H K P I D  --  Check lockfile pid  */
4684 /*
4685   Read pid from lockfile named f, check that it's still valid.
4686   If so, return 1.
4687   On failure to read pid, return 1.
4688   Otherwise, try to delete lockfile f and return 0 if successful, else 1.
4689 */
4690 static int
4691 ttchkpid(f) char *f; {
4692     int pid, mypid, x;
4693     pid = ttrpid(f);                    /* Read pid from file. */
4694     if (pid > -1) {                     /* If we were able to read the pid.. */
4695         debug(F101,"ttchkpid lock pid","",pid);
4696         errno = 0;                      /* See if process still exists. */
4697         mypid = (int)getpid();          /* Get my own pid. */
4698         debug(F101,"ttchkpid my pid","",mypid);
4699         if (pid == mypid) {             /* It's me! */
4700             x = -1;                     /* So I can delete it */
4701             errno = ESRCH;              /* pretend it's invalid */
4702         } else {                        /* It's not me */
4703             x = kill((PID_T)pid, 0);    /* See if it's a live process */
4704             debug(F101,"ttchkpid kill errno","",errno);
4705         }
4706         debug(F101,"ttchkpid pid test","",x);
4707         if (x < 0 && errno == ESRCH) { /* pid is invalid */
4708             debug(F111,"removing stale lock",f,pid);
4709             if (!backgrd)
4710               printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
4711             priv_on();
4712             x = unlink(f);              /* Remove the lockfile. */
4713             priv_off();
4714             debug(F111,"ttchkpid unlink",f,x);
4715             if (x > -1)
4716               return(0);                /* Device is not locked after all */
4717             else if (!backgrd)
4718               perror(f);
4719         }
4720         return(1);
4721     }
4722     return(1);                          /* Failure to read pid */
4723 }
4724
4725 #ifdef HPUX
4726
4727 /* Aliases (different drivers) for HP-UX dialout devices: */
4728
4729 static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
4730 static int ttydexists = 0;
4731
4732 #endif /* HPUX */
4733
4734 /*  T T R P I D  --  Read pid from lockfile "name" */
4735
4736 static int
4737 ttrpid(name) char *name; {
4738     long len;
4739     int x, fd, pid;
4740     short spid;
4741     char buf[32];
4742
4743     debug(F110,"ttrpid",name,0);
4744     if (!name) return(-1);
4745     if (!*name) return(-1);
4746     priv_on();
4747     len = zchki(name);                  /* Get file length */
4748     priv_off();
4749     debug(F101,"ttrpid zchki","",len);
4750     if (len < 0)
4751       return(-1);
4752     if (len > 31)
4753       return(-1);
4754     priv_on();
4755     fd = open(name,O_RDONLY);           /* Try to open lockfile. */
4756     priv_off();
4757     debug(F101,"ttrpid fd","",fd);
4758     if (fd <= 0)
4759       return(-1);
4760 /*
4761   Here we try to be flexible and allow for all different binary and string
4762   formats at runtime, rather than a specific format for each configuration
4763   hardwired at compile time.
4764 */
4765     pid = -1;
4766 #ifndef COHERENT
4767 /*
4768   COHERENT uses a string PID but without leading spaces or 0's, so there is
4769   no way to tell from the file's length whether it contains a string or binary
4770   pid.  So for COHERENT only, we only allow string pids.  For all others, we
4771   decide based on the size of the lockfile.
4772 */
4773     if (len > 4) {                      /* If file > 4 bytes it's a string */
4774 #endif /* COHERENT */
4775         x = read(fd,buf,(int)len);
4776         debug(F111,"ttrpid string read",buf,x);
4777         if (x < 0) {
4778             pid = -1;
4779         } else {
4780             buf[31] = '\0';
4781             x = sscanf(buf,"%d",&pid);  /* Get the integer pid from it. */
4782         }
4783 #ifndef COHERENT
4784     } else if (len == 4) {              /* 4 bytes so binary */
4785         x = read(fd, (char *)&pid, 4);  /* Read the bytes into an int */
4786         debug(F101,"ttrpid integer read","",x);
4787         if (x < 4)
4788           pid = -1;
4789     } else if (len == 2) {              /* 2 bytes binary */
4790         x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */
4791         debug(F101,"ttrpid short read","",x);
4792         if (x < 2)
4793           pid = -1;
4794         else
4795           pid = spid;
4796     } else
4797       pid = -1;
4798 #endif /* COHERENT */
4799     close(fd);                          /* Close the lockfile */
4800     debug(F101,"ttrpid pid","",pid);
4801     return(pid);
4802 }
4803 #endif /* NOUUCP */
4804
4805 /*  T T L O C K  */
4806
4807 /*
4808   This function attempts to coordinate use of the communication device with
4809   other copies of Kermit and any other program that follows the UUCP
4810   device-locking conventions, which, unfortunately, vary among different UNIX
4811   implementations.  The idea is to look for a file of a certain name, the
4812   "lockfile", in a certain directory.  If such a file is found, then the line
4813   is presumed to be in use, and Kermit should not use it.  If no such file is
4814   found, Kermit attempts to create one so that other programs will not use the
4815   same line at the same time.  Because the lockfile and/or the directory it's
4816   in might lack write permission for the person running Kermit, Kermit could
4817   find itself running setuid to uucp or other user that does have the
4818   necessary permissions.  At startup, Kermit has changed its effective uid to
4819   the user's real uid, and so ttlock() must switch back to the original
4820   effective uid in order to create the lockfile, and then back again to the
4821   real uid to prevent unauthorized access to other directories or files owned
4822   by the user the program is setuid to.
4823
4824   Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
4825   based on suggestions from Warren Tucker.  Call with pointer to name of
4826   tty device.  Returns:
4827
4828    0 on success
4829   -1 on failure
4830
4831   Note: Once privileges are turned on using priv_on(), it is essential that
4832   they are turned off again before this function returns.
4833 */
4834 #ifdef SVR4                             /* Lockfile uses device numbers. */
4835 /*
4836   Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
4837   it is the behavior of the "reference version" of SVR4, i.e. the Intel
4838   port from UNIX Systems Laboratories, then called Univel UnixWare,
4839   then called Novell UnixWare, then called SCO Unixware, then called Caldera
4840   Open UNIX...  It also makes much more sense than device-name-based lockfiles
4841   since there can be multiple names for the same device, symlinks, etc.
4842 */
4843 #ifndef NOLFDEVNO
4844 #ifndef LFDEVNO                         /* Define this for SVR4 */
4845 #ifndef AIXRS                           /* But not for RS/6000 AIX 3.2, etc. */
4846 #ifndef BSD44                           /* If anybody else needs it... */
4847 #ifndef __386BSD__
4848 #ifndef __FreeBSD__
4849 #ifndef HPUX10
4850 #ifndef IRIX51                          /* SGI IRIX 5.1 or later */
4851 #ifndef CK_SCOV5                        /* SCO Open Server 5.0 */
4852 #define LFDEVNO
4853 #endif /* CK_SCOV5 */
4854 #endif /* IRIX51 */
4855 #endif /* HPUX10 */
4856 #endif /* __FreeBSD__ */
4857 #endif /* __386BSD__ */
4858 #endif /* BSD44 */
4859 #endif /* AIXRS */
4860 #endif /* LFDEVNO */                    /* ... define it here or on CC */
4861 #endif /* NOLFDEVNO */
4862 #endif /* SVR4 */                       /* command line. */
4863
4864 #ifdef COHERENT
4865 #define LFDEVNO
4866 #endif /* COHERENT */
4867
4868 /*
4869   For platforms where the lockfile name is made from device/major/minor
4870   device number, as in SVR4.  Which, if we must have lockfiles at all, is
4871   by far the best format, since it eliminates all the confusion that stems
4872   from multiple names (or drivers) for the same port, not to mention
4873   symlinks.  It might even be a good idea to start using this form even
4874   on platforms where it's not supported, alongside the normal forms for those
4875   platforms, in order to get people used to it...
4876 */
4877 #ifdef LFDEVNO
4878 #ifndef major                           /* If we didn't find it */
4879 #ifdef SVR4                             /* then for Sys V R4 */
4880 #include <sys/mkdev.h>                  /* look here */
4881 #else                                   /* or for SunOS versions */
4882 #ifdef SUNOS4                           /* ... */
4883 #include <sys/sysmacros.h>              /* look here */
4884 #else                                   /* Otherwise take a chance: */
4885 #define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
4886 #define minor(dev) ( (int) ( (dev) & 0xff))
4887 #endif /* SUNOS4 */
4888 #endif /* SVR4 */
4889 #endif /* major */
4890 #endif /* LFDEVNO */
4891
4892 /* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
4893
4894 #ifdef LOCKF
4895 #ifndef F_TLOCK
4896 #undef LOCKF
4897 #ifndef NOLOCKF
4898 #define NOLOCKF
4899 #endif /* NOLOCKF */
4900 #endif /* F_TLOCK */
4901 #endif /* LOCKF */
4902
4903 #ifdef LOCKF
4904 #ifndef F_ULOCK
4905 #undef LOCKF
4906 #ifndef NOLOCKF
4907 #define NOLOCKF
4908 #endif /* NOLOCKF */
4909 #endif /* F_ULOCK */
4910 #endif /* LOCKF */
4911
4912 static char linkto[DEVNAMLEN+1];
4913 static char * linkdev = NULL;
4914
4915 #ifndef NOUUCP
4916 #ifdef USETTYLOCK
4917 #ifdef LOCK_DIR
4918 char * uucplockdir = LOCK_DIR;
4919 #else
4920 char * uucplockdir = "";
4921 #endif /* LOCK_DIR */
4922 #else
4923 #ifdef LOCK_DIR
4924 char * uucplockdir = LOCK_DIR;
4925 #else
4926 char * uucplockdir = "";
4927 #endif /* LOCK_DIR */
4928 #endif /* USETTYLOCK */
4929 #else
4930 char * uucplockdir = "";
4931 #endif /* NOUUCP */
4932
4933 #ifdef QNX                              /* Only for QNX4 */
4934 int                                     /* Visible to outside world */
4935 qnxopencount() {                        /* Get QNX device open count */
4936     struct _dev_info_entry info;
4937     int x;
4938
4939     x = -1;                             /* Unknown */
4940     if (ttyfd > -1) {
4941         if (!dev_info(ttyfd, &info)) {
4942             debug(F101,"ttlock QNX open_count","",info.open_count);
4943             x = info.open_count;
4944         }
4945     }
4946     return(x);
4947 }
4948 #endif /* QNX */
4949
4950 char *
4951 ttglckdir() {                           /* Get Lockfile directory name */
4952 #ifdef __OpenBSD__
4953     return("/var/spool/lock");
4954 #else /* __OpenBSD__ */
4955 #ifdef __FreeBSD__
4956     return("/var/spool/lock");
4957 #else  /* __FreeBSD__ */
4958 #ifdef LOCK_DIR
4959     char * s = LOCK_DIR;
4960 #endif /* LOCK_DIR */
4961 #ifdef NOUUCP
4962     return("");
4963 #else  /* NOUUCP */
4964 #ifdef LOCK_DIR
4965     return(s);
4966 #else  /* LOCK_DIR */
4967     return("");
4968 #endif /* LOCK_DIR */
4969 #endif /* NOUUCP */
4970 #endif /* __FreeBSD__ */
4971 #endif /* __OpenBSD__ */
4972 }
4973
4974 static int
4975 ttlock(ttdev) char *ttdev; {
4976
4977     int x, n;
4978     int islink = 0;
4979 #ifdef __FreeBSD__
4980     char *devname;
4981 #endif  /* __FreeBSD__ */
4982
4983 #ifdef NOUUCP
4984     debug(F100,"ttlock NOUUCP","",0);
4985     ckstrncpy(flfnam,"NOLOCK",FLFNAML);
4986     haslock = 1;
4987     return(0);
4988 #else /* !NOUUCP */
4989
4990 #ifdef USETTYLOCK
4991     haslock = 0;                        /* Not locked yet. */
4992     *flfnam = '\0';                     /* Lockfile name is empty. */
4993 #ifdef __FreeBSD__
4994     if ((devname = xxlast(ttdev,'/')) != NULL)
4995 #ifdef FREEBSD8
4996       ckstrncat(lockname,devname+1,DEVNAMLEN-ckstrncpy(lockname,"pts",4));
4997 #else
4998       ckstrncpy(lockname,devname+1,DEVNAMLEN);
4999 #endif  /* FREEBSD8 */
5000 #else
5001     if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
5002       ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
5003 #endif  /* __FreeBSD__ */
5004     else
5005       ckstrncpy(lockname,ttdev,DEVNAMLEN);
5006 /*
5007   This might be overkill, but it's not clear from the man pages whether
5008   ttylock() can be called without calling ttylocked() first, since the doc
5009   says that ttylocked() removes any stale lockfiles, but it does not say this
5010   about ttylock().  Also the docs don't say what ttylocked() returns in the
5011   case when it finds and removes a stale lockfile.  So one or both calls to
5012   to ttylocked() might be superfluous, but they should do no harm.  Also I'm
5013   assuming that we have to do all the same ID swapping, etc, with these
5014   routines as we do without them.  Thus the priv_on/off() sandwich.
5015 */
5016 #ifdef USE_UU_LOCK
5017     priv_on();                          /* Turn on privs */
5018     x = uu_lock(lockname);              /* Try to set the lock */
5019     priv_off();                         /* Turn privs off */
5020     debug(F111,"ttlock uu_lock",lockname,x);
5021     switch (x) {
5022       case UU_LOCK_INUSE:
5023         return(-2);
5024       case UU_LOCK_OK:
5025 #ifdef BSD44
5026         ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
5027 #endif /* BSD44 */
5028         haslock = 1;
5029         return(0);
5030       default:
5031         return(-1);
5032     }
5033 #else  /* USE_UU_LOCK */
5034     priv_on();                          /* Turn on privs */
5035     if (ttylocked(lockname)) {          /* This should remove any stale lock */
5036         if (ttylocked(lockname)) {      /* so check again. */
5037             priv_off();
5038             return(-5);                 /* Still locked, fail. */
5039         }
5040     }
5041     x = ttylock(lockname);              /* Lock it. */
5042     priv_off();                         /* Turn off privs */
5043
5044     debug(F111,"ttlock lockname",lockname,x);
5045     if (x > -1) {
5046         /*
5047           We don't really know the name of the lockfile, but
5048           this is what the man page says it is.  In USETTYLOCK
5049           builds, it is used only for display by SHOW COMM.
5050         */
5051         ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
5052         haslock = 1;
5053     }
5054     return(x);
5055 #endif /* USE_UU_LOCK */
5056 #else  /* Systems that don't have ttylock()... */
5057
5058 #ifndef HPUX
5059
5060     int lockfd;                         /* File descriptor for lock file. */
5061     PID_T pid;                          /* Process id of this process. */
5062     int tries;                          /* How many times we've tried... */
5063     struct stat devbuf;                 /* For device numbers (SVR4). */
5064
5065 #ifdef PIDSTRING
5066     char pid_str[32];                   /* My pid in string format. */
5067 #endif /* PIDSTRING */
5068
5069     char *device, *devname;
5070
5071 #define LFNAML 256                      /* Max length for lock file name. */
5072     char lockfil[LFNAML];               /* Lock file name */
5073 #ifdef RTAIX
5074     char lklockf[LFNAML];               /* Name for link to lock file  */
5075 #endif /* RTAIX */
5076 #ifdef CKSYMLINK
5077     char symlock[LFNAML];               /* Name for symlink lockfile name */
5078 #endif /* CKSYMLINK */
5079     char tmpnam[LFNAML+30];             /* Temporary lockfile name. */
5080     char *lockdir = LOCK_DIR;           /* Defined near top of this file, */
5081                                         /* or on cc command line. */
5082     haslock = 0;                        /* Not locked yet. */
5083     *flfnam = '\0';                     /* Lockfile name is empty. */
5084     lock2[0] = '\0';                    /* Clear secondary lockfile name. */
5085     pid = getpid();                     /* Get id of this process. */
5086
5087 /*  Construct name of lockfile and temporary file */
5088
5089 /*  device  = name of tty device without the path, e.g. "ttyh8" */
5090 /*  lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
5091
5092     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5093
5094     if (stat(ttdev,&devbuf) < 0)
5095       return(-1);
5096
5097 #ifdef CKSYMLINK
5098     islink = 1;                         /* Assume it's a symlink */
5099     linkto[0] = '\0';                   /* But we don't know to what */
5100 #ifdef COMMENT
5101 /*
5102   This is undependable.  If it worked it would save the readlink call if
5103   we knew the device name was not a link.
5104 */
5105 #ifdef S_ISLNK
5106     islink = S_ISLNK(devbuf.st_mode);
5107     debug(F101,"ttlock stat S_ISLNK","",islink);
5108 #endif /* S_ISLNK */
5109 #endif /* COMMENT */
5110     if (islink) {
5111         n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
5112         debug(F111,"ttlock readlink",ttdev,n);
5113         if (n > -1)                     /* It is */
5114           linkto[n] = '\0';
5115         else                            /* It's not */
5116           islink = 0;
5117         debug(F111,"ttlock link",linkto,islink);
5118     }
5119     if (islink) {
5120         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5121         debug(F110,"ttlock linkdev",linkdev,0);
5122     }
5123 #endif /* CKSYMLINK */
5124
5125 /*
5126   On SCO platforms, if we don't have a symlink, then let's pretend the
5127   name given for the device is a symlink, because later we will change
5128   the name if it contains any uppercase characters.
5129 */
5130 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5131     if (!islink) {
5132         islink = 1;
5133         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5134         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5135         debug(F110,"ttlock linkdev",linkdev,0);
5136     }
5137 #else
5138 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5139     if (!islink) {
5140         islink = 1;
5141         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5142         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5143         debug(F110,"ttlock linkdev",linkdev,0);
5144     }
5145 #endif /* M_XENIX */
5146 #endif /* CK_SCOV5 */
5147
5148 #ifdef ISIII                            /* Interactive System III, PC/IX */
5149     ckstrncpy(lockfil, device, DEVNAMLEN);
5150 #else  /* not ISIII */
5151 #ifdef LFDEVNO                          /* Lockfilename has device numbers. */
5152 #ifdef COHERENT
5153     sprintf(lockfil,"LCK..%d.%d",       /* SAFE */
5154             major(devbuf.st_rdev),         /* major device number */
5155             0x1f & minor(devbuf.st_rdev)); /* minor device number */
5156 #else
5157     /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
5158     /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
5159     sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
5160             major(devbuf.st_dev),       /* device */
5161             major(devbuf.st_rdev),      /* major device number */
5162             minor(devbuf.st_rdev));     /* minor device number */
5163 #endif /* COHERENT */
5164 #else  /* Not LFDEVNO */
5165 #ifdef PTX                              /* Dynix PTX */
5166     if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
5167         if ((int)strlen(device) + 8 < LFNAML)
5168           sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
5169         else
5170           ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5171     } else
5172 #endif /* PTX */
5173       if ((int)strlen(device) + 5 < LFNAML)
5174         sprintf(lockfil,"LCK..%s", device);
5175       else
5176         ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5177 #ifdef RTAIX
5178     ckstrncpy(lklockf,device,DEVNAMLEN);
5179 #endif /* RTAIX */
5180 #ifdef CKSYMLINK
5181     symlock[0] = '\0';
5182     if (islink)
5183       ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
5184 #endif /* CKSYMLINK */
5185 #endif /* LFDEVNO */
5186 #endif /* ISIII */
5187
5188 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5189     {
5190         /* Lowercase the entire filename. */
5191         /* SCO says we must do this in V5.0 and later. */
5192         /* BUT... watch out for devices -- like Digiboard Portserver */
5193         /* That can have hundreds of ports... */
5194         char *p = (char *)(lockfil + 5);
5195         while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
5196     }
5197 #ifdef CKSYMLINK
5198     if (islink) {                       /* If no change */
5199         if (!strcmp(lockfil,symlock)) { /* then no second lockfile needed */
5200             islink = 0;
5201             symlock[0] = '\0';
5202         }
5203     }
5204 #endif /* CKSYMLINK */
5205 #else
5206 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5207     {
5208         int x; char c;
5209         x = (int)strlen(lockfil) - 1;   /* Get last letter of device name. */
5210         if (x > 0) {                    /* If it's uppercase, lower it. */
5211             c = lockfil[x];
5212             if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
5213         }
5214     }
5215 #ifdef CKSYMLINK
5216     if (islink) {
5217         if (!strcmp(lockfil,symlock)) { /* No change */
5218             islink = 0;                 /* so no second lockfile */
5219             symlock[0] = '\0';
5220         }
5221     }
5222 #endif /* CKSYMLINK */
5223 #endif /* M_XENIX */
5224 #endif /* CK_SCOV5 */
5225
5226 /*  flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
5227 /*  tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
5228
5229     ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
5230
5231 #ifdef RTAIX
5232     ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
5233 #endif /* RTAIX */
5234
5235 #ifndef LFDEVNO
5236 #ifdef CKSYMLINK
5237     /* If it's a link then also make a lockfile for the real name */
5238     debug(F111,"ttlock link symlock",symlock,islink);
5239     if (islink && symlock[0]) {
5240         /* But only if the lockfile names would be different. */
5241         /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
5242         ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
5243         debug(F110,"ttlock lock2",lock2,0);
5244         if (!strcmp(lock2,flfnam)) {    /* Are lockfile names the same? */
5245             debug(F100,"ttlock lock2 cleared","",0);
5246             lock2[0] = '\0';            /* Clear secondary lockfile name. */
5247         }
5248     }
5249 #endif /* CKSYMLINK */
5250 #endif /* LFDEVNO */
5251
5252     sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
5253     debug(F110,"ttlock flfnam",flfnam,0);
5254     debug(F110,"ttlock tmpnam",tmpnam,0);
5255
5256     priv_on();                          /* Turn on privileges if possible. */
5257     lockfd = creat(tmpnam, 0444);       /* Try to create temp lock file. */
5258     if (lockfd < 0) {                   /* Create failed. */
5259         debug(F111,"ttlock creat failed",tmpnam,errno);
5260         if (errno == ENOENT) {
5261             perror(lockdir);
5262             printf("UUCP not installed or Kermit misconfigured\n");
5263         } else {
5264             if (!quiet)
5265               perror(lockdir);
5266             unlink(tmpnam);             /* Get rid of the temporary file. */
5267         }
5268         priv_off();                     /* Turn off privileges!!! */
5269         return(-1);                     /* Return failure code. */
5270     }
5271 /* Now write the pid into the temp lockfile in the appropriate format */
5272
5273 #ifdef PIDSTRING                        /* For Honey DanBer UUCP, */
5274     sprintf(                            /* write PID as decimal string */
5275             pid_str,
5276 #ifdef LINUXFSSTND                      /* The "Linux File System Standard" */
5277 #ifdef FSSTND10                         /* Version 1.0 calls for */
5278             "%010d\n",                  /* leading zeros */
5279 #else                                   /* while version 1.2 calls for */
5280             "%10d\n",                   /* leading spaces */
5281 #endif /* FSSTND10 */
5282 #else
5283 #ifdef COHERENT
5284             "%d\n",                     /* with leading nothing */
5285 #else
5286             "%10d\n",                   /* with leading blanks */
5287 #endif /* COHERENT */
5288 #endif /* LINUXFSSTND */
5289             (int) pid
5290             );                          /* safe */
5291     write(lockfd, pid_str, 11);
5292     debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
5293
5294 #else /* Not PIDSTRING, use integer PID */
5295
5296     write(lockfd, (char *)&pid, sizeof(pid) );
5297     debug(F101,"ttlock pid","",(int) pid);
5298
5299 #endif /* PIDSTRING */
5300
5301 /* Now try to rename the temp file to the real lock file name. */
5302 /* This will fail if a lock file of that name already exists.  */
5303
5304     close(lockfd);                      /* Close the temp lockfile. */
5305     chmod(tmpnam,0444);                 /* Permission for a valid lock. */
5306     tries = 0;
5307     while (!haslock && tries++ < 2) {
5308         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5309         if (haslock) {                        /* If we got the lockfile */
5310 #ifdef RTAIX
5311             link(flfnam,lkflfn);
5312 #endif /* RTAIX */
5313 #ifdef CKSYMLINK
5314 #ifndef LFDEVNO
5315             if (islink && lock2[0])
5316               link(flfnam,lock2);
5317 #endif /* LFDEVNO */
5318 #endif /* CKSYMLINK */
5319
5320 #ifdef COMMENT
5321 /* Can't do this any more because device is not open yet so no ttyfd. */
5322 #ifdef LOCKF
5323 /*
5324   Advisory file locking works on SVR4, so we use it.  In fact, it is
5325   necessary in some cases, e.g. when SLIP is involved.  But it still doesn't
5326   seem to prevent multiple users accessing the same device by different names.
5327 */
5328             while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
5329                 debug(F111, "ttlock lockf returns errno", "", errno);
5330                 if ((++tries >= 3) || (errno != EAGAIN)) {
5331                     x = unlink(flfnam); /* remove the lockfile */
5332 #ifdef RTAIX
5333                     unlink(lkflfn);     /* And any links to it... */
5334 #endif /* RTAIX */
5335 #ifdef CKSYMLINK
5336 #ifndef LFDEVNO
5337                     if (islink && lock2[0])
5338                       unlink(lock2);    /* ditto... */
5339 #endif /* LFDEVNO */
5340 #endif /* CKSYMLINK */
5341                     debug(F111,"ttlock unlink",flfnam,x);
5342                     haslock = 0;
5343                     break;
5344                 }
5345                 sleep(2);
5346             }
5347             if (haslock)                /* If we got an advisory lock */
5348 #endif /* LOCKF */
5349 #endif /* COMMENT */
5350               break;                    /* We're done. */
5351
5352         } else {                        /* We didn't create a new lockfile. */
5353             priv_off();
5354             if (ttchkpid(flfnam)) {     /* Check existing lockfile */
5355                 priv_on();              /* cause ttchkpid turns priv_off... */
5356                 unlink(tmpnam);         /* Delete the tempfile */
5357                 debug(F100,"ttlock found tty locked","",0);
5358                 priv_off();             /* Turn off privs */
5359                 return(-2);             /* Code for device is in use. */
5360             }
5361             priv_on();
5362         }
5363     }
5364     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5365     priv_off();                         /* Turn off privs */
5366     return(haslock ? 0 : -1);           /* Return link's return code. */
5367
5368 #else /* HPUX */
5369
5370 /*
5371   HP-UX gets its own copy of this routine, modeled after the observed behavior
5372   of the HP-UX 'cu' program.  HP-UX serial device names consist of a base name
5373   such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
5374   designator which is a string of digits, possibly containing an imbedded
5375   letter "p".  Examples (for base name "tty"):
5376
5377      /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
5378
5379   According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
5380   used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
5381   on other models.  In HP-UX 10.00, "0p0" notation was adopted for all models.
5382   However, we make and enforce no such distinctions; either notation is
5383   accepted on any model or HP-UX version as a valid unit designator.
5384
5385   If a valid unit is specified (as opposed to a designer name or symlink), we
5386   check for all aliases of the given unit according to the devprefix[] array.
5387   If no lockfiles are found for the given unit, we can have the device; we
5388   create a lockfile LCK..name in the lockfile directory appropriate for the
5389   HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
5390   9.xx and earlier).  If it is a "cua" or "cul" device, a second lockfile is
5391   created with the "ttyd" prefix.  This is exactly what cu does.
5392
5393   If the "set line" device does not have a valid unit designator, then it is
5394   used literally and no synomyms are searched for and only one lockfile is
5395   created.
5396
5397   -fdc, March 1998.
5398 */
5399 #define LFNAML 80                       /* Max length for lock file name. */
5400
5401     int lockfd;                         /* File descriptor for lock file. */
5402     PID_T pid;                          /* Process ID of this process. */
5403     int fpid;                           /* pid found in existing lockfile. */
5404     int tries;                          /* How many times we've tried... */
5405     int i, k;                           /* Workers */
5406
5407     char *device, *devname;             /* "/dev/xxx", "xxx" */
5408     char *unit, *p;                     /* <instance>p<port> part of xxx */
5409
5410     char lockfil[LFNAML];               /* Lockfile name (no path) */
5411     char tmpnam[LFNAML];                /* Temporary lockfile name. */
5412
5413 #ifdef HPUX10                           /* Lockfile directory */
5414     char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */
5415 #else  /* HP-UX 9.xx and below */
5416 #ifdef LOCK_DIR
5417     char *lockdir = LOCK_DIR;           /* Defined near top of this file */
5418 #else
5419     char *lockdir = "/usr/spool/uucp";  /* or not... */
5420 #endif /* LOCK_DIR */
5421 #endif /* HPUX10 */
5422
5423     haslock = 0;                        /* Not locked yet. */
5424     *flfnam = '\0';                     /* Lockfile name is empty. */
5425     lock2[0] = '\0';                    /* Second one too. */
5426     pid = getpid();                     /* Get my process ID */
5427 /*
5428   Construct name of lockfile and temporary file...
5429   device  = name of tty device without the path, e.g. "tty0p0"
5430   lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
5431 */
5432     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5433     debug(F110,"TTLOCK device",device,0);
5434     ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
5435
5436     k = 0;                              /* Assume device is not locked */
5437     n = 0;                              /* Digit counter */
5438     unit = device;                      /* Unit = <instance>p<port> */
5439     while (*unit && !isdigit(*unit))    /* Search for digit... */
5440       unit++;
5441     p = unit;                           /* Verify <num>p<num> format... */
5442     debug(F110,"TTLOCK unit 1",unit,0);
5443 /*
5444   The unit number is recognized as:
5445   (a) any sequence of digits that runs to the end of the string.
5446   (b) any (a) that includes one and only one letter "p", with at least
5447       one digit before and after it.
5448 */
5449     while (isdigit(*p)) p++, n++;       /* Get a run of digits */
5450     if (*p && n > 0) {                  /* Have a "p"? */
5451         if (*p == 'p' && isdigit(*(p+1))) {
5452             p++;
5453             n = 0;
5454             while (isdigit(*p)) p++, n++;
5455         }
5456     }
5457     if (n == 0 || *p) unit = "";
5458     debug(F110,"TTLOCK unit 2",unit,0);
5459
5460     if (*unit) {                        /* Device name has unit number. */
5461         /* The following loop not only searches for the various lockfile    */
5462         /* synonyms, but also removes all -- not just one -- stale lockfile */
5463         /* for the device, should there be more than one.  See ttchkpid().  */
5464         ttydexists = 0;
5465         for (i = 0; *devprefix[i]; i++) { /* For each driver... */
5466             /* Make device name */
5467             ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
5468             priv_on();                  /* Privs on */
5469             k = zchki(lock2) != -1;     /* See if device exists */
5470             priv_off();                 /* Privs off */
5471             debug(F111,"TTLOCK exist",lock2,k);
5472             if (k) {
5473                 if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
5474                   ttydexists = 1;
5475                 /* Make lockfile name */
5476                 ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
5477                 debug(F110,"TTLOCK checking",lock2,0);
5478                 priv_on();              /* Privs on */
5479                 k = zchki(lock2) != -1; /* See if lockfile exists */
5480                 priv_off();             /* Privs off */
5481                 debug(F111,"TTLOCK check for lock A",lock2,k);
5482                 if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
5483                     ckstrncpy(flfnam,lock2,FLFNAML);
5484                     return(-2);
5485                 }
5486             }
5487         }
5488     } else {                            /* Some other device-name format */
5489         /* This takes care of symbolic links, etc... */
5490         /* But does not chase them down! */
5491         ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
5492         priv_on();
5493         k = zchki(lock2) != -1;         /* Check for existing lockfile */
5494         priv_off();
5495         debug(F111,"TTLOCK check for lock B",lock2,k);
5496         if (k) if (ttchkpid(lock2)) {   /* Check pid from lockfile */
5497             ckstrncpy(flfnam,lock2,FLFNAML);
5498             debug(F110,"TTLOCK in use",device,0);
5499             debug(F101,"TTLOCK returns","",-2);
5500             return(-2);
5501         }
5502     }
5503 /*
5504   Get here only if there is no (more) lockfile, so now we make one (or two)...
5505   flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
5506   tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
5507 */
5508     ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
5509
5510     /* If dialout device, also make one for corresponding dialin device */
5511     lock2[0] = '\0';
5512     if (!strncmp(device,"cu",2) && *unit && ttydexists)
5513       ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
5514
5515     if ((int)strlen(lockdir)+12 < LFNAML)
5516       sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
5517 #ifdef DEBUG
5518     if (deblog) {
5519         debug(F110,"TTLOCK flfnam",flfnam,0);
5520         debug(F110,"TTLOCK lock2",lock2,0);
5521         debug(F110,"TTLOCK tmpnam",tmpnam,0);
5522     }
5523 #endif /* DEBUG */
5524 /*
5525    Lockfile permissions...
5526    444 is standard, HP-UX 10.00 uses 664.  It doesn't matter.
5527    Kermit uses 444; the difference lets us tell whether Kermit created
5528    the lock file.
5529 */
5530     priv_on();                          /* Turn on privileges. */
5531     lockfd = creat(tmpnam, 0444);       /* Try to create temporary file. */
5532     if (lockfd < 0) {                   /* Create failed. */
5533         debug(F111,"TTLOCK creat failed",tmpnam,errno);
5534         if (errno == ENOENT) {
5535             perror(lockdir);
5536             printf("UUCP not installed or Kermit misconfigured\n");
5537         } else {
5538             if (!quiet)
5539               perror(lockdir);
5540             unlink(tmpnam);             /* Get rid of the temporary file. */
5541         }
5542         priv_off();                     /* Turn off privileges!!! */
5543         debug(F101,"TTLOCK returns","",-1);
5544         return(-1);                     /* Return failure code. */
5545     }
5546     debug(F110,"TTLOCK temp ok",tmpnam,0);
5547
5548 /* Now write our pid into the temp lockfile in integer format. */
5549
5550     i = write(lockfd, (char *)&pid, sizeof(pid));
5551
5552 #ifdef DEBUG
5553     if (deblog) {
5554         debug(F101,"TTLOCK pid","",pid);
5555         debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
5556         debug(F101,"TTLOCK write pid returns","",i);
5557     }
5558 #endif /* DEBUG */
5559
5560 /*
5561   Now try to rename the temporary file to the real lockfile name.
5562   This will fail if a lock file of that name already exists, which
5563   will catch race conditions with other users.
5564 */
5565     close(lockfd);                      /* Close the temp lockfile. */
5566     chmod(tmpnam,0444);
5567
5568     tries = 0;
5569     while (!haslock && tries++ < 2) {
5570         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5571         debug(F101,"TTLOCK link","",haslock);
5572         if (haslock) {                  /* If we made the lockfile... */
5573
5574 #ifdef COMMENT
5575 /* We can't do this any more because we don't have a file descriptor yet. */
5576 #ifdef LOCKF                            /* Can be canceled with -DNOLOCKF */
5577 /*
5578   Create an advisory lock on the device through its file descriptor.
5579   This code actually seems to work.  If it is executed, and then another
5580   process tries to open the same device under a different name to circumvent
5581   the lockfile, they get a "device busy" error.
5582 */
5583             debug(F100,"TTLOCK LOCKF code...","",0);
5584             while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
5585                 debug(F111, "TTLOCK lockf error", "", errno);
5586                 if ((++tries >= 3) || (errno != EAGAIN)) {
5587                     x = unlink(flfnam); /* Remove the lockfile */
5588                     if (errno == EACCES && !quiet)
5589                       printf("Device already locked by another process\n");
5590                     haslock = 0;
5591                     break;
5592                 }
5593                 sleep(2);
5594             }
5595 #endif /* LOCKF */
5596 #endif /* COMMENT */
5597
5598             if (haslock) {              /* If we made the lockfile ... */
5599                 if (lock2[0]) {         /* if there is to be a 2nd lockfile */
5600                     lockfd = creat(lock2, 0444); /* Create it */
5601                     debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
5602                     if (lockfd > -1) {  /* Created OK, write pid. */
5603                         write(lockfd, (char *)&pid, sizeof(pid) );
5604                         close(lockfd);  /* Close and */
5605                         chmod(lock2, 0444); /* set permissions. */
5606                     } else {             /* Not OK, but don't fail. */
5607                         lock2[0] = '\0'; /* Just remember it's not there. */
5608                     }
5609                 }
5610                 break;                  /* and we're done. */
5611             }
5612         }
5613     }
5614     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5615     priv_off();                         /* Turn off privs */
5616     i = haslock ? 0 : -1;               /* Our return value */
5617     debug(F101,"TTLOCK returns","",i);
5618     return(i);
5619 #endif /* HPUX */
5620 #endif /* USETTYLOCK */
5621 #endif /* !NOUUCP */
5622 }
5623
5624 /*  T T U N L O C K  */
5625
5626 static int
5627 ttunlck() {                             /* Remove UUCP lockfile(s). */
5628 #ifndef NOUUCP
5629     int x;
5630
5631     debug(F111,"ttunlck",flfnam,haslock);
5632
5633 #ifdef USETTYLOCK
5634
5635     if (haslock && *flfnam) {
5636         int x;
5637         priv_on();                      /* Turn on privs */
5638 #ifdef USE_UU_LOCK
5639         x = uu_unlock(lockname);
5640 #else  /* USE_UU_LOCK */
5641         x = ttyunlock(lockname);        /* Try to unlock */
5642 #endif /* USE_UU_LOCK */
5643         priv_off();                     /* Turn off privs */
5644         if (x < 0 && !quiet)
5645           printf("Warning - Can't remove lockfile: %s\n", flfnam);
5646
5647         *flfnam = '\0';                 /* Erase the name. */
5648         haslock = 0;
5649         return(0);
5650     }
5651
5652 #else  /* No ttylock()... */
5653
5654     if (haslock && *flfnam) {
5655         /* Don't remove lockfile if we didn't make it ourselves */
5656         if ((x = ttrpid(flfnam)) != (int)getpid()) {
5657             debug(F111,"ttunlck lockfile seized",flfnam,x);
5658             printf("Warning - Lockfile %s seized by pid %d\n",
5659                    flfnam,
5660                    x
5661                    );
5662             return(0);
5663         }
5664         priv_on();                      /* Turn privileges on.  */
5665         errno = 0;
5666         x = unlink(flfnam);             /* Remove the lockfile. */
5667         debug(F111,"ttunlck unlink",flfnam,x);
5668         if (x < 0) {
5669             if (errno && !quiet)
5670               perror(ttnmsv);
5671             printf("Warning - Can't remove lockfile: %s\n", flfnam);
5672         }
5673         haslock = 0;
5674         *flfnam = '\0';                 /* Erase the name. */
5675
5676 #ifdef RTAIX
5677         errno = 0;
5678         x = unlink(lkflfn);             /* Remove link to lockfile */
5679         debug(F111,"ttunlck AIX link unlink",lkflfn,x);
5680         if (x < 0) {
5681             if (errno && !quiet)
5682               perror(ttnmsv);
5683             printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
5684         }
5685         *lkflfn = '\0';
5686 #else
5687         if (lock2[0]) {                 /* If there is a second lockfile, */
5688             errno = 0;
5689             x = unlink(lock2);          /*  remove it too. */
5690             debug(F111,"ttunlck lock2 unlink",lock2,x);
5691             if (x < 0) {
5692                 if (errno && !quiet)
5693                   perror(ttnmsv);
5694                 printf("Warning - Can't remove secondary lockfile: %s\n",
5695                        lock2
5696                        );
5697             }
5698             lock2[0] = '\0';            /* Forget its name. */
5699         }
5700 #endif /* RTAIX */
5701
5702 #ifdef COMMENT
5703 #ifdef LOCKF
5704         (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
5705 #endif /* LOCKF */
5706 #endif /* COMMENT */
5707
5708         priv_off();                     /* Turn privileges off. */
5709     }
5710 #endif /* USETTYLOCK */
5711 #endif /* !NOUUCP */
5712     return(0);
5713 }
5714
5715 /*
5716   4.3BSD-style UUCP line direction control.
5717   (Stan Barber, Rice U, 1980-something...)
5718 */
5719 #ifndef NOUUCP
5720 #ifdef ACUCNTRL
5721 VOID
5722 acucntrl(flag,ttname) char *flag, *ttname; {
5723     char x[DEVNAMLEN+32], *device, *devname;
5724
5725     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
5726       return;                           /* just return. */
5727     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
5728     if (strncmp(device,"LCK..",4) == 0) device += 5;
5729     ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
5730     debug(F110,"called ",x,0);
5731     zsyscmd(x);
5732 }
5733 #endif /* ACUCNTRL */
5734 #endif /* NOUUCP */
5735
5736 /*
5737   T T H F L O W  --  Set or Reset hardware flow control.
5738
5739   This is an attempt to collect all hardware-flow-control related code
5740   into a single module.  Thanks to Rick Sladkey and John Kohl for lots of
5741   help here.  Overview:
5742
5743   Hardware flow control is not supported in many UNIX implementions.  Even
5744   when it is supported, there is no (ha ha) "standard" for the programming
5745   interface.  In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
5746   SunOS, AIX, etc, have totally different methods.  (And, not strictly
5747   relevant here, the programming interface often brings one only to a no-op
5748   in the device driver!)
5749
5750   Among all these, we have two major types of APIs: those in which hardware
5751   flow control is determined by bits in the same termio/termios/sgtty mode
5752   word(s) that are used for controlling such items as CBREAK vs RAW mode, and
5753   which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
5754   for changing terminal modes.  And those that use entirely different
5755   mechanisms.
5756
5757   In the first category, it is important that any change in the mode bits be
5758   reflected in the relevant termio(s)/sgtty structure, so that subsequent
5759   changes to that structure do not wipe out the effects of this routine.  That
5760   is why a pointer, attrs, to the appropriate structure is passed as a
5761   parameter to this routine.
5762
5763   The second category should give us no worries, since any changes to hardware
5764   flow control accomplished by this routine should not affect the termio(s)/
5765   sgtty structures, and therefore will not be undone by later changes to them.
5766
5767   The second argument, status, means to turn on hardware flow control if
5768   nonzero, and to turn it off if zero.
5769
5770   Returns: 0 on apparent success, -1 on probable failure.
5771 */
5772
5773 /*
5774   The following business is for BSDI, where it was discovered that two
5775   separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
5776   but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
5777   bits, so hwfc only works in one direction if you use CRTSCTS to control it.
5778   Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
5779   define CRTSCTS correctly.
5780 */
5781 #ifdef FIXCRTSCTS
5782 #ifdef CRTSCTS
5783 #ifdef CCTS_OFLOW
5784 #ifdef CRTS_IFLOW
5785 #undef CRTSCTS
5786 #define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
5787 #endif /* CRTS_IFLOW */
5788 #endif /* CCTS_OFLOW */
5789 #endif /* CRTSCTS */
5790 #endif /* FIXCRTSCTS */
5791
5792 static int
5793 tthflow(flow, status, attrs)
5794     int flow,                           /* Type of flow control (ckcdeb.h) */
5795     status;                             /* Nonzero = turn it on */
5796                                         /* Zero = turn it off */
5797 #ifdef BSD44ORPOSIX                     /* POSIX or BSD44 */
5798     struct termios *attrs;
5799 #else                                   /* System V */
5800 #ifdef ATTSV
5801 #ifdef ATT7300
5802 #ifdef UNIX351M
5803 /* AT&T UNIX 3.51m can set but not test for hardware flow control */
5804 #define RTSFLOW CTSCD
5805 #define CTSFLOW CTSCD
5806 #endif /* ATT7300 */
5807 #endif /* UNIX351M */
5808     struct termio *attrs;
5809 #else                                   /* BSD, V7, etc */
5810     struct sgttyb *attrs;               /* sgtty info... */
5811 #endif /* ATTSV */
5812 #endif /* BSD44ORPOSIX */
5813 /* tthflow */ {
5814
5815     int x = 0;                          /* tthflow() return code */
5816
5817 #ifdef Plan9
5818     return p9tthflow(flow, status);
5819 #else
5820
5821 #ifndef OXOS                            /* NOT Olivetti X/OS... */
5822 /*
5823   For SunOS 4.0 and later in the BSD environment ...
5824
5825   The declarations are copied and interpreted from the System V header files,
5826   so we don't actually have to pull in all the System V junk when building
5827   C-Kermit for SunOS in the BSD environment, which would be dangerous because
5828   having those symbols defined would cause us to take the wrong paths through
5829   the code.  The code in this section is used in both the BSD and Sys V SunOS
5830   versions.
5831 */
5832 #ifdef SUNOS41
5833 /*
5834   In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
5835   because GNU CC uses different formats for the _IOxxx macros than regular CC;
5836   the POSIX forms work for both.  But the POSIX calls are not available in
5837   SunOS 4.0.
5838 */
5839 #define CRTSCTS 0x80000000              /* RTS/CTS flow control */
5840 #define TCSANOW 0                       /* Do it now */
5841
5842     struct termios {
5843         unsigned long c_iflag;          /* Input modes */
5844         unsigned long c_oflag;          /* Output modes */
5845         unsigned long c_cflag;          /* Control modes */
5846         unsigned long c_lflag;          /* Line discipline modes */
5847         char c_line;
5848         CHAR c_cc[17];
5849     };
5850     struct termios temp;
5851
5852 _PROTOTYP( int tcgetattr, (int, struct termios *) );
5853 _PROTOTYP( int tcsetattr, (int, int, struct termios *) );
5854 /*
5855   When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
5856   asserted.  So we don't set CRTSCTS unless CD is up.  This should be OK,
5857   since we don't need RTS/CTS during dialing, and after dialing is complete,
5858   we should have CD.  If not, we still communicate, but without RTS/CTS.
5859 */
5860     int mflags;                         /* Modem signal flags */
5861
5862 #ifdef NETCMD
5863     if (ttpipe) return(0);
5864 #endif /* NETCMD */
5865 #ifdef NETPTY
5866     if (ttpty) return(0);
5867 #endif /* NETPTY */
5868
5869     debug(F101,"tthflow SUNOS41 entry status","",status);
5870     if (!status) {                      /* Turn hard flow off */
5871         if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5872             (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5873             temp.c_cflag &= ~CRTSCTS;   /* It's there, remove it */
5874             x = tcsetattr(ttyfd,TCSANOW,&temp);
5875         }
5876     } else {                            /* Turn hard flow on */
5877         if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
5878             (mflags & TIOCM_CAR)) {             /* Check for CD */
5879             debug(F100,"tthflow SunOS has CD","",0);
5880             if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5881                 !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5882                 temp.c_cflag |= CRTSCTS;        /* Not there, add it */
5883                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5884             }
5885         } else {
5886             x = -1;
5887             debug(F100,"tthflow SunOS no CD","",0);
5888         }
5889     }
5890 #else
5891 #ifdef QNX
5892     struct termios temp;
5893 #ifdef NETCMD
5894     if (ttpipe) return(0);
5895 #endif /* NETCMD */
5896 #ifdef NETPTY
5897     if (ttpty) return(0);
5898 #endif /* NETPTY */
5899     debug(F101,"tthflow QNX entry status","",status);
5900     if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
5901         if (!status) {                  /* Turn hard flow off */
5902             if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
5903                 temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
5904                 attrs->c_cflag &= ~(IHFLOW|OHFLOW);
5905                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5906             }
5907         } else {                        /* Turn hard flow on */
5908             if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
5909                 temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
5910                 temp.c_iflag &= ~(IXON|IXOFF);   /* Bye to IXON/IXOFF */
5911                 ttraw.c_lflag |= IEXTEN;         /* Must be on */
5912                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5913                 attrs->c_cflag |= (IHFLOW|OHFLOW);
5914                 attrs->c_iflag &= ~(IXON|IXOFF);
5915             }
5916         }
5917     } else {
5918         x = -1;
5919         debug(F100, "tthflow QNX getattr fails", "", 0);
5920     }
5921 #else
5922 #ifdef POSIX_CRTSCTS
5923 /*
5924   POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
5925   Note: Do not assume CRTSCTS is a one-bit field!
5926 */
5927     struct termios temp;
5928 #ifdef NETCMD
5929     if (ttpipe) return(0);
5930 #endif /* NETCMD */
5931 #ifdef NETPTY
5932     if (ttpty) return(0);
5933 #endif /* NETPTY */
5934     debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
5935     errno = 0;
5936     x = tcgetattr(ttyfd, &temp);
5937     debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
5938     errno = 0;
5939     if (x < 0) {
5940         x = -1;
5941     } else {
5942         if (!status) {                  /* Turn hard flow off */
5943             if (
5944 #ifdef COMMENT
5945                 /* This can fail because of sign extension */
5946                 /* e.g. in Linux where it's Bit 31 */
5947                 (temp.c_cflag & CRTSCTS) == CRTSCTS
5948 #else
5949                 (temp.c_cflag & CRTSCTS) != 0
5950 #endif /* COMMENT */
5951                 ) {
5952                 temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
5953                 attrs->c_cflag &= ~CRTSCTS;
5954                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5955                 debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
5956                       ckitoa(x),errno);
5957             } else {                    /* John Dunlap 2010-01-26 */
5958                 debug(F001,
5959                       "tthflow before forcing off attrs CRTSCTS",
5960                       "",
5961                       attrs->c_cflag&CRTSCTS
5962                       );
5963                 attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */
5964                 debug(F001,
5965                       "tthflow after forcing off attrs CRTSCTS",
5966                       "",
5967                       attrs->c_cflag&CRTSCTS
5968                       );
5969                 }
5970         } else {                        /* Turn hard flow on */
5971             if (
5972 #ifdef COMMENT
5973                 /* This can fail because of sign extension */
5974                 (temp.c_cflag & CRTSCTS) != CRTSCTS
5975 #else
5976                 (temp.c_cflag & CRTSCTS) == 0
5977 #endif /* COMMENT */
5978                 ) {
5979                 temp.c_cflag |= CRTSCTS; /* Not there, add it */
5980                 temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
5981                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5982                 debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
5983                       ckitoa(x),errno);
5984                 attrs->c_cflag |= CRTSCTS;
5985                 attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
5986             }
5987         }
5988     }
5989 #else
5990 #ifdef SUNOS4
5991 /*
5992   SunOS 4.0 (and maybe earlier?).  This code is dangerous because it
5993   prevents compilation with GNU gcc, which uses different formats for the
5994   _IORxxx macros than regular cc.  SunOS 4.1 and later can use the POSIX
5995   routines above, which work for both cc and gcc.
5996 */
5997 #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
5998 #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
5999 #define CRTSCTS 0x80000000                /* RTS/CTS flow control */
6000
6001     struct termios {
6002         unsigned long c_iflag;          /* Input modes */
6003         unsigned long c_oflag;          /* Output modes */
6004         unsigned long c_cflag;          /* Control modes */
6005         unsigned long c_lflag;          /* Line discipline modes */
6006         char c_line;
6007         CHAR c_cc[17];
6008     };
6009     struct termios temp;
6010 #ifdef NETCMD
6011     if (ttpipe) return(0);
6012 #endif /* NETCMD */
6013 #ifdef NETPTY
6014     if (ttpty) return(0);
6015 #endif /* NETPTY */
6016     debug(F101,"tthflow entry status","",status);
6017     if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
6018         if (status) {                   /* Turn hard flow on */
6019             temp.c_cflag |= CRTSCTS;    /* Add RTS/CTS to them. */
6020             x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
6021             attrs->c_cflag |= CRTSCTS;  /* Add to global info. */
6022         } else {                        /* Turn hard flow off */
6023             temp.c_cflag &= ~CRTSCTS;
6024             x = ioctl(ttyfd,TCSETS,&temp);
6025             attrs->c_cflag &= ~CRTSCTS;
6026         }
6027     }
6028 #else                                   /* Not SunOS 4.0 or later */
6029 #ifdef AIXRS                            /* IBM AIX RS/6000 */
6030 #ifndef AIX41                           /* But only pre-4.x == SVR4 */
6031 #ifdef NETCMD
6032     if (ttpipe) return(0);
6033 #endif /* NETCMD */
6034 #ifdef NETPTY
6035     if (ttpty) return(0);
6036 #endif /* NETPTY */
6037     if (status) {
6038         if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
6039           debug(F100,"hardflow TXADDCD (rts) error", "", 0);
6040     } else {
6041         if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
6042           debug(F100,"hardflow TXDELCD (rts) error", "", 0);
6043     }
6044 #endif /* AIX41 */
6045 #else                                   /* Not AIX RS/6000 */
6046
6047 #ifdef ATTSV                            /* System V... */
6048
6049 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
6050 #define CK_SCOUNIX
6051 #else
6052 #ifdef M_UNIX                           /* SCO UNIX 3.2v4.x or earlier */
6053 #define CK_SCOUNIX
6054 #endif /* M_UNIX */
6055 #endif /* CK_SCOV5 */
6056
6057 #ifdef SCO_FORCE_RTSXOFF
6058 #ifdef CK_SCOUNIX                       /* But not SCO OpenServer 5.0.4 */
6059 #ifdef SCO_OSR504                       /* or later... */
6060 #undef CK_SCOUNIX
6061 #endif /* SCO_OSR504 */
6062 #endif /* CK_SCOUNIX */
6063 #endif /* SCO_FORCE_RTSXOFF */
6064
6065 #ifdef CK_SCOUNIX
6066 #ifdef POSIX
6067     struct termios temp;
6068 #ifdef NETCMD
6069     if (ttpipe) return(0);
6070 #endif /* NETCMD */
6071 #ifdef NETPTY
6072     if (ttpty) return(0);
6073 #endif /* NETPTY */
6074     debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
6075     errno = 0;
6076     x = tcgetattr(ttyfd, &temp);
6077     debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
6078 #else /* POSIX */
6079     struct termio temp;
6080 #ifdef NETCMD
6081     if (ttpipe) return(0);
6082 #endif /* NETCMD */
6083 #ifdef NETPTY
6084     if (ttpty) return(0);
6085 #endif /* NETPTY */
6086     debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
6087     x = ioctl(ttyfd, TCGETA, &temp);
6088     debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
6089 #endif /* POSIX */
6090 /*
6091   This is not really POSIX, since POSIX does not deal with hardware flow
6092   control, but we are using the POSIX APIs.  In fact, RTSFLOW and CTSFLOW
6093   are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif.  So
6094   let's try forcing their definitions here.
6095 */
6096 #ifndef CTSFLOW
6097 #define CTSFLOW 0020000
6098     debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
6099 #else
6100     debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
6101 #endif /* CTSFLOW */
6102 #ifndef RTSFLOW
6103 #define RTSFLOW 0040000
6104     debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
6105 #else
6106     debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
6107 #endif /* RTSFLOW */
6108 #ifndef ORTSFL
6109 #define ORTSFL 0100000
6110     debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
6111 #else
6112     debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
6113 #endif /* ORTSFL */
6114
6115     if (x != -1) {
6116         if (status) {                   /* Turn it ON */
6117             temp.c_cflag |= RTSFLOW|CTSFLOW;
6118             attrs->c_cflag |= RTSFLOW|CTSFLOW;
6119 #ifdef ORTSFL
6120             temp.c_cflag &= ~ORTSFL;
6121             attrs->c_cflag &= ~ORTSFL;
6122 #endif /* ORTSFL */
6123             temp.c_iflag &= ~(IXON|IXOFF|IXANY);
6124             attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
6125         } else {                        /* Turn it OFF */
6126 #ifdef ORTSFL
6127             temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6128             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6129 #else  /* ORTSFL */
6130             temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
6131             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
6132 #endif /* ORTSFL */
6133         }
6134 #ifdef POSIX
6135         x = tcsetattr(ttyfd, TCSADRAIN, &temp);
6136 #else
6137         x = ioctl(ttyfd, TCSETA, &temp);
6138 #endif /* POSIX */
6139         debug(F101,"tthflow SCO set modes","",x);
6140     }
6141 #else /* Not SCO UNIX */
6142 #ifdef NETCMD
6143     if (ttpipe) return(0);
6144 #endif /* NETCMD */
6145 #ifdef NETPTY
6146     if (ttpty) return(0);
6147 #endif /* NETPTY */
6148     if (!status) {                      /* Turn it OFF */
6149 #ifdef RTSXOFF
6150         debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
6151         rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
6152 #ifdef TCSETX
6153         x = ioctl(ttyfd,TCSETX,&rctsx);
6154         debug(F101,"tthflow ATTSV TCSETX OFF","",x);
6155 #else
6156         x = -1
6157         debug(F100,"tthflow TCSETX not defined","",0);
6158 #endif /* TCSETX */
6159 #else
6160         debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
6161 #endif /* RTSXOFF */
6162 #ifdef DTRXOFF
6163         debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
6164         rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6165         x = ioctl(ttyfd,TCSETX,&rctsx);
6166         debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
6167 #else
6168         debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6169 #endif /* DTRXOFF */
6170     } else {                            /* Turn it ON. */
6171         if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */
6172             debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
6173 #ifdef RTSXOFF
6174             /* This is the preferred way, according to SVID3 */
6175 #ifdef TCGETX
6176             x = ioctl(ttyfd,TCGETX,&rctsx);
6177             debug(F101,"tthflow TCGETX","",x);
6178             if (x > -1) {
6179                 rctsx.x_hflag |= RTSXOFF | CTSXON;
6180                 x = ioctl(ttyfd,TCSETX,&rctsx);
6181                 debug(F100,"tthflow ATTSV ioctl","",x);
6182             }
6183 #else
6184             debug(F100,"tthflow TCGETX not defined","",0);
6185             x = -1
6186 #endif /* TCGETX */
6187 #else
6188             debug(F100,"tthflow RTSXOFF not defined","",0);
6189             x = -1;
6190 #endif /* RTSXOFF */
6191         } else if (flow == FLO_DTRC) {  /* DTR/CD Flow control... */
6192             debug(F100,"tthflow ATTSV DTR/CD ON","",0);
6193 #ifdef DTRXOFF
6194             /* This is straight out of SVID R4 */
6195             if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
6196                 rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6197                 x = ioctl(ttyfd,TCSETX,&rctsx);
6198             }
6199 #else
6200             debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6201             x = -1;
6202 #endif /* DTRXOFF */
6203         }
6204     }
6205 #endif /* CK_SCOUNIX */
6206
6207 #else /* not System V... */
6208
6209 #ifdef CK_DTRCTS
6210 #ifdef LDODTR
6211 #ifdef LDOCTS
6212 #ifdef NETCMD
6213     if (ttpipe) return(0);
6214 #endif /* NETCMD */
6215 #ifdef NETPTY
6216     if (ttpty) return(0);
6217 #endif /* NETPTY */
6218     x = LDODTR | LDOCTS;                /* Found only on UTEK? */
6219     if (flow == FLO_DTRT && status) {   /* Use hardware flow control */
6220         if (lmodef) {
6221             x = ioctl(ttyfd,TIOCLBIS,&x);
6222             if (x < 0) {
6223                 debug(F100,"hardflow TIOCLBIS error","",0);
6224             } else {
6225                 lmodef++;
6226                 debug(F100,"hardflow TIOCLBIS ok","",0);
6227             }
6228         }
6229     } else {
6230         if (lmodef) {
6231             x = ioctl(ttyfd,TIOCLBIC,&x);
6232             if (x < 0) {
6233                 debug(F100,"hardflow TIOCLBIC error","",0);
6234             } else {
6235                 lmodef++;
6236                 debug(F100,"hardflow TIOCLBIC ok","",0);
6237             }
6238         }
6239     }
6240 #endif /* LDODTR */
6241 #endif /* LDOCTS */
6242 #endif /* CK_DTRCTS */
6243 #endif /* ATTSV */
6244 #endif /* AIXRS */
6245 #endif /* SUNOS4 */
6246 #endif /* QNX */
6247 #endif /* POSIX_CRTSCTS */
6248 #endif /* SUNOS41 */
6249
6250 #else /* OXOS */
6251
6252     struct termios temp;                /* Olivetti X/OS ... */
6253
6254 #ifdef NETCMD
6255     if (ttpipe) return(0);
6256 #endif /* NETCMD */
6257 #ifdef NETPTY
6258     if (ttpty) return(0);
6259 #endif /* NETPTY */
6260     x = ioctl(ttyfd,TCGETS,&temp);
6261     if (x == 0) {
6262         temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
6263         if (status) {
6264             switch (flow) {
6265               case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
6266                 break;
6267               case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
6268                 break;
6269             }
6270         }
6271         x = ioctl(ttyfd,TCSETS,&temp);
6272     }
6273 #endif /* OXOS */
6274     return(x);
6275
6276 #endif /* Plan9 */
6277 }
6278
6279 /*  T T P K T  --  Condition the communication line for packets */
6280 /*                 or for modem dialing */
6281
6282 /*
6283   If called with speed > -1, also set the speed.
6284   Returns 0 on success, -1 on failure.
6285
6286   NOTE: the "xflow" parameter is supposed to be the currently selected
6287   type of flow control, but for historical reasons, this parameter is also
6288   used to indicate that we are dialing.  Therefore, when the true flow
6289   control setting is needed, we access the external variable "flow", rather
6290   than trusting our "xflow" argument.
6291 */
6292 int
6293 #ifdef CK_ANSIC
6294 ttpkt(long speed, int xflow, int parity)
6295 #else
6296 ttpkt(speed,xflow,parity) long speed; int xflow, parity;
6297 #endif /* CK_ANSIC */
6298 /* ttpkt */ {
6299 #ifndef NOLOCAL
6300     int s2;
6301     int s = -1;
6302 #endif /* NOLOCAL */
6303     int x;
6304     extern int flow;                    /* REAL flow-control setting */
6305
6306     if (ttyfd < 0) return(-1);          /* Not open. */
6307
6308     debug(F101,"ttpkt parity","",parity);
6309     debug(F101,"ttpkt xflow","",xflow);
6310     debug(F101,"ttpkt speed","",(int) speed);
6311
6312     ttprty = parity;                    /* Let other tt functions see these. */
6313     ttspeed = speed;                    /* Make global copy for this module */
6314     ttpmsk = ttprty ? 0177 : 0377;      /* Parity stripping mask */
6315 #ifdef PARSENSE
6316     needpchk = ttprty ? 0 : 1;          /* Parity check needed? */
6317 #else
6318     needpchk = 0;
6319 #endif /* PARSENSE */
6320
6321     debug(F101,"ttpkt ttpmsk","",ttpmsk);
6322     debug(F101,"ttpkt netconn","",netconn);
6323
6324 #ifdef NETCONN                          /* No mode-changing for telnet */
6325     if (netconn) {
6326 #ifdef TCPSOCKET
6327 #ifdef TCP_NODELAY
6328         if (ttnet == NET_TCPB) {        /* But turn off Nagle */
6329             extern int tcp_nodelay;
6330             nodelay_sav = tcp_nodelay;
6331             no_delay(ttyfd,1);
6332         }
6333 #endif /* TCP_NODELAY */
6334 #ifdef TN_COMPORT
6335         if (istncomport()) {
6336             int rc = -1;
6337             if (tvtflg == 0 && speed == ttspeed && flow == ttflow
6338                  /* && ttcarr == curcarr */ ) {
6339                 debug(F100,"ttpkt modes already set, skipping...","",0);
6340                 return(0);              /* Already been called. */
6341             }
6342             if (flow != ttflow) {
6343                 if ((rc = tnsetflow(flow)) < 0)
6344                   return(rc);
6345                 ttflow = flow;
6346             }
6347             if (speed != ttspeed) {
6348                 if (speed <= 0) 
6349                   speed = tnc_get_baud();
6350                 else if ((rc = tnc_set_baud(speed)) < 0)
6351                   return(rc);
6352                 ttspeed = speed;
6353             }
6354             tnc_set_datasize(8);
6355             tnc_set_stopsize(stopbits);
6356
6357 #ifdef HWPARITY
6358             if (hwparity) {
6359                 switch (hwparity) {
6360                   case 'e':                     /* Even */
6361                     debug(F100,"ttres 8 bits + even parity","",0);
6362                     tnc_set_parity(3);
6363                     break;
6364                   case 'o':                     /* Odd */
6365                     debug(F100,"ttres 8 bits + odd parity","",0);
6366                     tnc_set_parity(2);
6367                     break;
6368                   case 'm':                     /* Mark */
6369                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
6370                     tnc_set_parity(4);
6371                     break;
6372                   case 's':                     /* Space */
6373                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
6374                     tnc_set_parity(5);
6375                     break;
6376                 }
6377             } else 
6378 #endif /* HWPARITY */
6379             {
6380                 tnc_set_parity(1);              /* None */
6381             }
6382             tvtflg = 0;
6383             return(0);
6384         }
6385 #endif /* TN_COMPORT */
6386 #endif /* TCPSOCKET */
6387         tvtflg = 0;
6388         return(0);
6389     }
6390 #endif /* NETCONN */
6391 #ifdef NETCMD
6392     if (ttpipe) return(0);
6393 #endif /* NETCMD */
6394 #ifdef NETPTY
6395     if (ttpty) return(0);
6396 #endif /* NETPTY */
6397
6398 #ifndef Plan9
6399     if (ttfdflg && !isatty(ttyfd)) return(0);
6400 #endif /* Plan9 */
6401
6402 #ifdef COHERENT
6403 #define SVORPOSIX
6404 #endif /* COHERENT */
6405
6406 #ifndef SVORPOSIX                       /* Berkeley, V7, etc. */
6407 #ifdef LPASS8
6408 /*
6409  For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
6410  after having previously set it to NONE without closing and reopening the
6411  device.  Unless there's something I overlooked below...
6412 */
6413     if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
6414         debug(F101,"ttpkt executing horrible flow kludge","",0);
6415         ttclos(0);                      /* Close it */
6416         x = 0;
6417         ttopen(ttnmsv,&x,ttmdm,0);      /* Open it again */
6418     }
6419 #endif /* LPASS8 */
6420 #endif /* SVORPOSIX */
6421
6422 #ifdef COHERENT                         /* This must be vestigial since we */
6423 #undef SVORPOSIX                        /* reverse it a few lines below... */
6424 #endif /* COHERENT */
6425
6426     if (xflow != FLO_DIAL && xflow != FLO_DIAX)
6427       ttflow = xflow;                   /* Now make this available too. */
6428
6429 #ifndef NOLOCAL
6430     if (xlocal) {
6431         s2 = (int) (speed / 10L);       /* Convert bps to cps */
6432         debug(F101,"ttpkt calling ttsspd","",s2);
6433         s = ttsspd(s2);                 /* Check and set the speed */
6434         debug(F101,"ttpkt ttsspd result","",s);
6435         carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
6436                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
6437         tvtflg = 0;                     /* So ttvt() will work next time */
6438     }
6439 #endif /* NOLOCAL */
6440
6441 #ifdef COHERENT
6442 #define SVORPOSIX
6443 #endif /* COHERENT */
6444
6445 #ifndef SVORPOSIX                       /* BSD section */
6446     if (flow == FLO_RTSC ||             /* Hardware flow control */
6447         flow == FLO_DTRC ||
6448         flow == FLO_DTRT) {
6449         tthflow(flow, 1, &ttraw);
6450         debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
6451         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6452         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6453     } else if (flow == FLO_NONE) {      /* No flow control */
6454         debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
6455         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6456         tthflow(flow, 0, &ttraw);       /* Turn off any hardware f/c too */
6457         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6458     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
6459         debug(F100,"ttpkt keeping original TANDEM","",0);
6460         ttraw.sg_flags &= ~TANDEM;
6461         ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
6462         /* NOTE: We should also handle hardware flow control here! */
6463     }
6464
6465 /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
6466
6467     if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
6468         debug(F100,"ttpkt turning on TANDEM","",0);
6469         ttraw.sg_flags |= TANDEM;       /* So ask for it. */
6470
6471 #ifdef LPASS8                           /* Can pass 8-bit data through? */
6472 /* If the LPASS8 local mode is available, then flow control can always  */
6473 /* be used, even if parity is none and we are transferring 8-bit data.  */
6474 /* But we only need to do all this if Xon/Xoff is requested. */
6475 /* BUT... this tends not to work through IP or LAT connections, terminal */
6476 /* servers, telnet, rlogin, etc, so it is currently disabled. */
6477         x = LPASS8;                     /* If LPASS8 defined, then */
6478         debug(F100,"ttpkt executing LPASS8 code","",0);
6479         if (lmodef) {                   /* TIOCLBIS must be too. */
6480             x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
6481             if (x < 0) {
6482                 debug(F100,"ttpkt TIOCLBIS error","",0);
6483             } else {
6484                 lmodef++;
6485                 debug(F100,"ttpkt TIOCLBIS ok","",0);
6486             }
6487         }
6488 /*
6489  But if we use LPASS8 mode, we must explicitly turn off
6490  terminal interrupts of all kinds.
6491 */
6492 #ifdef TIOCGETC                         /* Not rawmode, */
6493         if (tcharf && (xlocal == 0)) {  /* must turn off */
6494             tchnoi.t_intrc = -1;        /* interrupt character */
6495             tchnoi.t_quitc = -1;        /* and quit character. */
6496             tchnoi.t_startc = 17;       /* Make sure xon */
6497             tchnoi.t_stopc = 19;        /* and xoff not ignored. */
6498 #ifndef NOBRKC
6499             tchnoi.t_eofc = -1;         /* eof character. */
6500             tchnoi.t_brkc = -1;         /* brk character. */
6501 #endif /* NOBRKC */
6502             if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6503                 debug(F100,"ttpkt TIOCSETC failed","",0);
6504             } else {
6505                 tcharf = 1;
6506                 debug(F100,"ttpkt TIOCSETC ok","",0);
6507             }
6508 #ifdef COMMENT
6509 /* only for paranoid debugging */
6510             if (tcharf) {
6511                 struct tchars foo;
6512                 char tchbuf[100];
6513                 ioctl(0,TIOCGETC,&foo);
6514                 sprintf(tchbuf,
6515                     "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
6516                     foo.t_intrc, foo.t_quitc, foo.t_startc,
6517                     foo.t_stopc, foo.t_eofc,  foo.t_brkc);
6518                 debug(F110,"ttpkt chars",tchbuf,0);
6519             }
6520 #endif /* COMMENT */
6521         }
6522         ttraw.sg_flags |= CBREAK;       /* Needed for unknown reason */
6523 #endif /* TIOCGETC */
6524
6525 /* Prevent suspend during packet mode */
6526 #ifdef TIOCGLTC                         /* Not rawmode, */
6527         if (ltcharf && (xlocal == 0)) { /* must turn off */
6528             ltchnoi.t_suspc = -1;       /* suspend character */
6529             ltchnoi.t_dsuspc = -1;      /* and delayed suspend character */
6530             if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6531                 debug(F100,"ttpkt TIOCSLTC failed","",0);
6532             } else {
6533                 ltcharf = 1;
6534                 debug(F100,"ttpkt TIOCSLTC ok","",0);
6535             }
6536         }
6537 #endif /* TIOCGLTC */
6538
6539 #else /* LPASS8 not defined */
6540
6541 /* Previously, BSD-based implementations always */
6542 /* used rawmode for packets.  Now, we use rawmode only if parity is NONE. */
6543 /* This allows the flow control requested above to actually work, but only */
6544 /* if the user asks for parity (which also means they get 8th-bit quoting). */
6545
6546         if (parity) {                   /* If parity, */
6547             ttraw.sg_flags &= ~RAW;     /* use cooked mode */
6548 #ifdef COMMENT
6549 /* WHY??? */
6550             if (xlocal)
6551 #endif /* COMMENT */
6552               ttraw.sg_flags |= CBREAK;
6553             debug(F101,"ttpkt cooked, cbreak, parity","",parity);
6554 #ifdef TIOCGETC                         /* Not rawmode, */
6555             if (tcharf && (xlocal == 0)) { /* must turn off */
6556                 tchnoi.t_intrc = -1;    /* interrupt character */
6557                 tchnoi.t_quitc = -1;    /* and quit character. */
6558                 tchnoi.t_startc = 17;   /* Make sure xon */
6559                 tchnoi.t_stopc = 19;    /* and xoff not ignored. */
6560 #ifndef NOBRKC
6561                 tchnoi.t_eofc = -1;     /* eof character. */
6562                 tchnoi.t_brkc = -1;     /* brk character. */
6563 #endif /* NOBRKC */
6564                 if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6565                     debug(F100,"ttpkt TIOCSETC failed","",0);
6566                 } else {
6567                     tcharf = 1;
6568                     debug(F100,"ttpkt TIOCSETC ok","",0);
6569                 }
6570             }
6571 #endif /* TIOCGETC */
6572 #ifdef TIOCGLTC                         /* Not rawmode, */
6573 /* Prevent suspend during packet mode */
6574             if (ltcharf && (xlocal == 0)) { /* must turn off */
6575                 ltchnoi.t_suspc = -1;   /* suspend character */
6576                 ltchnoi.t_dsuspc = -1;  /* and delayed suspend character */
6577                 if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6578                     debug(F100,"ttpkt TIOCSLTC failed","",0);
6579                 } else {
6580                     ltcharf = 1;
6581                     debug(F100,"ttpkt TIOCSLTC ok","",0);
6582                 }
6583             }
6584 #endif /* TIOCGLTC */
6585         } else {                        /* If no parity, */
6586             ttraw.sg_flags |= RAW;      /* must use 8-bit raw mode. */
6587             debug(F101,"ttpkt setting rawmode, parity","",parity);
6588         }
6589 #endif /* LPASS8 */
6590     } /* End of Xon/Xoff section */
6591
6592     /* Don't echo, don't map CR to CRLF on output, don't fool with case */
6593 #ifdef LCASE
6594     ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
6595 #else
6596     ttraw.sg_flags &= ~(ECHO|CRMOD);
6597 #endif /* LCASE */
6598
6599 #ifdef TOWER1
6600     ttraw.sg_flags &= ~ANYP;            /* Must set this on old Towers */
6601 #endif /* TOWER1 */
6602
6603 #ifdef BELLV10
6604     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
6605       return(-1);
6606 #else
6607     errno = 0;
6608     if (stty(ttyfd,&ttraw) < 0) {       /* Set the new modes. */
6609         debug(F101,"ttpkt stty failed","",errno);
6610         return(-1);
6611     }
6612 #endif /* BELLV10 */
6613     debug(F100,"ttpkt stty ok","",0);
6614
6615 #ifdef sony_news
6616     x = xlocal ? km_ext : km_con;       /* Put line in ASCII mode. */
6617     if (x != -1) {                      /* Make sure we know original modes. */
6618         x &= ~KM_TTYPE;
6619         x |= KM_ASCII;
6620         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
6621             perror("ttpkt can't set ASCII mode");
6622             debug(F101,"ttpkt error setting ASCII mode","",x);
6623             return(-1);
6624         }
6625     }
6626     debug(F100,"ttpkt set ASCII mode ok","",0);
6627 #endif /* sony_news */
6628
6629     if (xlocal == 0) {                  /* Turn this off so we can read */
6630         signal(SIGINT,SIG_IGN);         /* Ctrl-C chars typed at console */
6631         sigint_ign = 1;
6632     }
6633     tvtflg = 0;                         /* So ttvt() will work next time */
6634     debug(F100,"ttpkt success","",0);
6635     return(0);
6636
6637 #endif /* Not ATTSV or POSIX */
6638
6639 /* AT&T UNIX and POSIX */
6640
6641 #ifdef COHERENT
6642 #define SVORPOSIX
6643 #endif /* COHERENT */
6644
6645 #ifdef SVORPOSIX
6646     if (flow == FLO_XONX) {             /* Xon/Xoff */
6647         ttraw.c_iflag |= (IXON|IXOFF);
6648         tthflow(flow, 0, &ttraw);
6649     } else if (flow == FLO_NONE) {      /* None */
6650         /* NOTE: We should also turn off hardware flow control here! */
6651         ttraw.c_iflag &= ~(IXON|IXOFF);
6652         tthflow(flow, 0, &ttraw);
6653     } else if (flow == FLO_KEEP) {      /* Keep */
6654         ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
6655         ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
6656         /* NOTE: We should also handle hardware flow control here! */
6657 #ifdef POSIX_CRTSCTS
6658 /* In Linux case, we do this, which is unlikely to be portable */
6659         ttraw.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
6660         ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
6661 #endif /* POSIX_CRTSCTS */
6662     } else if (flow == FLO_RTSC ||      /* Hardware */
6663                flow == FLO_DTRC ||
6664                flow == FLO_DTRT) {
6665         ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */
6666         tthflow(flow, 1, &ttraw);
6667     }
6668     ttraw.c_lflag &= ~(ICANON|ECHO);
6669     ttraw.c_lflag &= ~ISIG;             /* Do NOT check for interrupt chars */
6670
6671 #ifndef OXOS
6672 #ifdef QNX
6673     if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
6674 #endif /* QNX */
6675 #ifndef COHERENT
6676       ttraw.c_lflag &= ~IEXTEN;         /* Turn off ^O/^V processing */
6677 #endif /* COHERENT */
6678 #else /* OXOS */
6679     ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
6680 #endif /* OXOS */
6681     ttraw.c_lflag |= NOFLSH;            /* Don't flush */
6682     ttraw.c_iflag |= IGNPAR;            /* Ignore parity errors */
6683 #ifdef ATTSV
6684 #ifdef BSD44
6685     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
6686 #else
6687     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
6688 #endif /* BSD44 */
6689 #else /* POSIX */
6690     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
6691 #endif /* ATTSV */
6692     ttraw.c_oflag &= ~OPOST;
6693     ttraw.c_cflag &= ~(CSIZE);
6694     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
6695
6696 #ifdef CSTOPB
6697     if (xlocal) {
6698         if (stopbits == 2) {
6699             ttraw.c_cflag |= CSTOPB;    /* 2 stop bits */
6700             debug(F100,"ttpkt 2 stopbits","",0);
6701         } else if (stopbits == 1) {
6702             ttraw.c_cflag &= ~(CSTOPB); /* 1 stop bit */
6703             debug(F100,"ttpkt 1 stopbit","",0);
6704         }
6705     }
6706 #endif /* CSTOPB */
6707
6708 #ifdef HWPARITY
6709     if (hwparity && xlocal) {           /* Hardware parity */
6710         ttraw.c_cflag |= PARENB;        /* Enable parity */
6711 #ifdef COMMENT
6712 /* Uncomment this only if needed -- I don't think it is */
6713         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
6714         ttraw.c_cflag |= CS8;           /* And set it to 8 */
6715 #endif /* COMMENT */
6716 #ifdef IGNPAR
6717         ttraw.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
6718         debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
6719 #endif /* IGNPAR */
6720         switch (hwparity) {
6721           case 'e':                     /* Even */
6722             ttraw.c_cflag &= ~(PARODD);
6723             debug(F100,"ttpkt 8 bits + even parity","",0);
6724             break;
6725           case 'o':                     /* Odd */
6726             ttraw.c_cflag |= PARODD;
6727             debug(F100,"ttpkt 8 bits + odd parity","",0);
6728             break;
6729           case 'm':                     /* Mark */
6730           case 's':                     /* Space */
6731             /* PAREXT is mentioned in SVID but the details are not given. */
6732             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
6733             debug(F100,"ttpkt 8 bits + invalid parity","",0);
6734             break;
6735         }
6736     } else {                            /* We handle parity ourselves */
6737 #endif /* HWPARITY */
6738         ttraw.c_cflag &= ~(PARENB);     /* Don't enable parity */
6739 #ifdef HWPARITY
6740     }
6741 #endif /* HWPARITY */
6742
6743 #ifdef IX370
6744     ttraw.c_cc[4] = 48;  /* So Series/1 doesn't interrupt on every char */
6745     ttraw.c_cc[5] = 1;
6746 #else
6747 #ifndef VEOF                            /* for DGUX this is VEOF, not VMIN */
6748     ttraw.c_cc[4] = 1;   /* [VMIN]  return max of this many characters or */
6749 #else
6750 #ifndef OXOS
6751 #ifdef VMIN
6752     ttraw.c_cc[VMIN] = 1;
6753 #endif /* VMIN */
6754 #else /* OXOS */
6755     ttraw.c_min = 1;
6756 #endif /* OXOS */
6757 #endif /* VEOF */
6758 #ifndef VEOL                            /* for DGUX this is VEOL, not VTIME */
6759     ttraw.c_cc[5] = 0;   /* [VTIME] when this many secs/10 expire w/no input */
6760 #else
6761 #ifndef OXOS
6762 #ifdef VTIME
6763     ttraw.c_cc[VTIME] = 0;
6764 #endif /* VTIME */
6765 #else /* OXOS */
6766     ttraw.c_time = 0;
6767 #endif /* OXOS */
6768 #endif /* VEOL */
6769 #endif /* IX370 */
6770
6771 #ifdef VINTR                            /* Turn off interrupt character */
6772     if (xlocal == 0)                    /* so ^C^C can break us out of */
6773       ttraw.c_cc[VINTR] = 0;            /* packet mode. */
6774 #endif /* VINTR */
6775
6776 #ifdef Plan9
6777     if (p9ttyparity('n') < 0)
6778         return -1;
6779 #else
6780 #ifdef BSD44ORPOSIX
6781     errno = 0;
6782 #ifdef BEOSORBEBOX
6783     ttraw.c_cc[VMIN] = 0;               /* DR7 can only poll. */
6784 #endif /* BEOSORBEBOX */
6785
6786 #define TESTING234
6787 #ifdef TESTING234
6788     if (1) {
6789         debug(F100,"ttpkt TESTING234 rawmode","",0);
6790
6791         /* iflags */
6792         ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
6793         ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF);
6794         ttraw.c_iflag |= IGNBRK;
6795 #ifdef IMAXBEL
6796         ttraw.c_iflag &= ~IMAXBEL;
6797 #endif  /* IMAXBEL */
6798 #ifdef IXANY
6799         ttraw.c_iflag &= ~IXANY;
6800 #endif  /* IXANY */
6801 #ifdef IUCLC
6802         ttraw.c_iflag &= ~IUCLC;
6803 #endif /* IUCLC */
6804
6805         /* oflags */
6806         ttraw.c_oflag &= ~OPOST;
6807 #ifdef OXTABS
6808         ttraw.c_oflag &= ~OXTABS;
6809 #endif /* OXTABS */
6810 #ifdef ONOCR
6811         ttraw.c_oflag &= ~ONOCR;
6812 #endif /* ONOCR */
6813 #ifdef ONLRET
6814         ttraw.c_oflag &= ~ONLRET;
6815 #endif /* ONLRET */
6816 #ifdef ONLCR
6817         ttraw.c_oflag &= ~ONLCR;
6818 #endif /* ONLCR */
6819
6820         /* lflags */
6821         ttraw.c_lflag &= ~ECHO;
6822 #ifdef ECHOE
6823         ttraw.c_lflag &= ~ECHOE;
6824 #endif /* ECHOE */
6825 #ifdef ECHONL
6826         ttraw.c_lflag &= ~ECHONL;
6827 #endif /* ECHONL */
6828 #ifdef ECHOPRT
6829         ttraw.c_lflag &= ~ECHOPRT;
6830 #endif /* ECHOPRT */
6831 #ifdef ECHOKE
6832         ttraw.c_lflag &= ~ECHOKE;
6833 #endif /* ECHOKE */
6834 #ifdef ECHOCTL
6835         ttraw.c_lflag &= ~ECHOCTL;
6836 #endif /* ECHOCTL */
6837 #ifdef ALTWERASE
6838         ttraw.c_lflag &= ~ALTWERASE;
6839 #endif /* ALTWERASE */
6840 #ifdef EXTPROC
6841         ttraw.c_lflag &= ~EXTPROC;
6842 #endif /* EXTPROC */
6843         ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
6844 #ifdef NOKERNINFO
6845         ttraw.c_lflag |= NOKERNINFO;
6846 #endif  /* NOKERNINFO */
6847         /* ttraw.c_lflag |= NOFLSH; */
6848         ttraw.c_lflag &= ~NOFLSH;
6849
6850         /* cflags */
6851         ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD);
6852         ttraw.c_cflag |= CS8|CREAD;
6853 #ifdef VMIN
6854         ttraw.c_cc[VMIN] = 1;           /* Supposedly needed for AIX */
6855 #endif  /* VMIN */
6856
6857     }
6858 #endif /* TESTING234 */
6859
6860     debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
6861     x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
6862     debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
6863     if (x < 0) {
6864         debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
6865         return(-1);
6866     }
6867 #else /* BSD44ORPOSIX */
6868     x = ioctl(ttyfd,TCSETAW,&ttraw);
6869     debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
6870     if (x < 0) {  /* set new modes . */
6871         debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
6872         return(-1);
6873     }
6874 #endif /* BSD44ORPOSIX */
6875 #endif /* Plan9 */
6876     tvtflg = 0;
6877     debug(F100,"ttpkt ok","",0);
6878     return(0);
6879 #endif /* ATTSV */
6880
6881 #ifdef COHERENT
6882 #undef SVORPOSIX
6883 #endif /* COHERENT */
6884
6885 }
6886
6887 /*  T T S E T F L O W  --  Set flow control immediately.  */
6888
6889 #ifdef COHERENT
6890 #define SVORPOSIX
6891 #endif /* COHERENT */
6892
6893 int
6894 ttsetflow(flow) int flow; {
6895     if (ttyfd < 0)                      /* A channel must be open */
6896       return(-1);
6897
6898     debug(F101,"ttsetflow flow","",flow);
6899
6900 #ifdef TN_COMPORT
6901     if (netconn && istncomport()) {
6902         debug(F101,"ttsetflow net modem","",ttmdm);
6903         return(tnsetflow(flow));
6904     }
6905 #endif /* TN_COMPORT */
6906 #ifdef NETCMD
6907     if (ttpipe) return(0);
6908 #endif /* NETCMD */
6909 #ifdef NETPTY
6910     if (ttpty) return(0);
6911 #endif /* NETPTY */
6912
6913 #ifdef COMMENT
6914     /* This seems to hurt... */
6915     if (flow == FLO_KEEP)
6916       return(0);
6917 #endif /* COMMENT */
6918
6919     if (flow == FLO_RTSC ||             /* Hardware flow control... */
6920         flow == FLO_DTRC ||
6921         flow == FLO_DTRT) {
6922         tthflow(flow, 1, &ttraw);
6923 #ifndef SVORPOSIX
6924         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6925 #else
6926         ttraw.c_iflag &= ~(IXON|IXOFF);
6927 #endif /* SVORPOSIX */
6928
6929     } else if (flow == FLO_XONX) {      /* Xon/Xoff... */
6930
6931 #ifndef SVORPOSIX
6932         ttraw.sg_flags |= TANDEM;
6933 #else
6934         ttraw.c_iflag |= (IXON|IXOFF);
6935 #endif /* SVORPOSIX */
6936         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off hardware flow control */
6937
6938     } else if (flow == FLO_NONE) {      /* No flow control */
6939
6940 #ifndef SVORPOSIX
6941         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6942 #else
6943         ttraw.c_iflag &= ~(IXON|IXOFF);
6944 #endif /* SVORPOSIX */
6945         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off any hardware f/c too */
6946     }
6947
6948 /* Set the new modes... */
6949
6950 #ifndef SVORPOSIX                       /* BSD and friends */
6951 #ifdef BELLV10
6952     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
6953       return(-1);
6954 #else
6955 #ifndef MINIX2
6956     if (stty(ttyfd,&ttraw) < 0)
6957       return(-1);
6958 #endif /* MINIX2 */
6959 #endif /* BELLV10 */
6960 #else
6961 #ifdef BSD44ORPOSIX                     /* POSIX */
6962     if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
6963       return(-1);
6964 #else                                   /* System V */
6965     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
6966       return(-1);
6967 #endif /* BSD44ORPOSIX */
6968 #endif /* SVORPOSIX */
6969     return(0);
6970 }
6971 #ifdef COHERENT
6972 #undef SVORPOSIX
6973 #endif /* COHERENT */
6974
6975 /*  T T V T -- Condition communication device for use as virtual terminal. */
6976
6977 int
6978 #ifdef CK_ANSIC
6979 ttvt(long speed, int flow)
6980 #else
6981 ttvt(speed,flow) long speed; int flow;
6982 #endif /* CK_ANSIC */
6983 /* ttvt */ {
6984     int s, s2, x;
6985
6986     debug(F101,"ttvt ttyfd","",ttyfd);
6987     debug(F101,"ttvt tvtflg","",tvtflg);
6988     debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
6989     debug(F111,"ttvt flow",ckitoa(ttflow),flow);
6990     debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
6991
6992 /* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
6993 /* Maybe it would be simpler to use it... */
6994
6995     ttpmsk = 0xff;
6996 #ifdef NOLOCAL
6997     return(conbin((char)escchr));
6998 #else
6999     if (ttyfd < 0) {                    /* Not open. */
7000         if (ttchk() < 0)
7001           return(-1);
7002         else                            /* But maybe something buffered. */
7003           return(0);
7004     }
7005 #ifdef NETCMD
7006     if (ttpipe) return(0);
7007 #endif /* NETCMD */
7008 #ifdef NETPTY
7009     if (ttpty) return(0);
7010 #endif /* NETPTY */
7011 #ifdef NETCONN
7012     if (netconn) {
7013 #ifdef TCPSOCKET
7014 #ifdef TCP_NODELAY
7015         {
7016             extern int tcp_nodelay;
7017             if (ttnet == NET_TCPB) {
7018                 if (nodelay_sav > -1) {
7019                     no_delay(ttyfd,nodelay_sav);
7020                     nodelay_sav = -1;
7021                 }
7022             }
7023         }
7024 #endif /* TCP_NODELAY */
7025 #ifdef TN_COMPORT
7026         if (istncomport()) {
7027             int rc = -1;
7028             if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7029                  /* && ttcarr == curcarr */ ) {
7030                 debug(F100,"ttvt modes already set, skipping...","",0);
7031                 return(0);                      /* Already been called. */
7032             }
7033             if (flow != ttflow) {
7034                 if ((rc = tnsetflow(flow)) < 0)
7035                   return(rc);
7036                 ttflow = flow;
7037             }
7038             if (speed != ttspeed) {
7039                 if (speed <= 0) 
7040                   speed = tnc_get_baud();
7041                 else if ((rc = tnc_set_baud(speed)) < 0)
7042                   return(rc);
7043                 ttspeed = speed;
7044             }
7045             tnc_set_datasize(8);
7046             tnc_set_stopsize(stopbits);
7047
7048 #ifdef HWPARITY
7049             if (hwparity) {
7050                 switch (hwparity) {
7051                   case 'e':             /* Even */
7052                     debug(F100,"ttres 8 bits + even parity","",0);
7053                     tnc_set_parity(3);
7054                     break;
7055                   case 'o':             /* Odd */
7056                     debug(F100,"ttres 8 bits + odd parity","",0);
7057                     tnc_set_parity(2);
7058                     break;
7059                   case 'm':             /* Mark */
7060                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
7061                     tnc_set_parity(4);
7062                     break;
7063                   case 's':             /* Space */
7064                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
7065                     tnc_set_parity(5);
7066                     break;
7067                 }
7068             } else
7069 #endif /* HWPARITY */
7070             {
7071                 tnc_set_parity(1);      /* None */
7072             }
7073             tvtflg = 1;
7074             return(0);
7075         }
7076 #endif /* TN_COMPORT */
7077 #endif /* TCPSOCKET */
7078         tvtflg = 1;                     /* Network connections... */
7079         debug(F100,"ttvt network connection, skipping...","",0);
7080         return(0);                      /* ... require no special setup */
7081     }
7082 #endif /* NETCONN */
7083
7084     if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7085         /* && ttcarr == curcarr */ )
7086       {
7087           debug(F100,"ttvt modes already set, skipping...","",0);
7088           return(0);                    /* Already been called. */
7089       }
7090
7091     if (ttfdflg
7092 #ifndef Plan9
7093         && !isatty(ttyfd)
7094 #endif /* Plan9 */
7095         ) {
7096         debug(F100,"ttvt using external fd, skipping...","",0);
7097         return(0);
7098     }
7099
7100     debug(F100,"ttvt setting modes...","",0);
7101
7102     if (xlocal) {                       /* For external lines... */
7103         s2 = (int) (speed / 10L);
7104         s = ttsspd(s2);                 /* Check/set the speed */
7105         carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
7106                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
7107     } else
7108       s = s2 = -1;
7109
7110 #ifdef COHERENT
7111 #define SVORPOSIX
7112 #endif /* COHERENT */
7113
7114 #ifndef SVORPOSIX
7115     /* Berkeley, V7, etc */
7116     if (flow == FLO_RTSC ||             /* Hardware flow control */
7117         flow == FLO_DTRC ||
7118         flow == FLO_DTRT) {
7119         tthflow(flow, 1, &tttvt);
7120         debug(F100,"ttvt hard flow, TANDEM off","",0);
7121         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
7122     } else if (flow == FLO_XONX) {      /* Xon/Xoff flow control */
7123         debug(F100,"ttvt TANDEM on","",0);
7124         tttvt.sg_flags |= TANDEM;       /* Ask for it. */
7125         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7126     } else if (flow == FLO_NONE) {
7127         debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
7128         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
7129         tthflow(flow, 0, &tttvt);       /* Turn off any hardware f/c too */
7130         tttvt.sg_flags |= RAW;          /* Enter raw mode */
7131     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
7132         debug(F100,"ttvt keeping original TANDEM","",0);
7133         tttvt.sg_flags &= ~TANDEM;
7134         tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
7135         /* NOTE: We should also handle hardware flow control here! */
7136     }
7137     tttvt.sg_flags |= RAW;              /* Raw mode in all cases */
7138 #ifdef TOWER1
7139     tttvt.sg_flags &= ~(ECHO|ANYP);     /* No echo or parity */
7140 #else
7141     tttvt.sg_flags &= ~ECHO;            /* No echo */
7142 #endif /* TOWER1 */
7143
7144 #ifdef BELLV10
7145     if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
7146       return(-1);
7147 #else
7148     if (stty(ttyfd,&tttvt) < 0)         /* Set the new modes */
7149       return(-1);
7150 #endif /* BELLV10 */
7151
7152 #else /* It is ATTSV or POSIX */
7153
7154     if (flow == FLO_XONX) {             /* Software flow control */
7155         tttvt.c_iflag |= (IXON|IXOFF);  /* On if requested. */
7156         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7157         debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
7158     } else if (flow == FLO_NONE) {      /* NONE */
7159         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */
7160         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7161         debug(F100,"ttvt SVORPOSIX flow NONE","",0);
7162     } else if (flow == FLO_KEEP) {
7163         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
7164         tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
7165 #ifdef POSIX_CRTSCTS
7166         tttvt.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
7167         tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
7168 #endif /* POSIX_CRTSCTS */
7169         debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
7170     } else if (flow == FLO_RTSC ||      /* Hardware flow control */
7171                flow == FLO_DTRC ||
7172                flow == FLO_DTRT) {
7173         tttvt.c_iflag &= ~(IXON|IXOFF); /* (196) */
7174         tthflow(flow, 1, &tttvt);
7175         debug(F100,"ttvt SVORPOSIX flow HARD","",0);
7176     }
7177 #ifndef OXOS
7178 #ifdef COHERENT
7179     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7180 #else
7181     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
7182 #endif /* COHERENT */
7183 #ifdef QNX
7184     /* Needed for hwfc */
7185     if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
7186       tttvt.c_lflag |= IEXTEN;
7187 #endif /* QNX */
7188 #else /* OXOS */
7189     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7190     tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
7191 #endif /* OXOS */
7192
7193     tttvt.c_iflag |= (IGNBRK|IGNPAR);
7194
7195 /* Stop bits */
7196
7197 #ifdef CSTOPB
7198     if (xlocal) {
7199         if (stopbits == 2) {
7200             tttvt.c_cflag |= CSTOPB;    /* 2 stop bits */
7201             debug(F100,"ttvt 2 stopbits","",0);
7202         } else if (stopbits == 1) {
7203             tttvt.c_cflag &= ~(CSTOPB); /* 1 stop bit */
7204             debug(F100,"ttvt 1 stopbit","",0);
7205         }
7206     }
7207 #endif /* CSTOPB */
7208
7209 /* Parity */
7210
7211 #ifdef HWPARITY
7212     if (hwparity && xlocal) {           /* Hardware parity */
7213 #ifdef COMMENT
7214 /* Uncomment this only if needed -- I don't think it is */
7215         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
7216         ttraw.c_cflag |= CS8;           /* And set it to 8 */
7217 #endif /* COMMENT */
7218 #ifdef IGNPAR
7219         debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
7220         tttvt.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
7221 #endif /* IGNPAR */
7222         tttvt.c_cflag |= PARENB;        /* Enable parity */
7223
7224         switch (hwparity) {
7225           case 'e':                     /* Even */
7226             tttvt.c_cflag &= ~(PARODD);
7227             debug(F100,"ttvt 8 bits + even parity","",0);
7228             break;
7229           case 'o':                     /* Odd */
7230             tttvt.c_cflag |= PARODD;
7231             debug(F100,"ttvt 8 bits + odd parity","",0);
7232             break;
7233           case 'm':                     /* Mark */
7234           case 's':                     /* Space */
7235             /* PAREXT is mentioned in SVID but the details are not given. */
7236             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
7237             debug(F100,"ttvt 8 bits + invalid parity","",0);
7238             break;
7239         }
7240     } else {                            /* We handle parity ourselves */
7241 #endif /* HWPARITY */
7242         tttvt.c_cflag &= ~(PARENB);     /* Don't enable parity */
7243 #ifdef HWPARITY
7244     }
7245 #endif /* HWPARITY */
7246
7247 #ifdef ATTSV
7248 #ifdef BSD44
7249     /* Things not to do... */
7250     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
7251 #else
7252     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
7253 #endif /* BSD44 */
7254 #else /* POSIX */
7255     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
7256 #endif /* ATTSV */
7257     tttvt.c_cflag &= ~(CSIZE);          /* Zero out the char size field */
7258     tttvt.c_cflag |= (CS8|CREAD|HUPCL); /* Char size 8, enable receiver, hup */
7259     tttvt.c_oflag &= ~OPOST;            /* Don't postprocess output */
7260 #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
7261     tttvt.c_cc[4] = 1;
7262 #else
7263 #ifndef OXOS
7264 #ifdef VMIN
7265     tttvt.c_cc[VMIN] = 1;
7266 #endif /* VMIN */
7267 #else /* OXOS */
7268     tttvt.c_min = 1;
7269 #endif /* OXOS */
7270 #endif /* VEOF */
7271 #ifndef VEOL    /* DGUX termio has VEOL at entry 5, see comment above */
7272     tttvt.c_cc[5] = 0;
7273 #else
7274 #ifndef OXOS
7275 #ifdef VTIME
7276     tttvt.c_cc[VTIME] = 0;
7277 #endif /* VTIME */
7278 #else /* OXOS */
7279     tttvt.c_time = 0;
7280 #endif /* OXOS */
7281 #endif /* VEOL */
7282
7283 #ifdef Plan9
7284     if (p9ttyparity('n') < 0)
7285       return -1;
7286 #else
7287 #ifdef BSD44ORPOSIX
7288     errno = 0;
7289 #ifdef BEOSORBEBOX
7290     tttvt.c_cc[VMIN] = 0;               /* DR7 can only poll. */
7291 #endif /* BEOSORBEBOX */
7292
7293     x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
7294     debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
7295     if (x < 0) {
7296         debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
7297         return(-1);
7298     }
7299 #else /* ATTSV */
7300     x = ioctl(ttyfd,TCSETAW,&tttvt);
7301     debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
7302     if (x < 0) {                        /* set new modes . */
7303         debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
7304         return(-1);     
7305     }
7306 #endif /* BSD44ORPOSIX */
7307 #endif /* Plan9 */
7308 #endif /* ATTSV */
7309
7310     ttspeed = speed;                    /* Done, remember how we were */
7311     ttflow = flow;                      /* called, so we can decide how to */
7312     tvtflg = 1;                         /* respond next time. */
7313     debug(F100,"ttvt ok","",0);
7314     return(0);
7315
7316 #ifdef COHERENT
7317 #undef SVORPOSIX
7318 #endif /* COHERENT */
7319
7320 #endif /* NOLOCAL */
7321 }
7322
7323 #ifndef NOLOCAL
7324
7325 /* Serial speed department . . . */
7326
7327 /*
7328   SCO OSR5.0.x might or might not support high speeds.  Sometimes they are not
7329   defined in the header files but they are supported (e.g. when building with
7330   UDK compiler rather than /bin/cc), sometimes vice versa.  Even though 5.0.4
7331   was the first release that came with high serial speeds standard, releases
7332   back to 5.0.0 could use them if certain patches (or "supplements") were
7333   applied to the SIO driver.  Plus a lot of SCO installations run third-party
7334   drivers.
7335 */
7336 #ifdef CK_SCOV5
7337 #ifndef B38400
7338 #define B38400  0000017
7339 #endif /* B38400 */
7340 #ifndef B57600
7341 #define B57600  0000021
7342 #endif /* B57600 */
7343 #ifndef B76800
7344 #define B76800  0000022
7345 #endif /* B76800 */
7346 #ifndef B115200
7347 #define B115200 0000023
7348 #endif /* B115200 */
7349 #ifndef B230400
7350 #define B230400 0000024
7351 #endif /* B230400 */
7352 #ifndef B460800
7353 #define B460800 0000025
7354 #endif /* B460800 */
7355 #ifndef B921600
7356 #define B921600 0000026
7357 #endif /* B921600 */
7358 #endif /* CK_SCOV5 */
7359 /*
7360   Plan 9's native speed setting interface lets you set anything you like,
7361   but will fail if the hardware doesn't like it, so we allow all the common
7362   speeds.
7363 */
7364 #ifdef Plan9
7365 #ifndef B50
7366 #define B50 50
7367 #endif /* B50 */
7368 #ifndef B75
7369 #define B75 75
7370 #endif /* B75 */
7371 #ifndef B110
7372 #define B110 110
7373 #endif /* B110 */
7374 #ifndef B134
7375 #define B134 134
7376 #endif /* B134 */
7377 #ifndef B200
7378 #define B200 200
7379 #endif /* B200 */
7380 #ifndef B300
7381 #define B300 300
7382 #endif /* B300 */
7383 #ifndef B1200
7384 #define B1200 1200
7385 #endif /* B1200 */
7386 #ifndef B1800
7387 #define B1800 1800
7388 #endif /* B1800 */
7389 #ifndef B2400
7390 #define B2400 2400
7391 #endif /* B2400 */
7392 #ifndef B4800
7393 #define B4800 4800
7394 #endif /* B4800 */
7395 #ifndef B9600
7396 #define B9600 9600
7397 #endif /* B9600 */
7398 #ifndef B14400
7399 #define B14400 14400
7400 #endif /* B14400 */
7401 #ifndef B19200
7402 #define B19200 19200
7403 #endif /* B19200 */
7404 #ifndef B28800
7405 #define B28800 28800
7406 #endif /* B28800 */
7407 #ifndef B38400
7408 #define B38400 38400
7409 #endif /* B38400 */
7410 #ifndef B57600
7411 #define B57600 57600
7412 #endif /* B57600 */
7413 #ifndef B76800
7414 #define B76800 76800
7415 #endif /* B76800 */
7416 #ifndef B115200
7417 #define B115200 115200
7418 #endif /* B115200 */
7419 #ifndef B230400
7420 #define B230400 230400
7421 #endif /* B230400 */
7422 #ifndef B460800
7423 #define B460800 460800
7424 #endif /* B460800 */
7425 #ifndef B921600
7426 #define B921600 921600
7427 #endif /* B921600 */
7428 #endif /* Plan9 */
7429
7430 /*  T T S S P D  --  Checks and sets transmission rate.  */
7431
7432 /*  Call with speed in characters (not bits!) per second. */
7433 /*  Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
7434
7435 #ifdef USETCSETSPEED
7436 /*
7437   The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
7438   to be used as a speed to be set, rather than forcing a choice from a
7439   predefined list.  It seems to be peculiar to UnixWare 7.
7440
7441   These are the function codes to be passed to tc[gs]etspeed(),
7442   but for some reason they don't seem to be picked up from termios.h.
7443 */
7444 #ifndef TCS_ALL
7445 #define TCS_ALL 0
7446 #endif /* TCS_ALL */
7447 #ifndef TCS_IN
7448 #define TCS_IN 1
7449 #endif /* TCS_IN */
7450 #ifndef TCS_OUT
7451 #define TCS_OUT 2
7452 #endif /* TCS_OUT */
7453 #endif /* USETCSETSPEED */
7454
7455 int
7456 ttsspd(cps) int cps; {
7457     int x;
7458 #ifdef POSIX
7459 /* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
7460     speed_t
7461 #else
7462     int
7463 #endif /* POSIX */
7464       s, s2;
7465     int ok = 1;                         /* Speed check result, assume ok */
7466
7467 #ifdef OLINUXHISPEED
7468     unsigned int spd_flags = 0;
7469     struct serial_struct serinfo;
7470 #endif /* OLINUXHISPEED */
7471
7472     debug(F101,"ttsspd cps","",cps);
7473     debug(F101,"ttsspd ttyfd","",ttyfd);
7474     debug(F101,"ttsspd xlocal","",xlocal);
7475
7476     if (ttyfd < 0 || xlocal == 0)       /* Don't set speed on console */
7477       return(0);
7478
7479 #ifdef  NETCONN
7480     if (netconn) {
7481 #ifdef TN_COMPORT
7482         if (istncomport())
7483           return(tnc_set_baud(cps * 10));
7484         else
7485 #endif /* TN_COMPORT */
7486         return(0);
7487   }
7488 #endif  /* NETCONN */
7489 #ifdef NETCMD
7490     if (ttpipe) return(0);
7491 #endif /* NETCMD */
7492 #ifdef NETPTY
7493     if (ttpty) return(0);
7494 #endif /* NETPTY */
7495
7496     if (cps < 0) return(-1);
7497     s = s2 = 0;                         /* NB: s and s2 might be unsigned */
7498
7499 #ifdef USETCSETSPEED
7500
7501     s = cps * 10L;
7502
7503     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
7504     debug(F101,"ttsspd tcgetattr","",x);
7505     if (x < 0)
7506       return(-1);
7507     debug(F101,"ttsspd TCSETSPEED speed","",s);
7508
7509     errno = 0;
7510     if (s == 8880L) {                   /* 75/1200 split speed requested */
7511         tcsetspeed(TCS_IN, &ttcur, 1200L);
7512         tcsetspeed(TCS_OUT, &ttcur, 75L);
7513     } else
7514       tcsetspeed(TCS_ALL, &ttcur, s);   /* Put new speed in structs */
7515 #ifdef DEBUG
7516     if (errno & deblog) {
7517         debug(F101,"ttsspd TCSETSPEED errno","",errno);
7518     }
7519 #endif /* DEBUG */
7520
7521 #ifdef COMMENT
7522     tcsetspeed(TCS_ALL, &ttraw, s);
7523     tcsetspeed(TCS_ALL, &tttvt, s);
7524     tcsetspeed(TCS_ALL, &ttold, s);
7525 #else
7526     if (s == 8880L) {                   /* 75/1200 split speed requested */
7527         tcsetspeed(TCS_IN, &ttraw, 1200L);
7528         tcsetspeed(TCS_OUT, &ttraw, 75L);
7529         tcsetspeed(TCS_IN, &tttvt, 1200L);
7530         tcsetspeed(TCS_OUT, &tttvt, 75L);
7531         tcsetspeed(TCS_IN, &ttold, 1200L);
7532         tcsetspeed(TCS_OUT, &ttold, 75L);
7533     } else {
7534         tcsetspeed(TCS_ALL, &ttraw, s);
7535         tcsetspeed(TCS_ALL, &tttvt, s);
7536         tcsetspeed(TCS_ALL, &ttold, s);
7537     }
7538 #endif /* COMMENT */
7539
7540     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
7541     debug(F101,"ttsspd tcsetattr","",x);
7542     if (x < 0)
7543       return(-1);
7544
7545 #else  /* Not USETCSETSPEED */
7546
7547     /* First check that the given speed is valid. */
7548
7549     switch (cps) {
7550 #ifndef MINIX
7551       case 0:   s = B0;    break;
7552       case 5:   s = B50;   break;
7553       case 7:   s = B75;   break;
7554 #endif /* MINIX */
7555       case 11:  s = B110;  break;
7556 #ifndef MINIX
7557       case 13:  s = B134;  break;
7558       case 15:  s = B150;  break;
7559       case 20:  s = B200;  break;
7560 #endif /* MINIX */
7561       case 30:  s = B300;  break;
7562 #ifndef MINIX
7563       case 60:  s = B600;  break;
7564 #endif /* MINIX */
7565       case 120: s = B1200; break;
7566 #ifndef MINIX
7567       case 180: s = B1800; break;
7568 #endif /* MINIX */
7569       case 240: s = B2400; break;
7570       case 480: s = B4800; break;
7571 #ifndef MINIX
7572       case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
7573 #endif /* MINIX */
7574 #ifdef B7200
7575       case 720: s = B7200; break;
7576 #endif /* B7200 */
7577       case 960: s = B9600; break;
7578 #ifdef B14400
7579       case 1440: s = B14400; break;
7580 #endif /* B14400 */
7581 #ifdef B19200
7582       case 1920: s = B19200; break;
7583 #else
7584 #ifdef EXTA
7585       case 1920: s = EXTA; break;
7586 #endif /* EXTA */
7587 #endif /* B19200 */
7588 #ifdef B28800
7589       case 2880: s = B28800; break;
7590 #endif /* B28800 */
7591 #ifdef B38400
7592       case 3840: s = B38400;
7593 #ifdef OLINUXHISPEED
7594         spd_flags = ~ASYNC_SPD_MASK;    /* Nonzero, but zero flags */
7595 #endif /* OLINUXHISPEED */
7596         break;
7597 #else /* B38400 not defined... */
7598 #ifdef EXTB
7599       case 3840: s = EXTB; break;
7600 #endif /* EXTB */
7601 #endif /* B38400 */
7602
7603 #ifdef HPUX
7604 #ifdef _B57600
7605       case 5760: s = _B57600; break;
7606 #endif /* _B57600 */
7607 #ifdef _B115200
7608       case 11520: s = _B115200; break;
7609 #endif /* _B115200 */
7610 #else
7611 #ifdef OLINUXHISPEED
7612 /*
7613   This bit from <carlo@sg.tn.tudelft.nl>:
7614   "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
7615   setting the speed to 38400 will set the custom speed (and ttgspd returns
7616   38400), but speeds 57600 and 115200 won't work any more because I didn't
7617   want to mess up the speed flags when someone is doing sophisticated stuff
7618   like custom speeds..."
7619 */
7620       case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
7621       case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
7622 #else
7623 #ifdef B57600
7624       case 5760: s = B57600; break;
7625 #endif /* B57600 */
7626 #ifdef B76800
7627       case 7680: s = B76800; break;
7628 #endif /* B76800 */
7629 #ifdef B115200
7630       case 11520: s = B115200; break;
7631 #endif /* B115200 */
7632 #endif /* OLINUXHISPEED */
7633 #ifdef B153600
7634       case 15360: s = B153600; break;
7635 #endif /* B153600 */
7636 #ifdef B230400
7637       case 23040: s = B230400; break;
7638 #endif /* B230400 */
7639 #ifdef B307200
7640       case 30720: s = B307200; break;
7641 #endif /* B307200 */
7642 #ifdef B460800
7643       case 46080: s = B460800; break;
7644 #endif /* 460800 */
7645 #ifdef B921600
7646       case 92160: s = B921600; break;
7647 #endif /* B921600 */
7648 #endif /* HPUX */
7649       default:
7650         ok = 0;                         /* Good speed not found, so not ok */
7651         break;
7652     }
7653     debug(F101,"ttsspd ok","",ok);
7654     debug(F101,"ttsspd s","",s);
7655
7656     if (!ok) {
7657         debug(F100,"ttsspd fails","",0);
7658         return(-1);
7659     } else {
7660         if (!s2) s2 = s;                /* Set input speed */
7661 #ifdef Plan9
7662         if (p9ttsspd(cps) < 0)
7663           return(-1);
7664 #else
7665 #ifdef BSD44ORPOSIX
7666         x = tcgetattr(ttyfd,&ttcur);    /* Get current speed */
7667         debug(F101,"ttsspd tcgetattr","",x);
7668         if (x < 0)
7669           return(-1);
7670 #ifdef OLINUXHISPEED
7671         debug(F101,"ttsspd spd_flags","",spd_flags);
7672         if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
7673             if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
7674                 debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
7675                 return(-1);
7676             } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
7677             serinfo.flags &= ~ASYNC_SPD_MASK;
7678             serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
7679             if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
7680               return(-1);
7681         }
7682 #endif /* OLINUXHISPEED */
7683         cfsetospeed(&ttcur,s);
7684         cfsetispeed(&ttcur,s2);
7685         cfsetospeed(&ttraw,s);
7686         cfsetispeed(&ttraw,s2);
7687         cfsetospeed(&tttvt,s);
7688         cfsetispeed(&tttvt,s2);
7689         cfsetospeed(&ttold,s);
7690         cfsetispeed(&ttold,s2);
7691         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
7692         debug(F101,"ttsspd tcsetattr","",x);
7693         if (x < 0) return(-1);
7694 #else
7695 #ifdef ATTSV
7696         if (cps == 888) return(-1);     /* No split speeds, sorry. */
7697         x = ioctl(ttyfd,TCGETA,&ttcur);
7698         debug(F101,"ttsspd TCGETA ioctl","",x);
7699         if (x < 0) return(-1);
7700         ttcur.c_cflag &= ~CBAUD;
7701         ttcur.c_cflag |= s;
7702         tttvt.c_cflag &= ~CBAUD;
7703         tttvt.c_cflag |= s;
7704         ttraw.c_cflag &= ~CBAUD;
7705         ttraw.c_cflag |= s;
7706         ttold.c_cflag &= ~CBAUD;
7707         ttold.c_cflag |= s;
7708         x = ioctl(ttyfd,TCSETAW,&ttcur);
7709         debug(F101,"ttsspd TCSETAW ioctl","",x);
7710         if (x < 0) return(-1);
7711 #else
7712 #ifdef BELLV10
7713         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
7714         debug(F101,"ttsspd TIOCGDEV ioctl","",x);
7715         if (x < 0) return(-1);
7716         tdcur.ispeed = s2;
7717         tdcur.ospeed = s;
7718         errno = 0;
7719         ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
7720         debug(F101,"ttsspd BELLV10 ioctl","",ok);
7721         if (ok < 0) {
7722             perror(ttnmsv);
7723             debug(F101,"ttsspd BELLV10 errno","",ok);
7724             return(-1);
7725         }
7726 #else
7727         x = gtty(ttyfd,&ttcur);
7728         debug(F101,"ttsspd gtty","",x);
7729         if (x < 0) return(-1);
7730         ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
7731         tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
7732         ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
7733         ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
7734         x = stty(ttyfd,&ttcur);
7735         debug(F101,"ttsspd stty","",x);
7736         if (x < 0) return(-1);
7737 #endif /* BELLV10 */
7738 #endif /* ATTSV */
7739 #endif /* BSD44ORPOSIX */
7740 #endif /* Plan9 */
7741     }
7742     return(1);                          /* Return 1 = success. */
7743 #endif /* USETCSETSPEED */
7744 }
7745
7746 #endif /* NOLOCAL */
7747
7748 /* C O N G S P D  -  Get speed of console terminal  */
7749
7750 long
7751 congspd() {
7752 /*
7753   This is a disgusting hack.  The right way to do this would be to pass an
7754   argument to ttgspd(), but then we'd need to change the Kermit API and
7755   all of the ck?tio.c modules.  (Currently used only for rlogin.)
7756 */
7757     int t1;
7758     long spd;
7759 #ifdef NETCONN
7760     int t2 = netconn;
7761     netconn = 0;
7762 #endif /* NETCONN */
7763     t1 = ttyfd;
7764     ttyfd = -1;
7765     spd = ttgspd();
7766     debug(F101,"congspd","",spd);
7767 #ifdef NETCONN
7768     netconn = t2;
7769 #endif /* NETCONN */
7770     ttyfd = t1;
7771     return(spd);
7772 }
7773
7774 /*  T T S P D L I S T  -- Get list of serial speeds allowed on this platform */
7775
7776 #define NSPDLIST 64
7777 static long spdlist[NSPDLIST];
7778 /*
7779   As written, this picks up the speeds known at compile time, and thus
7780   apply to the system where C-Kermit was built, rather than to the one where
7781   it is running.  Suggestions for improvement are always welcome.
7782 */
7783 long *
7784 ttspdlist() {
7785     int i;
7786     for (i = 0; i < NSPDLIST; i++)      /* Initialize the list */
7787       spdlist[i] = -1L;
7788     i = 1;
7789
7790 #ifdef USETCSETSPEED                    /* No way to find out what's legal */
7791     debug(F100,"ttspdlist USETCSETSPEED","",0);
7792     spdlist[i++] = 50L;
7793 #ifndef UW7
7794     spdlist[i++] = 75L;
7795 #endif /* UW7 */
7796     spdlist[i++] = 110L;
7797 #ifndef UW7
7798     spdlist[i++] = 134L;
7799 #endif /* UW7 */
7800     spdlist[i++] = 150L;
7801     spdlist[i++] = 200L;
7802     spdlist[i++] = 300L;
7803     spdlist[i++] = 600L;
7804     spdlist[i++] = 1200L;
7805     spdlist[i++] = 1800L;
7806     spdlist[i++] = 2400L;
7807     spdlist[i++] = 4800L;
7808     spdlist[i++] = 8880L;
7809     spdlist[i++] = 9600L;
7810     spdlist[i++] = 14400L;
7811     spdlist[i++] = 19200L;
7812     spdlist[i++] = 28800L;
7813 #ifndef UW7
7814     spdlist[i++] = 33600L;
7815 #endif /* UW7 */
7816     spdlist[i++] = 38400L;
7817     spdlist[i++] = 57600L;
7818     spdlist[i++] = 76800L;
7819     spdlist[i++] = 115200L;
7820 #ifndef UW7
7821     spdlist[i++] = 153600L;
7822     spdlist[i++] = 230400L;
7823     spdlist[i++] = 307200L;
7824     spdlist[i++] = 460800L;
7825     spdlist[i++] = 921600L;
7826 #endif /* UW7 */
7827
7828 #else  /* USETCSETSPEED */
7829
7830     debug(F100,"ttspdlist no USETCSETSPEED","",0);
7831
7832 #ifdef B50
7833     debug(F101,"ttspdlist B50","",B50);
7834     spdlist[i++] = 50L;
7835 #endif /* B50 */
7836 #ifdef B75
7837     debug(F101,"ttspdlist B75","",B75);
7838     spdlist[i++] = 75L;
7839 #endif /* B75 */
7840 #ifdef B110
7841     debug(F101,"ttspdlist B110","",B110);
7842     spdlist[i++] = 110L;
7843 #endif /* B110 */
7844 #ifdef B134
7845     debug(F101,"ttspdlist B134","",B134);
7846     spdlist[i++] = 134L;
7847 #endif /* B134 */
7848 #ifdef B150
7849     debug(F101,"ttspdlist B150","",B150);
7850     spdlist[i++] = 150L;
7851 #endif /* B150 */
7852 #ifdef B200
7853     debug(F101,"ttspdlist B200","",B200);
7854     spdlist[i++] = 200L;
7855 #endif /* B200 */
7856 #ifdef B300
7857     debug(F101,"ttspdlist B300","",B300);
7858     spdlist[i++] = 300L;
7859 #endif /* B300 */
7860 #ifdef B600
7861     debug(F101,"ttspdlist B600","",B600);
7862     spdlist[i++] = 600L;
7863 #endif /* B600 */
7864 #ifdef B1200
7865     debug(F101,"ttspdlist B1200","",B1200);
7866     spdlist[i++] = 1200L;
7867 #endif /* B1200 */
7868 #ifdef B1800
7869     debug(F101,"ttspdlist B1800","",B1800);
7870     spdlist[i++] = 1800L;
7871 #endif /* B1800 */
7872 #ifdef B2400
7873     debug(F101,"ttspdlist B2400","",B2400);
7874     spdlist[i++] = 2400L;
7875 #endif /* B2400 */
7876 #ifdef B4800
7877     debug(F101,"ttspdlist B4800","",B4800);
7878     spdlist[i++] = 4800L;
7879 #endif /* B4800 */
7880 #ifdef B9600
7881     debug(F101,"ttspdlist B9600","",B9600);
7882     spdlist[i++] = 9600L;
7883 #endif /* B9600 */
7884 #ifdef B14400
7885     debug(F101,"ttspdlist B14400","",B14400);
7886     spdlist[i++] = 14400L;
7887 #endif /* B14400 */
7888 #ifdef B19200
7889     debug(F101,"ttspdlist B19200","",B19200);
7890     spdlist[i++] = 19200L;
7891 #else
7892 #ifdef EXTA
7893     debug(F101,"ttspdlist EXTA","",EXTA);
7894     spdlist[i++] = 19200L;
7895 #endif /* EXTA */
7896 #endif /* B19200 */
7897 #ifdef B28800
7898     debug(F101,"ttspdlist B28800","",B28800);
7899     spdlist[i++] = 28800L;
7900 #endif /* B28800 */
7901 #ifdef B33600
7902     debug(F101,"ttspdlist B33600","",B33600);
7903     spdlist[i++] = 33600L;
7904 #endif /* B33600 */
7905 #ifdef B38400
7906     debug(F101,"ttspdlist B38400","",B38400);
7907     spdlist[i++] = 38400L;
7908 #else
7909 #ifdef EXTB
7910     debug(F101,"ttspdlist EXTB","",EXTB);
7911     spdlist[i++] = 38400L;
7912 #endif /* EXTB */
7913 #endif /* B38400 */
7914 #ifdef _B57600
7915     debug(F101,"ttspdlist _B57600","",_B57600);
7916     spdlist[i++] = 57600L;
7917 #else
7918 #ifdef B57600
7919     debug(F101,"ttspdlist B57600","",B57600);
7920     spdlist[i++] = 57600L;
7921 #endif /* B57600 */
7922 #endif /* _B57600 */
7923 #ifdef B76800
7924     debug(F101,"ttspdlist B76800","",B76800);
7925     spdlist[i++] = 76800L;
7926 #endif /* B76800 */
7927 #ifdef _B115200
7928     debug(F101,"ttspdlist _B115200","",_B115200);
7929     spdlist[i++] = 115200L;
7930 #else
7931 #ifdef B115200
7932     debug(F101,"ttspdlist B115200","",B115200);
7933     spdlist[i++] = 115200L;
7934 #endif /* B115200 */
7935 #endif /* _B115200 */
7936 #ifdef B153600
7937     debug(F101,"ttspdlist B153600","",B153600);
7938     spdlist[i++] = 153600L;
7939 #endif /* B153600 */
7940 #ifdef B230400
7941     debug(F101,"ttspdlist B230400","",B230400);
7942     spdlist[i++] = 230400L;
7943 #endif /* B230400 */
7944 #ifdef B307200
7945     debug(F101,"ttspdlist B307200","",B307200);
7946     spdlist[i++] = 307200L;
7947 #endif /* B307200 */
7948 #ifdef B460800
7949     debug(F101,"ttspdlist B460800","",B460800);
7950     spdlist[i++] = 460800L;
7951 #endif /* B460800 */
7952 #ifdef B921600
7953     debug(F101,"ttspdlist B921600","",B921600);
7954     spdlist[i++] = 921600L;
7955 #endif /* B921600 */
7956 #endif /* USETCSETSPEED */
7957     spdlist[0] = i - 1;                 /* Return count in 0th element */
7958     debug(F111,"ttspdlist spdlist","0",spdlist[0]);
7959     return((long *)spdlist);
7960 }
7961
7962 /* T T G S P D  -  Get speed of currently selected tty line  */
7963
7964 /*
7965   Unreliable.  After SET LINE, it returns an actual speed, but not necessarily
7966   the real speed.  On some systems, it returns the line's nominal speed, from
7967   /etc/ttytab.  Even if you SET SPEED to something else, this function might
7968   not notice.
7969 */
7970 long
7971 ttgspd() {                              /* Get current serial device speed */
7972 #ifdef NOLOCAL
7973     return(-1L);
7974 #else
7975 #ifdef POSIX
7976     speed_t                             /* Should be unsigned */
7977 #else
7978     int                                 /* Isn't unsigned */
7979 #endif /* POSIX */
7980       s;
7981     int x;
7982     long ss;
7983 #ifdef OLINUXHISPEED
7984     unsigned int spd_flags = 0;
7985     struct serial_struct serinfo;
7986 #endif /* OLINUXHISPEED */
7987
7988 #ifdef NETCONN
7989     if (netconn) {
7990 #ifdef TN_COMPORT
7991         if (istncomport())
7992           return(tnc_get_baud());
7993         else
7994 #endif /* TN_COMPORT */
7995           return(-1);                   /* -1 if network connection */
7996     }
7997 #endif /* NETCONN */
7998 #ifdef NETCMD
7999     if (ttpipe) return(-1);
8000 #endif /* NETCMD */
8001 #ifdef NETPTY
8002     if (ttpty) return(-1);
8003 #endif /* NETPTY */
8004
8005     debug(F101,"ttgspd ttyfd","",ttyfd);
8006
8007 #ifdef USETCSETSPEED
8008
8009     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
8010     debug(F101,"ttgspd tcgetattr","",x);
8011     if (x < 0)
8012       return(-1);
8013     errno = 0;
8014     s = tcgetspeed(TCS_ALL, &ttcur);
8015     debug(F101,"ttsspd TCGETSPEED speed","",s);
8016     if (s == 0) {
8017         long s1, s2;
8018         s1 = tcgetspeed(TCS_IN, &ttcur);
8019         s2 = tcgetspeed(TCS_OUT, &ttcur);
8020         if (s1 == 1200L && s2 == 75L)
8021           return(8880L);
8022     }
8023 #ifdef DEBUG
8024     if (errno & deblog) {
8025         debug(F101,"ttsspd TCGETSPEED errno","",errno);
8026     }
8027 #endif /* DEBUG */
8028     return(s);
8029
8030 #else  /* Not USETCSETSPEED */
8031
8032 #ifdef Plan9
8033     if (ttyfd < 0)
8034       ss = -1;
8035     else
8036       ss = ttylastspeed;
8037 #else
8038 #ifdef OLINUXHISPEED
8039     debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
8040 #endif /* OLINUXHISPEED */
8041
8042     if (ttyfd < 0) {
8043 #ifdef BSD44ORPOSIX
8044         s = cfgetospeed(&ccold);
8045         debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
8046 #else
8047 #ifdef ATTSV
8048         s = ccold.c_cflag & CBAUD;
8049         debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
8050 #else
8051         s = ccold.sg_ospeed;            /* (obtained by congm()) */
8052         debug(F101,"ttgspd sg_ospeed 1","",s);
8053 #endif /* ATTSV */
8054 #endif /* BSD44POSIX */
8055
8056     } else {
8057 #ifdef BSD44ORPOSIX
8058         if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
8059         s = cfgetospeed(&ttcur);
8060         debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
8061 #ifdef OLINUXHISPEED
8062         if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
8063           spd_flags = serinfo.flags & ASYNC_SPD_MASK;
8064         debug(F101,"ttgspd spd_flags","",spd_flags);
8065 #endif /* OLINUXHISPEED */
8066 #else
8067 #ifdef ATTSV
8068         x = ioctl(ttyfd,TCGETA,&ttcur);
8069         debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
8070         debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
8071         if (x < 0) return(-1);
8072         s = ttcur.c_cflag & CBAUD;
8073         debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
8074 #else
8075 #ifdef BELLV10
8076         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
8077         debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
8078         if (x < 0) return(-1);
8079         s = tdcur.ospeed;
8080         debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
8081 #else
8082         x = gtty(ttyfd,&ttcur);
8083         debug(F101,"ttgspd gtty 2 x","",x);
8084         debug(F101,"ttgspd gtty 2 errno","",errno);
8085         if (x < 0) return(-1);
8086         s = ttcur.sg_ospeed;
8087         debug(F101,"ttgspd gtty 2 speed","",s);
8088 #endif /* BELLV10 */
8089 #endif /* ATTSV */
8090 #endif /* BSD44ORPOSIX */
8091     }
8092     debug(F101,"ttgspd code","",s);
8093 #ifdef OLINUXHISPEED
8094     debug(F101,"ttgspd spd_flags","",spd_flags);
8095 #endif /* OLINUXHISPEED */
8096     switch (s) {
8097 #ifdef B0
8098       case B0:    ss = 0L; break;
8099 #endif /* B0 */
8100
8101 #ifndef MINIX
8102 /*
8103  MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
8104  etc, making for many "duplicate case in switch" errors, which are fatal.
8105 */
8106 #ifdef B50
8107       case B50:   ss = 50L; break;
8108 #endif /* B50 */
8109 #ifdef B75
8110       case B75:   ss = 75L; break;
8111 #endif /* B75 */
8112 #endif /* MINIX */
8113
8114 #ifdef B110
8115       case B110:  ss = 110L; break;
8116 #endif /* B110 */
8117
8118 #ifndef MINIX
8119 #ifdef B134
8120       case B134:  ss = 134L; break;
8121 #endif /* B134 */
8122 #ifdef B150
8123       case B150:  ss = 150L; break;
8124 #endif /* B150 */
8125 #endif /* MINIX */
8126
8127 #ifdef B200
8128       case B200:  ss = 200L; break;
8129 #endif /* B200 */
8130
8131 #ifdef B300
8132       case B300:  ss = 300L; break;
8133 #endif /* B300 */
8134
8135 #ifdef B600
8136       case B600:  ss = 600L; break;
8137 #endif /* B600 */
8138
8139 #ifdef B1200
8140       case B1200: ss = 1200L; break;
8141 #endif /* B1200 */
8142
8143 #ifdef B1800
8144       case B1800: ss = 1800L; break;
8145 #endif /* B1800 */
8146
8147 #ifdef B2400
8148       case B2400: ss = 2400L; break;
8149 #endif /* B2400 */
8150
8151 #ifdef B4800
8152       case B4800: ss = 4800L; break;
8153 #endif /* B4800 */
8154
8155 #ifdef B7200
8156       case B7200: ss = 7200L; break;
8157 #endif /* B7200 */
8158
8159 #ifdef B9600
8160       case B9600: ss = 9600L; break;
8161 #endif /* B9600 */
8162
8163 #ifdef B19200
8164       case B19200: ss = 19200L; break;
8165 #else
8166 #ifdef EXTA
8167       case EXTA: ss = 19200L; break;
8168 #endif /* EXTA */
8169 #endif /* B19200 */
8170
8171 #ifndef MINIX
8172 #ifdef B38400
8173       case B38400:
8174         ss = 38400L;
8175 #ifdef OLINUXHISPEED
8176         switch(spd_flags) {
8177           case ASYNC_SPD_HI:  ss =  57600L; break;
8178           case ASYNC_SPD_VHI: ss = 115200L; break;
8179         }
8180 #endif /* OLINUXHISPEED */
8181         break;
8182 #else
8183 #ifdef EXTB
8184       case EXTB: ss = 38400L; break;
8185 #endif /* EXTB */
8186 #endif /* B38400 */
8187 #endif /* MINIX */
8188
8189 #ifdef HPUX
8190 #ifdef _B57600
8191       case _B57600: ss = 57600L; break;
8192 #endif /* _B57600 */
8193 #ifdef _B115200
8194       case _B115200: ss = 115200L; break;
8195 #endif /* _B115200 */
8196 #else
8197 #ifdef B57600
8198       case B57600: ss = 57600L; break;
8199 #endif /* B57600 */
8200 #ifdef B76800
8201       case B76800: ss = 76800L; break;
8202 #endif /* B76800 */
8203 #ifdef B115200
8204       case B115200: ss = 115200L; break;
8205 #endif /* B115200 */
8206 #ifdef B153600
8207       case B153600: ss = 153600L; break;
8208 #endif /* B153600 */
8209 #ifdef B230400
8210       case B230400: ss = 230400L; break;
8211 #endif /* B230400 */
8212 #ifdef B307200
8213       case B307200: ss = 307200L; break;
8214 #endif /* B307200 */
8215 #ifdef B460800
8216       case B460800: ss = 460800L; break;
8217 #endif /* B460800 */
8218 #endif /* HPUX */
8219 #ifdef B921600
8220       case B921600: ss = 921600L; break;
8221 #endif /* B921600 */
8222       default:
8223         ss = -1; break;
8224     }
8225 #endif /* Plan9 */
8226     debug(F101,"ttgspd speed","",ss);
8227     return(ss);
8228
8229 #endif /* USETCSETSPEED */
8230 #endif /* NOLOCAL */
8231 }
8232 #ifdef MINIX2                           /* Another hack alert */
8233 #define MINIX
8234 #endif /* MINIX2 */
8235
8236 /*
8237   FIONREAD data type...  This has been defined as "long" for many, many
8238   years, and it worked OK until 64-bit platforms appeared.  Thus we use
8239   int for 64-bit platforms, but keep long for the others.  If we changed
8240   the default PEEKTYPE to int, this would probably break 16-bit builds
8241   (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
8242   of which we have no way of testing any more.  Therefore, do not change
8243   the default definition of PEEKTYPE -- only add exceptions to it as needed.
8244 */
8245 #ifdef COHERENT
8246 #ifdef FIONREAD
8247 #undef FIONREAD
8248 #endif /* FIONREAD */
8249 /* #define FIONREAD TIOCQUERY */
8250 /* #define PEEKTYPE int */
8251 #else  /* Not COHERENT... */
8252
8253 #ifdef OSF32                            /* Digital UNIX 3.2 or higher */
8254 #define PEEKTYPE int
8255 #else
8256 #define PEEKTYPE long                   /* Elsewhere (see notes above) */
8257 #endif /* OSF32 */
8258 #endif /* COHERENT */
8259
8260 /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
8261
8262 #ifdef MYREAD
8263
8264 /* Private buffer for myread() and its companions.  Not for use by anything
8265  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
8266  * allowed to read my_count.
8267  *
8268  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
8269  *
8270  * A global parity mask variable could be useful too.  We could use it to
8271  * let myread() strip the parity on its own, instead of stripping sign
8272  * bits as it does now.
8273  */
8274 #ifdef BIGBUFOK
8275 #define MYBUFLEN 32768
8276 #else
8277 #ifdef pdp11
8278 #define MYBUFLEN 256
8279 #else
8280 #define MYBUFLEN 1024
8281 #endif /* pdp11 */
8282 #endif /* BIGBUFOK */
8283
8284 #ifdef ANYX25
8285 #undef MYBUFLEN
8286 #define MYBUFLEN 256
8287 /*
8288   On X.25 connections, there is an extra control byte at the beginning.
8289 */
8290 static CHAR x25buf[MYBUFLEN+1];         /* Communication device input buffer */
8291 static CHAR  *mybuf = x25buf+1;
8292 #else
8293 static CHAR mybuf[MYBUFLEN];
8294 #endif /* ANYX25 */
8295
8296 static int my_count = 0;                /* Number of chars still in mybuf */
8297 static int my_item = -1;                /* Last index read from mybuf[]   */
8298
8299 /*  T T P E E K  --  Peek into our internal communications input buffers. */
8300
8301 /*
8302   NOTE: This routine is peculiar to UNIX, and is used only by the
8303   select()-based CONNECT module, ckucns.c.  It need not be replicated in
8304   the ck?tio.c of other platforms.
8305 */
8306 int
8307 ttpeek() {
8308 #ifdef TTLEBUF
8309     int rc = 0;
8310     if (ttpush >= 0)
8311       rc++;
8312     rc += le_inbuf();
8313     if (rc > 0)
8314       return(rc);
8315     else
8316 #endif /* TTLEBUF */
8317
8318 #ifdef MYREAD
8319     return(my_count);
8320 #else
8321     return(0);
8322 #endif /* MYREAD */
8323 }
8324
8325 /* myread() -- Efficient read of one character from communications line.
8326  *
8327  * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw
8328  * bytes from connection, so when the connection is encrypted, these bytes
8329  * must be decrypted.
8330  *
8331  * Uses a private buffer to minimize the number of expensive read() system
8332  * calls.  Essentially performs the equivalent of read() of 1 character, which
8333  * is then returned.  By reading all available input from the system buffers
8334  * to the private buffer in one chunk, and then working from this buffer, the
8335  * number of system calls is reduced in any case where more than one character
8336  * arrives during the processing of the previous chunk, for instance high
8337  * baud rates or network type connections where input arrives in packets.
8338  * If the time needed for a read() system call approaches the time for more
8339  * than one character to arrive, then this mechanism automatically compensates
8340  * for that by performing bigger read()s less frequently.  If the system load
8341  * is high, the same mechanism compensates for that too.
8342  *
8343  * myread() is a macro that returns the next character from the buffer.  If the
8344  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
8345  * returns.
8346  *
8347  * This should be efficient enough for any one-character-at-a-time loops.
8348  * For even better efficiency you might use memcpy()/bcopy() or such between
8349  * buffers (since they are often better optimized for copying), but it may not
8350  * be worth it if you have to take an extra pass over the buffer to strip
8351  * parity and check for CTRL-C anyway.
8352  *
8353  * Note that if you have been using myread() from another program module, you
8354  * may have some trouble accessing this macro version and the private variables
8355  * it uses.  In that case, just add a function in this module, that invokes the
8356  * macro.
8357  */
8358 #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
8359
8360 /* Specification: Push back up to one character onto myread()'s queue.
8361  *
8362  * This implementation: Push back characters into mybuf. At least one character
8363  * must have been read through myread() before myunrd() may be used.  After
8364  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
8365  * one character can be pushed back, but only one character is guaranteed.
8366  * Since a previous myread() must have read its character out of mybuf[],
8367  * that guarantees that there is space for at least one character.  If push
8368  * back was really needed after EOF, a small addition could provide that.
8369  *
8370  * As of 02/2007 myunrd() is used by ttinl().
8371  */
8372 VOID
8373 #ifdef CK_ANSIC
8374 myunrd(CHAR ch)
8375 #else
8376 myunrd(ch) CHAR ch;
8377 #endif  /* CK_ANSIC */
8378 {
8379     if (my_item >= 0) {
8380         mybuf[my_item--] = ch;
8381         ++my_count;
8382     }
8383 }
8384
8385 /*  T T P U S H B A C K  --  Put n bytes back into the myread buffer */
8386
8387 static CHAR * pushbuf = NULL;
8388 /* static int pushed = 0; */
8389
8390 int
8391 ttpushback(s,n) CHAR * s; int n; {
8392     debug(F101,"ttpushback n","",n);
8393     if (pushbuf || n > MYBUFLEN || n < 1)
8394       return(-1);
8395     debug(F101,"ttpushback my_count","",my_count);
8396     if (my_count > 0) {
8397         if (!(pushbuf = (CHAR *)malloc(n+1)))
8398           return(-1);
8399         memcpy(pushbuf,mybuf,my_count);
8400         /* pushed = my_count; */ /* (set but never used) */
8401     }
8402     memcpy(mybuf,s,n);
8403     my_count = n;
8404     my_item = -1;
8405     return(0);
8406 }
8407
8408 /* mygetbuf() -- Fill buffer for myread() and return first character.
8409  *
8410  * This function is what myread() uses when it can't get the next character
8411  * directly from its buffer.  First, it calls a system dependent myfillbuf()
8412  * to read at least one new character into the buffer, and then it returns
8413  * the first character just as myread() would have done.  This function also
8414  * is responsible for all error conditions that myread() can indicate.
8415  *
8416  * Returns: When OK     => a positive character, 0 or greater.
8417  *          When EOF    => -2.
8418  *          When error  => -3, error code in errno.
8419  *
8420  * Older myread()s additionally returned -1 to indicate that there was nothing
8421  * to read, upon which the caller would call myread() again until it got
8422  * something.  The new myread()/mygetbuf() always gets something.  If it
8423  * doesn't, then make it do so!  Any program that actually depends on the old
8424  * behaviour will break.
8425  *
8426  * The older version also used to return -2 both for EOF and other errors,
8427  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
8428  * other errors now return different results, although Kermit currently never
8429  * checks to see which it was.  It just disconnects in both cases.
8430  *
8431  * Kermit lets the user use the quit key to perform some special commands
8432  * during file transfer.  This causes read(), and thus also mygetbuf(), to
8433  * finish without reading anything and return the EINTR error.  This should
8434  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
8435  * but if there is nothing to read, this could delay Kermit's reaction to
8436  * the command, and make Kermit appear unresponsive.
8437  *
8438  * The debug() call should be removed for optimum performance.
8439  */
8440 int
8441 mygetbuf() {
8442     int x;
8443     errno = 0;
8444 #ifdef DEBUG
8445     if (deblog && my_count > 0)
8446       debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
8447 #endif /* DEBUG */
8448     if (my_count <= 0)
8449       my_count = myfillbuf();
8450
8451 #ifdef DEBUG
8452 #ifdef COMMENT
8453     if (deblog) debug(F101, "mygetbuf read", "", my_count);
8454 #else /* COMMENT */
8455     ckhexdump("mygetbuf read", mybuf, my_count);
8456 #endif /* COMMENT */
8457 #endif /* DEBUG */
8458     x = my_count;
8459     if (my_count <= 0) {
8460         my_count = 0;
8461         my_item = -1;
8462         debug(F101,"mygetbuf errno","",errno);
8463 #ifdef TCPSOCKET
8464         if (netconn && ttnet == NET_TCPB && errno != 0) {
8465             if (errno != EINTR) {
8466                 debug(F101,"mygetbuf TCP error","",errno);
8467                 ttclos(0);              /* Close the connection. */
8468             }
8469             return(-3);
8470         }
8471 #endif /* TCPSOCKET */
8472         if (!netconn && xlocal && errno) {
8473             if (errno != EINTR) {
8474                 debug(F101,"mygetbuf SERIAL error","",errno);
8475                 x = -3;
8476                 ttclos(0);              /* Close the connection. */
8477             }
8478         }
8479         return((x < 0) ? -3 : -2);
8480     }
8481     --my_count;
8482     return((unsigned)(0xff & mybuf[my_item = 0]));
8483 }
8484
8485 /* myfillbuf():
8486  * System-dependent read() into mybuf[], as many characters as possible.
8487  *
8488  * Returns: OK => number of characters read, always more than zero.
8489  *          EOF => 0
8490  *          Error => -1, error code in errno.
8491  *
8492  * If there is input available in the system's buffers, all of it should be
8493  * read into mybuf[] and the function return immediately.  If no input is
8494  * available, it should wait for a character to arrive, and return with that
8495  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
8496  * character, but be aware that any such delay lengthens the packet turnaround
8497  * time during kermit file transfers.  Should never return with zero characters
8498  * unless EOF or irrecoverable read error.
8499  *
8500  * Correct functioning depends on the correct tty parameters being used.
8501  * Better control of current parameters is required than may have been the
8502  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
8503  * no longer be sometimes off and sometimes on like it used to, unless a
8504  * special myfillbuf() is written to handle that.  Otherwise the ordinary
8505  * myfillbuf()s may think they have come to EOF.
8506  *
8507  * If your system has a facility to directly perform the functioning of
8508  * myfillbuf(), then use it.  If the system can tell you how many characters
8509  * are available in its buffers, then read that amount (but not less than 1).
8510  * If the system can return a special indication when you try to read without
8511  * anything to read, while allowing you to read all there is when there is
8512  * something, you may loop until there is something to read, but probably that
8513  * is not good for the system load.
8514  */
8515
8516 #ifdef SVORPOSIX
8517         /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
8518          * and CLOCAL set any way you like.  This way, read() will do exactly
8519          * what is required by myfillbuf(): If there is data in the buffers
8520          * of the O.S., all available data is read into mybuf, up to the size
8521          * of mybuf.  If there is none, the first character to arrive is
8522          * awaited and returned.
8523          */
8524 int
8525 myfillbuf() {
8526     int fd, n;
8527 #ifdef NETCMD
8528     if (ttpipe)
8529       fd = fdin;
8530     else
8531 #endif /* NETCMD */
8532       fd = ttyfd;
8533
8534 #ifdef sxaE50
8535     /* From S. Dezawa at Fujifilm in Japan.  I don't know why this is */
8536     /* necessary for the sxa E50, but it is. */
8537     return read(fd, mybuf, 255);
8538 #else
8539 #ifdef BEOSORBEBOX
8540     while (1) {
8541 #ifdef NETCONN
8542         if (netconn) {
8543             n = netxin(sizeof(mybuf), (char *)mybuf);
8544             debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
8545         }
8546         else
8547 #endif /* NETCONN */
8548           n = read(fd, mybuf, sizeof(mybuf));
8549         debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
8550         if (n > 0)
8551           return(n);
8552         snooze(1000.0);
8553     }
8554 #else /* BEOSORBEBOX */
8555     errno = 0;
8556     /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */
8557 #ifdef IBMX25
8558     if (netconn && (nettype == NET_IX25)) {
8559         /* can't use sizeof because mybuf is a pointer, and not an array! */
8560         n = x25xin( MYBUFLEN, mybuf );
8561     } else
8562 #endif /* IBMX25 */
8563
8564 #ifdef CK_SSL
8565       if (ssl_active_flag || tls_active_flag) {
8566           int error, n = 0;
8567           debug(F100,"myfillbuf calling SSL_read() fd","",0);
8568           while (n == 0) {
8569               if (ssl_active_flag)
8570                 n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8571               else if (tls_active_flag)
8572                 n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8573               else
8574                 break;
8575               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8576                 case SSL_ERROR_NONE:
8577                   if (n > 0)
8578                     return(n);
8579                   if (n < 0)
8580                     return(-2);
8581                   msleep(50);
8582                   break;
8583                 case SSL_ERROR_WANT_WRITE:
8584                 case SSL_ERROR_WANT_READ:
8585                   return(-1);
8586                 case SSL_ERROR_SYSCALL:
8587                   if (n != 0)
8588                     return(-1);
8589                 case SSL_ERROR_WANT_X509_LOOKUP:
8590                 case SSL_ERROR_SSL:
8591                 case SSL_ERROR_ZERO_RETURN:
8592                 default:
8593                   ttclos(0);
8594                   return(-3);
8595             }
8596         }
8597     }
8598 #endif /* CK_SSL */
8599 #ifdef CK_KERBEROS
8600 #ifdef KRB4
8601 #ifdef RLOGCODE
8602     if (ttnproto == NP_EK4LOGIN) {
8603         debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd);
8604         if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8605           return(-3);
8606         else
8607           return(n);
8608     }
8609 #endif /* RLOGCODE */
8610 #endif /* KRB4 */
8611 #ifdef KRB5
8612 #ifdef RLOGCODE
8613     if (ttnproto == NP_EK5LOGIN) {
8614         debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd);
8615         if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0)
8616           return(-3);
8617         else
8618           return(n);
8619     }
8620 #endif /* RLOGCODE */
8621 #ifdef KRB5_U2U
8622     if (ttnproto == NP_K5U2U) {
8623         debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd);
8624         if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8625           return(-3);
8626         else
8627           return(n);
8628     }
8629 #endif /* KRB5_U2U */
8630 #endif /* KRB5 */
8631 #endif /* CK_KERBEROS */
8632
8633 #ifdef NETPTY
8634 #ifdef HAVE_PTYTRAP
8635     /* Special handling for HP-UX pty i/o */
8636   ptyread:
8637     if (ttpty && pty_trap_pending(ttyfd) > 0) {
8638         debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd);
8639         if (pty_trap_handler(ttyfd) > 0) {
8640             ttclos(0);
8641             return(-3);
8642         }
8643     }
8644 #endif /* HAVE_PTYTRAP */
8645 #endif /* NETPTY */
8646     debug(F101,"myfillbuf calling read() fd","",ttyfd);
8647     n = read(fd, mybuf, sizeof(mybuf));
8648     debug(F101,"SVORPOSIX myfillbuf read","",n);
8649     debug(F101,"SVORPOSIX myfillbuf errno","",errno);
8650     debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
8651     if (n < 1) {
8652 #ifdef NETPTY
8653 #ifdef HAVE_PTYTRAP
8654         /* When we have a PTY trap in place the connection cannot */
8655         /* be closed until the trap receives a close indication.  */
8656         if (n == 0 && ttpty)
8657             goto ptyread;
8658 #endif /* HAVE_PTYTRAP */
8659 #endif /* NETPTY */
8660         return(-3);
8661     }
8662     return(n);
8663 #endif /* BEOSORBEBOX */
8664 #endif /* sxaE50 */
8665 }
8666
8667 #else /* not AT&T or POSIX */
8668
8669 #ifdef aegis
8670         /* This is quoted from the old myread().  The semantics seem to be
8671          * alright, but maybe errno would not need to be set even when
8672          * there is no error?  I don't know aegis.
8673          */
8674 int
8675 myfillbuf() {
8676     int count;
8677 #ifdef NETCMD
8678     if (ttpipe)
8679       fd = fdin;
8680     else
8681 #endif /* NETCMD */
8682       fd = ttyfd;
8683
8684     count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
8685     errno = EIO;
8686     if (st.all == ios_$get_conditional_failed) /* get at least one */
8687       count = ios_$get((short)fd, 0, mybuf, 1L, st);
8688     if (st.all == ios_$end_of_file)
8689       return(-3);
8690     else if (st.all != status_$ok) {
8691         errno = EIO;
8692         return(-1);
8693     }
8694     return(count > 0 ? count : -3);
8695 }
8696 #else /* !aegis */
8697
8698 #ifdef FIONREAD
8699         /* This is for systems with FIONREAD.  FIONREAD returns the number
8700          * of characters available for reading. If none are available, wait
8701          * until something arrives, otherwise return all there is.
8702          */
8703 int
8704 myfillbuf() {
8705     PEEKTYPE avail = 0;
8706     int x, fd;
8707 #ifdef NETCMD
8708     if (ttpipe)
8709       fd = fdin;
8710     else
8711 #endif /* NETCMD */
8712       fd = ttyfd;
8713
8714 #ifdef SUNX25
8715 /*
8716   SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
8717   Depends on SunOS having FIONREAD, not because we use it, but just so this
8718   code is grouped correctly within the #ifdefs.  Let's hope Solaris keeps it.
8719
8720   We call x25xin() instead of read() so that Q-Bit packets, which contain
8721   X.25 service-level information (e.g. PAD parameter changes), can be processed
8722   transparently to the upper-level code.  This is a blocking read, and so
8723   we depend on higher-level code (such as ttinc()) to set any necessary alarms.
8724 */
8725     extern int nettype;
8726     if (netconn && nettype == NET_SX25) {
8727         while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
8728         return(x - 1);          /* "-1" compensates for extra status byte */
8729     }
8730 #endif /* SUNX25 */
8731
8732 #ifdef CK_SSL
8733     if (ssl_active_flag || tls_active_flag) {
8734         int error, n = 0;
8735         while (n == 0) {
8736             if (ssl_active_flag)
8737               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8738             else
8739               n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8740             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8741               case SSL_ERROR_NONE:
8742                 if (n > 0)
8743                   return(n);
8744                 if (n < 0)
8745                   return(-2);
8746                 msleep(50);
8747                 break;
8748               case SSL_ERROR_WANT_WRITE:
8749               case SSL_ERROR_WANT_READ:
8750                 return(-1);
8751               case SSL_ERROR_SYSCALL:
8752                 if (n != 0)
8753                   return(-1);
8754               case SSL_ERROR_WANT_X509_LOOKUP:
8755               case SSL_ERROR_SSL:
8756               case SSL_ERROR_ZERO_RETURN:
8757               default:
8758                 ttclos(0);
8759                 return(-2);
8760             }
8761         }
8762     }
8763 #endif /* CK_SSL */
8764 #ifdef CK_KERBEROS
8765 #ifdef KRB4
8766 #ifdef RLOGCODE
8767     if (ttnproto == NP_EK4LOGIN) {
8768         if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8769           return(-1);
8770         else
8771           return(x);
8772     }
8773 #endif /* RLOGCODE */
8774 #endif /* KRB4 */
8775 #ifdef KRB5
8776 #ifdef RLOGCODE
8777     if (ttnproto == NP_EK5LOGIN) {
8778         if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8779           return(-1);
8780         else
8781           return(x);
8782     }
8783 #endif /* RLOGCODE */
8784 #ifdef KRB5_U2U
8785     if (ttnproto == NP_K5U2U) {
8786         if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8787           return(-1);
8788         else
8789           return(x);
8790     }
8791 #endif /* KRB5_U2U */
8792 #endif /* KRB5 */
8793 #endif /* CK_KERBEROS */
8794
8795     errno = 0;
8796     debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
8797     x = ioctl(fd, FIONREAD, &avail);
8798 #ifdef DEBUG
8799     if (deblog) {
8800         debug(F101,"myfillbuf FIONREAD","",x);
8801         debug(F101,"myfillbuf FIONREAD avail","",avail);
8802         debug(F101,"myfillbuf FIONREAD errno","",errno);
8803     }
8804 #endif /* DEBUG */
8805     if (x < 0 || avail == 0)
8806       avail = 1;
8807
8808     if (avail > MYBUFLEN)
8809       avail = MYBUFLEN;
8810
8811     errno = 0;
8812
8813     x = read(fd, mybuf, (int) avail);
8814 #ifdef DEBUG
8815     if (deblog) {
8816         debug(F101,"myfillbuf avail","",avail);
8817         debug(F101,"myfillbuf read","",x);
8818         debug(F101,"myfillbuf read errno","",errno);
8819         if (x > 0)
8820           ckhexdump("myfillbuf mybuf",mybuf,x);
8821     }
8822 #endif /* DEBUG */
8823     if (x < 1) x = -3;                  /* read 0 == connection loss */
8824     return(x);
8825 }
8826
8827 #else /* !FIONREAD */
8828 /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
8829 /* When there is no other possibility, read 1 character at a time. */
8830 int
8831 myfillbuf() {
8832     int x;
8833
8834 #ifdef CK_SSL
8835     if (ssl_active_flag || tls_active_flag) {
8836         int error, n = 0;
8837         while (n == 0) {
8838             if (ssl_active_flag)
8839               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8840             else
8841               count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8842             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8843               case SSL_ERROR_NONE:
8844                 if (n > 0)
8845                   return(n);
8846                 if (n < 0)
8847                   return(-2);
8848                 msleep(50);
8849                 break;
8850               case SSL_ERROR_WANT_WRITE:
8851               case SSL_ERROR_WANT_READ:
8852                 return(-1);
8853               case SSL_ERROR_SYSCALL:
8854                 if (n != 0)
8855                   return(-1);
8856               case SSL_ERROR_WANT_X509_LOOKUP:
8857               case SSL_ERROR_SSL:
8858               case SSL_ERROR_ZERO_RETURN:
8859               default:
8860                 ttclos(0);
8861                 return(-2);
8862             }
8863         }
8864     }
8865 #endif /* CK_SSL */
8866 #ifdef CK_KERBEROS
8867 #ifdef KRB4
8868 #ifdef RLOGCODE
8869     if (ttnproto == NP_EK4LOGIN) {
8870         if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8871           return(-1);
8872         else
8873           return(len);
8874     }
8875 #endif /* RLOGCODE */
8876 #endif /* KRB4 */
8877 #ifdef KRB5
8878 #ifdef RLOGCODE
8879     if (ttnproto == NP_EK5LOGIN) {
8880         if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8881           return(-1);
8882         else
8883           return(len);
8884     }
8885 #endif /* RLOGCODE */
8886 #ifdef KRB5_U2U
8887     if (ttnproto == NP_K5U2U) {
8888         if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8889           return(-1);
8890         else
8891           return(len);
8892     }
8893 #endif /* KRB5_U2U */
8894 #endif /* KRB5 */
8895 #endif /* CK_KERBEROS */
8896
8897 #ifdef NETCMD
8898     if (ttpipe)
8899       fd = fdin;
8900     else
8901 #endif /* NETCMD */
8902       fd = ttyfd;
8903     x = read(fd, mybuf, 1);
8904     return(x > 0 ? x : -3);
8905 }
8906
8907 #endif /* !FIONREAD */
8908 #endif /* !aegis */
8909 #endif /* !ATTSV */
8910
8911 #endif /* MYREAD */
8912
8913 /*  T T _ T N O P T  --  Handle Telnet negotions in incoming data */
8914 /*
8915   Call with the IAC that was encountered.
8916   Returns:
8917    -3: If connection has dropped or gone bad.
8918    -2: On Telnet protocol error resulting in inconsistent states.
8919     0: If negotiation OK and caller has nothing to do.
8920     1: If packet start character has changed (new value is in global stchr).
8921   255: If there was a quoted IAC as data.
8922    or: Not at all if we got a legitimate Telnet Logout request.
8923 */
8924 #ifdef TCPSOCKET
8925 static int
8926 tt_tnopt(n) int n; {                    /* Handle Telnet options */
8927     /* In case caller did not already check these conditions...  */
8928     if (n == IAC &&
8929         ((xlocal && netconn && IS_TELNET()) ||
8930          (!xlocal && sstelnet))) {
8931         extern int server;
8932         int tx = 0;
8933         debug(F100,"ttinl calling tn_doop()","",0);
8934         tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
8935         debug(F111,"ttinl tn_doop() returned","tx",tx);
8936         switch (tx) {
8937           case 0:
8938             return(0);
8939           case -1:                      /* I/O error */
8940             ttimoff();                  /* Turn off timer */
8941             return(-3);
8942           case -2:                      /* Connection failed. */
8943           case -3:
8944             ttimoff();                  /* Turn off timer */
8945             ttclos(0);
8946             return(-3);
8947           case 1:                       /* ECHO change */
8948             duplex = 1;
8949             return(0);
8950           case 2:                       /* ECHO change */
8951             duplex = 0;
8952             return(0);
8953           case 3:                       /* Quoted IAC */
8954             n = 255;
8955             return((unsigned)255);
8956 #ifdef IKS_OPTION
8957           case 4: {
8958               if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
8959 #ifdef IKSD
8960                   && !inserver
8961 #endif /* IKSD */
8962                   ) {                   /* Remote in Server mode */
8963                   ttimoff();            /* Turn off timer */
8964                   debug(F100,"u_start and !inserver","",0);
8965                   return(-2);           /* End server mode */
8966               } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
8967                          server
8968                          ) {            /* I'm no longer in Server Mode */
8969                   debug(F100,"me_start and server","",0);
8970                   ttimoff();
8971                   return(-2);
8972               }
8973               return(0);
8974           }
8975           case 5: {                     /* Start character change */
8976               /* extern CHAR stchr; */
8977               /* start = stchr; */
8978               return(1);
8979           }
8980 #endif /* IKS_OPTION */
8981           case 6:                       /* Remote Logout */
8982             ttimoff();
8983             ttclos(0);
8984 #ifdef IKSD
8985             if (inserver && !local)
8986               doexit(GOOD_EXIT,0);
8987             else
8988 #endif /* IKSD */
8989               return(-2);
8990           default:
8991             return(0);
8992         }
8993     } else
8994       return(0);
8995 }
8996 #endif /* TCPSOCKET */
8997
8998 /*  T T F L U I  --  Flush tty input buffer */
8999
9000 void
9001 ttflux() {                              /* But first... */
9002 #ifdef MYREAD
9003 /*
9004   Flush internal MYREAD buffer.
9005 */
9006 #ifdef TCPSOCKET
9007     int dotnopts, x;
9008     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
9009                  (!xlocal && sstelnet)));
9010 #endif /* TCPSOCKET */
9011     debug(F101,"ttflux my_count","",my_count);
9012 #ifdef TCPSOCKET
9013     if (dotnopts) {
9014         CHAR ch = '\0';
9015         while (my_count > 0) {
9016             ch = myread();
9017 #ifdef CK_ENCRYPTION
9018             if (TELOPT_U(TELOPT_ENCRYPTION))
9019               ck_tn_decrypt((char *)&ch,1);
9020 #endif /* CK_ENCRYPTION */
9021             if (ch == IAC)
9022               x = tt_tnopt(ch);
9023         }
9024     } else
9025 #endif /* TCPSOCKET */
9026 #ifdef COMMENT
9027 #ifdef CK_ENCRYPTION
9028     if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
9029       ck_tn_decrypt(&mybuf[my_item+1],my_count);
9030 #endif /* CK_ENCRYPTION */
9031 #endif /* COMMENT */
9032     my_count = 0;                       /* Reset count to zero */
9033     my_item = -1;                       /* And buffer index to -1 */
9034 #endif /* MYREAD */
9035 }
9036
9037 int
9038 ttflui() {
9039     int n, fd;
9040 #ifdef TCPSOCKET
9041     int dotnopts;
9042     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
9043                  (!xlocal && sstelnet)));
9044 #endif /* TCPSOCKET */
9045
9046 #ifdef NETCMD
9047     if (ttpipe)
9048       fd = fdin;
9049     else
9050 #endif /* NETCMD */
9051       fd = ttyfd;
9052
9053 #ifdef TTLEBUF
9054     ttpush = -1;                        /* Clear the peek-ahead char */
9055     while (le_data && (le_inbuf() > 0)) {
9056         CHAR ch = '\0';
9057         if (le_getchar(&ch) > 0) {      /* Clear any more... */
9058             debug(F101,"ttflui le_inbuf ch","",ch);
9059         }
9060     }
9061 #endif /* TTLEBUF */
9062     debug(F101,"ttflui ttpipe","",ttpipe);
9063
9064 #ifdef MYREAD
9065 /*
9066   Flush internal MYREAD buffer *NEXT*, in all cases.
9067 */
9068     ttflux();
9069 #endif /* MYREAD */
9070
9071 #ifdef NETCONN
9072 /* Network flush is done specially, in the network support module. */
9073     if ((netconn || sstelnet) && !ttpipe && !ttpty) {
9074         debug(F100,"ttflui netflui","",0);
9075 #ifdef COMMENT
9076 #ifdef TN_COMPORT
9077         if (istncomport())
9078             tnc_send_purge_data(TNC_PURGE_RECEIVE);
9079 #endif /* TN_COMPORT */
9080 #endif /* COMMENT */
9081         return(netflui());
9082     }
9083 #endif /* NETCONN */
9084
9085     debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
9086     if (ttyfd < 0)
9087       return(-1);
9088
9089 #ifdef aegis
9090     sio_$control((short)yfd, sio_$flush_in, true, st);
9091     if (st.all != status_$ok) {
9092         fprintf(stderr, "flush failed: "); error_$print(st);
9093     } else {      /* sometimes the flush doesn't work */
9094         for (;;) {
9095             char buf[256];
9096             /* eat all the characters that shouldn't be available */
9097             ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
9098             if (st.all == ios_$get_conditional_failed) break;
9099             fprintf(stderr, "flush failed(2): "); error_$print(st);
9100         }
9101     }
9102 #else
9103 #ifdef BSD44                            /* 4.4 BSD */
9104     n = FREAD;                          /* Specify read queue */
9105     debug(F100,"ttflui BSD44","",0);
9106     ioctl(fd,TIOCFLUSH,&n);
9107 #else
9108 #ifdef Plan9
9109 #undef POSIX                            /* Uh oh... */
9110 #endif /* Plan9 */
9111 #ifdef POSIX                            /* POSIX */
9112     debug(F100,"ttflui POSIX","",0);
9113     tcflush(fd,TCIFLUSH);
9114 #else
9115 #ifdef ATTSV                            /* System V */
9116 #ifndef VXVE
9117     debug(F100,"ttflui ATTSV","",0);
9118     ioctl(fd,TCFLSH,0);
9119 #endif /* VXVE */
9120 #else                                   /* Not BSD44, POSIX, or Sys V */
9121 #ifdef TIOCFLUSH                        /* Those with TIOCFLUSH defined */
9122 #ifdef ANYBSD                           /* Berkeley */
9123     n = FREAD;                          /* Specify read queue */
9124     debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
9125     ioctl(fd,TIOCFLUSH,&n);
9126 #else                                   /* Others (V7, etc) */
9127     debug(F100,"ttflui TIOCFLUSH","",0);
9128     ioctl(fd,TIOCFLUSH,0);
9129 #endif /* ANYBSD */
9130 #else                                   /* All others... */
9131 /*
9132   No system call (that we know about) for input buffer flushing.
9133   So see how many there are and read them in a loop, using ttinc().
9134   ttinc() is buffered, so we're not getting charged with a system call
9135   per character, just a function call.
9136 */
9137     if ((n = ttchk()) > 0) {
9138         debug(F101,"ttflui read loop","",n);
9139         while ((n--) && ttinc(0) > 0) ;
9140     }
9141 #endif /* TIOCFLUSH */
9142 #endif /* ATTSV */
9143 #endif /* POSIX */
9144 #ifdef Plan9
9145 #define POSIX
9146 #endif /* Plan9 */
9147 #endif /* BSD44 */
9148 #endif /* aegis */
9149     return(0);
9150 }
9151
9152 int
9153 ttfluo() {                              /* Flush output buffer */
9154     int fd;
9155 #ifdef NETCMD
9156     if (ttpipe)
9157       fd = fdout;
9158     else
9159 #endif /* NETCMD */
9160       fd = ttyfd;
9161
9162 #ifdef Plan9
9163     return 0;
9164 #else
9165 #ifdef POSIX
9166     return(tcflush(fd,TCOFLUSH));
9167 #else
9168 #ifdef OXOS
9169     return(ioctl(fd,TCFLSH,1));
9170 #else
9171     return(0);                          /* All others, nothing */
9172 #endif /* OXOS */
9173 #endif /* POSIX */
9174 #endif /* Plan9 */
9175 }
9176
9177 /* Interrupt Functions */
9178
9179 /* Set up terminal interrupts on console terminal */
9180
9181 #ifndef FIONREAD                        /* We don't need esctrp() */
9182 #ifndef SELECT                          /* if we have any of these... */
9183 #ifndef CK_POLL
9184 #ifndef RDCHK
9185
9186 #ifndef OXOS
9187 #ifdef SVORPOSIX
9188 SIGTYP
9189 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9190     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9191     conesc = 1;
9192     debug(F101,"esctrp caught SIGQUIT","",conesc);
9193 }
9194 #endif /* SVORPOSIX */
9195 #endif /* OXOS */
9196
9197 #ifdef V7
9198 #ifndef MINIX2
9199 SIGTYP
9200 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9201     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9202     conesc = 1;
9203     debug(F101,"esctrp caught SIGQUIT","",conesc);
9204 }
9205 #endif /* MINIX2 */
9206 #endif /* V7 */
9207
9208 #ifdef C70
9209 SIGTYP
9210 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9211     conesc = 1;
9212     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9213 }
9214 #endif /* C70 */
9215
9216 #endif /* RDCHK */
9217 #endif /* CK_POLL */
9218 #endif /* SELECT */
9219 #endif /* FIONREAD */
9220
9221 /*  C O N B G T  --  Background Test  */
9222
9223 static int jc = 0;                      /* 0 = no job control */
9224
9225 /*
9226   Call with flag == 1 to prevent signal test, which can not be expected
9227   to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
9228
9229   Call with flag == 0 to use the signal test, but only if the process-group
9230   test fails, as it does on some UNIX systems, where getpgrp() is buggy,
9231   requires an argument when the man page says it doesn't, or vice versa.
9232
9233   If flag == 0 and the process-group test fails, then we determine background
9234   status simply (but not necessarily reliably) from isatty().
9235
9236   conbgt() sets the global backgrd = 1 if we appear to be in the background,
9237   and to 0 if we seem to be in the foreground.  conbgt() is highly prone to
9238   misbehavior.
9239 */
9240 VOID
9241 conbgt(flag) int flag; {
9242     int x = -1,                         /* process group or SIGINT test */
9243         y = 0;                          /* isatty() test */
9244 /*
9245   Check for background operation, even if not running on real tty, so that
9246   background flag can be set correctly.  If background status is detected,
9247   then Kermit will not issue its interactive prompt or most messages.
9248   If your prompt goes away, you can blame (and fix?) this function.
9249 */
9250
9251 /* Use process-group test if possible. */
9252
9253 #ifdef POSIX                            /* We can do it in POSIX */
9254 #define PGROUP_T
9255 #else
9256 #ifdef BSD4                             /* and in BSD 4.x. */
9257 #define PGROUP_T
9258 #else
9259 #ifdef HPUXJOBCTL                       /* and in most HP-UX's */
9260 #define PGROUP_T
9261 #else
9262 #ifdef TIOCGPGRP                        /* and anyplace that has this ioctl. */
9263 #define PGROUP_T
9264 #endif /* TIOCGPGRP */
9265 #endif /* HPUXJOBCTL */
9266 #endif /* BSD4 */
9267 #endif /* POSIX */
9268
9269 #ifdef MIPS                             /* Except if it doesn't work... */
9270 #undef PGROUP_T
9271 #endif /* MIPS */
9272
9273 #ifdef MINIX
9274 #undef PGROUP_T
9275 #endif  /* MINIX */
9276
9277 #ifdef PGROUP_T
9278 /*
9279   Semi-reliable process-group test.  Check whether this process's group is
9280   the same as the controlling terminal's process group.  This works if the
9281   getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
9282 */
9283     PID_T mypgrp = (PID_T)0;            /* Kermit's process group */
9284     PID_T ctpgrp = (PID_T)0;            /* The terminal's process group */
9285 #ifndef _POSIX_SOURCE
9286 /*
9287   The getpgrp() prototype is obtained from system header files for POSIX
9288   and Sys V R4 compilations.  Other systems, who knows.  Some complain about
9289   a duplicate declaration here, others don't, so it's safer to leave it in
9290   if we don't know for certain.
9291 */
9292 #ifndef SVR4
9293 #ifndef PS2AIX10
9294 #ifndef HPUX9
9295     extern PID_T getpgrp();
9296 #endif /* HPUX9 */
9297 #endif /* PS2AIX10 */
9298 #endif /* SVR4 */
9299 #endif /* _POSIX_SOURCE */
9300
9301 /* Get my process group. */
9302
9303 #ifdef SVR3 /* Maybe this should be ATTSV? */
9304 /* This function is not described in SVID R2 */
9305     mypgrp = getpgrp();
9306     /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
9307 #else
9308 #ifdef POSIX
9309     mypgrp = getpgrp();
9310     /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
9311 #else
9312 #ifdef OSFPC
9313     mypgrp = getpgrp();
9314     /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
9315 #else
9316 #ifdef QNX
9317     mypgrp = getpgrp();
9318     /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
9319 #else
9320 #ifdef OSF32                            /* (was OSF40) */
9321     mypgrp = getpgrp();
9322     /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
9323 #else /* BSD, V7, etc */
9324 #ifdef MINIX2
9325     mypgrp = getpgrp();
9326 #else
9327     mypgrp = getpgrp(0);
9328 #endif /* MINIX2 */
9329     /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
9330 #endif /* OSF32 */
9331 #endif /* QNX */
9332 #endif /* OSFPC */
9333 #endif /* POSIX */
9334 #endif /* SVR3 */
9335
9336 #ifdef MINIX
9337     /* MINIX does not support job control so Kermit is always in foreground */
9338     x = 0;
9339
9340 #else  /* Not MINIX */
9341
9342 /* Now get controlling tty's process group */
9343 #ifdef BSD44ORPOSIX
9344     ctpgrp = tcgetpgrp(1);              /* The POSIX way */
9345     /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
9346 #else
9347     ioctl(1, TIOCGPGRP, &ctpgrp);       /* Or the BSD way */
9348    /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
9349 #endif /* BSD44ORPOSIX */
9350
9351     if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
9352       x = (mypgrp == ctpgrp) ? 0 : 1;   /* If they differ, then background. */
9353     else x = -1;                        /* If error, remember. */
9354     debug(F101,"conbgt process group test","",x);
9355 #endif /* PGROUP_T */
9356 #endif  /* MINIX */
9357
9358 /* Try to see if job control is available */
9359
9360 #ifdef NOJC                             /* User override */
9361     jc = 0;                             /* No job control allowed */
9362     debug(F111,"NOJC","jc",jc);
9363 #else
9364 #ifdef BSD44
9365     jc = 1;
9366 #else
9367 #ifdef SVR4ORPOSIX                      /* POSIX actually tells us */
9368     debug(F100,"SVR4ORPOSIX jc test...","",0);
9369 #ifdef _SC_JOB_CONTROL
9370 #ifdef __bsdi__
9371     jc = 1;
9372 #else
9373 #ifdef __386BSD__
9374     jc = 1;
9375 #else
9376     jc = sysconf(_SC_JOB_CONTROL);      /* Whatever system says */
9377     if (jc < 0) {
9378         debug(F101,"sysconf fails, jcshell","",jcshell);
9379         jc = (jchdlr == SIG_DFL) ? 1 : 0;
9380     } else
9381       debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
9382 #endif /* __386BSD__ */
9383 #endif /* __bsdi__ */
9384 #else
9385 #ifdef _POSIX_JOB_CONTROL
9386     jc = 1;                             /* By definition */
9387     debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
9388 #else
9389     jc = 0;                             /* Assume job control not allowed */
9390     debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
9391 #endif /* _POSIX_JOB_CONTROL */
9392 #endif /* _SC_JOB_CONTROL */
9393 #else
9394 #ifdef BSD4
9395     jc = 1;                             /* Job control allowed */
9396     debug(F111,"BSD job control","jc",jc);
9397 #else
9398 #ifdef SVR3JC
9399     jc = 1;                             /* JC allowed */
9400     debug(F111,"SVR3 job control","jc",jc);
9401 #else
9402 #ifdef OXOS
9403     jc = 1;                             /* JC allowed */
9404     debug(F111,"X/OS job control","jc",jc);
9405 #else
9406 #ifdef HPUX9
9407     jc = 1;                             /* JC allowed */
9408     debug(F111,"HP-UX 9.0 job control","jc",jc);
9409 #else
9410 #ifdef HPUX10
9411     jc = 1;                             /* JC allowed */
9412     debug(F111,"HP-UX 10.0 job control","jc",jc);
9413 #else
9414     jc = 0;                             /* JC not allowed */
9415     debug(F111,"job control catch-all","jc",jc);
9416 #endif /* HPUX10 */
9417 #endif /* HPUX9 */
9418 #endif /* OXOS */
9419 #endif /* SVR3JC */
9420 #endif /* BSD4 */
9421 #endif /* SVR4ORPOSIX */
9422 #endif /* BSD44 */
9423 #endif /* NOJC */
9424     debug(F101,"conbgt jc","",jc);
9425 #ifndef NOJC
9426     debug(F101,"conbgt jcshell","",jcshell);
9427 /*
9428   At this point, if jc == 1 but jcshell == 0, it means that the OS supports
9429   job control, but the shell or other process we are running under does not
9430   (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
9431   will come of it.  So...
9432 */
9433     if (jc < 0) jc = 0;
9434     if (jc > 0 && jcshell == 0) jc = 0;
9435 #endif /* NOJC */
9436
9437 /*
9438   Another background test.
9439   Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
9440   which is done by the shell (sh) if the program is started with '&'.
9441   Unfortunately, this is NOT done by csh or ksh so watch out!
9442   Note, it's safe to set SIGINT to SIG_IGN here, because further down
9443   we always set it to something else.
9444   Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
9445   SIG_IGN ourselves.
9446 */
9447     if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
9448
9449         SIGTYP (*osigint)();
9450
9451         osigint = signal(SIGINT,SIG_IGN);       /* What is SIGINT set to? */
9452         sigint_ign = 1;
9453         x = (osigint == SIG_IGN) ? 1 : 0;       /* SIG_IGN? */
9454         /* debug(F101,"conbgt osigint","",osigint); */
9455         /* debug(F101,"conbgt signal test","",x); */
9456     }
9457
9458 /* Also check to see if we're running with redirected stdio. */
9459 /* This is not really background operation, but we want to act as though */
9460 /* it were. */
9461
9462 #ifdef IKSD
9463     if (inserver) {                     /* Internet Kermit Server */
9464         backgrd = 0;                    /* is not in the background */
9465         return;
9466     }
9467 #endif /* IKSD */
9468
9469     y = (isatty(0) && isatty(1)) ? 1 : 0;
9470     debug(F101,"conbgt isatty test","",y);
9471
9472 #ifdef BSD29
9473 /* The process group and/or signal test doesn't work under these... */
9474     backgrd = !y;
9475 #else
9476 #ifdef sxaE50
9477     backgrd = !y;
9478 #else
9479 #ifdef MINIX
9480     backgrd = !y;
9481 #else
9482 #ifdef MINIX2
9483     backgrd = !y;
9484 #else
9485     if (x > -1)
9486       backgrd = (x || !y) ? 1 : 0;
9487     else backgrd = !y;
9488 #endif /* BSD29 */
9489 #endif /* sxaE50 */
9490 #endif /* MINIX */
9491 #endif /* MINIX2 */
9492     debug(F101,"conbgt backgrd","",backgrd);
9493 }
9494
9495 /*  C O N I N T  --  Console Interrupt setter  */
9496
9497 /*
9498   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
9499   Second arg is pointer to function to handle SIGTSTP (suspend).
9500 */
9501
9502 VOID                                    /* Set terminal interrupt traps. */
9503 #ifdef CK_ANSIC
9504 #ifdef apollo
9505 conint(f,s) SIGTYP (*f)(), (*s)();
9506 #else
9507 conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
9508 #endif /* apollo */
9509 #else
9510 conint(f,s) SIGTYP (*f)(), (*s)();
9511 #endif /* CK_ANSIC */
9512 /* conint */ {
9513
9514     debug(F101,"conint conistate","",conistate);
9515
9516     conbgt(0);                          /* Do background test. */
9517
9518 /* Set the desired handlers for hangup and software termination. */
9519
9520 #ifdef SIGTERM
9521     signal(SIGTERM,f);                  /* Software termination */
9522 #endif /* SIGTERM */
9523
9524 /*
9525   Prior to July 1999 we used to call sighup() here but now it's called in
9526   sysinit() so SIGHUP can be caught during execution of the init file or
9527   a kerbang script.
9528 */
9529
9530 /* Now handle keyboard stop, quit, and interrupt signals. */
9531 /* Check if invoked in background -- if so signals set to be ignored. */
9532 /* However, if running under a job control shell, don't ignore them. */
9533 /* We won't be getting any, as we aren't in the terminal's process group. */
9534
9535     debug(F101,"conint backgrd","",backgrd);
9536     debug(F101,"conint jc","",jc);
9537
9538     if (backgrd && !jc) {               /* In background, ignore signals */
9539         debug(F101,"conint background ignoring signals, jc","",jc);
9540 #ifdef SIGTSTP
9541         signal(SIGTSTP,SIG_IGN);        /* Keyboard stop */
9542 #endif /* SIGTSTP */
9543         signal(SIGQUIT,SIG_IGN);        /* Keyboard quit */
9544         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
9545         sigint_ign = 1;
9546         conistate = CONI_NOI;
9547     } else {                            /* Else in foreground or suspended */
9548         debug(F101,"conint foreground catching signals, jc","",jc);
9549         signal(SIGINT,f);               /* Catch terminal interrupt */
9550         sigint_ign = (f == SIG_IGN) ? 1 : 0;
9551
9552 #ifdef SIGTSTP                          /* Keyboard stop (suspend) */
9553         /* debug(F101,"conint SIGSTSTP","",s); */
9554         if (s == NULL) s = SIG_DFL;
9555 #ifdef NOJC                             /* No job control allowed. */
9556         signal(SIGTSTP,SIG_IGN);
9557 #else                                   /* Job control allowed */
9558         if (jc)                         /* if available. */
9559           signal(SIGTSTP,s);
9560         else
9561           signal(SIGTSTP,SIG_IGN);
9562 #endif /* NOJC */
9563 #endif /* SIGTSTP */
9564
9565 #ifndef OXOS
9566 #ifdef SVORPOSIX
9567 #ifndef FIONREAD                        /* Watch out, we don't know this... */
9568 #ifndef SELECT
9569 #ifndef CK_POLL
9570 #ifndef RDCHK
9571         signal(SIGQUIT,esctrp);         /* Quit signal, Sys III/V. */
9572 #endif /* RDCHK */
9573 #endif /* CK_POLL */
9574 #endif /* SELECT */
9575 #endif /* FIONREAD */
9576         if (conesc) conesc = 0;         /* Clear out pending escapes */
9577 #else
9578 #ifdef V7
9579         signal(SIGQUIT,esctrp);         /* V7 like Sys III/V */
9580         if (conesc) conesc = 0;
9581 #else
9582 #ifdef aegis
9583         signal(SIGQUIT,f);              /* Apollo, catch it like others. */
9584 #else
9585         signal(SIGQUIT,SIG_IGN);        /* Others, ignore like 4D & earlier. */
9586 #endif /* aegis */
9587 #endif /* V7 */
9588 #endif /* SVORPOSIX */
9589 #endif /* OXOS */
9590         conistate = CONI_INT;
9591     }
9592 }
9593
9594
9595 /*  C O N N O I  --  Reset console terminal interrupts */
9596
9597 VOID
9598 connoi() {                              /* Console-no-interrupts */
9599
9600     debug(F101,"connoi conistate","",conistate);
9601 #ifdef SIGTSTP
9602     signal(SIGTSTP,SIG_IGN);            /* Suspend */
9603 #endif /* SIGTSTP */
9604     conint(SIG_IGN,SIG_IGN);            /* Interrupt */
9605     sigint_ign = 1;                     /* Remember we did this ourselves */
9606 #ifdef SIGQUIT
9607     signal(SIGQUIT,SIG_IGN);            /* Quit */
9608 #endif /* SIGQUIT */
9609 #ifdef SIGTERM
9610     signal(SIGTERM,SIG_IGN);            /* Term */
9611 #endif /* SIGTERM */
9612     conistate = CONI_NOI;
9613 }
9614
9615 /*  I N I T R A W Q  --  Set up to read /dev/kmem for character count.  */
9616
9617 #ifdef  V7
9618 /*
9619  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
9620  eliminates blocking on a read, because we can read /dev/kmem to get the
9621  number of characters available for raw input.  If your system can't
9622  or you won't let the world read /dev/kmem then you must figure out a
9623  different way to do the counting of characters available, or else replace
9624  this by a dummy function that always returns 0.
9625 */
9626 /*
9627  * Call this routine as: initrawq(tty)
9628  * where tty is the file descriptor of a terminal.  It will return
9629  * (as a char *) the kernel-mode memory address of the rawq character
9630  * count, which may then be read.  It has the side-effect of flushing
9631  * input on the terminal.
9632  */
9633 /*
9634  * John Mackin, Physiology Dept., University of Sydney (Australia)
9635  * ...!decvax!mulga!physiol.su.oz!john
9636  *
9637  * Permission is hereby granted to do anything with this code, as
9638  * long as this comment is retained unmodified and no commercial
9639  * advantage is gained.
9640  */
9641 #ifndef MINIX
9642 #ifndef MINIX2
9643 #ifndef COHERENT
9644 #include <a.out.h>
9645 #include <sys/proc.h>
9646 #endif /* COHERENT */
9647 #endif /* MINIX2 */
9648 #endif /* MINIX */
9649
9650 #ifdef COHERENT
9651 #include <l.out.h>
9652 #include <sys/proc.h>
9653 #endif /* COHERENT */
9654
9655 char *
9656 initrawq(tty) int tty; {
9657 #ifdef MINIX
9658     return(0);
9659 #else
9660 #ifdef MINIX2
9661     return(0);
9662 #else
9663 #ifdef UTS24
9664     return(0);
9665 #else
9666 #ifdef BSD29
9667     return(0);
9668 #else
9669     long lseek();
9670     static struct nlist nl[] = {
9671         {PROCNAME},
9672         {NPROCNAME},
9673         {""}
9674     };
9675     static struct proc *pp;
9676     char *qaddr, *p, c;
9677     int m;
9678     PID_T pid, me;
9679     NPTYPE xproc;                       /* Its type is defined in makefile. */
9680     int catch();
9681
9682     me = getpid();
9683     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
9684     nlist(BOOTNAME, nl);
9685     if (nl[0].n_type == 0) err("proc array");
9686
9687     if (nl[1].n_type == 0) err("nproc");
9688
9689     lseek(m, (long)(nl[1].n_value), 0);
9690     read (m, &xproc, sizeof(xproc));
9691     saval = signal(SIGALRM, catch);
9692     if ((pid = fork()) == 0) {
9693         while(1)
9694             read(tty, &c, 1);
9695     }
9696     alarm(2);
9697
9698     if(setjmp(jjbuf) == 0) {
9699         while(1)
9700           read(tty, &c, 1);
9701     }
9702     signal(SIGALRM, SIG_DFL);
9703
9704 #ifdef DIRECT
9705     pp = (struct proc *) nl[0].n_value;
9706 #else
9707     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
9708     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
9709 #endif
9710     lseek(m, (long)(nl[1].n_value), 0);
9711     read(m, &xproc, sizeof(xproc));
9712
9713     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
9714     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
9715     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
9716         err("read proc table");
9717     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
9718         if (pp -> p_pid == (short) pid) goto iout;
9719     }
9720     err("no such proc");
9721
9722 iout:
9723     close(m);
9724     qaddr = (char *)(pp -> p_wchan);
9725     free (p);
9726     kill(pid, SIGKILL);
9727     wait((WAIT_T *)0);
9728     return (qaddr);
9729 #endif
9730 #endif
9731 #endif
9732 #endif
9733 }
9734
9735 /*  More V7-support functions...  */
9736
9737 static VOID
9738 err(s) char *s; {
9739     char buf[200];
9740
9741     ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
9742     perror(buf);
9743     doexit(1,-1);
9744 }
9745
9746 static VOID
9747 catch(foo) int foo; {
9748     longjmp(jjbuf, -1);
9749 }
9750
9751
9752 /*  G E N B R K  --  Simulate a modem break.  */
9753
9754 #ifdef MINIX
9755 #define BSPEED B110
9756 #else
9757 #ifdef MINIX2
9758 #define BSPEED B110
9759 #else
9760 #define BSPEED B150
9761 #endif /* MINIX2 */
9762 #endif /* MINIX */
9763
9764 #ifndef MINIX2
9765 VOID
9766 genbrk(fn,msec) int fn, msec; {
9767     struct sgttyb ttbuf;
9768     int ret, sospeed, x, y;
9769
9770     ret = ioctl(fn, TIOCGETP, &ttbuf);
9771     sospeed = ttbuf.sg_ospeed;
9772     ttbuf.sg_ospeed = BSPEED;
9773     ret = ioctl(fn, TIOCSETP, &ttbuf);
9774     y = (int)strlen(brnuls);
9775     x = ( BSPEED * 100 ) / msec;
9776     if (x > y) x = y;
9777     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9778     ttbuf.sg_ospeed = sospeed;
9779     ret = ioctl(fn, TIOCSETP, &ttbuf);
9780     ret = write(fn, "@", 1);
9781     return;
9782 }
9783 #endif /* MINIX2 */
9784
9785 #ifdef MINIX2
9786 int
9787 genbrk(fn,msec) int fn, msec; {
9788     struct termios ttbuf;
9789     int ret, x, y;
9790     speed_t sospeed;
9791
9792     ret = tcgetattr(fn, &ttbuf);
9793     sospeed = ttbuf.c_ospeed;
9794     ttbuf.c_ospeed = BSPEED;
9795     ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
9796     y = (int)strlen(brnuls);
9797     x = ( BSPEED * 100 ) / msec;
9798     if (x > y) x = y;
9799     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9800     ttbuf.c_ospeed = sospeed;
9801     ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
9802     ret = write(fn, "@", 1);
9803     return ret;
9804 }
9805 #endif /* MINIX2 */
9806 #endif /* V7 */
9807
9808 /*
9809   I N C H K  --  Check if chars waiting to be read on given file descriptor.
9810
9811   This routine is a merger of ttchk() and conchk().
9812   Call with:
9813     channel == 0 to check console.
9814     channel == 1 to check communications connection.
9815   and:
9816     fd = file descriptor.
9817   Returns:
9818    >= 0: number of characters waiting, 0 or greater,
9819      -1: on any kind of error,
9820      -2: if there is (definitely) no connection.
9821   Note: In UNIX we don't have to call nettchk() because a socket
9822   file descriptor works just like in serial i/o, ioctls and all.
9823   (But this will change if we add non-file-descriptor channels,
9824   such as IBM X.25 for AIX...)
9825 */
9826 static int
9827 in_chk(channel, fd) int channel, fd; {
9828     int x, n = 0;                       /* Workers, n = return value */
9829     extern int clsondisc;               /* Close on disconnect */
9830 /*
9831   The first section checks to make sure we have a connection,
9832   but only if we're in local mode.
9833 */
9834 #ifdef DEBUG
9835     if (deblog) {
9836         debug(F111,"in_chk entry",ckitoa(fd),channel);
9837         debug(F101,"in_chk ttyfd","",ttyfd);
9838         debug(F101,"in_chk ttpty","",ttpty);
9839     }
9840 #endif /* DEBUG */
9841 /*
9842   But don't say connection is gone if we have any buffered-stuff.
9843 */
9844 #ifdef TTLEBUF
9845     debug(F101,"in_chk ttpush","",ttpush);
9846     if (channel == 1) {
9847         if (ttpush >= 0)
9848           n++;
9849         n += le_inbuf();
9850         if (n > 0)
9851           return(n);
9852     }
9853 #endif /* TTLEBUF */
9854
9855 #ifdef NETPTY
9856 #ifdef HAVE_PTYTRAP
9857     /* Special handling for HP-UX pty i/o */
9858     if (ttpty && pty_trap_pending(ttyfd) > 0) {
9859         if (pty_trap_handler(ttyfd) > 0) {
9860             ttclos(0);
9861             return(-2);
9862         }
9863     }
9864 #endif /* HAVE_PTYTRAP */
9865 #endif /* NETPTY */
9866
9867     if (channel) {                      /* Checking communications channel */
9868         if (ttyfd < 0) {                /* No connection */
9869           return(-2);                   /* That's what this means */
9870         } else if (xlocal &&            /* In local mode */
9871                    (!netconn            /* Serial connection or */
9872 #ifdef TN_COMPORT
9873                     || istncomport()    /* Telnet Com Port */
9874 #endif /* TN_COMPORT */
9875                    ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
9876 #ifdef COMMENT
9877 #ifdef MYREAD
9878 /*
9879   Seems like this would be a good idea but it prevents C-Kermit from
9880   popping back to the prompt automatically when carrier drops.  However,
9881   commenting this out prevents us from seeing the NO CARRIER message.
9882   Needs more work...
9883 */
9884                    && my_count < 1      /* Nothing in our internal buffer */
9885 #endif /* MYREAD */
9886 #endif /* COMMENT */
9887                    ) {
9888             int x;
9889             x = ttgmdm();               /* So get modem signals */
9890             debug(F101,"in_chk close-on-disconnect","",clsondisc);
9891             if (x > -1) {               /* Check for carrier */
9892                 if (!(x & BM_DCD)) {    /* No carrier */
9893                     debug(F101,"in_chk carrier lost","",x);
9894                     if (clsondisc)      /* If "close-on-disconnect" */
9895                       ttclos(0);        /* close device & release lock. */
9896                     return(-2);         /* This means "disconnected" */
9897                 }
9898             /* In case I/O to device after CD dropped always fails */
9899             /* as in Debian Linux 2.1 and Unixware 2.1... */
9900             } else {
9901                 debug(F101,"in_chk ttgmdm I/O error","",errno);
9902                 debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
9903                 if (gotsigs) {          /* If we got signals before... */
9904                     if (errno == 5 || errno == 6) { /* I/O error etc */
9905                         if (clsondisc)  /* like when modem hangs up */
9906                           ttclos(0);
9907                         return(-2);
9908                     }
9909                 }
9910                 /* If we never got modem signals successfully on this */
9911                 /* connection before, we can't conclude that THIS failure */
9912                 /* means the connection was lost. */
9913                 return(0);
9914             }
9915         }
9916     }
9917
9918 /* We seem to have a connection so now see if any bytes are waiting on it */
9919
9920 #ifdef CK_SSL
9921     if (ssl_active_flag || tls_active_flag) {
9922         n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
9923         debug(F101,"in_chk SSL_pending","",n);
9924         if (n < 0) {
9925             ttclos(0);
9926             return(-1);
9927         } else if (n > 0) {
9928             return(n);
9929         }
9930     }
9931 #endif /* CK_SSL */
9932 #ifdef RLOGCODE
9933 #ifdef CK_KERBEROS
9934     /* It is not safe to read any data when using encrypted Klogin */
9935     if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
9936 #ifdef KRB4
9937         if (ttnproto == NP_EK4LOGIN) {
9938             n += krb4_des_avail(ttyfd);
9939             debug(F101,"in_chk krb4_des_avail","",n);
9940         }
9941 #endif /* KRB4 */
9942 #ifdef KRB5
9943         if (ttnproto == NP_EK5LOGIN) {
9944             n += krb5_des_avail(ttyfd);
9945             debug(F101,"in_chk krb5_des_avail","",n);
9946         }
9947 #ifdef KRB5_U2U
9948         if (ttnproto == NP_K5U2U) {
9949             n += krb5_u2u_avail(ttyfd);
9950             debug(F101,"in_chk krb5_des_avail","",n);
9951         }
9952 #endif /* KRB5_U2U */
9953 #endif /* KRB5 */
9954         if (n < 0)                      /* Is this right? */
9955           return(-1);
9956         else
9957           return(n);
9958     }
9959 #endif /* CK_KERBEROS */
9960 #endif /* RLOGCODE */
9961
9962     errno = 0;                          /* Reset this so we log good info */
9963 #ifdef FIONREAD
9964     x = ioctl(fd, FIONREAD, &n);        /* BSD and lots of others */
9965 #ifdef DEBUG                            /* (the more the better) */
9966     if (deblog) {
9967         debug(F101,"in_chk FIONREAD return code","",x);
9968         debug(F101,"in_chk FIONREAD count","",n);
9969         debug(F101,"in_chk FIONREAD errno","",errno);
9970     }
9971 #endif /* DEBUG */
9972 #else /* FIONREAD not defined */
9973 /*
9974   Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
9975   with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
9976   portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
9977   that I looked at, but it is needed to prevent the call from blocking), and
9978   the msghdr struct differs from place to place, so we would need another
9979   avalanche of ifdefs.  Still, when FIONREAD is not available, this is the
9980   only other known method of asking the OS for the *number* of characters
9981   available for reading.
9982 */
9983 #ifdef V7                               /* UNIX V7: look in kernel memory */
9984 #ifdef MINIX
9985     n = 0;                              /* But not in MINIX */
9986 #else
9987 #ifdef MINIX2
9988     n = 0;
9989 #else
9990     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
9991     x = read(kmem[TTY], &n, sizeof(int));
9992     if (x != sizeof(int))
9993       n = 0;
9994 #endif /* MINIX2 */
9995 #endif /* MINIX */
9996 #else /* Not V7 */
9997 #ifdef PROVX1
9998     x = ioctl(fd, TIOCQCNT, &ttbuf);    /* DEC Pro/3xx Venix V.1 */
9999     n = ttbuf.sg_ispeed & 0377;         /* Circa 1984 */
10000     if (x < 0) n = 0;
10001 #else
10002 #ifdef MYREAD
10003 /*
10004   Here we skip all the undependable and expensive calls below if we
10005   already have something in our internal buffer.  This tends to work quite
10006   nicely, so the only really bad case remaining is the one in which neither
10007   FIONREAD or MYREAD are defined, which is increasingly rare these days.
10008 */
10009     if (channel != 0 && my_count > 0) {
10010         debug(F101,"in_chk buf my_count","",my_count);
10011         n = my_count;                   /* n was 0 before we got here */
10012         return(n);
10013     }
10014 #endif /* MYREAD */
10015 /*
10016   rdchk(), select(), and poll() tell us *if* data is available to be read, but
10017   not how much, so these should be used only as a final resort.  Especially
10018   since these calls tend to add a lot overhead.
10019 */
10020 #ifdef RDCHK                            /* This mostly SCO-specific */
10021     n = rdchk(fd);
10022     debug(F101,"in_chk rdchk","",n);
10023 #else /* No RDCHK */
10024 #ifdef SELECT
10025 #ifdef Plan9
10026     /* Only allows select on the console ... don't ask */
10027     if (channel == 0)
10028 #endif /* Plan9 */
10029       {
10030         fd_set rfds;                    /* Read file descriptors */
10031 #ifdef BELLV10
10032         FD_ZERO(rfds);                  /* Initialize them */
10033         FD_SET(fd,rfds);                /* We want to look at this fd */
10034 #else
10035         FD_ZERO(&rfds);                 /* Initialize them */
10036         FD_SET(fd,&rfds);               /* We want to look at this fd */
10037         tv.tv_sec = tv.tv_usec = 0L;    /* A 0-valued timeval structure */
10038 #endif /* BELLV10 */
10039 #ifdef Plan9
10040         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10041         debug(F101,"in_chk Plan 9 select","",n);
10042 #else
10043 #ifdef BELLV10
10044         n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
10045         debug(F101,"in_chk BELLV10 select","",n);
10046 #else
10047 #ifdef BSD44
10048         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10049         debug(F101,"in_chk BSD44 select","",n);
10050 #else
10051 #ifdef BSD43
10052         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10053         debug(F101,"in_chk BSD43 select","",n);
10054 #else
10055 #ifdef SOLARIS
10056         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10057         debug(F101,"in_chk SOLARIS select","",n);
10058 #else
10059 #ifdef QNX6
10060         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10061         debug(F101,"in_chk QNX6 select","",n);
10062 #else
10063 #ifdef QNX
10064         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10065         debug(F101,"in_chk QNX select","",n);
10066 #else
10067 #ifdef COHERENT
10068         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10069         debug(F101,"in_chk COHERENT select","",n);
10070 #else
10071 #ifdef SVR4
10072         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10073         debug(F101,"in_chk SVR4 select","",n);
10074 #else
10075 #ifdef __linux__
10076         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10077         debug(F101,"in_chk LINUX select","",n);
10078 #ifdef OSF
10079         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10080         debug(F101,"in_chk OSF select","",n);
10081 #else
10082         n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
10083         debug(F101,"in_chk catchall select","",n);
10084 #endif /* OSF */
10085 #endif /* __linux__ */
10086 #endif /* SVR4 */
10087 #endif /* COHERENT */
10088 #endif /* QNX */
10089 #endif /* QNX6 */
10090 #endif /* SOLARIS */
10091 #endif /* BSD43 */
10092 #endif /* BSD44 */
10093 #endif /* BELLV10 */
10094 #endif /* Plan9 */
10095     }
10096 #else  /* Not SELECT */
10097 #ifdef CK_POLL
10098     {
10099       struct pollfd pfd;
10100
10101       pfd.fd = fd;
10102       pfd.events = POLLIN;
10103       pfd.revents = 0;
10104       n = poll(&pfd, 1, 0);
10105       debug(F101,"in_chk poll","",n);
10106       if ((n > 0) && (pfd.revents & POLLIN))
10107         n = 1;
10108     }
10109 #endif /* CK_POLL */
10110 #endif /* SELECT */
10111 #endif /* RDCHK */
10112 #endif /* PROVX1 */
10113 #endif /* V7 */
10114 #endif /* FIONREAD */
10115
10116 /* From here down, treat console and communication device differently... */
10117
10118     if (channel == 0) {                 /* Console */
10119
10120 #ifdef SVORPOSIX
10121 #ifndef FIONREAD
10122 #ifndef SELECT
10123 #ifndef CK_POLL
10124 #ifndef RDCHK
10125 /*
10126   This is the hideous hack used in System V and POSIX systems that don't
10127   support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
10128   CONNECT-mode escape character is attached to SIGQUIT.  Used, obviously,
10129   only on the console.
10130 */
10131         if (conesc) {                   /* Escape character typed == SIGQUIT */
10132             debug(F100,"in_chk conesc","",conesc);
10133             conesc = 0;
10134             signal(SIGQUIT,esctrp);     /* Restore signal */
10135             n += 1;
10136         }
10137 #endif /* RDCHK */
10138 #endif /* CK_POLL */
10139 #endif /* SELECT */
10140 #endif /* FIONREAD */
10141 #endif /* SVORPOSIX */
10142
10143         return(n);                      /* Done with console */
10144     }
10145
10146     if (channel != 0) {                 /* Communications connection */
10147
10148 #ifdef MYREAD
10149 #ifndef FIONREAD
10150 /*
10151   select() or rdchk(), etc, has told us that something is waiting, but we
10152   don't know how much.  So we do a read to get it and then we know.  Note:
10153   This read is NOT nonblocking if nothing is there (because of VMIN=1), but
10154   it should be safe in this case since the OS tells us at least one byte is
10155   waiting to be read, and MYREAD reads return as much as is there without
10156   waiting for any more.  Controlled tests on Solaris and Unixware (with
10157   FIONREAD deliberately undefined) show this to be true.
10158 */
10159         debug(F101,"in_chk read my_count","",my_count);
10160         debug(F101,"in_chk read n","",n);
10161         if (n > 0 && my_count == 0) {
10162             /* This also catches disconnects etc */
10163             /* Do what mygetbuf does except don't grab a character */
10164             my_count = myfillbuf();
10165             my_item = -1;               /* ^^^ */
10166             debug(F101,"in_chk myfillbuf my_count","",my_count);
10167             if (my_count < 0)
10168               return(-1);
10169             else
10170               n = 0;                    /* NB: n is replaced by my_count */
10171         }
10172 #endif /* FIONREAD */
10173 /*
10174   Here we add whatever we think is unread to what is still in our
10175   our internal buffer.  Thus the importance of setting n to 0 just above.
10176 */
10177         debug(F101,"in_chk my_count","",my_count);
10178         debug(F101,"in_chk n","",n);
10179         if (my_count > 0)
10180           n += my_count;
10181 #endif /* MYREAD */
10182     }
10183     debug(F101,"in_chk result","",n);
10184
10185     /* Errors here don't prove the connection has dropped so just say 0 */
10186
10187     return(n < 0 ? 0 : n);
10188 }
10189
10190
10191 /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
10192
10193 int
10194 ttchk() {
10195     int fd;
10196 #ifdef NETCMD
10197     if (ttpipe)
10198       fd = fdin;
10199     else
10200 #endif /* NETCMD */
10201       fd = ttyfd;
10202     return(in_chk(1,fd));
10203 }
10204
10205 /*  T T X I N  --  Get n characters from tty input buffer  */
10206
10207 /*  Returns number of characters actually gotten, or -1 on failure  */
10208
10209 /*  Intended for use only when it is known that n characters are actually */
10210 /*  Available in the input buffer.  */
10211
10212 int
10213 ttxin(n,buf) int n; CHAR *buf; {
10214     register int x = 0, c = -2;
10215 #ifdef TTLEBUF
10216     register int i = 0;
10217 #endif /* TTLEBUF */
10218     int fd;
10219
10220     if (n < 1)                          /* Nothing to do */
10221       return(0);
10222
10223 #ifdef TTLEBUF
10224     if (ttpush >= 0) {
10225         buf[0] = ttpush;                /* Put pushed char in buffer*/
10226         ttpush = -1;                    /* Clear the push buffer */
10227         if (ttchk() > 0)
10228           return(ttxin(n-1, &buf[1]) + 1);
10229         else
10230           return(1);
10231     }
10232     if (le_data) {
10233         while (le_inbuf() > 0) {
10234             if (le_getchar(&buf[i])) {
10235                 i++;
10236                 n--;
10237             }
10238         }
10239         if (ttchk() > 0)
10240           return(ttxin(n,&buf[i])+i);
10241         else
10242           return(i);
10243     }
10244 #endif /* TTLEBUF */
10245
10246 #ifdef NETCMD
10247     if (ttpipe)
10248       fd = fdin;
10249     else
10250 #endif /* NETCMD */
10251       fd = ttyfd;
10252
10253 #ifdef SUNX25
10254     if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
10255       return(x25xin(n,buf));
10256 #endif /* SUNX25 */
10257
10258 #ifdef IBMX25
10259     /* riehm: possibly not needed. Test worked with normal reads and writes */
10260     if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
10261         x = x25xin(n,buf);
10262         if (x > 0) buf[x] = '\0';
10263         return(x);
10264     }
10265 #endif /* IBMX25 */
10266
10267 #ifdef MYREAD
10268     debug(F101,"ttxin MYREAD","",n);
10269     while (x < n) {
10270         c = myread();
10271         if (c < 0) {
10272             debug(F101,"ttxin myread returns","",c);
10273             if (c == -3) x = -1;
10274             break;
10275         }
10276         buf[x++] = c & ttpmsk;
10277 #ifdef RLOGCODE
10278 #ifdef CK_KERBEROS
10279         /* It is impossible to know how many characters are waiting */
10280         /* to be read when you are using Encrypted Rlogin or SSL    */
10281         /* as the transport since the number of real data bytes     */
10282         /* can be greater or less than the number of bytes on the   */
10283         /* wire which is what ttchk() returns.                      */
10284         if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
10285           if (ttchk() <= 0)
10286             break;
10287 #endif /* CK_KERBEROS */
10288 #endif /* RLOGCODE */
10289 #ifdef CK_SSL
10290         if (ssl_active_flag || tls_active_flag)
10291           if (ttchk() <= 0)
10292             break;
10293 #endif /* CK_SSL */
10294     }
10295 #else
10296     debug(F101,"ttxin READ","",n);
10297     x = read(fd,buf,n);
10298     for (c = 0; c < n; c++)             /* Strip any parity */
10299       buf[c] &= ttpmsk;
10300 #endif /* MYREAD */
10301
10302     debug(F101,"ttxin x","",x);         /* Done */
10303     if (x > 0) buf[x] = '\0';
10304     if (x < 0) x = -1;
10305     return(x);
10306 }
10307
10308 /*  T T O L  --  Write string s, length n, to communication device.  */
10309 /*
10310   Returns:
10311    >= 0 on success, number of characters actually written.
10312    -1 on failure.
10313 */
10314 #ifdef CK_ENCRYPTION
10315 CHAR * xpacket = NULL;
10316 int nxpacket = 0;
10317 #endif /* CK_ENCRYPTION */
10318
10319 #define TTOLMAXT 5
10320 int
10321 ttol(s,n) int n; CHAR *s; {
10322     int x, len, tries, fd;
10323 #ifdef CKXXCHAR
10324     extern int dblflag;                 /* For SET SEND DOUBLE-CHARACTER */
10325     extern short dblt[];
10326     CHAR *p = NULL, *p2, *s2, c;
10327     int n2 = 0;
10328 #endif /* CKXXCHAR */
10329
10330     if (ttyfd < 0)                      /* Not open? */
10331       return(-3);
10332 #ifdef DEBUG
10333     if (deblog) {
10334         /* debug(F101,"ttol ttyfd","",ttyfd); */
10335         ckhexdump("ttol s",s,n);
10336     }
10337 #endif /* DEBUG */
10338
10339 #ifdef NETCMD
10340     if (ttpipe)
10341       fd = fdout;
10342     else
10343 #endif /* NETCMD */
10344       fd = ttyfd;
10345
10346 #ifdef CKXXCHAR
10347 /*  Double any characters that must be doubled.  */
10348     debug(F101,"ttol dblflag","",dblflag);
10349     if (dblflag) {
10350         p = (CHAR *) malloc(n + n + 1);
10351         if (p) {
10352             s2 = s;
10353             p2 = p;
10354             n2 = 0;
10355             while (*s2) {
10356                 c = *s2++;
10357                 *p2++ = c;
10358                 n2++;
10359                 if (dblt[(unsigned) c] & 2) {
10360                     *p2++ = c;
10361                     n2++;
10362                 }
10363             }
10364             s = p;
10365             n = n2;
10366             s[n] = '\0';
10367         }
10368 #ifdef DEBUG
10369         ckhexdump("ttol doubled s",s,n);
10370 #endif /* DEBUG */
10371     }
10372 #endif /* CKXXCHAR */
10373
10374     tries = TTOLMAXT;                   /* Allow up to this many tries */
10375     len = n;                            /* Remember original length */
10376
10377 #ifdef CK_ENCRYPTION
10378 /*
10379   This is to avoid encrypting a packet that is already encrypted, e.g.
10380   when we resend a packet directly out of the packet buffer, and also to
10381   avoid encrypting a constant (literal) string, which can cause a memory
10382   fault.
10383 */
10384     if (TELOPT_ME(TELOPT_ENCRYPTION)) {
10385         int x;
10386         if (nxpacket < n) {
10387             if (xpacket) {
10388                 free(xpacket);
10389                 xpacket = NULL;
10390                 nxpacket = 0;
10391             }
10392             x = n > 10240 ? n : 10240;
10393             xpacket = (CHAR *)malloc(x);
10394             if (!xpacket) {
10395                 fprintf(stderr,"ttol malloc failure\n");
10396                 return(-1);
10397             } else
10398               nxpacket = x;
10399         }
10400         memcpy((char *)xpacket,(char *)s,n);
10401         s = xpacket;
10402         ck_tn_encrypt((char *)s,n);
10403     }
10404 #endif /* CK_ENCRYPTION */
10405
10406     while (n > 0 &&
10407            (tries-- > 0
10408 #ifdef CK_ENCRYPTION
10409             /* keep trying if we are encrypting */
10410             || TELOPT_ME(TELOPT_ENCRYPTION)
10411 #endif /* CK_ENCRYPTION */
10412             )) {                        /* Be persistent */
10413         debug(F101,"ttol try","",TTOLMAXT - tries);
10414 #ifdef BEOSORBEBOX
10415         if (netconn && !ttpipe && !ttpty)
10416           x = nettol((char *)s,n);      /* Write string to device */
10417         else
10418 #endif /* BEOSORBEBOX */
10419 #ifdef IBMX25
10420           if (ttnet == NET_IX25)
10421             /*
10422              * this is a more controlled way of writing to X25
10423              * STREAMS, however write should also work!
10424              */
10425             x = x25write(ttyfd, s, n);
10426           else
10427 #endif /* IBMX25 */
10428 #ifdef CK_SSL
10429             if (ssl_active_flag || tls_active_flag) {
10430                 int error;
10431                 /* Write using SSL */
10432                 ssl_retry:
10433                 if (ssl_active_flag)
10434                   x = SSL_write(ssl_con, s, n);
10435                 else
10436                   x = SSL_write(tls_con, s, n);
10437                 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
10438                 case SSL_ERROR_NONE:
10439                     if (x == n)
10440                       return(len);
10441                     s += x;
10442                     n -= x;
10443                     goto ssl_retry;
10444                   case SSL_ERROR_WANT_WRITE:
10445                   case SSL_ERROR_WANT_READ:
10446                     x = 0;
10447                     break;
10448                   case SSL_ERROR_SYSCALL:
10449                     if (x != 0)
10450                       return(-1);
10451                   case SSL_ERROR_WANT_X509_LOOKUP:
10452                   case SSL_ERROR_SSL:
10453                   case SSL_ERROR_ZERO_RETURN:
10454                   default:
10455                     ttclos(0);
10456                     return(-3);
10457                 }
10458             } else
10459 #endif /* CK_SSL */
10460 #ifdef CK_KERBEROS
10461 #ifdef KRB4
10462 #ifdef RLOGCODE
10463             if (ttnproto == NP_EK4LOGIN) {
10464                 return(krb4_des_write(ttyfd,s,n));
10465             } else
10466 #endif /* RLOGCODE */
10467 #endif /* KRB4 */
10468 #ifdef KRB5
10469 #ifdef RLOGCODE
10470             if (ttnproto == NP_EK5LOGIN) {
10471                 return(krb5_des_write(ttyfd,(char *)s,n,0));
10472             } else
10473 #endif /* RLOGCODE */
10474 #ifdef KRB5_U2U
10475             if (ttnproto == NP_K5U2U) {
10476                 return(krb5_u2u_write(ttyfd,(char *)s,n));
10477             } else
10478 #endif /* KRB5_U2U */
10479 #endif /* KRB5 */
10480 #endif /* CK_KERBEROS */
10481               x = write(fd,s,n);        /* Write string to device */
10482
10483         if (x == n) {                   /* Worked? */
10484             debug(F101,"ttol ok","",x); /* OK */
10485 #ifdef CKXXCHAR
10486             if (p) free(p);
10487 #endif /* CKXXCHAR */
10488             return(len);                /* Done */
10489         } else if (x < 0) {             /* No, got error? */
10490             debug(F101,"ttol write error","",errno);
10491 #ifdef EWOULDBLOCK
10492             if (errno == EWOULDBLOCK) {
10493                 msleep(10);
10494                 continue;
10495             } else
10496 #endif /* EWOULDBLOCK */
10497 #ifdef TCPSOCKET
10498             if (netconn && ttnet == NET_TCPB) {
10499                 debug(F101,"ttol TCP error","",errno);
10500                 ttclos(0);              /* Close the connection. */
10501                 x = -3;
10502             }
10503 #endif /* TCPSOCKET */
10504 #ifdef CKXXCHAR
10505             if (p) free(p);
10506 #endif /* CKXXCHAR */
10507             return(x);
10508         } else {                        /* No error, so partial success */
10509             debug(F101,"ttol partial","",x); /* This never happens */
10510             s += x;                     /* Point to part not written yet */
10511             n -= x;                     /* Adjust length */
10512             if (x > 0) msleep(10);      /* Wait 10 msec */
10513         }                               /* Go back and try again */
10514     }
10515 #ifdef CKXXCHAR
10516     if (p) free(p);
10517 #endif /* CKXXCHAR */
10518     return(n < 1 ? len : -1);           /* Return the results */
10519 }
10520
10521 /*  T T O C  --  Output a character to the communication line  */
10522
10523 /*
10524  This function should only be used for interactive, character-mode operations,
10525  like terminal connection, script execution, dialer i/o, where the overhead
10526  of the signals and alarms does not create a bottleneck.
10527 */
10528 int
10529 #ifdef CK_ANSIC
10530 ttoc(char c)
10531 #else
10532 ttoc(c) char c;
10533 #endif /* CK_ANSIC */
10534 /* ttoc */ {
10535 #define TTOC_TMO 15                     /* Timeout in case we get stuck */
10536     int xx, fd;
10537
10538     if (ttyfd < 0)                      /* Check for not open. */
10539       return(-1);
10540
10541 #ifdef NETCMD
10542     if (ttpipe)
10543       fd = fdout;
10544     else
10545 #endif /* NETCMD */
10546       fd = ttyfd;
10547
10548     c &= 0xff;
10549     /* debug(F101,"ttoc","",(CHAR) c); */
10550     saval = signal(SIGALRM,timerh);     /* Enable timer interrupt */
10551     xx = alarm(TTOC_TMO);               /* for this many seconds. */
10552     if (xx < 0) xx = 0;                 /* Save old alarm value. */
10553     /* debug(F101,"ttoc alarm","",xx); */
10554     if (
10555 #ifdef CK_POSIX_SIG
10556         sigsetjmp(sjbuf,1)
10557 #else
10558         setjmp(sjbuf)
10559 #endif /* CK_POSIX_SIG */
10560         ) {             /* Timer went off? */
10561         ttimoff();                      /* Yes, cancel this alarm. */
10562         if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
10563         /* debug(F100,"ttoc timeout","",0); */
10564 #ifdef NETCONN
10565         if (!netconn) {
10566 #endif /* NETCONN */
10567             debug(F101,"ttoc timeout","",c);
10568             if (ttflow == FLO_XONX) {
10569                 debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
10570 #ifndef Plan9
10571 #ifdef POSIX
10572                 /* POSIX way to unstick. */
10573                 debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
10574 #else
10575 #ifdef BSD4                             /* Berkeley way to do it. */
10576 #ifdef TIOCSTART
10577 /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);".  Who knows? */
10578                 {
10579                   int x = 0;
10580                   debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
10581                 }
10582 #endif /* TIOCSTART */
10583 #endif /* BSD4 */
10584                                         /* Is there a Sys V way to do this? */
10585 #endif /* POSIX */
10586 #endif /* Plan9 */
10587             }
10588 #ifdef NETCONN
10589         }
10590 #endif /* NETCONN */
10591         return(-1);                     /* Return failure code. */
10592     } else {
10593         int rc;
10594 #ifdef BEOSORBEBOX
10595 #ifdef NETCONN
10596         if (netconn && !ttpipe && !ttpty)
10597           rc = nettoc(c);
10598         else
10599 #endif /*  BEOSORBEBOX */
10600 #endif /* NETCONN */
10601 #ifdef CK_ENCRYPTION
10602           if (TELOPT_ME(TELOPT_ENCRYPTION))
10603             ck_tn_encrypt(&c,1);
10604 #endif /* CK_ENCRYPTION */
10605 #ifdef IBMX25
10606         /* riehm: maybe this isn't necessary after all. Test program
10607          * worked fine with data being sent and retrieved with normal
10608          * read's and writes!
10609          */
10610         if (ttnet == NET_IX25)
10611           rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
10612         else
10613 #endif /* IBMX25 */
10614 #ifdef CK_SSL
10615           if (ssl_active_flag || tls_active_flag) {
10616               int error;
10617               /* Write using SSL */
10618               if (ssl_active_flag)
10619                 rc = SSL_write(ssl_con, &c, 1);
10620               else
10621                 rc = SSL_write(tls_con, &c, 1);
10622               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
10623                 case SSL_ERROR_NONE:
10624                   break;
10625                 case SSL_ERROR_WANT_WRITE:
10626                 case SSL_ERROR_WANT_READ:
10627                   rc = 0;
10628                   break;
10629                 case SSL_ERROR_SYSCALL:
10630                   if (rc != 0)
10631                     return(-1);
10632                 case SSL_ERROR_WANT_X509_LOOKUP:
10633                 case SSL_ERROR_SSL:
10634                 case SSL_ERROR_ZERO_RETURN:
10635                 default:
10636                   ttclos(0);
10637                   return(-1);
10638               }
10639           } else
10640 #endif /* CK_SSL */
10641 #ifdef CK_KERBEROS
10642 #ifdef KRB4
10643 #ifdef RLOGCODE
10644           if (ttnproto == NP_EK4LOGIN) {
10645               rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1);
10646           } else
10647 #endif /* RLOGCODE */
10648 #endif /* KRB4 */
10649 #ifdef KRB5
10650 #ifdef RLOGCODE
10651           if (ttnproto == NP_EK5LOGIN) {
10652               rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
10653           } else
10654 #endif /* RLOGCODE */
10655 #ifdef KRB5_U2U
10656           if (ttnproto == NP_K5U2U) {
10657               rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
10658           } else
10659 #endif /* KRB5_U2U */
10660 #endif /* KRB5 */
10661 #endif /* CK_KERBEROS */
10662             rc = write(fd,&c,1);        /* Try to write the character. */
10663         if (rc < 1) {                   /* Failed */
10664             ttimoff();                  /* Turn off the alarm. */
10665             alarm(xx);                  /* Restore previous alarm. */
10666             debug(F101,"ttoc errno","",errno); /* Log the error, */
10667             return(-1);                 /* and return the error code. */
10668         }
10669     }
10670     ttimoff();                          /* Success, turn off the alarm. */
10671     alarm(xx);                          /* Restore previous alarm. */
10672     return(0);                          /* Return good code. */
10673 }
10674
10675 /*  T T I N L  --  Read a record (up to break character) from comm line.  */
10676 /*
10677   Reads up to "max" characters from the connection, terminating on:
10678     (a) the packet length field if the "turn" argument is zero, or
10679     (b) on the packet-end character (eol) if the "turn" argument is nonzero
10680     (c) a certain number of Ctrl-C's in a row
10681
10682   Returns:
10683     >= 0, the number of characters read upon success;
10684     -1 if "max" exceeded, timeout, or other correctable error;
10685     -2 on user interruption (c);
10686     -3 on fatal error like connection lost.
10687
10688   The name of this routine dates from the early days when Kermit packets
10689   were, indeed, always lines of text.  That was before control-character
10690   unprefixing and length-driven packet framing were introduced, which this
10691   version handle.  NB: this routine is ONLY for reading incoming Kermit
10692   packets, nothing else.  To read other kinds of incoming material, use
10693   ttinc() or ttxin().
10694
10695   The bytes that were input are copied into "dest" with their parity bits
10696   stripped if parity was selected.  Returns the number of bytes read.
10697   Bytes after the eol are available upon the next call to this function.
10698
10699   The idea is to minimize the number of system calls per packet, and also to
10700   minimize timeouts.  This function is the inner loop of the protocol and must
10701   be as efficient as possible.  The current strategy is to use myread(), a
10702   macro to manage buffered (and generally nonblocking) reads.
10703
10704   WARNING: This function calls parchk(), which is defined in another module.
10705   Normally, ckutio.c does not depend on code from any other module, but there
10706   is an exception in this case because all the other ck?tio.c modules also
10707   need to call parchk(), so it's better to have it defined in a common place.
10708 */
10709 #ifdef CTRLC
10710 #undef CTRLC
10711 #endif /* CTRLC */
10712 #define CTRLC '\03'
10713 /*
10714   We have four different declarations here because:
10715   (a) to allow Kermit to be built without the automatic parity sensing feature
10716   (b) one of each type for ANSI C, one for non-ANSI.
10717 */
10718 #ifndef NOXFER
10719
10720 static int pushedback = 0;
10721
10722 int
10723 #ifdef PARSENSE
10724 #ifdef CK_ANSIC
10725 ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
10726 #else
10727 ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
10728 #endif /* CK_ANSIC */
10729 #else /* not PARSENSE */
10730 #ifdef CK_ANSIC
10731 ttinl(CHAR *dest, int max,int timo, CHAR eol)
10732 #else
10733 ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
10734 #endif /* CK_ANSIC */
10735 #endif /* PARSENSE */
10736 /* ttinl */ {
10737
10738 #ifndef MYREAD
10739     CHAR ch, dum;
10740 #endif /* MYREAD */
10741 #ifdef PARSENSE
10742     int pktlen = -1;
10743     int lplen = 0;
10744     int havelen = 0;
10745 #endif /* PARSENSE */
10746     int fd;
10747     int sopmask = 0xff;                 /* Start-Of-Packet mask */
10748 #ifdef CKXXCHAR
10749     extern short dblt[];                /* Ignore-character table */
10750     extern int ignflag;
10751 #endif /* CKXXCHAR */
10752 #ifdef TCPSOCKET
10753     extern CHAR stchr;
10754 #endif /* TCPSOCKET */
10755     int x;
10756 #ifdef STREAMING
10757     extern int streaming;
10758     extern int sndtyp;
10759 #endif /* STREAMING */
10760
10761     if (ttyfd < 0) return(-3);          /* Not open. */
10762 /*
10763   In February 2007 I fixed ttinl() to work better under the truly awful
10764   conditions encountered by the AM-APEX oceanographic floats that gather
10765   hurricane data and phone home using Iridium satellite modems, which under
10766   certain conditions, can send two packets back to back after a long pause.
10767   In this case the second packet would be ignored because the SOH was skipped
10768   due to the ttflui() call.  But the reworked lookahead/pushback logic broke
10769   Kermit transfers on encrypted connections.  This was fixed 12-13 August
10770   2007.  All of this happened after 8.0.212 Dev.27 was released and before
10771   Dev.28, so no harm done other than the delay.
10772 */
10773     debug(F101,"ttinl max","",max);
10774     debug(F101,"ttinl timo","",timo);
10775
10776 #ifdef NETCMD
10777     if (ttpipe)
10778       fd = fdin;
10779     else
10780 #endif /* NETCMD */
10781       fd = ttyfd;
10782
10783 #ifdef COMMENT
10784     if (xlocal && conchk() > 0)         /* Allow for console interruptions */
10785       return(-1);
10786 #endif /* COMMENT */
10787
10788     *dest = '\0';                       /* Clear destination buffer */
10789     if (timo < 0) timo = 0;             /* Safety */
10790     if (timo) {                         /* Don't time out if timo == 0 */
10791         int xx;
10792         saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
10793         xx = alarm(timo);               /* Set it. */
10794         debug(F101,"ttinl alarm","",xx);
10795     }
10796     if (
10797 #ifdef CK_POSIX_SIG
10798         sigsetjmp(sjbuf,1)
10799 #else
10800         setjmp(sjbuf)
10801 #endif /* CK_POSIX_SIG */
10802         ) {                             /* Timer went off? */
10803         debug(F100,"ttinl timout","",0); /* Get here on timeout. */
10804         /* debug(F110," with",(char *) dest,0); */
10805         ttimoff();                      /* Turn off timer */
10806         return(-1);                     /* and return error code. */
10807     } else {
10808         register int i, n = -1;         /* local variables */
10809         int ccn = 0;
10810 #ifdef PARSENSE
10811         register int flag = 0;
10812         debug(F000,"ttinl start","",start);
10813 #endif /* PARSENSE */
10814
10815         ttpmsk = ttprty ? 0177 : 0377;  /* Set parity stripping mask. */
10816         sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
10817
10818 /* Now read into destination, stripping parity and looking for the */
10819 /* the packet terminator, and also for several Ctrl-C's typed in a row. */
10820
10821         i = 0;                          /* Destination index */
10822         debug(F101,"ttinl eol","",eol);
10823
10824         while (i < max-1) {
10825 #ifdef MYREAD
10826             errno = 0;
10827             /* On encrypted connections myread returns encrypted bytes */
10828             n = myread();
10829             debug(F000,"TTINL myread char","",n);
10830             if (n < 0) {        /* Timeout or i/o error? */
10831 #ifdef DEBUG
10832                 if (deblog) {
10833                     debug(F101,"ttinl myread failure, n","",n);
10834                     debug(F101,"ttinl myread errno","",errno);
10835                 }
10836 #endif /* DEBUG */
10837                 /* Don't let EINTR break packets. */
10838                 if (n == -3) {
10839                     if (errno == EINTR && i > 0) {
10840                         debug(F111,"ttinl EINTR myread i","continuing",i);
10841                         continue;
10842                     } else {
10843                         debug(F110,"ttinl non-EINTR -3","closing",0);
10844                         wasclosed = 1;
10845                         ttimoff();      /* Turn off timer */
10846                         ttclos(0);
10847                         return(n);
10848                     }
10849                 } else if (n == -2 && netconn /* && timo == 0 */ ) {
10850                     /* Here we try to catch broken network connections */
10851                     /* even when ioctl() and read() do not catch them */
10852                     debug(F111,"ttinl network myread failure","closing",n);
10853                     wasclosed = 1;
10854                     ttimoff();
10855                     ttclos(0);
10856                     return(-3);
10857                 }
10858 #ifdef STREAMING
10859                 /* Streaming and no data to read */
10860                 else if (n == 0 && streaming && sndtyp == 'D')
10861                   return(0);
10862 #endif /* STREAMING */
10863                 break;                  /* Break out of while loop */
10864             }
10865
10866 #else /* not MYREAD (is this code used anywhere any more?) */
10867 /*
10868   The non-MYREAD code dates from the 1980s and was needed on certain platforms
10869   where there were no nonblocking reads.  -fdc, 2007/02/22.
10870 */
10871             if ((n = read(fd, &n, 1)) < 1)
10872               break;                    /* Error - break out of while loop */
10873
10874 #endif /* MYREAD */
10875
10876             /* Get here with char in n */
10877
10878 #ifdef CK_ENCRYPTION
10879             if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) {
10880                 CHAR ch = n;
10881                 ck_tn_decrypt((char *)&ch,1);
10882                 n = ch;
10883                 debug(F000,"TTINL decryp char","",n);
10884             }
10885             pushedback = 0;
10886 #endif /* CK_ENCRYPTION */
10887
10888 #ifdef TCPSOCKET
10889             if (n == IAC &&             /* Handle Telnet options */
10890                 ((xlocal && netconn && IS_TELNET()) ||
10891                 (!xlocal && sstelnet))) {
10892                 n = tt_tnopt(n);
10893                 if (n < 0)
10894                   return(n);
10895 #ifndef NOPARSEN
10896                 else if (n == 1)
10897                   start = stchr;
10898 #endif /* NOPARSEN */
10899                 if (n != 255)           /* No data - go back for next char */
10900                   continue;
10901             }                           /* Quoted IAC - keep going */
10902 #endif /* TCPSOCKET */
10903
10904 #ifdef CKXXCHAR
10905             if (ignflag)
10906               if (dblt[(unsigned) n] & 1) /* Character to ignore? */
10907                 continue;
10908 #endif /* CKXXCHAR */
10909 /*
10910   Use parity mask, rather than always stripping parity, to check for
10911   cancellation.  Otherwise, runs like \x03\x83\x03 in a packet could cancel
10912   the transfer when parity is NONE.  (Note that \x03\x03\x03 is extremely
10913   unlikely due to run-length encoding.)
10914 */
10915             /* Check cancellation */
10916             if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
10917                 if (++ccn >= xfrnum) {  /* If xfrnum in a row, bail out. */
10918                     if (timo) {         /* Clear timer. */
10919                         ttimoff();
10920                     }
10921                     if (xfrchr < 32)
10922                       printf("^%c...\r\n",(char)(xfrchr+64));
10923                     else
10924                       printf("Canceled...\r\n");
10925                     return(-2);
10926                 }
10927             } else ccn = 0;             /* No cancellation, reset counter, */
10928
10929 #ifdef PARSENSE
10930 /*
10931   Restructured code allows for a new packet to appear somewhere in the
10932   middle of a previous one.  -fdc, 24 Feb 2007.
10933 */
10934             if ((n & sopmask) == start) { /* Start of Packet */
10935                 debug(F101,"ttinl SOP i","",i);
10936                 flag = 1;               /* Flag that we are in a packet */
10937                 havelen = 0;            /* Invalidate previous length */
10938                 pktlen = -1;            /* (if any) in case we were */
10939                 lplen = 0;              /* alread processand a packet */
10940                 i = 0;                  /* and reset the dest buffer pointer */
10941             }
10942             if (flag == 0) {            /* No SOP yet... */
10943                 debug(F000,"ttinl skipping","",n);
10944                 continue;
10945             }
10946             dest[i++] = n & ttpmsk;
10947 /*
10948   If we have not been instructed to wait for a turnaround character, we can go
10949   by the packet length field.  If turn != 0, we must wait for the end of line
10950   (eol) character before returning.  This is an egregious violation of all
10951   principles of layering...  (Less egregious in C-Kermit 9.0, in which we go
10952   by the length field but also look for the eol in case it arrives early,
10953   e.g. if the length field was corrupted upwards.)
10954 */
10955             if (!havelen) {
10956                 if (i == 2) {
10957                     if ((dest[1] & 0x7f) < 32) /* Garbage in length field */
10958                       return(-1);       /* fdc - 13 Apr 2010 */
10959                     pktlen = xunchar(dest[1] & 0x7f);
10960                     if (pktlen > 94)    /* Rubout in length field */
10961                       return(-1);       /* fdc - 13 Apr 2010 */
10962                     if (pktlen > 1) {
10963                         havelen = 1;
10964                         debug(F101,"ttinl pktlen value","",pktlen);
10965                     }
10966                 } else if (i == 5 && pktlen == 0) {
10967                     lplen = xunchar(dest[4] & 0x7f);
10968                 } else if (i == 6 && pktlen == 0) {
10969                     pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
10970                     havelen = 1;
10971                     debug(F101,"ttinl extended length","",pktlen);
10972                 }
10973             }
10974
10975 /*
10976   Suppose we looked at the sequence number here and found it was out of
10977   range?  This would mean either (a) incoming packets had SOP unprefixed
10978   and we are out of sync, or (b) the packet is damaged.  Since (a) is bad
10979   practice, let's ignore it.  So what should we do here if we know the
10980   packet is damaged?
10981
10982    1. Nothing -- keep trying to read the packet till we find what we think
10983       is the end, or we time out, and let the upper layer decide what to
10984       do.  But since either the packet is corrupt or we are out of sync,
10985       our criterion for finding the end does not apply and we are likely
10986       to time out (or swallow a piece of the next packet) if our assumed
10987       length is too long.  (This was the behavior prior to version 7.0.)
10988
10989    2. set flag = 0 and continue?  This would force us to wait for the
10990       next packet to come in, and therefore (in the nonwindowing case),
10991       would force a timeout in the other Kermit.
10992
10993    3. set flag = 0 and continue, but only if the window size is > 1 and
10994       the window is not blocked?  Talk about cheating!
10995
10996    4. Return a failure code and let the upper layer decide what to do.
10997       This should be equivalent to 3, but without the cheating.  So let's
10998       do it that way...  But note that we must ignore the parity bit
10999       in case this is the first packet and we have not yet run parchk().
11000 */
11001             if (i == 3) {               /* Peek at sequence number */
11002                 x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
11003                 if (x < 0 || x > 63) {
11004                     debug(F111,"ttinl bad seq",dest,x);
11005                     if (timo) ttimoff();
11006                     return(-1);         /* return a nonfatal error */
11007                 }
11008             }
11009
11010 #else /* PARSENSE */
11011             dest[i++] = n & ttpmsk;
11012 #endif /* PARSENSE */
11013
11014     /* Check for end of packet */
11015
11016             if (
11017                 ((n & ttpmsk) == eol)   /* Always break on the eol char */
11018 #ifdef PARSENSE
11019                  ||                     /* fdc - see notes of 13 Apr 2010 */
11020 /*
11021   Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
11022   This allows packet terminators and handshake characters to appear
11023   literally inside a packet data field.
11024 */
11025                 (havelen && (i > pktlen+1) &&
11026                  (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
11027
11028 #endif /* PARSENSE */
11029                 ) {
11030 /*
11031   Here we have either read the last byte of the packet based on its length
11032   field, or else we have read the packet terminator (eol) or the half-duplex
11033   line-turnaround char (turn).
11034 */
11035 #ifndef PARSENSE
11036                 debug(F101,"ttinl got eol","",eol); /* (or turn) */
11037                 dest[i] = '\0';         /* Yes, terminate the string, */
11038                 /* debug(F101,"ttinl i","",i); */
11039
11040 #else  /* PARSENSE */
11041
11042 #ifdef DEBUG
11043                 if (deblog) {
11044                     if ((n & ttpmsk) != eol) {
11045                         debug(F101,"ttinl EOP length","",pktlen);
11046                         debug(F000,"ttinl EOP current char","",n);
11047                         debug(F101,"ttinl EOP packet buf index","",i);
11048                     } else debug(F101,"ttinl got eol","",eol);
11049                 }
11050 #endif /* DEBUG */
11051
11052 #ifdef MYREAD
11053 /*
11054   The packet was read based on its length.  This leaves the packet terminator
11055   unread, and so ttchk() will always return at least 1 because of this,
11056   possibly giving a false positive to the "is there another packet waiting?"
11057   test.  But if we know the terminator (or any other interpacket junk) is
11058   there, we can safely get rid of it.
11059
11060   NOTE: This code reworked to (a) execute even if the debug log isn't active;
11061   and (b) actually work.  -fdc, 2007/02/22.  And again 2007/08/12-13 to also
11062   work on encrypted connections.
11063 */      
11064                 debug(F101,"TTINL my_count","",my_count);
11065                 if ((n & ttpmsk) != eol) { /* Not the packet terminator */
11066                     int x;
11067                     while (my_count > 0) {
11068                         x = myread();      /* (was ttinc(0) */
11069                         debug(F000,"TTINL lkread char","",x);
11070 #ifdef CK_ENCRYPTION
11071                         if (TELOPT_U(TELOPT_ENCRYPTION)) {
11072                             CHAR ch = x;
11073                             ck_tn_decrypt((char *)&ch,1);
11074                             x = ch;
11075                             debug(F000,"TTINL lkdecr char","",x); 
11076                         }
11077 #endif  /* CK_ENCRYPTION */
11078                         /*
11079                           Note: while it might seem more elegant to simply
11080                           push back the encrypted byte, that desynchronizes
11081                           the decryption stream; the flag is necessary so we
11082                           don't try to decrypt the same byte twice.
11083                         */
11084                         if ((x & ttpmsk) == start) { /* Start of next packet */
11085                             myunrd(x);  /* Push back the decrypted byte */
11086                             pushedback = 1; /* And set flag */
11087                             debug(F000,"TTINL lkpush char","",x);
11088                             break;
11089                         }
11090                     }
11091                 }
11092 #endif /* MYREAD */
11093
11094                 dest[i] = '\0';         /* Terminate the string, */
11095                 if (needpchk) {         /* Parity checked yet? */
11096                     if (ttprty == 0) {  /* No, check. */
11097                         if ((ttprty = parchk(dest,start,i)) > 0) {
11098                             int j;
11099                             debug(F101,"ttinl senses parity","",ttprty);
11100                             debug(F110,"ttinl packet before",dest,0);
11101                             ttpmsk = 0x7f;
11102                             for (j = 0; j < i; j++)
11103                               dest[j] &= 0x7f;  /* Strip parity from packet */
11104                             debug(F110,"ttinl packet after ",dest,0);
11105                         } else ttprty = 0; /* Restore if parchk error */
11106                     }
11107                     sopmask = ttpmsk;
11108                     needpchk = 0;
11109                 }
11110 #endif /* PARSENSE */
11111
11112                 if (timo)               /* Turn off timer if it was on */
11113                   ttimoff();
11114                 ckhexdump("ttinl got",dest,i);
11115
11116 #ifdef STREAMING
11117                 /* ttinl() was called because there was non-packet */
11118                 /* data sitting in the back channel.  Ignore it.   */
11119                 if (streaming && sndtyp == 'D')
11120                   return(-1);
11121 #endif /* STREAMING */
11122                 return(i);
11123             }
11124         } /* End of while() */
11125         ttimoff();
11126         return(n);
11127     }
11128 }
11129 #endif /* NOXFER */
11130
11131 /*  T T I N C --  Read a character from the communication line  */
11132 /*
11133  On success, returns the character that was read, >= 0.
11134  On failure, returns -1 or other negative myread error code,
11135    or -2 if connection is broken or ttyfd < 0.
11136    or -3 if session limit has expired,
11137    or -4 if something or other...
11138  NOTE: The API does not provide for ttinc() returning a special code
11139  upon timeout, but we need it.  So for this we have a global variable,
11140  ttinctimo.
11141 */
11142 static int ttinctimo = 0;               /* Yuk */
11143
11144 int
11145 ttinc(timo) int timo; {
11146
11147     int n = 0, fd;
11148     int is_tn = 0;
11149     CHAR ch = 0;
11150
11151     ttinctimo = 0;
11152
11153     if (ttyfd < 0) return(-2);          /* Not open. */
11154
11155     is_tn = (xlocal && netconn && IS_TELNET()) ||
11156             (!xlocal && sstelnet);
11157
11158 #ifdef TTLEBUF
11159     if (ttpush >= 0) {
11160         debug(F111,"ttinc","ttpush",ttpush);
11161         ch = ttpush;
11162         ttpush = -1;
11163         return(ch);
11164     }
11165     if (le_data) {
11166         if (le_getchar(&ch) > 0) {
11167             debug(F111,"ttinc le_getchar","ch",ch);
11168             return(ch);
11169         }
11170     }
11171 #endif /* TTLEBUF */
11172
11173 #ifdef NETCMD
11174     if (ttpipe)
11175       fd = fdin;
11176     else
11177 #endif /* NETCMD */
11178       fd = ttyfd;
11179
11180     if ((timo <= 0)                     /* Untimed. */
11181 #ifdef MYREAD
11182         || (my_count > 0)               /* Buffered char already waiting. */
11183 #endif /* MYREAD */
11184         ) {
11185 #ifdef MYREAD
11186         /* Comm line failure returns -1 thru myread, so no &= 0377 */
11187         n = myread();                   /* Wait for a character... */
11188         /* debug(F000,"ttinc MYREAD n","",n); */
11189 #ifdef CK_ENCRYPTION
11190         /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
11191         if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11192             ch = n;
11193             ck_tn_decrypt((char *)&ch,1);
11194             n = ch;
11195         }
11196 #endif /* CK_ENCRYPTION */
11197
11198 #ifdef NETPTY
11199         if (ttpty && n < 0) {
11200             debug(F101,"ttinc error on pty","",n);
11201             ttclos(0);
11202             return(n);
11203         }
11204 #endif /* NETPTY */
11205
11206 #ifdef TNCODE
11207         if ((n > -1) && is_tn)
11208           return((unsigned)(n & 0xff));
11209         else
11210 #endif /* TNCODE */
11211           return(n < 0 ? n : (unsigned)(n & ttpmsk));
11212
11213 #else  /* MYREAD */
11214
11215         while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
11216         /* Shouldn't have to loop in ver 5A. */
11217 #ifdef NETCONN
11218           if (netconn) {                /* Special handling for net */
11219               netclos();                /* If read() returns 0 it means */
11220               netconn = 0;              /* the connection has dropped. */
11221               errno = ENOTCONN;
11222               return(-2);
11223           }
11224 #endif /* NETCONN */
11225           ;
11226         /* debug(F101,"ttinc","",ch); */
11227 #ifdef TNCODE
11228         if ((n > 0) && is_tn) {
11229 #ifdef CK_ENCRYPTION
11230             if (TELOPT_U(TELOPT_ENCRYPTION)) {
11231                 ck_tn_decrypt(&ch,1);
11232                 n = ch;
11233             }
11234 #endif /* CK_ENCRYPTION */
11235             return((unsigned)(ch & 0xff));
11236         } else
11237 #endif /* TNCODE */
11238         return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
11239 #endif /* MYREAD */
11240
11241     } else {                            /* Timed read */
11242
11243         int oldalarm;
11244         saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
11245         oldalarm = alarm(timo);         /* Set alarm, save old one. */
11246         if (
11247 #ifdef CK_POSIX_SIG
11248             sigsetjmp(sjbuf,1)
11249 #else
11250             setjmp(sjbuf)
11251 #endif /* CK_POSIX_SIG */
11252             ) {                         /* Timer expired */
11253             ttinctimo = 1;
11254             n = -1;                     /* set flag */
11255         } else {
11256 #ifdef MYREAD
11257             n = myread();               /* If managing own buffer... */
11258             debug(F101,"ttinc myread","",n);
11259             ch = n;
11260 #else
11261             n = read(fd,&ch,1);         /* Otherwise call the system. */
11262             if (n == 0) n = -1;
11263             debug(F101,"ttinc read","",n);
11264 #endif /* MYREAD */
11265
11266 #ifdef CK_ENCRYPTION
11267             if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11268                 ck_tn_decrypt((char *)&ch,1);
11269             }
11270 #endif /* CK_ENCRYPTION */
11271             if (n >= 0)
11272               n = (unsigned) (ch & 0xff);
11273             else
11274               n = (n < 0) ? -4 : -2;    /* Special return codes. */
11275         }
11276         ttimoff();                      /* Turn off the timer */
11277         if (oldalarm > 0) {
11278             if (n == -1)                /* and restore any previous alarm */
11279               oldalarm -= timo;
11280             if (oldalarm < 0)           /* adjusted by our timeout interval */
11281               oldalarm = 0;
11282             if (oldalarm) {
11283                 debug(F101,"ttinc restoring oldalarm","",oldalarm);
11284                 alarm(oldalarm);
11285             }
11286         }
11287 #ifdef NETCONN
11288         if (netconn) {
11289             if (n == -2) {              /* read() returns 0 */
11290                 netclos();              /* on network read failure */
11291                 netconn = 0;
11292                 errno = ENOTCONN;
11293             }
11294         }
11295 #endif  /* NETCONN */
11296 #ifdef TNCODE
11297         if ((n > -1) && is_tn)
11298           return((unsigned)(n & 0xff));
11299         else
11300 #endif /* TNCODE */
11301           /* Return masked char or neg. */
11302           return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
11303     }
11304 }
11305
11306 /*  S N D B R K  --  Send a BREAK signal of the given duration  */
11307
11308 static int
11309 #ifdef CK_ANSIC
11310 sndbrk(int msec) {                      /* Argument is milliseconds */
11311 #else
11312 sndbrk(msec) int msec; {
11313 #endif /* CK_ANSIC */
11314 #ifndef POSIX
11315     int x, n;
11316 #endif /* POSIX */
11317
11318 #ifdef OXOS
11319 #define BSDBREAK
11320 #endif /* OXOS */
11321
11322 #ifdef ANYBSD
11323 #define BSDBREAK
11324 #endif /* ANYBSD */
11325
11326 #ifdef BSD44
11327 #define BSDBREAK
11328 #endif /* BSD44 */
11329
11330 #ifdef COHERENT
11331 #ifdef BSDBREAK
11332 #undef BSDBREAK
11333 #endif /* BSDBREAK */
11334 #endif /* COHERENT */
11335
11336 #ifdef BELLV10
11337 #ifdef BSDBREAK
11338 #undef BSDBREAK
11339 #endif /* BSDBREAK */
11340 #endif /* BELLV10 */
11341
11342 #ifdef PROVX1
11343     char spd;
11344 #endif /* PROVX1 */
11345
11346     debug(F101,"ttsndb ttyfd","",ttyfd);
11347     if (ttyfd < 0) return(-1);          /* Not open. */
11348
11349 #ifdef Plan9
11350     return p9sndbrk(msec);
11351 #else
11352 #ifdef NETCONN
11353 #ifdef NETCMD
11354     if (ttpipe)                         /* Pipe */
11355       return(ttoc('\0'));
11356 #endif /* NETCMD */
11357 #ifdef NETPTY
11358     if (ttpty)
11359       return(ttoc('\0'));
11360 #endif /* NETPTY */
11361     if (netconn)                        /* Send network BREAK */
11362       return(netbreak());
11363 #endif /* NETCONN */
11364
11365     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
11366
11367 #ifdef POSIX                            /* Easy in POSIX */
11368     {
11369         int x;
11370         debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
11371         errno = 0;
11372         x = tcsendbreak(ttyfd,msec / 375);
11373         debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
11374         return(x);
11375     }
11376 #else
11377 #ifdef PROVX1
11378     gtty(ttyfd,&ttbuf);                 /* Get current tty flags */
11379     spd = ttbuf.sg_ospeed;              /* Save speed */
11380     ttbuf.sg_ospeed = B50;              /* Change to 50 baud */
11381     stty(ttyfd,&ttbuf);                 /*  ... */
11382     n = (int)strlen(brnuls);            /* Send the right number of nulls */
11383     x = msec / 91;
11384     if (x > n) x = n;
11385     write(ttyfd,brnuls,n);
11386     ttbuf.sg_ospeed = spd;              /* Restore speed */
11387     stty(ttyfd,&ttbuf);                 /*  ... */
11388     return(0);
11389 #else
11390 #ifdef aegis
11391     sio_$control((short)ttyfd, sio_$send_break, msec, st);
11392     return(0);
11393 #else
11394 #ifdef BSDBREAK
11395     n = FWRITE;                         /* Flush output queue. */
11396 /* Watch out for int vs long problems in &n arg! */
11397     debug(F101,"sndbrk BSDBREAK","",msec);
11398     ioctl(ttyfd,TIOCFLUSH,&n);          /* Ignore any errors.. */
11399     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {  /* Turn on BREAK */
11400         perror("Can't send BREAK");
11401         return(-1);
11402     }
11403     x = msleep(msec);                    /* Sleep for so many milliseconds */
11404     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {  /* Turn off BREAK */
11405         perror("BREAK stuck!!!");
11406         doexit(BAD_EXIT,-1);            /* Get out, closing the line. */
11407                                         /*   with bad exit status */
11408     }
11409     return(x);
11410 #else
11411 #ifdef ATTSV
11412 /*
11413   No way to send a long BREAK in Sys V, so send a bunch of regular ones.
11414   (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
11415   but there's no way for this code to know for sure.)
11416 */
11417     debug(F101,"sndbrk ATTSV","",msec);
11418     x = msec / 275;
11419     for (n = 0; n < x; n++) {
11420         /* Reportedly the cast breaks this function on some systems */
11421         /* But then why was it here in the first place? */
11422         if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
11423             perror("Can't send BREAK");
11424             return(-1);
11425         }
11426     }
11427     return(0);
11428 #else
11429 #ifdef  V7
11430     debug(F101,"sndbrk V7","",msec);
11431     return(genbrk(ttyfd,250));          /* Simulate a BREAK */
11432 #else
11433     debug(F101,"sndbrk catchall","",msec);
11434     ttoc(0);ttoc(0);ttoc(0);ttoc(0);
11435     return(0);
11436 #endif /* V7 */
11437 #endif /* BSDBREAK */
11438 #endif /* ATTSV */
11439 #endif /* aegis */
11440 #endif /* PROVX1 */
11441 #endif /* POSIX */
11442 #endif /* Plan9 */
11443 }
11444
11445 /*  T T S N D B  --  Send a BREAK signal  */
11446
11447 int
11448 ttsndb() {
11449 #ifdef TN_COMPORT
11450     if (netconn && istncomport())
11451       return((tnsndb(275L) >= 0) ? 0 : -1);
11452     else
11453 #endif /* TN_COMPORT */
11454       return(sndbrk(275));
11455 }
11456
11457 /*  T T S N D L B  --  Send a Long BREAK signal  */
11458
11459 int
11460 ttsndlb() {
11461 #ifdef TN_COMPORT
11462     if (netconn && istncomport())
11463       return((tnsndb(1800L) >= 0) ? 0 : -1);
11464     else
11465 #endif /* TN_COMPORT */
11466     return(sndbrk(1500));
11467 }
11468
11469 /*  M S L E E P  --  Millisecond version of sleep().  */
11470
11471 /*
11472   Call with number of milliseconds (thousandths of seconds) to sleep.
11473   Intended only for small intervals.  For big ones, just use sleep().
11474   Highly system-dependent.
11475   Returns 0 always, even if it didn't work.
11476 */
11477
11478 /* Define MSLFTIME for systems that must use an ftime() loop. */
11479 #ifdef ANYBSD                           /* For pre-4.2 BSD versions */
11480 #ifndef BSD4
11481 #define MSLFTIME
11482 #endif /* BSD4 */
11483 #endif /* ANYBSD */
11484
11485 #ifdef TOWER1                           /* NCR Tower OS 1.0 */
11486 #define MSLFTIME
11487 #endif /* TOWER1 */
11488
11489 #ifdef COHERENT         /* Coherent... */
11490 #ifndef _I386           /* Maybe Coherent/386 should get this, too */
11491 #define MSLFTIME        /* Opinions are divided */
11492 #endif /* _I386 */
11493 #endif /* COHERENT */
11494
11495 #ifdef COMMENT
11496 #ifdef GETMSEC
11497
11498 /* Millisecond timer */
11499
11500 static long msecbase = 0L;              /* Unsigned long not portable */
11501
11502 long
11503 getmsec() {                             /* Milliseconds since base time */
11504     struct timeval xv;
11505     struct timezone xz;
11506     long secs, msecs;
11507     if (
11508 #ifdef GTODONEARG
11509         gettimeofday(&tv)
11510 #else
11511 #ifdef PTX
11512         gettimeofday(&tv, NULL)
11513 #else
11514         gettimeofday(&tv, &tz)
11515 #endif /* PTX */
11516 #endif /* GTODONEARG */
11517         < 0)
11518       return(-1);
11519     if (msecbase == 0L) {               /* First call, set base time. */
11520         msecbase = tv.tv_sec;
11521         debug(F101,"getmsec base","",msecbase);
11522     }
11523     return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
11524 }
11525 #endif /* GETMSEC */
11526 #endif /* COMMENT */
11527
11528 #ifdef SELECT
11529 int
11530 ttwait(fd, secs) int fd, secs; {
11531     int x;
11532     fd_set rfds;
11533     FD_ZERO(&rfds);
11534     FD_SET(fd,&rfds);
11535     tv.tv_sec = secs;
11536     tv.tv_usec = 0L;
11537     errno = 0;
11538     if ((x = select(FD_SETSIZE,
11539 #ifdef HPUX9
11540                     (int *)
11541 #else
11542 #ifdef HPUX1000
11543                     (int *)
11544 #endif /* HPUX1000 */
11545 #endif /* HPUX9 */
11546                     &rfds,
11547                     0, 0, &tv)) < 0) {
11548         debug(F101,"ttwait select errno","",errno);
11549         return(0);
11550     } else {
11551         debug(F101,"ttwait OK","",errno);
11552         x = FD_ISSET(fd, &rfds);
11553         debug(F101,"ttwait select x","",x);
11554         return(x ? 1 : 0);
11555     }
11556 }
11557 #endif /* SELECT */
11558
11559 int
11560 msleep(m) int m; {
11561 /*
11562   Other possibilities here are:
11563    nanosleep(), reportedly defined in POSIX.4.
11564    sginap(), IRIX only (back to what IRIX version I don't know).
11565 */
11566 #ifdef Plan9
11567     return _SLEEP(m);
11568 #else
11569 #ifdef BEOSORBEBOX
11570     snooze(m*1000);
11571 #else /* BEOSORBEBOX */
11572 #ifdef SELECT
11573     int t1, x;
11574     debug(F101,"msleep SELECT 1","",m);
11575     if (m <= 0) return(0);
11576     if (m >= 1000) {                    /* Catch big arguments. */
11577         sleep(m/1000);
11578         m = m % 1000;
11579         if (m < 10) return(0);
11580     }
11581     debug(F101,"msleep SELECT 2","",m);
11582 #ifdef BELLV10
11583     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
11584     debug(F101,"msleep BELLV10 select","",x);
11585 #else /* BELLV10 */
11586 #ifdef HPUX9
11587     gettimeofday(&tv, &tz);
11588 #else
11589
11590 #ifndef COHERENT
11591 #ifdef GTODONEARG
11592     if (gettimeofday(&tv) < 0)
11593 #else
11594 #ifdef PTX
11595     if (gettimeofday(&tv,NULL) < 0)
11596 #else
11597 #ifdef NOTIMEZONE
11598     if (gettimeofday(&tv, NULL) < 0)    /* wonder what this does... */
11599 #else
11600     if (gettimeofday(&tv, &tz) < 0)
11601 #endif /* NOTIMEZONE */
11602 #endif /* PTX */
11603 #endif /* GTODONEARG */
11604       return(-1);
11605     t1 = tv.tv_sec;                     /* Seconds */
11606 #endif /* COHERENT */
11607 #endif /* HPUX9 */
11608     tv.tv_sec = 0;                      /* Use select() */
11609     tv.tv_usec = m * 1000L;
11610 #ifdef BSD44
11611     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11612     debug(F101,"msleep BSD44 select","",x);
11613 #else /* BSD44 */
11614 #ifdef __linux__
11615     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11616     debug(F101,"msleep __linux__ select","",x);
11617 #else /* __linux__ */
11618 #ifdef BSD43
11619     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11620     debug(F101,"msleep BSD43 select","",x);
11621 #else /* BSD43 */
11622 #ifdef QNX6
11623     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11624     debug(F101,"msleep QNX6 select","",x);
11625 #else /* QNX6 */
11626 #ifdef QNX
11627     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11628     debug(F101,"msleep QNX select","",x);
11629 #else /* QNX */
11630 #ifdef COHERENT
11631     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11632     debug(F101,"msleep COHERENT select","",x);
11633 #else /* COHERENT */
11634 #ifdef HPUX1000                         /* 10.00 only, not 10.10 or later */
11635     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11636     debug(F101,"msleep HP-UX 10.00 select","",x);
11637 #else /* HPUX1000 */
11638 #ifdef SVR4
11639     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11640     debug(F101,"msleep SVR4 select","",x);
11641 #else /* SVR4 */
11642 #ifdef OSF40
11643     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11644     debug(F101,"msleep OSF40 select","",x);
11645 #else /* OSF40 */
11646 #ifdef PTX
11647     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11648     debug(F101,"msleep OSF40 select","",x);
11649 #else
11650     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11651     debug(F101,"msleep catch-all select","",x);
11652 #endif /* PTX */
11653 #endif /* OSF40 */
11654 #endif /* HP1000 */
11655 #endif /* SVR4 */
11656 #endif /* COHERENT */
11657 #endif /* QNX */
11658 #endif /* QNX6 */
11659 #endif /* BSD43 */
11660 #endif /* __linux__ */
11661 #endif /* BSD44 */
11662 #endif /* BELLV10 */
11663     return(0);
11664
11665 #else                                   /* Not SELECT */
11666 #ifdef CK_POLL                          /* We have poll() */
11667     struct pollfd pfd;                  /* Supply a valid address for poll() */
11668
11669 #ifdef ODT30                            /* But in SCO ODT 3.0 */
11670 #ifdef NAP                              /* we should use nap() instead */
11671     debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
11672     nap((long)m);                          /* seems to break dialing. */
11673     return(0);
11674 #else
11675     debug(F101,"msleep ODT 3.0 POLL","",m);
11676     poll(&pfd, 0, m);
11677     return(0);
11678 #endif /* NAP */
11679 #else
11680     debug(F101,"msleep POLL","",m);
11681     poll(&pfd, 0, m);
11682     return(0);
11683 #endif /* ODT30 */
11684
11685 /*
11686   We could handle the above more cleanly by just letting nap() always
11687   take precedence over poll() in this routine, but there is no way to know
11688   whether that would break something else.
11689 */
11690
11691 #else                                   /* Not POLL */
11692 #ifdef USLEEP
11693 /*
11694   "This routine is implemented using setitimer(2); it requires eight
11695   system calls...".  In other words, it might take 5 minutes to sleep
11696   10 milliseconds...
11697 */
11698     debug(F101,"msleep USLEEP","",m);
11699     if (m >= 1000) {                    /* Catch big arguments. */
11700         sleep(m/1000);
11701         m = m % 1000;
11702         if (m < 10) return(0);
11703     }
11704     usleep((unsigned int)(m * 1000));
11705     return(0);
11706 #else
11707 #ifdef aegis
11708     time_$clock_t dur;
11709     debug(F101,"msleep aegis","",m);
11710     dur.c2.high16 = 0;
11711     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
11712     time_$wait(time_$relative, dur, st);
11713     return(0);
11714 #else
11715 #ifdef PROVX1
11716     debug(F101,"msleep Venix","",m);
11717     if (m <= 0) return(0);
11718     sleep(-((m * 60 + 500) / 1000));
11719     return(0);
11720 #else
11721 #ifdef NAP
11722     debug(F101,"msleep NAP","",m);
11723     nap((long)m);
11724     return(0);
11725 #else
11726 #ifdef ATTSV
11727 #ifndef BSD44
11728     extern long times();                /* Or #include <times.h> ? */
11729 #endif /* BSD44 */
11730     long t1, t2, tarray[4];
11731     int t3;
11732     char *cp = getenv("HZ");
11733     int CLOCK_TICK;
11734     int hertz;
11735
11736     if (cp && (hertz = atoi(cp))) {
11737         CLOCK_TICK  = 1000 / hertz;
11738     } else {                            /* probably single user mode */
11739 #ifdef HZ
11740         CLOCK_TICK  = 1000 / HZ;
11741 #else
11742         static warned = 0;
11743         /* HZ always exists in, for instance, SCO Xenix, so you don't have to
11744          * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
11745          * have Xenix, you have should have nap(), so the best is to use -DNAP
11746          * in the makefile. Most systems have HZ.
11747          */
11748         CLOCK_TICK = 17;                /* 1/60 sec */
11749         if (!warned) {
11750           printf("warning: environment variable HZ bad... using HZ=%d\r\n",
11751                  1000 / CLOCK_TICK);
11752           warned = 1;
11753         }
11754 #endif /* !HZ */
11755     }
11756     debug(F101,"msleep ATTSV","",m);
11757     if (m <= 0) return(0);
11758     if (m >= 1000) {                    /* Catch big arguments. */
11759         sleep(m/1000);
11760         m = m % 1000;
11761         if (m < 10) return(0);
11762     }
11763     if ((t1 = times(tarray)) < 0) return(-1);
11764     while (1) {
11765         if ((t2 = times(tarray)) < 0) return(-1);
11766         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
11767         if (t3 > m) return(t3);
11768     }
11769 #else /* Not ATTSV */
11770 #ifdef MSLFTIME                         /* Use ftime() loop... */
11771     int t1, t3 = 0;
11772     debug(F101,"msleep MSLFTIME","",m);
11773     if (m <= 0) return(0);
11774     if (m >= 1000) {                    /* Catch big arguments. */
11775         sleep(m/1000);
11776         m = m % 1000;
11777         if (m < 10) return(0);
11778     }
11779 #ifdef QNX
11780     ftime(&ftp);                        /* void ftime() in QNX */
11781 #else
11782     if (ftime(&ftp) < 0) return(-1);    /* Get base time. */
11783 #endif /* QNX */
11784     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
11785     while (1) {
11786         ftime(&ftp);                    /* Get current time and compare. */
11787         t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
11788         if (t3 > m) return(0);
11789     }
11790 #else
11791 /* This includes true POSIX, which has no way to do this. */
11792     debug(F101,"msleep busy loop","",m);
11793     if (m >= 1000) {                    /* Catch big arguments. */
11794         sleep(m/1000);
11795         m = m % 1000;
11796         if (m < 10) return(0);
11797     }
11798     if (m > 0) while (m > 0) m--;       /* Just a dumb busy loop */
11799     return(0);
11800 #endif /* MSLFTIME */
11801 #endif /* ATTSV */
11802 #endif /* NAP */
11803 #endif /* PROVX1 */
11804 #endif /* aegis */
11805 #endif /* CK_POLL */
11806 #endif /* SELECT */
11807 #endif /* BEOSORBEBOX */
11808 #endif /* USLEEP */
11809 #endif /* Plan9 */
11810 }
11811
11812 /*  R T I M E R --  Reset elapsed time counter  */
11813
11814 VOID
11815 rtimer() {
11816     tcount = time( (time_t *) 0 );
11817 }
11818
11819
11820 /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
11821
11822 int
11823 gtimer() {
11824     int x;
11825     x = (int) (time( (time_t *) 0 ) - tcount);
11826     debug(F101,"gtimer","",x);
11827     return( (x < 0) ? 0 : x );
11828 }
11829
11830 #ifdef GFTIMER
11831 /*
11832   Floating-point timers.  Require not only floating point support, but
11833   also gettimeofday().
11834 */
11835 static struct timeval tzero;
11836
11837 VOID
11838 rftimer() {
11839 #ifdef GTODONEARG                       /* Account for Mot's definition */
11840     (VOID) gettimeofday(&tzero);
11841 #else
11842     (VOID) gettimeofday(&tzero, (struct timezone *)0);
11843 #endif /* GTODONEARG */
11844 }
11845
11846 CKFLOAT
11847 gftimer() {
11848     struct timeval tnow, tdelta;
11849     CKFLOAT s;
11850 #ifdef DEBUG
11851     char fpbuf[64];
11852 #endif /* DEBUG */
11853 #ifdef GTODONEARG                       /* Account for Mot's definition */
11854     (VOID) gettimeofday(&tnow);
11855 #else
11856     (VOID) gettimeofday(&tnow, (struct timezone *)0);
11857 #endif /* GTODONEARG */
11858
11859     tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
11860     tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
11861
11862     if (tdelta.tv_usec < 0) {
11863         tdelta.tv_sec--;
11864         tdelta.tv_usec += 1000000;
11865     }
11866     s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
11867     if (s < GFMINTIME)
11868       s = GFMINTIME;
11869 #ifdef DEBUG
11870     if (deblog) {
11871         sprintf(fpbuf,"%f",s);
11872         debug(F110,"gftimer",fpbuf,0);
11873     }
11874 #endif /* DEBUG */
11875     return(s);
11876 }
11877 #endif /* GFTIMER */
11878
11879 /*  Z T I M E  --  Return asctime()-format date/time string  */
11880 /*
11881   NOTE: as a side effect of calling this routine, we can also set the
11882   following two variables, giving the micro- and milliseconds (fractions of
11883   seconds) of the clock time.  Currently this is done only in BSD-based builds
11884   that use gettimeofday().  When these variables are not filled in, they are
11885   left with a value of -1L.
11886 */
11887 static char asctmbuf[64];
11888
11889 VOID
11890 ztime(s) char **s; {
11891
11892 #ifdef GFTIMER
11893 /*
11894   The gettimeofday() method, which also sets ztmsec and ztusec, works for
11895   all GFTIMER builds.  NOTE: ztmsec and ztusec are defined in ckcmai.c,
11896   and extern declarations for them are in ckcdeb.h; thus they are
11897   declared in this file by inclusion of ckcdeb.h.
11898 */
11899     char *asctime();
11900     struct tm *localtime();
11901     struct tm *tp;
11902     ztmsec = -1L;
11903     ztusec = -1L;
11904
11905     if (!s)
11906       debug(F100,"ztime s==NULL","",0);
11907
11908 #ifdef GTODONEARG
11909     /* No 2nd arg in Motorola SV88 and some others */
11910     if (gettimeofday(&tv) > -1)
11911 #else
11912 #ifndef COHERENT
11913 #ifdef PTX
11914     if (gettimeofday(&tv,NULL) > -1)
11915 #else
11916 #ifdef NOTIMEZONE
11917     if (gettimeofday(&tv, NULL) > -1)   /* wonder what this does... */
11918 #else
11919     if (gettimeofday(&tv, &tz) > -1)
11920 #endif /* NOTIMEZONE */
11921 #endif /* PTX */
11922 #endif /* COHERENT */
11923 #endif /* GTODONEARG */
11924       {                                 /* Fill in tm struct */
11925         ztusec = tv.tv_usec;            /* Microseconds */
11926         ztmsec = ztusec / 1000L;        /* Milliseconds */
11927 #ifdef HPUX9
11928         {
11929             time_t zz;
11930             zz = tv.tv_sec;
11931             tp = localtime(&zz);        /* Convert to local time */
11932         }
11933 #else
11934 #ifdef HPUX1000
11935         {
11936             time_t zz;
11937             zz = tv.tv_sec;
11938             tp = localtime(&zz);
11939         }
11940 #else
11941 #ifdef LINUX
11942         {   /* avoid unaligned access trap on 64-bit platforms */
11943             time_t zz;
11944             zz = tv.tv_sec;
11945             tp = localtime(&zz);
11946         }
11947 #else
11948 #ifdef MACOSX
11949         tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
11950 #else
11951         tp = localtime(&tv.tv_sec);
11952 #endif /* MACOSX */
11953 #endif /* LINUX */
11954 #endif /* HPUX1000 */
11955 #endif /* HPUX9 */
11956         if (s) {
11957             char * s2;
11958             s2 = asctime(tp);           /* Convert result to ASCII string */
11959             asctmbuf[0] = '\0';
11960             if (s2) ckstrncpy(asctmbuf,s2,64);
11961             *s = asctmbuf;
11962             debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
11963         }
11964     }
11965 #else  /* Not GFTIMER */
11966
11967 #undef ZTIMEV7                          /* Which systems need to use */
11968 #ifdef COHERENT                         /* old UNIX Version 7 way... */
11969 #define ZTIMEV7
11970 #endif /* COHERENT */
11971 #ifdef TOWER1
11972 #define ZTIMEV7
11973 #endif /* TOWER1 */
11974 #ifdef ANYBSD
11975 #ifndef BSD42
11976 #define ZTIMEV7
11977 #endif /* BSD42 */
11978 #endif /* ANYBSD */
11979 #ifdef V7
11980 #ifndef MINIX
11981 #define ZTIMEV7
11982 #endif /* MINIX */
11983 #endif /* V7 */
11984 #ifdef POSIX
11985 #define ZTIMEV7
11986 #endif /* POSIX */
11987
11988 #ifdef HPUX1020
11989 /*
11990   Prototypes are in <time.h>, included above.
11991 */
11992     time_t clock_storage;
11993     clock_storage = time((void *) 0);
11994     if (s) {
11995         *s = ctime(&clock_storage);
11996         debug(F110,"ztime: HPUX 10.20",*s,0);
11997     }
11998 #else
11999 #ifdef ATTSV                            /* AT&T way */
12000 /*  extern long time(); */              /* Theoretically these should */
12001     char *ctime();                      /* already been dcl'd in <time.h> */
12002     time_t clock_storage;
12003     clock_storage = time(
12004 #ifdef IRIX60
12005                          (time_t *)
12006 #else
12007 #ifdef BSD44
12008                          (time_t *)
12009 #else
12010                          (long *)
12011 #endif /* BSD44 */
12012 #endif /* IRIX60 */
12013                          0 );
12014     if (s) {
12015         *s = ctime( &clock_storage );
12016         debug(F110,"ztime: ATTSV",*s,0);
12017     }
12018 #else
12019 #ifdef PROVX1                           /* Venix 1.0 way */
12020     int utime[2];
12021     time(utime);
12022     if (s) {
12023         *s = ctime(utime);
12024         debug(F110,"ztime: PROVX1",*s,0);
12025     }
12026 #else
12027 #ifdef BSD42                            /* 4.2BSD way */
12028     char *asctime();
12029     struct tm *localtime();
12030     struct tm *tp;
12031     gettimeofday(&tv, &tz);
12032     ztusec = tv.tv_usec;
12033     ztmsec = tv.tv_usec / 1000L;
12034     tp = localtime(&tv.tv_sec);
12035     if (s) {
12036         *s = asctime(tp);
12037         debug(F111,"ztime: BSD42",*s,ztusec);
12038     }
12039 #else
12040 #ifdef MINIX                            /* MINIX way */
12041 #ifdef COMMENT
12042     extern long time();                 /* Already got these from <time.h> */
12043     extern char *ctime();
12044 #endif /* COMMENT */
12045     time_t utime[2];
12046     time(utime);
12047     if (s) {
12048         *s = ctime(utime);
12049         debug(F110,"ztime: MINIX",*s,0);
12050     }
12051 #else
12052 #ifdef ZTIMEV7                          /* The regular way */
12053     char *asctime();
12054     struct tm *localtime();
12055     struct tm *tp;
12056     long xclock;                        /* or unsigned long for BeBox? */
12057     time(&xclock);
12058     tp = localtime(&xclock);
12059     if (s) {
12060         *s = asctime(tp);
12061         debug(F110,"ztime: ZTIMEV7",*s,0);
12062     }
12063 #else                                   /* Catch-all for others... */
12064     if (s) {
12065         *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
12066         debug(F110,"ztime: catch-all",*s,0);
12067     }
12068 #endif /* ZTIMEV7 */
12069 #endif /* MINIX */
12070 #endif /* BSD42 */
12071 #endif /* PROVX1 */
12072 #endif /* ATTSV */
12073 #endif /* HPUX1020 */
12074 #endif /* GFTIMER */
12075 }
12076
12077 /*  C O N G M  --  Get console terminal modes.  */
12078
12079 /*
12080   Saves initial console mode, and establishes variables for switching
12081   between current (presumably normal) mode and other modes.
12082   Should be called when program starts, but only after establishing
12083   whether program is in the foreground or background.
12084   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
12085 */
12086 int
12087 congm() {
12088     int fd;
12089     if (backgrd || !isatty(0)) {        /* If in background. */
12090         cgmf = -1;                      /* Don't bother, modes are garbage. */
12091         return(-1);
12092     }
12093     if (cgmf > 0) return(0);            /* Already did this. */
12094     debug(F100,"congm getting modes","",0); /* Need to do it. */
12095 #ifdef aegis
12096     ios_$inq_type_uid(ios_$stdin, conuid, st);
12097     if (st.all != status_$ok) {
12098         fprintf(stderr, "problem getting stdin objtype: ");
12099         error_$print(st);
12100     }
12101     concrp = (conuid == mbx_$uid);
12102     conbufn = 0;
12103 #endif /* aegis */
12104
12105 #ifndef BEBOX
12106     if ((fd = open(CTTNAM,2)) < 0) {    /* Open controlling terminal */
12107 #ifdef COMMENT
12108         fprintf(stderr,"Error opening %s\n", CTTNAM);
12109         perror("congm");
12110         return(-1);
12111 #else
12112         fd = 0;
12113 #endif /* COMMENT */
12114     }
12115 #else
12116     fd = 0;
12117 #endif /* !BEBOX */
12118 #ifdef BSD44ORPOSIX
12119     if (tcgetattr(fd,&ccold) < 0) return(-1);
12120     if (tcgetattr(fd,&cccbrk) < 0) return(-1);
12121     if (tcgetattr(fd,&ccraw) < 0) return(-1);
12122 #else
12123 #ifdef ATTSV
12124     if (ioctl(fd,TCGETA,&ccold)  < 0) return(-1);
12125     if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
12126     if (ioctl(fd,TCGETA,&ccraw)  < 0) return(-1);
12127 #ifdef VXVE
12128     cccbrk.c_line = 0;                  /* STTY line 0 for CDC VX/VE */
12129     if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
12130     ccraw.c_line = 0;                   /* STTY line 0 for CDC VX/VE */
12131     if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
12132 #endif /* VXVE */
12133 #else
12134 #ifdef BELLV10
12135     if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
12136     if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
12137     if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
12138     debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
12139 #else
12140     if (gtty(fd,&ccold) < 0) return(-1);
12141     if (gtty(fd,&cccbrk) < 0) return(-1);
12142     if (gtty(fd,&ccraw) < 0) return(-1);
12143 #endif /* BELLV10 */
12144 #endif /* ATTSV */
12145 #endif /* BSD44ORPOSIX */
12146 #ifdef sony_news                        /* Sony NEWS */
12147     if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
12148         perror("congm error getting Kanji mode");
12149         debug(F101,"congm error getting Kanji mode","",0);
12150         km_con = -1;                    /* Make sure this stays undefined. */
12151         return(-1);
12152     }
12153 #endif /* sony_news */
12154     if (fd > 0)
12155       close(fd);
12156     cgmf = 1;                           /* Flag that we got them. */
12157     return(1);
12158 }
12159
12160
12161 static VOID
12162 congetbuf(x) int x; {
12163     int n;
12164     n = CONBUFSIZ - (conbufp - conbuf); /* How much room left in buffer? */
12165     if (x > n) {
12166         debug(F101,"congetbuf char loss","",x-n);
12167         x = n;
12168     }
12169     x = read(0,conbufp,x);
12170     conbufn += x;
12171     debug(F111,"congetbuf readahead",conbuf,x);
12172 }
12173
12174
12175 /*  C O N C B --  Put console in cbreak mode.  */
12176
12177 /*  Returns 0 if ok, -1 if not  */
12178
12179 int
12180 #ifdef CK_ANSIC
12181 concb(char esc)
12182 #else
12183 concb(esc) char esc;
12184 #endif /* CK_ANSIC */
12185 /* concb */ {
12186     int x, y = 0;
12187     debug(F101,"concb constate","",constate);
12188     debug(F101,"concb cgmf","",cgmf);
12189     debug(F101,"concb backgrd","",backgrd);
12190
12191     if (constate == CON_CB)
12192       return(0);
12193
12194     if (cgmf < 1)                       /* Did we get console modes yet? */
12195       if (!backgrd)                     /* No, in background? */
12196         congm();                        /* No, try to get them now. */
12197     if (cgmf < 1)                       /* Still don't have them? */
12198       return(0);                        /* Give up. */
12199     debug(F101,"concb ttyfd","",ttyfd);
12200     debug(F101,"concb ttfdflg","",ttfdflg);
12201 #ifdef COMMENT
12202     /* This breaks returning to prompt after protocol with "-l 0" */
12203     /* Commented out July 1998 */
12204     if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
12205       return(0);
12206 #endif /* COMMENT */
12207     x = isatty(0);
12208     debug(F101,"concb isatty","",x);
12209     if (!x) return(0);                  /* Only when running on real ttys */
12210     debug(F101,"concb xsuspend","",xsuspend);
12211     if (backgrd)                        /* Do nothing if in background. */
12212       return(0);
12213     escchr = esc;                       /* Make this available to other fns */
12214     ckxech = 1;                         /* Program can echo characters */
12215 #ifdef aegis
12216     conbufn = 0;
12217     if (concrp) return(write(1, "\035\002", 2));
12218     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
12219 #endif /* aegis */
12220
12221 #ifdef COHERENT
12222 #define SVORPOSIX
12223 #endif /* COHERENT */
12224
12225 #ifdef Plan9
12226     x = p9concb();
12227 #else
12228 #ifndef SVORPOSIX                       /* BSD, V7, etc */
12229     debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
12230     debug(F101,"concb stty CBREAK","",0);
12231     cccbrk.sg_flags |= (CBREAK|CRMOD);  /* Set to character wakeup, */
12232     cccbrk.sg_flags &= ~ECHO;           /* no echo. */
12233     debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
12234     errno = 0;
12235 /*
12236   BSD stty() clears the console buffer.  So if anything is waiting in it,
12237   we have to read it now to avoid losing it.
12238 */
12239     x = conchk();
12240     if (x > 0)
12241       congetbuf(x);
12242
12243 #ifdef BELLV10
12244     x = ioctl(0,TIOCSETP,&cccbrk);
12245 #else
12246     x = stty(0,&cccbrk);
12247     debug(F101,"cccbrk.sg_flags concb x","", x);
12248 #endif /* BELLV10 */
12249 #else                                   /* Sys V and POSIX */
12250 #ifndef OXOS
12251     debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
12252 #ifdef QNX
12253     /* Don't mess with IEXTEN */
12254     cccbrk.c_lflag &= ~(ICANON|ECHO);
12255 #else
12256 #ifdef COHERENT
12257     cccbrk.c_lflag &= ~(ICANON|ECHO);
12258 #else
12259     cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
12260 #endif /* COHERENT */
12261 #endif /* QNX */
12262     cccbrk.c_lflag |= ISIG;             /* Allow signals in command mode. */
12263     cccbrk.c_iflag |= IGNBRK;           /* But ignore BREAK signal */
12264     cccbrk.c_iflag &= ~BRKINT;
12265
12266 #else /* OXOS */
12267     debug(F100,"concb OXOS is defined","",0);
12268     cccbrk.c_lflag &= ~(ICANON|ECHO);
12269     cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
12270 #endif /* OXOS */
12271 #ifdef COMMENT
12272 /*
12273   Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
12274   array reference is out of bounds.  It's only a debug() call so who needs it.
12275 */
12276 #ifdef VSUSP
12277     debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
12278 #endif /* VSUSP */
12279 #endif /* COMMENT */
12280 #ifndef VINTR
12281     debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
12282     cccbrk.c_cc[0] = 003;               /* Interrupt char is Control-C */
12283 #else
12284     debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
12285     cccbrk.c_cc[VINTR] = 003;
12286 #endif /* VINTR */
12287 #ifndef VQUIT
12288     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
12289 #else
12290     cccbrk.c_cc[VQUIT] = escchr;
12291 #endif /* VQUIT */
12292 #ifndef VEOF
12293     cccbrk.c_cc[4] = 1;
12294 #else
12295 #ifndef OXOS
12296 #ifdef VMIN
12297     cccbrk.c_cc[VMIN] = 1;
12298 #endif /* VMIN */
12299 #else /* OXOS */
12300     cccbrk.c_min = 1;
12301 #endif /* OXOS */
12302 #endif /* VEOF */
12303 #ifdef ZILOG
12304     cccbrk.c_cc[5] = 0;
12305 #else
12306 #ifndef VEOL
12307     cccbrk.c_cc[5] = 1;
12308 #else
12309 #ifndef OXOS
12310 #ifdef VTIME
12311     cccbrk.c_cc[VTIME] = 1;
12312 #endif /* VTIME */
12313 #else /* OXOS */
12314     cccbrk.c_time = 1;
12315 #endif /* OXOS */
12316 #endif /* VEOL */
12317 #endif /* ZILOG */
12318     errno = 0;
12319 #ifdef BSD44ORPOSIX                     /* Set new modes */
12320     x = tcsetattr(0,TCSADRAIN,&cccbrk);
12321 #else /* ATTSV */                       /* or the POSIX way */
12322     x = ioctl(0,TCSETAW,&cccbrk);       /* the Sys V way */
12323 #endif /* BSD44ORPOSIX */
12324 #endif /* SVORPOSIX */
12325
12326 #ifdef COHERENT
12327 #undef SVORPOSIX
12328 #endif /* COHERENT */
12329
12330     debug(F101,"concb x","",x);
12331     debug(F101,"concb errno","",errno);
12332
12333 #ifdef  V7
12334 #ifndef MINIX
12335     if (kmem[CON] < 0) {
12336         qaddr[CON] = initrawq(0);
12337         if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
12338             fprintf(stderr, "Can't read /dev/kmem in concb.\n");
12339             perror("/dev/kmem");
12340             exit(1);
12341         }
12342     }
12343 #endif /* MINIX */
12344 #endif /* V7 */
12345 #endif /* Plan9 */
12346
12347     if (x > -1)
12348       constate = CON_CB;
12349
12350     debug(F101,"concb returns","",x);
12351     return(x);
12352 }
12353
12354 /*  C O N B I N  --  Put console in binary mode  */
12355
12356 /*  Returns 0 if ok, -1 if not  */
12357
12358 int
12359 #ifdef CK_ANSIC
12360 conbin(char esc)
12361 #else
12362 conbin(esc) char esc;
12363 #endif /* CK_ANSIC */
12364 /* conbin */  {
12365
12366     int x;
12367
12368     debug(F101,"conbin constate","",constate);
12369
12370     if (constate == CON_BIN)
12371       return(0);
12372
12373     if (!isatty(0)) return(0);          /* only for real ttys */
12374     congm();                            /* Get modes if necessary. */
12375     debug(F100,"conbin","",0);
12376     escchr = esc;                       /* Make this available to other fns */
12377     ckxech = 1;                         /* Program can echo characters */
12378 #ifdef aegis
12379     conbufn = 0;
12380     if (concrp) return(write(1, "\035\002", 2));
12381     if (conuid == input_pad_$uid) {
12382         pad_$raw(ios_$stdin, st);
12383         return(0);
12384       }
12385 #endif /* aegis */
12386
12387 #ifdef COHERENT
12388 #define SVORPOSIX
12389 #endif /* COHERENT */
12390
12391 #ifdef Plan9
12392     return p9conbin();
12393 #else
12394 #ifdef SVORPOSIX
12395 #ifndef OXOS
12396 #ifdef QNX
12397     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12398 #else
12399 #ifdef COHERENT
12400     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12401 #else
12402     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
12403 #endif /* COHERENT */
12404 #endif /* QNX */
12405 #else /* OXOS */
12406     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12407     ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
12408 #endif /* OXOS */
12409     ccraw.c_iflag |= IGNPAR;
12410 /*
12411   Note that for terminal sessions we disable Xon/Xoff flow control to allow
12412   the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
12413   transfers to work when C-Kermit is in the middle, etc.  Hardware flow
12414   control, if in use, is not affected.
12415 */
12416 #ifdef ATTSV
12417 #ifdef BSD44
12418     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
12419                         |INPCK|ISTRIP);
12420 #else
12421     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
12422                         |INPCK|ISTRIP);
12423 #endif /* BSD44 */
12424 #else /* POSIX */
12425     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
12426 #endif /* ATTSV */
12427     ccraw.c_oflag &= ~OPOST;
12428 #ifdef COMMENT
12429 /*
12430   WHAT THE HECK WAS THIS FOR?
12431   The B9600 setting (obviously) prevents CONNECT from working at any
12432   speed other than 9600 when you are logged in to the 7300 on a serial
12433   line.  Maybe some of the other flags are necessary -- if so, put back
12434   the ones that are needed.  This code is supposed to work the same, no
12435   matter whether you are logged in to the 7300 on the real console device,
12436   or through a serial port.
12437 */
12438 #ifdef ATT7300
12439     ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
12440 #endif /* ATT7300 */
12441 #endif /* COMMENT */
12442
12443 /*** Kermit used to put the console in 8-bit raw mode, but some users have
12444  *** pointed out that this should not be done, since some sites actually
12445  *** use terminals with parity settings on their Unix systems, and if we
12446  *** override the current settings and stop doing parity, then their terminals
12447  *** will display blotches for characters whose parity is wrong.  Therefore,
12448  *** the following two lines are commented out (Larry Afrin, Clemson U):
12449  ***
12450  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
12451  ***   ccraw.c_cflag |= (CS8|CREAD);
12452  ***
12453  *** Sys III/V sites that have trouble with this can restore these lines.
12454  ***/
12455 #ifndef VINTR
12456     ccraw.c_cc[0] = 003;                /* Interrupt char is Ctrl-C */
12457 #else
12458     ccraw.c_cc[VINTR] = 003;
12459 #endif /* VINTR */
12460 #ifndef VQUIT
12461     ccraw.c_cc[1] = escchr;             /* Escape during packet mode */
12462 #else
12463     ccraw.c_cc[VQUIT] = escchr;
12464 #endif /* VQUIT */
12465 #ifndef VEOF
12466     ccraw.c_cc[4] = 1;
12467 #else
12468 #ifndef OXOS
12469 #ifdef VMIN
12470     ccraw.c_cc[VMIN] = 1;
12471 #endif /* VMIN */
12472 #else /* OXOS */
12473     ccraw.c_min = 1;
12474 #endif /* OXOS */
12475 #endif /* VEOF */
12476
12477 #ifdef ZILOG
12478     ccraw.c_cc[5] = 0;
12479 #else
12480 #ifndef VEOL
12481     ccraw.c_cc[5] = 1;
12482 #else
12483 #ifndef OXOS
12484 #ifdef VTIME
12485     ccraw.c_cc[VTIME] = 1;
12486 #endif /* VTIME */
12487 #else /* OXOS */
12488     ccraw.c_time = 1;
12489 #endif /* OXOS */
12490 #endif /* VEOL */
12491 #endif /* ZILOG */
12492
12493 #ifdef BSD44ORPOSIX
12494     x = tcsetattr(0,TCSADRAIN,&ccraw);  /* Set new modes. */
12495 #else
12496     x = ioctl(0,TCSETAW,&ccraw);
12497 #endif /* BSD44ORPOSIX */
12498 #else /* Berkeley, etc. */
12499     x = conchk();                       /* Because stty() is destructive */
12500     if (x > 0)
12501       congetbuf(x);
12502     ccraw.sg_flags |= (RAW|TANDEM);     /* Set rawmode, XON/XOFF (ha) */
12503     ccraw.sg_flags &= ~(ECHO|CRMOD);    /* Set char wakeup, no echo */
12504 #ifdef BELLV10
12505     x = ioctl(0,TIOCSETP,&ccraw);
12506 #else
12507     x = stty(0,&ccraw);
12508 #endif /* BELLV10 */
12509 #endif /* SVORPOSIX */
12510 #endif /* Plan9 */
12511
12512     if (x > -1)
12513       constate = CON_BIN;
12514
12515     debug(F101,"conbin returns","",x);
12516     return(x);
12517
12518 #ifdef COHERENT
12519 #undef SVORPOSIX
12520 #endif /* COHERENT */
12521
12522 }
12523
12524
12525 /*  C O N R E S  --  Restore the console terminal  */
12526
12527 int
12528 conres() {
12529     int x;
12530     debug(F101,"conres cgmf","",cgmf);
12531     debug(F101,"conres constate","",constate);
12532
12533     if (cgmf < 1)                       /* Do nothing if modes unchanged */
12534       return(0);
12535     if (constate == CON_RES)
12536       return(0);
12537
12538     if (!isatty(0)) return(0);          /* only for real ttys */
12539     debug(F100,"conres isatty ok","",0);
12540     ckxech = 0;                         /* System should echo chars */
12541
12542 #ifdef aegis
12543     conbufn = 0;
12544     if (concrp) return(write(1, "\035\001", 2));
12545     if (conuid == input_pad_$uid) {
12546         pad_$cooked(ios_$stdin, st);
12547         constate = CON_RES;
12548         return(0);
12549     }
12550 #endif /* aegis */
12551
12552 #ifdef Plan9
12553     p9conres();
12554 #else
12555 #ifdef BSD44ORPOSIX
12556     debug(F100,"conres restoring tcsetattr","",0);
12557     x = tcsetattr(0,TCSADRAIN,&ccold);
12558 #else
12559 #ifdef ATTSV
12560     debug(F100,"conres restoring ioctl","",0);
12561     x = ioctl(0,TCSETAW,&ccold);
12562 #else /* BSD, V7, and friends */
12563 #ifdef sony_news                        /* Sony NEWS */
12564     if (km_con != -1)
12565       ioctl(0,TIOCKSET,&km_con);        /* Restore console Kanji mode */
12566 #endif /* sony_news */
12567     msleep(100);
12568     debug(F100,"conres restoring stty","",0);
12569     x = conchk();                       /* Because stty() is destructive */
12570     if (x > 0)
12571       congetbuf(x);
12572 #ifdef BELLV10
12573     x = ioctl(0,TIOCSETP,&ccold);
12574 #else
12575     x = stty(0,&ccold);
12576 #endif /* BELLV10 */
12577 #endif /* ATTSV */
12578 #endif /* BSD44ORPOSIX */
12579 #endif /* Plan9 */
12580     if (x > -1)
12581       constate = CON_RES;
12582
12583     debug(F101,"conres returns","",x);
12584     return(x);
12585 }
12586
12587 /*  C O N O C  --  Output a character to the console terminal  */
12588
12589 int
12590 #ifdef CK_ANSIC
12591 conoc(char c)
12592 #else
12593 conoc(c) char c;
12594 #endif /* CK_ANSIC */
12595 /* conoc */ {
12596
12597 #ifdef IKSD
12598     if (inserver && !local)
12599       return(ttoc(c));
12600
12601 #ifdef CK_ENCRYPTION
12602     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12603         ck_tn_encrypt(&c,1);
12604 #endif /* CK_ENCRYPTION */
12605 #endif /* IKSD */
12606
12607 #ifdef Plan9
12608     return conwrite(&c,1);
12609 #else
12610     return(write(1,&c,1));
12611 #endif /* Plan9 */
12612 }
12613
12614 /*  C O N X O  --  Write x characters to the console terminal  */
12615
12616 int
12617 conxo(x,s) int x; char *s; {
12618
12619 #ifdef IKSD
12620     if (inserver && !local)
12621       return(ttol((CHAR *)s,x));
12622
12623 #ifdef CK_ENCRYPTION
12624     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12625         ck_tn_encrypt(s,x);
12626 #endif /* CK_ENCRYPTION */
12627 #endif /* IKSD */
12628
12629 #ifdef Plan9
12630     return(conwrite(s,x));
12631 #else
12632     return(write(1,s,x));
12633 #endif /* Plan9 */
12634 }
12635
12636 /*  C O N O L  --  Write a line to the console terminal  */
12637
12638 int
12639 conol(s) char *s; {
12640     int len;
12641     if (!s) s = "";                     /* Always do this! */
12642     len = strlen(s);
12643     if (len == 0)
12644       return(0);
12645
12646 #ifdef IKSD
12647     if (inserver && !local)
12648       return(ttol((CHAR *)s,len));
12649
12650 #ifdef CK_ENCRYPTION
12651     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
12652         if (nxpacket < len) {
12653             if (xpacket) {
12654                 free(xpacket);
12655                 xpacket = NULL;
12656                 nxpacket = 0;
12657             }
12658             len = len > 10240 ? len : 10240;
12659             xpacket = (CHAR *)malloc(len);
12660             if (!xpacket) {
12661                 fprintf(stderr,"ttol malloc failure\n");
12662                 return(-1);
12663             } else
12664               nxpacket = len;
12665         }
12666         memcpy(xpacket,s,len);
12667         s = (char *)xpacket;
12668         ck_tn_encrypt(s,len);
12669     }
12670 #endif /* CK_ENCRYPTION */
12671 #endif /* IKSD */
12672
12673 #ifdef Plan9
12674     return(conwrite(s,len));
12675 #else
12676     return(write(1,s,len));
12677 #endif /* Plan9 */
12678 }
12679
12680 /*  C O N O L A  --  Write an array of lines to the console terminal */
12681
12682 int
12683 conola(s) char *s[]; {
12684     char * p;
12685     int i, x;
12686
12687
12688     if (!s) return(0);
12689     for (i = 0; ; i++) {
12690         p = s[i];
12691         if (!p) p = "";                 /* Let's not dump core shall we? */
12692         if (!*p)
12693           break;
12694 #ifdef IKSD
12695         if (inserver && !local)
12696           x = ttol((CHAR *)p,(int)strlen(p));
12697         else
12698 #endif /* IKSD */
12699           x = conol(p);
12700         if (x < 0)
12701           return(-1);
12702     }
12703     return(0);
12704 }
12705
12706 /*  C O N O L L  --  Output a string followed by CRLF  */
12707
12708 int
12709 conoll(s) char *s; {
12710     CHAR buf[3];
12711     buf[0] = '\r';
12712     buf[1] = '\n';
12713     buf[2] = '\0';
12714     if (!s) s = "";
12715
12716 #ifdef IKSD
12717     if (inserver && !local) {
12718         if (*s) ttol((CHAR *)s,(int)strlen(s));
12719         return(ttol(buf,2));
12720     }
12721 #endif /* IKSD */
12722
12723     if (*s) conol(s);
12724 #ifdef IKSD
12725 #ifdef CK_ENCRYPTION
12726     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12727       ck_tn_encrypt((char *)buf,2);
12728 #endif /* CK_ENCRYPTION */
12729 #endif /* IKSD */
12730
12731 #ifdef Plan9
12732     return(conwrite(buf, 2));
12733 #else
12734     return(write(1,buf,2));
12735 #endif /* Plan9 */
12736 }
12737
12738 /*  C O N C H K  --  Return how many characters available at console  */
12739 /*
12740   We could also use select() here to cover a few more systems that are not
12741   covered by any of the following, e.g. HP-UX 9.0x on the model 800.
12742 */
12743 int
12744 conchk() {
12745     static int contyp = 0;              /* +1 for isatty, -1 otherwise */
12746
12747     if (contyp == 0)                    /* This prevents unnecessary */
12748       contyp = (isatty(0) ? 1 : -1);    /* duplicated calls to isatty() */
12749     debug(F101,"conchk contyp","",contyp);
12750     if (backgrd || (contyp < 0))
12751       return(0);
12752
12753 #ifdef aegis
12754     if (conbufn > 0) return(conbufn);   /* use old count if nonzero */
12755
12756     /* read in more characters */
12757     conbufn = ios_$get(ios_$stdin,
12758               ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
12759     if (st.all != status_$ok) conbufn = 0;
12760     conbufp = conbuf;
12761     return(conbufn);
12762 #else
12763 #ifdef IKSD
12764     if (inserver && !local)
12765       return(in_chk(1,ttyfd));
12766     else
12767 #endif /* IKSD */
12768       return(in_chk(0,0));
12769 #endif /* aegis */
12770 }
12771
12772 /*  C O N I N C  --  Get a character from the console  */
12773 /*
12774   Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
12775   read.  Upon success, returns the character.  Upon failure, returns -1.
12776   A timed read that does not complete within the timeout period returns -2.
12777 */
12778 int
12779 coninc(timo) int timo; {
12780     int n = 0; CHAR ch;
12781     int xx;
12782
12783     if (conbufn > 0) {                  /* If something already buffered */
12784         --conbufn;
12785         return((unsigned)(*conbufp++ & 0xff));
12786     }
12787
12788     errno = 0;                          /* Clear this */
12789 #ifdef IKSD
12790     if (inserver && !local) {
12791         xx = ttinc(timo);
12792         if (xx < 0)
12793           return(ttinctimo ? -2 : -1);
12794         else
12795           return(xx);
12796     }
12797 #endif /* IKSD */
12798
12799 #ifdef aegis                            /* Apollo Aegis only... */
12800     debug(F101,"coninc timo","",timo);
12801     fflush(stdout);
12802     if (conchk() > 0) {
12803         --conbufn;
12804         return((unsigned)(*conbufp++ & 0xff));
12805     }
12806 #endif /* aegis */
12807
12808 #ifdef TTLEBUF
12809     if (
12810 #ifdef IKSD
12811         inserver &&
12812 #endif /* IKSD */
12813         !xlocal
12814         ) {
12815         if (ttpush >= 0) {
12816             debug(F111,"ttinc","ttpush",ttpush);
12817             ch = ttpush;
12818             ttpush = -1;
12819             return(ch);
12820         }
12821         if (le_data) {
12822             if (le_getchar(&ch) > 0) {
12823                 debug(F111,"ttinc LocalEchoInBuf","ch",ch);
12824                 return(ch);
12825             }
12826         }
12827     }
12828 #endif /* TTLEBUF */
12829
12830     if (timo <= 0) {                    /* Untimed, blocking read. */
12831         while (1) {                     /* Keep trying till we get one. */
12832             n = read(0, &ch, 1);        /* Read a character. */
12833             if (n == 0) continue;       /* Shouldn't happen. */
12834             if (n > 0) {                /* If read was successful, */
12835 #ifdef IKSD
12836 #ifdef CK_ENCRYPTION
12837                 debug(F100,"coninc decrypt 1","",0);
12838                 if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12839                   ck_tn_decrypt((char *)&ch,1);
12840 #endif /* CK_ENCRYPTION */
12841 #endif /* IKSD */
12842                 return((unsigned)(ch & 0xff)); /* return the character. */
12843             }
12844
12845 /* Come here if read() returned an error. */
12846
12847             debug(F101, "coninc(0) errno","",errno); /* Log the error. */
12848 #ifndef OXOS
12849 #ifdef SVORPOSIX
12850 #ifdef CIE                             /* CIE Regulus has no EINTR symbol? */
12851 #ifndef EINTR
12852 #define EINTR 4
12853 #endif /* EINTR */
12854 #endif /* CIE */
12855 /*
12856   This routine is used for several different purposes.  In CONNECT mode, it is
12857   used to do an untimed, blocking read from the keyboard in the lower CONNECT
12858   fork.  During local-mode file transfer, it reads a character from the
12859   console to interrupt the file transfer (like A for a status report, X to
12860   cancel a file, etc).  Obviously, we don't want the reads in the latter case
12861   to be blocking, or the file transfer would stop until the user typed
12862   something.  Unfortunately, System V does not allow the console device input
12863   buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
12864   used instead.  During local-mode file transfer, the SIGQUIT signal is armed
12865   and trapped by esctrp(), and this routine pretends to have read the quit
12866   character from the keyboard normally.  But, kludge or no kludge, the read()
12867   issued by this command, under System V only, can fail if a signal -- ANY
12868   signal -- is caught while the read is pending.  This can occur not only when
12869   the user types the quit character, but also during telnet negotiations, when
12870   the lower CONNECT fork signals the upper one about an echoing mode change.
12871   When this happens, we have to post the read() again.  This is apparently not
12872   a problem in BSD-based UNIX versions.
12873 */
12874             if (errno == EINTR)         /* Read interrupted. */
12875               if (conesc)  {            /* If by SIGQUIT, */
12876                  conesc = 0;            /* the conesc variable is set, */
12877                  return(escchr);        /* so return the escape character. */
12878              } else continue;           /* By other signal, try again. */
12879 #else
12880 /*
12881   This might be dangerous, but let's do this on non-System V versions too,
12882   since at least one SunOS 4.1.2 user complains of immediate disconnections
12883   upon first making a TELNET connection.
12884 */
12885             if (errno == EINTR)         /* Read interrupted. */
12886               continue;
12887 #endif /* SVORPOSIX */
12888 #else /* OXOS */
12889             if (errno == EINTR)         /* Read interrupted. */
12890               continue;
12891 #endif /* OXOS */
12892             return(-1);                 /* Error */
12893         }
12894     }
12895 #ifdef DEBUG
12896     if (deblog && timo <= 0) {
12897         debug(F100,"coninc timeout logic error","",0);
12898         timo = 1;
12899     }
12900 #endif /* DEBUG */
12901
12902 /* Timed read... */
12903
12904     saval = signal(SIGALRM,timerh);     /* Set up timeout handler. */
12905     xx = alarm(timo);                   /* Set the alarm. */
12906     debug(F101,"coninc alarm set","",timo);
12907     if (
12908 #ifdef CK_POSIX_SIG
12909         sigsetjmp(sjbuf,1)
12910 #else
12911         setjmp(sjbuf)
12912 #endif /* CK_POSIX_SIG */
12913         )                               /* The read() timed out. */
12914       n = -2;                           /* Code for timeout. */
12915     else
12916       n = read(0, &ch, 1);
12917     ttimoff();                          /* Turn off timer */
12918     if (n > 0) {                        /* Got character OK. */
12919 #ifdef IKSD
12920 #ifdef CK_ENCRYPTION
12921         debug(F100,"coninc decrypt 2","",0);
12922         if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12923           ck_tn_decrypt((char *)&ch,1);
12924 #endif /* CK_ENCRYPTION */
12925 #endif /* IKSD */
12926         return((unsigned)(ch & 0xff));  /* Return it. */
12927     }
12928 /*
12929   read() returned an error.  Same deal as above, but without the loop.
12930 */
12931     debug(F101, "coninc(timo) n","",n);
12932     debug(F101, "coninc(timo) errno","",errno);
12933 #ifndef OXOS
12934 #ifdef SVORPOSIX
12935     if (n == -1 && errno == EINTR && conesc != 0) {
12936         conesc = 0;
12937         return(escchr);                 /* User entered escape character. */
12938     }
12939 #endif /* SVORPOSIX */
12940     if (n == 0 && errno > 0) {          /* It's an error */
12941         return(-1);
12942     }
12943 #endif /* ! OXOS */
12944     return(n);
12945 }
12946
12947 /*  C O N G K S  --  Console Get Keyboard Scancode  */
12948
12949 #ifndef congks
12950 /*
12951   This function needs to be filled in with the various system-dependent
12952   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
12953   keyboard scan code.  Unfortunately there aren't any.
12954 */
12955 int
12956 congks(timo) int timo; {
12957
12958 #ifdef IKSD
12959     if (inserver && !local)
12960       return(ttinc(timo));
12961 #endif /* IKSD */
12962
12963     return(coninc(timo));
12964 }
12965 #endif /* congks */
12966
12967 #ifdef ATT7300
12968
12969 /*  A T T D I A L  --  Dial up the remote system using internal modem
12970  * Purpose: to open and dial a number on the internal modem available on the
12971  * ATT7300 UNIX PC.  Written by Joe Doupnik. Superceeds version written by
12972  * Richard E. Hill, Dickinson, TX. which employed dial(3c).
12973  * Uses information in <sys/phone.h> and our status int attmodem.
12974  */
12975 attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
12976     char *telnum;
12977
12978     attmodem &= ~ISMODEM;                       /* modem not in use yet */
12979                     /* Ensure O_NDELAY is set, else i/o traffic hangs */
12980                     /* We turn this flag off once the dial is complete */
12981     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
12982
12983     /* Condition line, check availability & DATA mode, turn on speaker */
12984     if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
12985         printf("cannot access phone\n");
12986         ttclos(0);
12987         return (-2);
12988     }
12989     ioctl(ttyfd,PIOCGETP,&dialer);      /* get phone dialer parameters */
12990
12991     if (dialer.c_lineparam & VOICE) {   /* phone must be in DATA mode */
12992         printf(" Should not dial with modem in VOICE mode.\n");
12993         printf(" Exit Kermit, switch to DATA and retry call.\n");
12994         ttclos(0);
12995         return (-2);
12996     }
12997 #ifdef ATTTONED                         /* Old way, tone dialing only. */
12998     dialer.c_lineparam = DATA | DTMF;   /* Dial with tones, */
12999     dialer.c_lineparam &= ~PULSE;       /* not with pulses. */
13000 #else
13001     /* Leave current pulse/tone state alone. */
13002     /* But what about DATA?  Add it back if you have trouble. */
13003     /* sys/phone says you get DATA automatically by opening device RDWR */
13004 #endif
13005     dialer.c_waitdialtone = 5;                  /* wait 5 sec for dialtone */
13006 #ifdef COMMENT
13007     dialer.c_feedback = SPEAKERON|NORMSPK|RINGON;  /* control speaker */
13008 #else
13009     /* sys/phone says RINGON used only for incoming voice calls */
13010     dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
13011     dialer.c_feedback |= SPEAKERON|NORMSPK;
13012 #endif
13013     dialer.c_waitflash = 500;                   /* 0.5 sec flash hook */
13014     if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) {   /* set phone parameters */
13015         printf("Cannot set modem characteristics\n");
13016         ttclos(0);
13017         return (-2);
13018     }
13019     ioctl(ttyfd,PIOCRECONN,0);          /* Turns on speaker for pulse */
13020
13021 #ifdef COMMENT
13022     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
13023 line_status:%o feedback:%o\n",
13024     dialer.c_lineparam, dialer.c_waitdialtone,
13025     dialer.c_linestatus, dialer.c_feedback);
13026 #endif
13027
13028     attmodem |= ISMODEM;                        /* modem is now in-use */
13029     sleep(1);
13030     for (telnum = telnbr; *telnum != '\0'; telnum++)    /* dial number */
13031 #ifdef ATTTONED
13032       /* Tone dialing only */
13033       if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13034           perror("Error in dialing");
13035           ttclos(0);
13036           return(-2);
13037       }
13038 #else /* Allow Pulse or Tone dialing */
13039     switch (*telnum) {
13040       case 't': case 'T': case '%':     /* Tone dialing requested */
13041         dialer.c_lineparam |= DTMF;
13042         dialer.c_lineparam &= ~PULSE;
13043         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13044             printf("Cannot set modem to tone dialing\n");
13045             ttclos(0);
13046             return(-2);
13047         }
13048         break;
13049       case 'd': case 'D': case 'p': case 'P': case '^':
13050         dialer.c_lineparam |= PULSE;
13051         dialer.c_lineparam &= ~DTMF;
13052         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13053             printf("Cannot set modem to pulse dialing\n");
13054             ttclos(0);
13055             return(-2);
13056         }
13057         break;
13058       default:
13059         if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13060             perror("Dialing error");
13061             ttclos(0);
13062             return(-2);
13063         }
13064         break;
13065     }
13066 #endif
13067
13068     ioctl(ttyfd,PIOCDIAL,"@");          /* terminator for data call */
13069     do {                                /* wait for modems to Connect */
13070         if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */
13071             perror("Cannot get modems to connect");
13072             ttclos(0);
13073             return(-2);
13074         }
13075     } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
13076     /* Turn off O_NDELAY flag now. */
13077     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
13078     signal(SIGHUP, sighup);             /* hangup on loss of carrier */
13079     return(0);                          /* return success */
13080 }
13081
13082 /*
13083   Offgetty, ongetty functions. These function get the 'getty(1m)' off
13084   and restore it to the indicated line.  Shell's return codes are:
13085     0: Can't do it.  Probably a user logged on.
13086     1: No need.  No getty on that line.
13087     2: Done, you should restore the getty when you're done.
13088   DOGETY System(3), however, returns them as 0, 256, 512, respectively.
13089   Thanks to Kevin O'Gorman, Anarm Software Systems.
13090
13091    getoff.sh looks like:   geton.sh looks like:
13092      setgetty $1 0           setgetty $1 1
13093      err=$?                  exit $?
13094      sleep 2
13095      exit $err
13096 */
13097
13098 /*  O F F G E T T Y  --  Turn off getty(1m) for the communications tty line
13099  * and get status so it can be restarted after the line is hung up.
13100  */
13101 int
13102 offgetty(ttname) char *ttname; {
13103     char temp[30];
13104     while (*ttname != '\0') ttname++;       /* seek terminator of path */
13105     ttname -= 3;                            /* get last 3 chars of name */
13106     sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
13107     return(zsyscmd(temp));
13108 }
13109
13110 /*  O N G E T T Y  --  Turn on getty(1m) for the communications tty line */
13111
13112 int
13113 ongetty(ttname) char *ttname; {
13114     char temp[30];
13115     while (*ttname != '\0') ttname++;       /* comms tty path name */
13116     ttname -= 3;
13117     sprintf(temp,"/usr/bin/geton.sh %s",ttname);
13118     return(zsyscmd(temp));
13119 }
13120 #endif /* ATT7300 */
13121
13122 /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
13123  *
13124  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
13125  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
13126  *  2 = Auto: For "modem direct": The same as "Off".
13127  *            For real modem types: Heed carrier during connect, but ignore
13128  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
13129  *
13130  * As you can see, this setting does not affect dialing, which always ignores
13131  * carrier (unless there is some special exception for some modem type).  It
13132  * does affect ttopen() if it is set before ttopen() is used.  This setting
13133  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
13134  * (or should be) always called before any communications is tried, which
13135  * means that, practically speaking, the effect is immediate.
13136  *
13137  * Of course, nothing of this applies to remote mode (xlocal = 0).
13138  *
13139  * Someone has yet to uncover how to manipulate the carrier in the BSD
13140  * environment (or any non-termio using environment).  Until that time, this
13141  * will simply be a no-op for BSD.
13142  *
13143  * Note that in previous versions, the carrier was most often left unchanged
13144  * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX.  This
13145  * has changed.  Now it is controlled by ttcarr in conjunction with these
13146  * modes.
13147  */
13148 int
13149 ttscarr(carrier) int carrier; {
13150     ttcarr = carrier;
13151     debug(F101, "ttscarr","",ttcarr);
13152     return(ttcarr);
13153 }
13154
13155 /* C A R R C T L  --  Set tty modes for carrier treatment.
13156  *
13157  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
13158  * (actually, there are no bits in sgttyb for that), or performs any other
13159  * operations needed to control this on the current system.  The function does
13160  * not do the actual TCSETA or stty, since often we want to set other bits too
13161  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
13162  *
13163  * We don't know how to do anything like carrier control on non-ATTSV systems,
13164  * except, apparently, ultrix.  See above.  It is also known that this doesn't
13165  * have much effect on a Xenix system.  For Xenix, one should switch back and
13166  * forth between the upper and lower case device files.  Maybe later.
13167  * Presently, Xenix will stick to the mode it was opened with.
13168  *
13169  * carrier: 0 = ignore carrier, 1 = require carrier.
13170  * The current state is saved in curcarr, and checked to save labour.
13171  */
13172 #ifdef SVORPOSIX
13173 int
13174 #ifdef BSD44ORPOSIX
13175 carrctl(ttpar, carrier) struct termios *ttpar; int carrier;
13176 #else /* ATTSV */
13177 carrctl(ttpar, carrier) struct termio *ttpar; int carrier;
13178 #endif /* BSD44ORPOSIX */
13179 /* carrctl */ {
13180     debug(F101, "carrctl","",carrier);
13181     if (carrier)
13182       ttpar->c_cflag &= ~CLOCAL;
13183     else
13184       ttpar->c_cflag |= CLOCAL;
13185     return(0);
13186 }
13187 #else /* Berkeley, V7, et al... */
13188 int
13189 carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
13190     debug(F101, "carrctl","",carrier);
13191     if (carrier == curcarr)
13192       return(0);
13193     curcarr = carrier;
13194 #ifdef ultrix
13195 #ifdef COMMENT
13196 /*
13197   Old code from somebody at DEC that tends to get stuck, time out, etc.
13198 */
13199     if (carrier) {
13200         ioctl(ttyfd, TIOCMODEM, &temp);
13201         ioctl(ttyfd, TIOCHPCL, 0);
13202     } else {
13203         /* (According to the manuals, TIOCNCAR should be preferred */
13204         /* over TIOCNMODEM...) */
13205         ioctl(ttyfd, TIOCNMODEM, &temp);
13206     }
13207 #else
13208 /*
13209   New code from Jamie Watson that, he says, eliminates the problems.
13210 */
13211     if (carrier) {
13212         ioctl(ttyfd, TIOCCAR);
13213         ioctl(ttyfd, TIOCHPCL);
13214     } else {
13215         ioctl(ttyfd, TIOCNCAR);
13216     }
13217 #endif /* COMMENT */
13218 #endif /* ultrix */
13219     return(0);
13220 }
13221 #endif /* SVORPOSIX */
13222
13223
13224 /*  T T G M D M  --  Get modem signals  */
13225 /*
13226  Looks for RS-232 modem signals, and returns those that are on in as its
13227  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
13228  Returns:
13229  -3 Not implemented
13230  -2 if the communication device does not have modem control (e.g. telnet)
13231  -1 on error.
13232  >= 0 on success, with a bit mask containing the modem signals that are on.
13233 */
13234
13235 /*
13236   Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
13237   modem control, namely the TIOCMGET ioctl.
13238 */
13239
13240 #ifdef BSD43
13241 #define K_MDMCTL
13242 #endif /* BSD43 */
13243
13244 #ifdef SUNOS4
13245 #define K_MDMCTL
13246 #endif /* SUNOS4 */
13247
13248 /*
13249   SCO OpenServer R5.0.4.  The TIOCMGET definition is hardwired in because it
13250   is skipped in termio.h when _POSIX_SOURCE is defined.  But _POSIX_SOURCE
13251   must be defined in order to get the high serial speeds that are new to
13252   5.0.4.  However, the regular SCO drivers do not implement TIOCMGET, so the
13253   ioctl() returns -1 with errno 22 (invalid function).  But third-party
13254   drivers, e.g. for Digiboard, do implement it, and so it should work on ports
13255   driven by those drivers.
13256 */
13257 #ifdef SCO_OSR504
13258 #ifndef TIOCMGET
13259 #define TIOCMGET (('t'<<8)|29)
13260 #endif /* TIOCMGET */
13261 #endif /* SCO_OSR504 */
13262
13263 #ifdef CK_SCOV5
13264 /* Because POSIX strictness in <sys/termio.h> won't let us see these. */
13265 #ifndef TIOCM_DTR
13266 #define TIOCM_DTR       0x0002          /* data terminal ready */
13267 #define TIOCM_RTS       0x0004          /* request to send */
13268 #define TIOCM_CTS       0x0020          /* clear to send */
13269 #define TIOCM_CAR       0x0040          /* carrier detect */
13270 #define TIOCM_RNG       0x0080          /* ring */
13271 #define TIOCM_DSR       0x0100          /* data set ready */
13272 #define TIOCM_CD        TIOCM_CAR
13273 #define TIOCM_RI        TIOCM_RNG
13274 #endif /* TIOCM_DTR */
13275 #endif /* CK_SCOV5 */
13276
13277 #ifdef QNX
13278 #define K_MDMCTL
13279 #else
13280 #ifdef TIOCMGET
13281 #define K_MDMCTL
13282 #endif /* TIOCMGET */
13283 #endif /* QNX */
13284 /*
13285   "A serial communication program that can't read modem signals
13286    is like a car without windows."
13287 */
13288 int
13289 ttgmdm() {
13290
13291 #ifdef QNX
13292 #include <sys/qioctl.h>
13293
13294     unsigned long y, mdmbits[2];
13295     int x, z = 0;
13296
13297     if (xlocal && ttyfd < 0)
13298       return(-1);
13299
13300 #ifdef NETCONN
13301     if (netconn) {                      /* Network connection */
13302 #ifdef TN_COMPORT
13303         if (istncomport()) {
13304             gotsigs = 1;
13305             return(tngmdm());
13306         } else
13307 #endif /* TN_COMPORT */
13308           return(-2);                   /* No modem signals */
13309     }
13310 #endif /* NETCONN */
13311
13312 #ifdef NETCMD
13313     if (ttpipe) return(-2);
13314 #endif /* NETCMD */
13315 #ifdef NETPTY
13316     if (ttpty) return(-2);
13317 #endif /* NETPTY */
13318
13319     mdmbits[0] = 0L;
13320     mdmbits[1] = 0L;
13321 /*
13322  * From <sys/qioctl.h>:
13323  *
13324  * SERIAL devices   (all Dev.ser versions)
13325  * 0 : DTR           8 = Data Bits 0  16 - reserved     24 - reserved
13326  * 1 : RTS           9 = Data Bits 1  17 - reserved     25 - reserved
13327  * 2 = Out 1        10 = Stop Bits    18 - reserved     26 - reserved
13328  * 3 = Int Enable   11 = Par Enable   19 - reserved     27 - reserved
13329  * 4 = Loop         12 = Par Even     20 = CTS          28 - reserved
13330  * 5 - reserved     13 = Par Stick    21 = DSR          29 - reserved
13331  * 6 - reserved     14 : Break        22 = RI           30 - reserved
13332  * 7 - reserved     15 = 0            23 = CD           31 - reserved
13333  */
13334     errno = 0;
13335     x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
13336     debug(F101,"ttgmdm qnx_ioctl","",x);
13337     debug(F101,"ttgmdm qnx_ioctl errno","",errno);
13338     if (!x) {
13339         debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
13340         debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
13341         y = mdmbits[0];
13342         if (y & 0x000001L) z |= BM_DTR; /* Bit  0 */
13343         if (y & 0x000002L) z |= BM_RTS; /* Bit  1 */
13344         if (y & 0x100000L) z |= BM_CTS; /* Bit 20 */
13345         if (y & 0x200000L) z |= BM_DSR; /* Bit 21 */
13346         if (y & 0x400000L) z |= BM_RNG; /* Bit 22 */
13347         if (y & 0x800000L) z |= BM_DCD; /* Bit 23 */
13348         debug(F101,"ttgmdm qnx result","",z);
13349         debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
13350         gotsigs = 1;
13351         return(z);
13352     } else return(-1);
13353 #else /* QNX */
13354 #ifdef HPUX                             /* HPUX has its own way */
13355     int x, z;
13356
13357 #ifdef HPUX10                           /* Modem flag word */
13358     mflag y;                            /* mflag typedef'd in <sys/modem.h> */
13359 #else
13360 #ifdef HPUX9
13361     mflag y;
13362 #else
13363 #ifdef HPUX8
13364     mflag y;
13365 #else
13366     unsigned long y;                    /* Not sure about pre-8.0... */
13367 #endif /* HPUX8 */
13368 #endif /* HPUX9 */
13369 #endif /* HPUX10 */
13370
13371     if (xlocal && ttyfd < 0)
13372       return(-1);
13373
13374 #ifdef NETCONN
13375     if (netconn) {                      /* Network connection */
13376 #ifdef TN_COMPORT
13377         if (istncomport()) {
13378             gotsigs = 1;
13379             return(tngmdm());
13380         } else
13381 #endif /* TN_COMPORT */
13382           return(-2);                   /* No modem signals */
13383     }
13384 #endif /* NETCONN */
13385
13386 #ifdef NETCMD
13387     if (ttpipe) return(-2);
13388 #endif /* NETCMD */
13389 #ifdef NETPTY
13390     if (ttpty) return(-2);
13391 #endif /* NETPTY */
13392
13393     if (xlocal)                         /* Get modem signals */
13394       x = ioctl(ttyfd,MCGETA,&y);
13395     else
13396       x = ioctl(0,MCGETA,&y);
13397     if (x < 0) return(-1);
13398     debug(F101,"ttgmdm","",y);
13399
13400     z = 0;                              /* Initialize return value */
13401
13402 /* Now set bits for each modem signal that is reported to be on. */
13403
13404 #ifdef MCTS
13405     /* Clear To Send */
13406     debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
13407     if (y & MCTS) z |= BM_CTS;
13408 #endif
13409 #ifdef MDSR
13410     /* Data Set Ready */
13411     debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
13412     if (y & MDSR) z |= BM_DSR;
13413 #endif
13414 #ifdef MDCD
13415     /* Carrier */
13416     debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
13417     if (y & MDCD) z |= BM_DCD;
13418 #endif
13419 #ifdef MRI
13420     /* Ring Indicate */
13421     debug(F101,"ttgmdm HPUX RI","",y & MRI);
13422     if (y & MRI) z |= BM_RNG;
13423 #endif
13424 #ifdef MDTR
13425     /* Data Terminal Ready */
13426     debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
13427     if (y & MDTR) z |= BM_DTR;
13428 #endif
13429 #ifdef MRTS
13430     /* Request To Send */
13431     debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
13432     if (y & MRTS) z |= BM_RTS;
13433 #endif
13434     gotsigs = 1;
13435     return(z);
13436
13437 #else /* ! HPUX */
13438
13439 #ifdef K_MDMCTL
13440 /*
13441   Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
13442   If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
13443   are needed.
13444 */
13445 #ifndef TIOCMGET
13446 #include <sys/ttycom.h>
13447 #endif /* TIOCMGET */
13448
13449     int x, y, z;
13450
13451     debug(F100,"ttgmdm K_MDMCTL defined","",0);
13452
13453 #ifdef NETCONN
13454     if (netconn) {                      /* Network connection */
13455 #ifdef TN_COMPORT
13456         if (istncomport()) {
13457             gotsigs = 1;
13458             return(tngmdm());
13459         } else
13460 #endif /* TN_COMPORT */
13461           return(-2);                   /* No modem signals */
13462     }
13463 #endif /* NETCONN */
13464
13465 #ifdef NETCMD
13466     if (ttpipe) return(-2);
13467 #endif /* NETCMD */
13468 #ifdef NETPTY
13469     if (ttpty) return(-2);
13470 #endif /* NETPTY */
13471
13472     if (xlocal && ttyfd < 0)
13473       return(-1);
13474
13475     if (xlocal)
13476       x = ioctl(ttyfd,TIOCMGET,&y);     /* Get modem signals. */
13477     else
13478       x = ioctl(0,TIOCMGET,&y);
13479     debug(F101,"ttgmdm TIOCMGET ioctl","",x);
13480     if (x < 0) {
13481         debug(F101,"ttgmdm errno","",errno);
13482         return(-1);
13483     }
13484     debug(F101,"ttgmdm bits","",y);
13485
13486     z = 0;                              /* Initialize return value. */
13487 #ifdef TIOCM_CTS
13488     /* Clear To Send */
13489     if (y & TIOCM_CTS) z |= BM_CTS;
13490     debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS); 
13491 #else
13492     debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
13493 #endif
13494 #ifdef TIOCM_DSR
13495     /* Data Set Ready */
13496     if (y & TIOCM_DSR) z |= BM_DSR;
13497     debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR); 
13498 #else
13499     debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
13500 #endif
13501 #ifdef TIOCM_CAR
13502     /* Carrier */
13503     if (y & TIOCM_CAR) z |= BM_DCD;
13504     debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR); 
13505 #else
13506     debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
13507 #endif
13508 #ifdef TIOCM_RNG
13509     /* Ring Indicate */
13510     if (y & TIOCM_RNG) z |= BM_RNG;
13511     debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG); 
13512 #else
13513     debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
13514 #endif
13515 #ifdef TIOCM_DTR
13516     /* Data Terminal Ready */
13517     if (y & TIOCM_DTR) z |= BM_DTR;
13518     debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR); 
13519 #else
13520     debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
13521 #endif
13522 #ifdef TIOCM_RTS
13523     /* Request To Send */
13524     if (y & TIOCM_RTS) z |= BM_RTS;
13525     debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS); 
13526 #else
13527     debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
13528 #endif
13529     gotsigs = 1;
13530     return(z);
13531
13532 #else /* !K_MDMCTL catch-All */
13533
13534     debug(F100,"ttgmdm K_MDMCTL not defined","",0);
13535 #ifdef TIOCMGET
13536     debug(F100,"ttgmdm TIOCMGET defined","",0);
13537 #else
13538     debug(F100,"ttgmdm TIOCMGET not defined","",0);
13539 #endif /* TIOCMGET */
13540 #ifdef _SVID3
13541     debug(F100,"ttgmdm _SVID3 defined","",0);
13542 #else
13543     debug(F100,"ttgmdm _SVID3 not defined","",0);
13544 #endif /* _SVID3 */
13545
13546 #ifdef NETCONN
13547     if (netconn) {                      /* Network connection */
13548 #ifdef TN_COMPORT
13549         if (istncomport()) {
13550             gotsigs = 1;
13551             return(tngmdm());
13552         } else
13553 #endif /* TN_COMPORT */
13554           return(-2);                   /* No modem signals */
13555     }
13556 #endif /* NETCONN */
13557
13558 #ifdef NETCMD
13559     if (ttpipe) return(-2);
13560 #endif /* NETCMD */
13561 #ifdef NETPTY
13562     if (ttpty) return(-2);
13563 #endif /* NETPTY */
13564
13565     return(-3);                         /* Sorry, I don't know how... */
13566
13567 #endif /* K_MDMCTL */
13568 #endif /* HPUX */
13569 #endif /* QNX */
13570 }
13571
13572 /*  P S U S P E N D  --  Put this process in the background.  */
13573
13574 /*
13575   Call with flag nonzero if suspending is allowed, zero if not allowed.
13576   Returns 0 on apparent success, -1 on failure (flag was zero, or
13577   kill() returned an error code.
13578 */
13579 int
13580 psuspend(flag) int flag; {
13581
13582 #ifdef RTU
13583     extern int rtu_bug;
13584 #endif /* RTU */
13585
13586     if (flag == 0) return(-1);
13587
13588 #ifdef NOJC
13589     return(-1);
13590 #else
13591 #ifdef SIGTSTP
13592 /*
13593   The big question here is whether job control is *really* supported.
13594   There's no way Kermit can know for sure.  The fact that SIGTSTP is
13595   defined does not guarantee the Unix kernel supports it, and the fact
13596   that the Unix kernel supports it doesn't guarantee that the user's
13597   shell (or other process that invoked Kermit) supports it.
13598 */
13599 #ifdef RTU
13600     rtu_bug = 1;
13601 #endif /* RTU */
13602     if (kill(0,SIGSTOP) < 0
13603 #ifdef MIPS
13604 /* Let's try this for MIPS too. */
13605         && kill(getpid(),SIGSTOP) < 0
13606 #endif /* MIPS */
13607         ) {                             /* If job control, suspend the job */
13608         perror("suspend");
13609         debug(F101,"psuspend error","",errno);
13610         return(-1);
13611     }
13612     debug(F100,"psuspend ok","",0);
13613     return(0);
13614 #else
13615     return(-1);
13616 #endif /* SIGTSTP */
13617 #endif /* NOJC */
13618 }
13619
13620 /*
13621   setuid package, by Kristoffer Eriksson, with contributions from Dean
13622   Long and fdc.
13623 */
13624
13625 /* The following is for SCO when CK_ANSILIBS is defined... */
13626 #ifdef M_UNIX
13627 #ifdef CK_ANSILIBS
13628 #ifndef NOGETID_PROTOS
13629 #define NOGETID_PROTOS
13630 #endif /* NOGETID_PROTOS */
13631 #endif /* CK_ANSILIBS */
13632 #endif /* M_UNIX */
13633
13634 #ifndef _POSIX_SOURCE
13635 #ifndef SUNOS4
13636 #ifndef NEXT
13637 #ifndef PS2AIX10
13638 #ifndef sequent
13639 #ifndef HPUX9
13640 #ifndef HPUX10
13641 #ifndef COHERENT
13642 #ifndef NOGETID_PROTOS
13643 _PROTOTYP( UID_T getuid, (void) );
13644 _PROTOTYP( UID_T geteuid, (void) );
13645 _PROTOTYP( UID_T getreuid, (void) );
13646 _PROTOTYP( UID_T getgid, (void) );
13647 _PROTOTYP( UID_T getegid, (void) );
13648 _PROTOTYP( UID_T getregid, (void) );
13649 #endif /* NOGETID_PROTOS */
13650 #else
13651 _PROTOTYP( UID_T getreuid, (void) );
13652 _PROTOTYP( UID_T getregid, (void) );
13653 #endif /* COHERENT */
13654 #endif /* HPUX10 */
13655 #endif /* HPUX9 */
13656 #endif /* sequent */
13657 #endif /* PS2AIX10 */
13658 #endif /* NEXT */
13659 #endif /* SUNOS4 */
13660 #endif /* _POSIX_SOURCE */
13661
13662 /*
13663 Subject: Set-user-id
13664 To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
13665 Date: Sat, 21 Apr 90 4:48:25 MES
13666 From: Kristoffer Eriksson <ske@pkmab.se>
13667
13668 This is a set of functions to be used in programs that may be run set-user-id
13669 and/or set-group-id. They handle both the case where the program is not run
13670 with such privileges (nothing special happens then), and the case where one
13671 or both of these set-id modes are used.  The program is made to run with the
13672 user's real user and group ids most of the time, except for when more
13673 privileges are needed.  Don't set-user-id to "root".
13674
13675 This works on System V and POSIX.  In BSD, it depends on the
13676 "saved-set-user-id" feature.
13677 */
13678
13679 #define UID_ROOT 0                      /* Root user and group ids */
13680 #define GID_ROOT 0
13681
13682 /*
13683   The following code defines the symbol SETEUID for UNIX systems based
13684   on BSD4.4 (either -Encumbered or -Lite).  This program will then use
13685   seteuid() and setegid() instead of setuid() and setgid(), which still
13686   don't allow arbitrary switching.  It also avoids setreuid() and
13687   setregid(), which are included in BSD4.4 for compatibility only, are
13688   insecure, and print warnings to stderr under at least one system (NetBSD
13689   1.0).  Note that POSIX systems should still use setuid() and setgid();
13690   the seteuid() and setegid() functions are BSD4.4 extensions to the
13691   POSIX model.  Mike Long <mike.long@analog.com>, 8/94.
13692 */
13693 #ifdef BSD44
13694 #define SETEUID
13695 #endif /* BSD44 */
13696
13697 /*
13698   The following construction automatically defines the symbol SETREUID for
13699   UNIX versions based on Berkeley Unix 4.2 and 4.3.  If this symbol is
13700   defined, then this program will use getreuid() and getregid() calls in
13701   preference to getuid() and getgid(), which in Berkeley-based Unixes do
13702   not allow arbitrary switching back and forth of real & effective uid.
13703   This construction also allows -DSETREUID to be put on the cc command line
13704   for any system that has and wants to use setre[ug]id().  It also prevents
13705   automatic definition of SETREUID if -DNOSETREU is included on the cc
13706   command line (or otherwise defined).
13707 */
13708 #ifdef FT18                             /* None of this for Fortune. */
13709 #define NOSETREU
13710 #endif /* FT18 */
13711
13712 #ifdef ANYBSD
13713 #ifndef BSD29
13714 #ifndef BSD41
13715 #ifndef SETREUID
13716 #ifndef NOSETREU
13717 #ifndef SETEUID
13718 #define SETREUID
13719 #endif /* SETEUID */
13720 #endif /* NOSETREU */
13721 #endif /* SETREUID */
13722 #endif /* !BSD41 */
13723 #endif /* !BSD29 */
13724 #endif /* ANYBSD */
13725
13726 /* Variables for user and group IDs. */
13727
13728 static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
13729 static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
13730
13731
13732 /* P R I V _ I N I  --  Initialize privileges package  */
13733
13734 /* Called as early as possible in a set-uid or set-gid program to store the
13735  * set-to uid and/or gid and step down to the users real uid and gid. The
13736  * stored id's can be temporarily restored (allowed in System V) during
13737  * operations that require the privilege.  Most of the time, the program
13738  * should execute in unpriviliged state, to not impose any security threat.
13739  *
13740  * Note: Don't forget that access() always uses the real id:s to determine
13741  * file access, even with privileges restored.
13742  *
13743  * Returns an error mask, with error values or:ed together:
13744  *   1 if setuid() fails,
13745  *   2 if setgid() fails, and
13746  *   4 if the program is set-user-id to "root", which can't be handled.
13747  *
13748  * Only the return value 0 indicates real success. In case of failure,
13749  * those privileges that could be reduced have been, at least, but the
13750  * program should be aborted none-the-less.
13751  *
13752  * Also note that these functions do not expect the uid or gid to change
13753  * without their knowing. It may work if it is only done temporarily, but
13754  * you're on your own.
13755  */
13756 int
13757 priv_ini() {
13758     int err = 0;
13759
13760 #ifndef HAVE_LOCKDEV
13761
13762     /* Save real ID:s. */
13763     realuid = getuid();
13764     realgid = getgid();
13765
13766     /* Save current effective ID:s, those set to at program exec. */
13767     privuid = geteuid();
13768     privgid = getegid();
13769
13770     /* If running set-uid, go down to real uid, otherwise remember that
13771      * no privileged uid is available.
13772      *
13773      * Exceptions:
13774      *
13775      * 1) If the real uid is already "root" and the set-uid uid (the
13776      * initial effective uid) is not "root", then we would have trouble
13777      * if we went "down" to "root" here, and then temporarily back to the
13778      * set-uid uid (not "root") and then again tried to become "root". I
13779      * think the "saved set-uid" is lost when changing uid from effective
13780      * uid "root", which changes all uid, not only the effective uid. But
13781      * in this situation, we can simply go to "root" and stay there all
13782      * the time. That should give sufficient privilege (understatement!),
13783      * and give the right uids for subprocesses.
13784      *
13785      * 2) If the set-uid (the initial effective uid) is "root", and we
13786      * change uid to the real uid, we can't change it back to "root" when
13787      * we need the privilege, for the same reason as in 1). Thus, we can't
13788      * handle programs that are set-user-id to "root" at all. The program
13789      * should be stopped.  Use some other uid.  "root" is probably too
13790      * privileged for such things, anyway. (The uid is reverted to the
13791      * real uid until termination.)
13792      *
13793      * These two exceptions have the effect that the "root" uid will never
13794      * be one of the two uids that are being switched between, which also
13795      * means we don't have to check for such cases in the switching
13796      * functions.
13797      *
13798      * Note that exception 1) is handled by these routines (by constantly
13799      * running with uid "root", while exception 2) is a serious error, and
13800      * is not provided for at all in the switching functions.
13801      */
13802     if (realuid == privuid)
13803         privuid = (UID_T) -1;           /* Not running set-user-id. */
13804
13805     /* If running set-gid, go down to real gid, otherwise remember that
13806      * no privileged gid is available.
13807      *
13808      * There are no exception like there is for the user id, since there
13809      * is no group id that is privileged in the manner of uid "root".
13810      * There could be equivalent problems for group changing if the
13811      * program sometimes ran with uid "root" and sometimes not, but
13812      * that is already avoided as explained above.
13813      *
13814      * Thus we can expect always to be able to switch to the "saved set-
13815      * gid" when we want, and back to the real gid again. You may also
13816      * draw the conclusion that set-gid provides for fewer hassles than
13817      * set-uid.
13818      */
13819
13820 #ifdef SUIDDEBUG
13821     fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
13822     fprintf(stderr,"realuid=%d\n",realuid);
13823     fprintf(stderr,"privuid=%d\n",privuid);
13824 #endif /* SUIDDEBUG */
13825
13826     if (realgid == privgid)             /* If not running set-user-id, */
13827       privgid = (GID_T) -1;             /*  remember it this way. */
13828
13829     err = priv_off();                   /* Turn off setuid privilege. */
13830
13831     if (privuid == UID_ROOT)            /* If setuid to root, */
13832       err |= 4;                         /* return this error. */
13833
13834     if (realuid == UID_ROOT) {          /* If real id is root, */
13835         privuid = (UID_T) -1;           /* stay root at all times. */
13836 #ifdef ATT7300
13837         /* If Kermit installed SUID uucp and user is running as root */
13838         err &= ~1;                      /* System V R0 does not save UID */
13839 #endif /* ATT7300 */
13840     }
13841 #endif /* HAVE_LOCKDEV */
13842     return(err);
13843 }
13844
13845
13846 /* Macros for hiding the differences in UID/GID setting between various Unix
13847  * systems. These macros should always be called with both the privileged ID
13848  * and the non-privileged ID. The one in the second argument, will become the
13849  * effective ID. The one in the first argument will be retained for later
13850  * retrieval.
13851  */
13852 #ifdef SETREUID
13853 #ifdef SAVEDUID
13854 /* On BSD systems with the saved-UID feature, we just juggle the effective
13855  * UID back and forth, and leave the real UID at its true value.  The kernel
13856  * allows switching to both the current real UID, the effective UID, and the
13857  * UID which the program is set-UID to.  The saved set-UID always holds the
13858  * privileged UID for us, and the real UID will always be the non-privileged,
13859  * and we can freely choose one of them for the effective UID at any time.
13860  */
13861 #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
13862 #define switchgid(hidden,active) setregid( (GID_T) -1, active)
13863
13864 #else   /* SETREUID,!SAVEDUID */
13865
13866 /* On systems with setreXid() but without the saved-UID feature, notably
13867  * BSD 4.2, we swap the real and effective UIDs each time.  It's
13868  * the effective UID that we are interested in, but we have to retain the
13869  * unused UID somewhere to enable us to restore it later, and we do this
13870  * in the real UID.  The kernel only allows switching to either the current
13871  * real or the effective UID, unless you're "root".
13872  */
13873 #define switchuid(hidden,active)        setreuid(hidden,active)
13874 #define switchgid(hidden,active)        setregid(hidden,active)
13875 #endif
13876
13877 #else /* !SETREUID, !SAVEDUID */
13878
13879 #ifdef SETEUID
13880 /*
13881   BSD 4.4 works similarly to System V and POSIX (see below), but uses
13882   seteXid() instead of setXid() to change effective IDs.  In addition, the
13883   seteXid() functions work the same for "root" as for other users.
13884 */
13885 #define switchuid(hidden,active)        seteuid(active)
13886 #define switchgid(hidden,active)        setegid(active)
13887
13888 #else /* !SETEUID */
13889
13890 /* On System V and POSIX, the only thing we can change is the effective UID
13891  * (unless the current effective UID is "root", but initsuid() avoids that for
13892  * us).  The kernel allows switching to the current real UID or to the saved
13893  * set-UID.  These are always set to the non-privileged UID and the privileged
13894  * UID, respectively, and we only change the effective UID.  This breaks if
13895  * the current effective UID is "root", though, because for "root" setuid/gid
13896  * becomes more powerful, which is why initsuid() treats "root" specially.
13897  * Note: That special treatment maybe could be ignored for BSD?  Note: For
13898  * systems that don't fit any of these four cases, we simply can't support
13899  * set-UID.
13900  */
13901 #define switchuid(hidden,active)        setuid(active)
13902 #define switchgid(hidden,active)        setgid(active)
13903
13904 #endif /* SETEUID */
13905 #endif /* SETREUID */
13906
13907
13908 /* P R I V _ O N  --  Turn on the setuid and/or setgid */
13909
13910 /* Go to the privileged uid (gid) that the program is set-user-id
13911  * (set-group-id) to, unless the program is running unprivileged.
13912  * If setuid() fails, return value will be 1. If getuid() fails it
13913  * will be 2.  Return immediately after first failure, and the function
13914  * tries to restore any partial work done.  Returns 0 on success.
13915  * Group id is changed first, since it is less serious than user id.
13916  */
13917 int
13918 priv_on() {
13919 #ifndef HAVE_LOCKDEV
13920     if (privgid != (GID_T) -1)
13921       if (switchgid(realgid,privgid))
13922         return(2);
13923
13924     if (privuid != (UID_T) -1)
13925       if (switchuid(realuid,privuid)) {
13926           if (privgid != (GID_T) -1)
13927             switchgid(privgid,realgid);
13928           return(1);
13929       }
13930 #endif /* HAVE_LOCKDEV */
13931     return(0);
13932 }
13933
13934 /* P R I V _ O F F  --  Turn on the real uid and gid */
13935
13936 /* Return to the unprivileged uid (gid) after an temporary visit to
13937  * privileged status, unless the program is running without set-user-id
13938  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
13939  * in setgid() or:ed together. The functions tries to return both uid
13940  * and gid to unprivileged state, regardless of errors. Returns 0 on
13941  * success.
13942  */
13943 int
13944 priv_off() {
13945     int err = 0;
13946 #ifndef HAVE_LOCKDEV
13947     if (privuid != (UID_T) -1)
13948        if (switchuid(privuid,realuid))
13949           err |= 1;
13950
13951     if (privgid != (GID_T) -1)
13952        if (switchgid(privgid,realgid))
13953         err |= 2;
13954 #endif /* HAVE_LOCKDEV */
13955     return(err);
13956 }
13957
13958 /* Turn off privilege permanently.  No going back.  This is necessary before
13959  * a fork() on BSD43 machines that don't save the setUID or setGID, because
13960  * we swap the real and effective ids, and we don't want to let the forked
13961  * process swap them again and get the privilege back. It will work on other
13962  * machines too, such that you can rely on its effect always being the same,
13963  * for instance, even when you're in priv_on() state when this is called.
13964  * (Well, that part about "permanent" is on System V only true if you follow
13965  * this with a call to exec(), but that's what we want it for anyway.)
13966  * Added by Dean Long -- dlong@midgard.ucsc.edu
13967  */
13968 int
13969 priv_can() {
13970 #ifndef HAVE_LOCKDEV
13971 #ifdef SETREUID
13972     int err = 0;
13973     if (privuid != (UID_T) -1)
13974        if (setreuid(realuid,realuid))
13975           err |= 1;
13976
13977     if (privgid != (GID_T) -1)
13978         if (setregid(realgid,realgid))
13979           err |= 2;
13980
13981     return(err);
13982
13983 #else
13984 #ifdef SETEUID
13985     int err = 0;
13986     if (privuid != (UID_T) -1)
13987         if (setuid(realuid)) {
13988             debug(F101,"setuid failed","",errno);
13989             err |= 1;
13990             debug(F101,"ruid","",getuid());
13991             debug(F101,"euid","",geteuid());
13992         }
13993     debug(F101,"setuid","",realuid);
13994     if (privgid != (GID_T) -1)
13995         if (setgid(realgid)) {
13996             debug(F101,"setgid failed","",errno);
13997             err |= 2;
13998             debug(F101,"rgid","",getgid());
13999             debug(F101,"egid","",getegid());
14000         }
14001     debug(F101,"setgid","",realgid);
14002     return(err);
14003 #else
14004     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
14005     return(priv_off());
14006 #endif /* SETEUID */
14007 #endif /* SETREUID */
14008 #else
14009     return(0);
14010 #endif /* HAVE_LOCKDEV */
14011 }
14012
14013 /* P R I V _ O P N  --  For opening protected files or devices. */
14014
14015 int
14016 priv_opn(name, modes) char *name; int modes; {
14017     int x;
14018     priv_on();                          /* Turn privileges on */
14019     debug(F111,"priv_opn",name,modes);
14020     errno = 0;
14021     x = open(name, modes);              /* Try to open the device */
14022     debug(F101,"priv_opn result","",x);
14023     debug(F101,"priv_opn errno","",errno);
14024     priv_off();                         /* Turn privileges off */
14025     return(x);                          /* Return open's return code */
14026 }
14027
14028 /*  P R I V _ C H K  --  Check privileges.  */
14029
14030 /*  Try to turn them off.  If turning them off did not succeed, cancel them */
14031
14032 int
14033 priv_chk() {
14034     int x, y = 0;
14035     x = priv_off();                     /* Turn off privs. */
14036     if (x != 0 || getuid() == privuid || geteuid() == privuid)
14037       y = priv_can();
14038     if (x != 0 || getgid() == privgid || getegid() == privgid)
14039       y = y | priv_can();
14040     return(y);
14041 }
14042
14043 UID_T
14044 real_uid() {
14045     return(realuid);
14046 }
14047
14048 VOID
14049 ttimoff() {                             /* Turn off any timer interrupts */
14050     /* int xx; */
14051 /*
14052   As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
14053   SIG_DFL (to catch alarms, or if there is no handler, to exit).  This is to
14054   cure (mask, really) a deeper problem with stray alarms that occurs on some
14055   systems, possibly having to do with sleep(), that caused core dumps.  It
14056   should be OK to do this, because no code in this module uses nested alarms.
14057   (But we still have to watch out for SCRIPT and DIAL...)
14058 */
14059     /* xx = */ alarm(0);
14060     /* debug(F101,"ttimoff alarm","",xx); */
14061     if (saval) {                        /* Restore any previous */
14062         signal(SIGALRM,saval);          /* alarm handler. */
14063         /* debug(F101,"ttimoff alarm restoring saval","",saval); */
14064         saval = NULL;
14065     } else {
14066         signal(SIGALRM,SIG_IGN);        /* Used to be SIG_DFL */
14067         /* debug(F100,"ttimoff alarm SIG_IGN","",0); */
14068     }
14069 }
14070
14071
14072 int
14073 tt_is_secure() {          /* Tells whether the current connection is secure */
14074
14075     if (ttyfd == -1)
14076       return(0);
14077
14078     if (0
14079 #ifdef SSHBUILTIN
14080         || IS_SSH()
14081 #endif /* SSHBUILTIN */
14082 #ifdef CK_ENCRYPTION
14083         || ck_tn_encrypting() && ck_tn_decrypting()
14084 #endif /* CK_ENCRYPTION */
14085 #ifdef CK_SSL
14086         || tls_active_flag || ssl_active_flag
14087 #endif /* CK_SSL */
14088 #ifdef RLOGCODE
14089 #ifdef CK_KERBEROS
14090 #ifdef CK_ENCRYPTION
14091         || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
14092 #endif /* CK_ENCRYPTION */
14093 #endif /* CK_KERBEROS */
14094 #endif /* RLOGCODE */
14095         )
14096       return(1);
14097     return(0);
14098 }
14099
14100 #ifdef CK_REDIR
14101   
14102 /* External protocol handler parameters from ckuus3.c */
14103 extern int exp_handler, exp_stderr, exp_timo;
14104
14105 #ifdef SELECT
14106 #ifdef NETPTY
14107
14108 /* The right size is 24576 */
14109
14110 #ifndef PTY_PBUF_SIZE                   /* Size of buffer to read from pty */
14111 #define PTY_PBUF_SIZE 24576             /* and write to net. */
14112 #endif  /* PTY_PBUF_SIZE */
14113
14114 #ifndef PTY_TBUF_SIZE                   /* Size of buffer to read from net */
14115 #define PTY_TBUF_SIZE 24576             /* and write to pty. */
14116 #endif  /* PTY_TBUF_SIZE */
14117
14118 #ifdef O_NDELAY                         /* Whether to use nonblocking */
14119 #ifndef PTY_NO_NDELAY                   /* reads on the pseudoterminal */
14120 #ifndef PTY_USE_NDELAY
14121 #define PTY_USE_NDELAY
14122 #endif  /* PTY_USE_NDELAY */
14123 #endif  /* PTY_NO_NDELAY */
14124 #endif  /* O_NDELAY */
14125
14126 #ifndef HAVE_OPENPTY
14127 #ifndef USE_CKUPTY_C
14128 #define USE_CKUPTY_C
14129 #endif /* USE_CKUPTY_C */
14130 #endif /* HAVE_OPENPTY */
14131
14132 VOID
14133 pty_make_raw(fd) int fd; {
14134     int x = -23, i;
14135
14136 #ifdef BSD44ORPOSIX                     /* POSIX */
14137     struct termios tp;
14138 #else
14139 #ifdef ATTSV                            /* AT&T UNIX */
14140 #ifdef CK_ANSIC
14141     struct termio tp = {0};
14142 #else
14143     struct termio tp;
14144 #endif  /* CK_ANSIC */
14145 #else
14146     struct sgttyb tp;                   /* Traditional */
14147 #endif /* ATTSV */
14148 #endif /* BSD44ORPOSIX */
14149
14150     debug(F101,"pty_make_raw fd","",fd);
14151     errno = 0;
14152
14153 #ifdef BSD44ORPOSIX                     /* POSIX */
14154     x = tcgetattr(fd,&tp);
14155     debug(F101,"pty_make_raw tcgetattr","",x);
14156 #else
14157 #ifdef ATTSV                            /* AT&T UNIX */
14158     x = ioctl(fd,TCGETA,&tp);
14159     debug(F101,"pty_make_raw TCGETA ioctl","",x);
14160 #else
14161     x = gtty(fd,&tp);
14162     debug(F101,"pty_make_raw ttty","",x);
14163 #endif /* ATTSV */
14164 #endif /* BSD44ORPOSIX */
14165     debug(F101,"pty_make_raw GET errno","",errno);
14166
14167 #ifdef USE_CFMAKERAW
14168     errno = 0;
14169     cfmakeraw(&tp);
14170     debug(F101,"pty_make_raw cfmakeraw errno","",errno);
14171 #else  /* USE_CFMAKERAW */
14172
14173 #ifdef COMMENT
14174
14175 /* This very simple version recommended by Serg Iakolev doesn't work */
14176
14177     tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
14178     tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
14179     tp.c_cflag &= ~(CSIZE|PARENB);
14180     tp.c_cflag |= CS8;
14181     tp.c_oflag &= ~(OPOST);
14182     tp.c_cc[VMIN] = 1;
14183     tp.c_cc[VTIME] = 0;
14184
14185     debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS);
14186     debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag);
14187     debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag);
14188     debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag);
14189     debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag);
14190
14191 #else
14192 #ifdef COMMENT
14193 /*
14194   In this version we unset everything and then set only the
14195   bits we know we need.
14196 */
14197     /* iflags */
14198     tp.c_iflag = 0L;
14199     tp.c_iflag |= IGNBRK;
14200 #ifdef IMAXBEL
14201     tp.c_iflag |= IMAXBEL;
14202 #endif /* IMAXBEL */
14203
14204     /* oflags */
14205     tp.c_oflag = 0L;
14206
14207     /* lflags */
14208     tp.c_lflag = 0L;
14209 #ifdef NOKERNINFO
14210     tp.c_lflag |= NOKERNINFO;
14211 #endif  /* NOKERNINFO */
14212
14213     /* cflags */
14214     tp.c_cflag = 0L;
14215     tp.c_cflag |= CS8|CREAD;
14216
14217     for (i = 0; i < NCCS; i++) {        /* No special characters */
14218         tp.c_cc[i] = 0;
14219     }
14220 #ifdef VMIN
14221     tp.c_cc[VMIN] = 1;                  /* But always wait for input */
14222 #endif  /* VMIN */
14223     debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS);
14224     debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag);
14225     debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag);
14226     debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag);
14227     debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag);
14228
14229 #else  /* COMMENT */
14230 /*
14231   In this version we set or unset every single flag explicitly.  It works a
14232   bit better than the simple version just above, but it's still far from
14233   adequate.
14234 */
14235     /* iflags */
14236     tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
14237     tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF);
14238     tp.c_iflag |= IGNBRK;
14239 #ifdef IMAXBEL
14240 #ifdef COMMENT
14241     tp.c_iflag |= IMAXBEL;
14242 #else
14243     tp.c_iflag &= ~IMAXBEL;
14244 #endif /* COMMENT */
14245 #endif /* IMAXBEL */
14246 #ifdef IUCLC
14247     tp.c_iflag &= ~IUCLC;
14248 #endif /* IUCLC */
14249
14250     /* oflags */
14251 #ifdef BSDLY
14252     tp.c_oflag &= ~BSDLY;
14253 #endif /* BSDLY */
14254 #ifdef CRDLY
14255     tp.c_oflag &= ~CRDLY;
14256 #endif /* CRDLY */
14257 #ifdef FFDLY
14258     tp.c_oflag &= ~FFDLY;
14259 #endif /* FFDLY */
14260 #ifdef NLDLY
14261     tp.c_oflag &= ~NLDLY;
14262 #endif /* NLDLY */
14263 #ifdef TABDLY
14264     tp.c_oflag &= ~TABDLY;
14265 #endif /* TABDLY */
14266 #ifdef VTDLY
14267     tp.c_oflag &= ~VTDLY;
14268 #endif /* VTDLY */
14269 #ifdef OFDEL
14270     tp.c_oflag &= ~OFDEL;
14271 #endif /* OFDEL */
14272 #ifdef OFILL
14273     tp.c_oflag &= ~OFILL;
14274 #endif /* OFILL */
14275 #ifdef OLCUC
14276     tp.c_oflag &= ~OLCUC;
14277 #endif /* OLCUC */
14278 #ifdef CMSPAR
14279     tp.c_oflag &= ~CMSPAR;
14280 #endif /* CMSPAR */
14281     tp.c_oflag &= ~OPOST;
14282 #ifdef OXTABS
14283     tp.c_oflag &= ~OXTABS;
14284 #endif /* OXTABS */
14285 #ifdef COMMENT
14286 #ifdef ONOCR
14287     tp.c_oflag &= ~ONOCR;               /* Maybe should be |=? */
14288     tp.c_oflag |= ONOCR;                /* makes no difference either way */
14289 #endif /* ONOCR */
14290 #endif /* COMMENT */
14291 #ifdef ONOEOT
14292     tp.c_oflag &= ~ONOEOT;
14293 #endif /* ONOEOT */
14294 #ifdef ONLRET
14295     tp.c_oflag &= ~ONLRET;
14296 #endif /* ONLRET */
14297 #ifdef ONLCR
14298     tp.c_oflag &= ~ONLCR;
14299 #endif /* ONLCR */
14300 #ifdef OCRNL
14301     tp.c_oflag &= ~OCRNL;
14302 #endif /* OCRNL */
14303
14304     /* lflags */
14305     tp.c_lflag &= ~ECHO;
14306 #ifdef ECHOE
14307     tp.c_lflag &= ~ECHOE;
14308 #endif /* ECHOE */
14309 #ifdef ECHONL
14310     tp.c_lflag &= ~ECHONL;
14311 #endif /* ECHONL */
14312 #ifdef ECHOPRT
14313     tp.c_lflag &= ~ECHOPRT;
14314 #endif /* ECHOPRT */
14315 #ifdef ECHOKE
14316     tp.c_lflag &= ~ECHOKE;
14317 #endif /* ECHOKE */
14318 #ifdef ECHOCTL
14319     tp.c_lflag &= ~ECHOCTL;
14320 #endif /* ECHOCTL */
14321 #ifdef XCASE
14322     tp.c_lflag &= ~XCASE;
14323 #endif /* XCASE */
14324 #ifdef ALTWERASE
14325     tp.c_lflag &= ~ALTWERASE;
14326 #endif /* ALTWERASE */
14327 #ifdef EXTPROC
14328     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC);
14329 #else
14330     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
14331 #endif  /* EXTPROC */
14332 #ifdef NOKERNINFO
14333     tp.c_lflag |= NOKERNINFO;
14334 #endif  /* NOKERNINFO */
14335 #ifndef COMMENT
14336     tp.c_lflag &= ~NOFLSH;              /* TRY IT THE OTHER WAY? */
14337 #else
14338     tp.c_lflag |= NOFLSH;               /* No, this way is worse */
14339 #endif /* COMMENT */
14340
14341     /* cflags */
14342     tp.c_cflag &= ~(CSIZE|PARENB|PARODD);
14343     tp.c_cflag |= CS8|CREAD;
14344
14345 #ifdef MDMBUF
14346     tp.c_cflag &= ~(MDMBUF);
14347 #else
14348 #ifdef CCAR_OFLOW
14349     tp.c_cflag &= ~(CCAR_OFLOW);        /* two names for the same thing */
14350 #endif /* CCAR_OFLOW */
14351 #endif /* MDMBUF */
14352
14353 #ifdef CCTS_OFLOW
14354     tp.c_cflag &= ~(CCTS_OFLOW);
14355 #endif /* CCTS_OFLOW */
14356 #ifdef CDSR_OFLOW
14357     tp.c_cflag &= ~(CDSR_OFLOW);
14358 #endif /* CDSR_OFLOW */
14359 #ifdef CDTR_IFLOW
14360     tp.c_cflag &= ~(CDTR_IFLOW);
14361 #endif /* CDTR_IFLOW */
14362 #ifdef CRTS_IFLOW
14363     tp.c_cflag &= ~(CRTS_IFLOW);
14364 #endif /* CRTS_IFLOW */
14365 #ifdef CRTSXOFF
14366     tp.c_cflag &= ~(CRTSXOFF);
14367 #endif /* CRTSXOFF */
14368 #ifdef CRTSCTS
14369     tp.c_cflag &= ~(CRTSCTS);
14370 #endif /* CRTSCTS */
14371 #ifdef CLOCAL
14372     tp.c_cflag &= ~(CLOCAL);
14373 #endif /* CLOCAL */
14374 #ifdef CSTOPB
14375     tp.c_cflag &= ~(CSTOPB);
14376 #endif /* CSTOPB */
14377 #ifdef HUPCL
14378     tp.c_cflag &= ~(HUPCL);
14379 #endif /* HUPCL */
14380
14381     for (i = 0; i < NCCS; i++) {        /* No special characters */
14382         tp.c_cc[i] = 0;
14383     }
14384 #ifdef VMIN
14385     tp.c_cc[VMIN] = 1;                  /* But always wait for input */
14386 #endif  /* VMIN */
14387     debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS);
14388     debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag);
14389     debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag);
14390     debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag);
14391     debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag);
14392 #endif /* COMMENT */
14393 #endif /* COMMENT */
14394
14395     errno = 0;
14396 #ifdef BSD44ORPOSIX                     /* POSIX */
14397     x = tcsetattr(fd,TCSANOW,&tp);
14398     debug(F101,"pty_make_raw tcsetattr","",x);
14399 #else
14400 #ifdef ATTSV                            /* AT&T UNIX */
14401     x = ioctl(fd,TCSETA,&tp);
14402     debug(F101,"pty_make_raw ioctl","",x);
14403 #else
14404     x = stty(fd,&tp);                   /* Traditional */
14405     debug(F101,"pty_make_raw stty","",x);
14406 #endif /* ATTSV */
14407 #endif /* BSD44ORPOSIX */
14408     debug(F101,"pty_make_raw errno","",errno);
14409
14410 #endif /* __NetBSD__ */
14411 }
14412
14413 static int
14414 pty_chk(fd) int fd; {
14415     int x, n = 0;
14416     errno = 0;
14417 #ifdef FIONREAD
14418     x = ioctl(fd, FIONREAD, &n);        /* BSD and most others */
14419     ckmakmsg(msgbuf,500,
14420              "pty_chk ioctl FIONREAD errno=",
14421              ckitoa(errno),
14422              " count=",
14423              ckitoa(n));
14424     debug(F100,msgbuf,"",0);
14425 #else
14426 #ifdef RDCHK
14427     n = rdchk(fd);
14428     debug(F101,"pty_chk rdchk","",n);
14429 #else
14430     n = 1;
14431 #endif  /* RDCHK */
14432 #endif  /* FIONREAD */
14433     return((n > -1) ? n : 0);
14434 }
14435
14436 static int
14437 pty_get_status(fd,pid) int fd; PID_T pid; {
14438     int x, status = -1;
14439     PID_T w;
14440
14441     debug(F101,"pty_get_status fd","",fd);
14442     debug(F101,"pty_get_status pid","",pid);
14443
14444     if (pexitstat > -1)
14445       return(pexitstat);
14446
14447 #ifdef COMMENT
14448     /* Not only unnecessary but harmful */
14449     errno = 0;
14450     x = kill(pty_fork_pid,0);
14451     debug(F101,"pty_get_status kill value","",x);
14452     debug(F101,"pty_get_status kill errno","",errno);
14453     if (x > -1 && errno != ESRCH)
14454       return(-1);                       /* Fork still there */
14455     /* Fork seems to be gone */
14456 #endif  /* COMMENT */
14457
14458     errno = 0;
14459     x = waitpid(pty_fork_pid,&status,WNOHANG);
14460     debug(F111,"pty_get_status waitpid",ckitoa(errno),x);
14461     if (x <= 0 && errno == 0) {
14462         debug(F101,"pty_get_status waitpid return","",-1);
14463         return(-1);
14464     }
14465     if (x > 0) {
14466         if (x != pty_fork_pid)
14467           debug(F101,
14468                 "pty_get_status waitpid pid doesn't match","",pty_fork_pid); 
14469         debug(F101,"pty_get_status waitpid status","",status);
14470         debug(F101,"pty_get_status waitpid errno","",errno);
14471         if (WIFEXITED(status)) {
14472             debug(F100,"pty_get_status WIFEXITED","",0);
14473             status = WEXITSTATUS(status);
14474             debug(F101,"pty_get_status fork exit status","",status);
14475 #ifdef COMMENT
14476             end_pty();
14477 #endif  /* COMMENT */
14478             close(fd);
14479             pexitstat = status;
14480         } else {
14481             debug(F100,"pty_get_status waitpid unexpected status","",0);
14482         }
14483     }
14484     debug(F101,"pty_get_status return status","",status);
14485     return(status);
14486 }
14487
14488 /* t t p t y c m d  --  Run command on pty and forward to net */
14489
14490 /*
14491   Needed for running external protocols on secure connections.
14492   For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet
14493   connection, and then needs to transfer a file with Zmodem, which is
14494   an external program, this routine reads Zmodem's output, encrypts it,
14495   and then forwards it out the connection, and reads the encrypted data
14496   stream coming in from the connection, decrypts it, and forwards it to
14497   Zmodem.
14498
14499   Works like a TCP/IP port forwarder except one end is a pty rather
14500   than a socket, which introduces some complications:
14501
14502    . On most platforms, select() always indicates the output side of
14503      the pty has characters waiting to be read, even when it doesn't,
14504      even when the pty process has already exited.
14505
14506    . Nonblocking reads must be used on the pty, because there is no
14507      way on certain platforms (e.g. NetBSD) to find out how many characters
14508      are available to be read (the FIONREAD ioctl always says 0).  The code
14509      also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not
14510      defined, or if PTY_NO_NDELAY is defined), but on some platforms this can
14511      result in single-byte reads and writes (NetBSD again).
14512
14513    . Testing for "EOF" on the pty is problematic.  select() never gives
14514      any indication.  After the pty process has exited and the fork has
14515      disappeared, read() can still return with 0 bytes read but without an
14516      error (NetBSD); no known test on the pty file descriptor will indicate
14517      that it is no longer valid.  The process ID of the pty fork can be
14518      tested on some platforms (NetBSD, luckily) but not others (Solaris,
14519      Linux).
14520
14521   On the network side, we use ttinc() and ttoc(), which, for network 
14522   connections, handle any active security methods.
14523
14524   Call with s = command.
14525   Returns 0 on failure, 1 on success.
14526   fdc - December 2006 - August 2007.
14527
14528   NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are
14529   defined in the header files, which should be true of every recent Unix
14530   platform.  If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when
14531   building C-Kermit:
14532
14533     touch ckutio.c
14534     make platformname KFLAGS=-DPTY_NO_NODELAY
14535 */
14536 static int have_pty = 0;                /* Do we have a pty? */
14537
14538 static SIGTYP (*save_sigchld)() = NULL; /* For catching SIGCHLD */
14539
14540 static VOID
14541 sigchld_handler(sig) int sig; {
14542     have_pty = 0;                       /* We don't have a pty */
14543 #ifdef DEBUG
14544     if (save_sigchld) {
14545         (VOID) signal(SIGCHLD,save_sigchld);
14546         save_sigchld = NULL;
14547     }
14548     if (deblog) {
14549         debug(F100,"**************","",0);
14550         debug(F100,"SIGCHLD caught","",0);
14551         debug(F100,"**************","",0);
14552     }
14553 #endif  /* DEBUG */
14554 }
14555 #define HAVE_IAC 1
14556 #define HAVE_CR  2
14557
14558 int
14559 ttptycmd(s) char *s; {
14560     CHAR tbuf[PTY_TBUF_SIZE];           /* Read from net, write to pty */
14561     int tbuf_avail = 0;                 /* Pointers for tbuf */
14562     int tbuf_written = 0;
14563     static int in_state = 0;            /* For TELNET IAC and NVT in */
14564     static int out_prev = 0;            /* Simpler scheme for out */
14565
14566     CHAR pbuf[PTY_PBUF_SIZE];           /* Read from pty, write to net */
14567     CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */
14568     int pbuf_avail = 0;                 /* Pointers for pbuf */
14569     int pbuf_written = 0;
14570
14571     int ptyfd = -1;                     /* Pty file descriptor */
14572     int have_net = 0;                   /* We have a network connection */
14573     int pty_err = 0;                    /* Got error on pty */
14574     int net_err = 0;                    /* Got error on net */
14575     int status = -1;                    /* Pty process exit status */
14576     int rc = 0;                         /* Our return code */
14577
14578     int x1 = 0, x2 = 0;                 /* Workers... */
14579     int c, n, m, t, x;                  /* Workers */
14580
14581     long seconds_to_wait = 0L;          /* select() timeout */
14582     struct timeval tv, *tv2;            /* For select() */
14583 #ifdef INTSELECT
14584     int in, out, err;                   /* For select() */
14585 #else
14586     fd_set in, out, err;
14587 #endif /* INTSELECT */
14588     int nfds = 0;                       /* For select() */
14589
14590     int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */
14591     int read_net_bytes = 0;             /* Stats */
14592     int write_net_bytes = 0;            /* Stats */
14593     int read_pty_bytes = 0;             /* Stats */
14594     int write_pty_bytes = 0;            /* Stats */
14595     int is_tn = 0;                      /* TELNET protocol is active */
14596
14597     int masterfd = -1;
14598     int slavefd = -1;
14599 #ifndef USE_CKUPTY_C
14600     struct termios term;
14601     struct winsize twin;
14602     struct stringarray * q;
14603     char ** args = NULL;
14604 #endif /* USE_CKUPTY_C */
14605
14606     in_state = 0;                       /* No previous character yet */
14607
14608     if (ttyfd == -1) {
14609         printf("?Sorry, communication channel is not open\n");
14610         return(0);
14611     } else {
14612         have_net = 1;
14613     }
14614     if (nopush) {
14615         debug(F100,"ttptycmd fail: nopush","",0);
14616         return(0);
14617     }
14618     if (!s) s = "";                     /* Defense de bogus arguments */
14619     if (!*s) return(0);
14620     pexitstat = -1;                     /* Fork process exit status */
14621
14622 #ifdef TNCODE
14623     is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */
14624             (!xlocal && sstelnet);
14625 #endif /* TNCODE */
14626
14627     debug(F110,"ttptycmd command",s,0);
14628     debug(F101,"ttptycmd ttyfd","",ttyfd);
14629     debug(F101,"ttptycmd is_tn","",is_tn);
14630     debug(F101,"ttptycmd ckermit pid","",getpid());
14631
14632 #ifdef USE_CKUPTY_C
14633     /* Call ckupty.c module to get and set up the pty fork */
14634     /* fc 1 == "run an external protocol" */
14635     debug(F100,"ttptycmd using ckupty.c","",0);
14636     if (do_pty(&ptyfd,s,1) < 0) {       /* Start the command on a pty */
14637         debug(F100,"ttptycmd do_pty fails","",0);
14638         return(0);
14639     }
14640     masterfd = ptyfd;
14641     pty_master_fd = ptyfd;
14642 #ifdef COMMENT
14643     slavefd = pty_slave_fd;             /* This is not visible to us */
14644 #endif /* COMMENT */
14645     debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd);
14646     debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd);
14647     debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid);
14648 #ifndef SOLARIS
14649     /* "ioctl inappropriate on device" for pty master */
14650     pty_make_raw(masterfd);
14651 #endif /* SOLARIS */
14652
14653 #else /* USE_CKUPTY_C */
14654
14655     debug(F100,"ttptycmd OPENPTY","",0);
14656     if (tcgetattr(0, &term) == -1) {    /* Get controlling terminal's modes */
14657         perror("tcgetattr");
14658         return(0);
14659     }
14660     if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */
14661         perror("ioctl TIOCGWINSZ");
14662         return(0);
14663     }
14664     if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) {
14665         debug(F101,"ttptycmd openpty failed errno","",errno);
14666         perror("opentpy");
14667         return(0);
14668     }
14669     debug(F101,"ttptycmd openpty masterfd","",masterfd);
14670     debug(F101,"ttptycmd openpty slavefd","",slavefd);
14671     pty_master_fd = masterfd;
14672     pty_slave_fd = slavefd;
14673     debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd);
14674
14675     /* Put pty master in raw mode but let forked app control the slave */
14676     pty_make_raw(masterfd);
14677
14678 #ifdef COMMENT
14679 #ifdef TIOCREMOTE
14680     /* TIOCREMOTE,0 = disable all termio processing */
14681     x = ioctl(masterfd, TIOCREMOTE, 1);
14682     debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno);
14683 #endif  /* TIOCREMOTE */
14684 #ifdef TIOCTTY
14685     /* TIOCTTY,0 = disable all termio processing */
14686     x = ioctl(masterfd, TIOCTTY, 0);
14687     debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno);
14688 #endif  /* TIOCTTY */
14689 #endif /* COMMENT */
14690
14691     have_pty = 1;                       /* We have an open pty */
14692     save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */
14693
14694     pty_fork_pid = fork();              /* Make fork for external protocol */
14695     debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid);
14696     if (pty_fork_pid == -1) {
14697         perror("fork");
14698         return(0);
14699     } else if (pty_fork_pid == 0) {     /* In new fork */
14700         int x;
14701         debug(F101,"ttptycmd new fork pid","",getpid());
14702         close(masterfd);                /* Slave quarters no masters allowed */
14703         x = setsid();
14704         debug(F101,"ttptycmd new fork setsid","",x);
14705         if (x == -1) {
14706             perror("ttptycmd setsid");
14707             exit(1);
14708         }
14709         signal(SIGINT,SIG_IGN);         /* Let upper fork catch this */
14710         
14711 #ifdef COMMENT
14712 #ifdef TIOCSCTTY
14713         /* Make pty the controlling terminal for the process */
14714         /* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */
14715         x = ioctl(slavefd, TIOCSCTTY, NULL);
14716         debug(F101,"ttptycmd TIOCSCTTY","",x);
14717 #endif  /* TIOCSCTTY */
14718 #endif  /* COMMENT */
14719
14720         /* Initialize slave pty modes and size to those of our terminal */
14721         if (tcsetattr(slavefd, TCSANOW, &term) == -1) {
14722             perror("ttptycmd tcsetattr");
14723             exit(1);
14724         }
14725         if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) {
14726             perror("ttptycmd ioctl");
14727             exit(1);
14728         }
14729 #ifdef COMMENT
14730 #ifdef TIOCNOTTY
14731         /* Disassociate this process from its terminal */
14732         /* THIS HAS NO EFFECT */
14733         x = ioctl(slavefd, TIOCNOTTY, NULL);
14734         debug(F101,"ttptycmd TIOCNOTTY","",x);
14735 #endif  /* TIOCNOTTY */
14736 #endif  /* COMMENT */
14737
14738 #ifdef COMMENT
14739 #ifdef SIGTTOU  
14740         /* Ignore terminal output interrupts */
14741         /* THIS HAS NO EFFECT */
14742         debug(F100,"ttptycmd ignoring SIGTTOU","",0);
14743         signal(SIGTTOU, SIG_IGN);
14744 #endif  /* SIGTTOU */
14745 #ifdef SIGTSTP  
14746         /* Ignore terminal output interrupts */
14747         /* THIS HAS NO EFFECT */
14748         debug(F100,"ttptycmd ignoring SIGTSTP","",0);
14749         signal(SIGTSTP, SIG_IGN);
14750 #endif  /* SIGTSTP */
14751 #endif  /* COMMENT */
14752
14753         pty_make_raw(slavefd);          /* Put it in rawmode */
14754
14755         errno = 0;
14756         if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO ||
14757             dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) {
14758             debug(F101,"ttptycmd new fork dup2 error","",errno);
14759             perror("ttptycmd dup2");
14760             exit(1);
14761         }
14762         debug(F100,"ttptycmd new fork dup2 ok","",0);
14763
14764         /* Parse external protocol command line */
14765         q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
14766         if (!q) {
14767             debug(F100,"ttptycmd cksplit failed","",0);
14768             exit(1);
14769         } else {
14770             int i, n;
14771             debug(F100,"ttptycmd cksplit ok","",0);
14772             n = q->a_size;
14773             args = q->a_head + 1;
14774             for (i = 0; i <= n; i++) {
14775                 if (!args[i]) {
14776                     break;
14777                 } else {
14778                     /* sometimes cksplit() doesn't terminate the list */
14779                     if ((i == n) && args[i]) {
14780                         if ((int)strlen(args[i]) == 0)
14781                           makestr(&(args[i]),NULL);
14782                     }
14783                 }
14784             }       
14785         }
14786 #ifdef COMMENT
14787 /*
14788   Putting the slave pty in rawmode should not be necessary because the
14789   external protocol program is supposed to do that itself.  Yet doing this
14790   here cuts down on Zmodem binary-file transmission errors by 30-50% but
14791   still doesn't eliminate them.
14792 */
14793         pty_make_raw(STDIN_FILENO);
14794         pty_make_raw(STDOUT_FILENO);
14795 #endif /* COMMENT */
14796
14797         debug(F100,"ttptycmd execvp'ing external protocol","",0);
14798         execvp(args[0],args);
14799         perror("execvp failed");
14800         debug(F101,"ttptycmd execvp failed","",errno);
14801         close(slavefd);
14802         exit(1);
14803     } 
14804     /* (there are better ways to do this...) */
14805     msleep(1000);                 /* Make parent wait for child to be ready */
14806     ptyfd = masterfd;                   /* We talk to the master */
14807
14808 #endif /* USE_CKUPTY_C */
14809
14810     debug(F101,"ttptycmd ptyfd","",ptyfd);
14811     if (ptyfd < 0) {
14812         printf("?Failure to get pty\n");
14813         return(-9);
14814     }
14815     have_pty = 1;             /* We have an open pty or we wouldn't he here */
14816
14817     debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE);
14818     debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE);
14819
14820 #ifdef PTY_USE_NDELAY
14821     /* 
14822        NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications
14823        on the pty, we don't need nonblocking reads.  Performance of either
14824        method seems to be about the same, so use whatever works.
14825     */
14826     errno = 0;
14827     x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY);
14828     ckmakmsg(msgbuf,500,
14829              "ttptycmd set O_NDELAY errno=",
14830              ckitoa(errno),
14831              " fcntl=",
14832              ckitoa(x));
14833     debug(F100,msgbuf,"",0);
14834 #endif /* PTY_USE_NDELAY */
14835
14836 #ifdef COMMENT
14837 /* Not necessary, the protocol module already did this */
14838
14839 #ifdef USE_CFMAKERAW
14840     if (tcgetattr(ttyfd, &term) > -1) {
14841         cfmakeraw(&term);
14842         debug(F101,"ttptycmd net cfmakeraw errno","",errno);
14843         x tcsetattr(ttyfd, TCSANOW, &term);
14844         debug(F101,"ttptycmd net tcsetattr","",x);
14845         debug(F101,"ttptycmd net tcsetattr","",errno);
14846     }
14847 #else
14848     if (local)                          /* Put network connection in */
14849       ttpkt(ttspeed,ttflow,ttprty);     /* "packet mode". */
14850     else
14851       conbin((char)escchr);             /* OR... pty_make_raw(0) */
14852 #endif /* USE_CFMAKERAW */
14853 #endif /* COMMENT */
14854
14855 #ifdef TNCODE
14856     if (is_tn) {
14857       debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY));
14858       debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY));
14859     }
14860 #endif /* TNCODE */
14861
14862     debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait);
14863
14864     while (have_pty || have_net) {
14865         FD_ZERO(&in);                   /* Initialize select() structs */
14866         FD_ZERO(&out);
14867         FD_ZERO(&err);                  /* (not used because useless) */
14868         nfds = -1;
14869
14870         debug(F101,"ttptycmd loop top have_pty","",have_pty);
14871         debug(F101,"ttptycmd loop top have_net","",have_net);
14872
14873         /* Pty is open and we have room to read from it? */
14874         if (have_pty && pbuf_avail < PTY_PBUF_SIZE) {
14875             debug(F100,"ttptycmd FD_SET ptyfd in","",0);
14876             FD_SET(ptyfd, &in);
14877             nfds = ptyfd;
14878         }
14879         /* Network is open and we have room to read from it? */
14880         if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) {
14881             debug(F100,"ttptycmd FD_SET ttyfd in","",0);
14882             FD_SET(ttyfd, &in);
14883             if (ttyfd > nfds) nfds = ttyfd;
14884         }
14885         /* Pty is open and we have stuff to write to it? */
14886         if (have_pty && tbuf_avail - tbuf_written > 0) {
14887             debug(F100,"ttptycmd FD_SET ptyfd out","",0);
14888             FD_SET (ptyfd, &out);
14889             if (ptyfd > nfds) nfds = ptyfd;
14890         }
14891         /* Net is open and we have stuff to write to it? */
14892         debug(F101,"ttptycmd pbuf_avail-pbuf_written","",
14893               pbuf_avail - pbuf_written);
14894         if (have_net && pbuf_avail - pbuf_written > 0) {
14895             debug(F100,"ttptycmd FD_SET ttyfd out","",0);
14896             FD_SET (ttyfd, &out);
14897             if (ttyfd > nfds) nfds = ttyfd;
14898         }
14899         /* We don't use err because it's not really for errors, */
14900         /* but for out of band data on the TCP socket, which, if it is */
14901         /* to be handled at all, is handled in the tt*() routines */
14902
14903         nfds++;                         /* 0-based to 1-based */
14904         debug(F101,"ttptycmd nfds","",nfds);
14905         if (!nfds) {
14906             debug(F100,"ttptycmd NO FDs set for select","",0);
14907             if (have_pty) {
14908                 /* This is not right -- sleeping won't accomplish anything */
14909                 debug(F101,"ttptycmd msleep","",100);
14910                 msleep(100);        
14911             } else {
14912                 debug(F100,"ttptycmd no pty - quitting loop","",0);
14913                 break;
14914             }
14915         }
14916         errno = 0;
14917
14918         if (seconds_to_wait > 0L) {     /* Timeout in case nothing happens */
14919             tv.tv_sec = seconds_to_wait; /* for a long time */
14920             tv.tv_usec = 0L;            
14921             tv2 = &tv;
14922         } else {
14923             tv2 = NULL;
14924         }
14925         x = select(nfds, &in, &out, NULL, tv2);
14926         debug(F101,"ttptycmd select","",x);
14927         if (x < 0) {
14928             if (errno == EINTR)
14929               continue;
14930             debug(F101,"ttptycmd select error","",errno);
14931             break;
14932         }
14933         if (x == 0) {
14934             debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait); 
14935             if (have_pty) {
14936                 status = pty_get_status(ptyfd,pty_fork_pid);
14937                 debug(F101,"ttptycmd pty_get_status A","",status);
14938                 if (status > -1) pexitstat = status;
14939                 have_pty = 0;
14940             }
14941             break;
14942         }
14943         /* We want to handle any pending writes first to make room */
14944         /* for new incoming. */
14945
14946         if (FD_ISSET(ttyfd, &out)) {    /* Can write to net? */
14947             CHAR * s;
14948             s = pbuf + pbuf_written;    /* Current spot for sending */
14949 #ifdef TNCODE
14950             if (is_tn) {                /* ttol() doesn't double IACs */
14951                 CHAR c;                 /* Rewrite string with IACs doubled */
14952                 int i;
14953                 s = pbuf + pbuf_written; /* Source */
14954                 x = 0;                   /* Count */
14955                 for (i = 0; i < pbuf_avail - pbuf_written; i++) {
14956                     c = s[i];           /* Next character */
14957                     if (c == IAC) {     /* If it's IAC */
14958                         dbuf[x++] = c;  /* put another one */
14959                         debug(F000,">>> QUOTED IAC","",c);
14960                     } else if (c != 0x0a && out_prev == 0x0d) { /* Bare CR */
14961                         if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */
14962                             c = 0x00;
14963                             dbuf[x++] = c;
14964                             debug(F000,">>> CR-NUL","",c);
14965                         }                       
14966                     }
14967                     dbuf[x++] = c;      /* Copy and count it */
14968                     debug(F000,">>> char",ckitoa(in_state),c);
14969                     out_prev = c;
14970                 }
14971                 s = dbuf;               /* New source */
14972             } else
14973 #endif /* TNCODE */
14974               x = pbuf_avail - pbuf_written; /* How much to send */
14975
14976             debug(F101,"ttptycmd bytes to send","",x);
14977             x = ttol(s, x);
14978             debug(F101,">>> ttol","",x);
14979             if (x < 0) {
14980                 net_err++;
14981                 debug(F111,"ttptycmd ttol error",ckitoa(x),errno);
14982                 x = 0;
14983             }
14984             write_net_bytes += x;
14985             pbuf_written += x;
14986         }
14987         if (FD_ISSET(ptyfd, &out)) {    /* Can write to pty? */
14988             debug(F100,"ttptycmd FD_ISSET ptyfd out","",0);
14989             errno = 0;
14990 #ifndef COMMENT
14991             x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written);
14992 #else
14993             /* Byte loop to rule out data overruns in the pty */
14994             /* (it makes no difference) */
14995             {
14996                 char *p = tbuf+tbuf_written;
14997                 int n = tbuf_avail - tbuf_written;
14998                 for (x = 0; x < n; x++) {
14999                     msleep(10);
15000                     if (write(ptyfd,&(p[x]),1) < 0)
15001                       break;
15002                 }
15003             }
15004 #endif /* COMMENT */
15005             debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x);
15006             if (x > 0) {
15007                 tbuf_written += x;
15008                 write_pty_bytes += x;
15009             } else {
15010                 x = 0;
15011                 pty_err++;
15012                 if (pexitstat < 0) {
15013                     status = pty_get_status(ptyfd,pty_fork_pid);
15014                     debug(F101,"ttptycmd pty_get_status B","",status);
15015                     if (status > -1) pexitstat = status;
15016                     have_pty = 0;
15017                 }
15018                 debug(F100,"ttptycmd +++ ptyfd write error","",0);
15019             }
15020         }
15021         if (FD_ISSET(ttyfd, &in)) {     /* Can read from net? */
15022             tset++;
15023             debug(F100,"ttptycmd FD_ISSET ttyfd in","",0);
15024             n = in_chk(1,ttyfd);
15025             debug(F101,"ttptycmd in_chk(ttyfd)","",n); 
15026             if (n < 0 || ttyfd == -1) {
15027                 debug(F101,"ttptycmd +++ ttyfd errno","",errno);
15028                 net_err++;
15029             } else if (n > 0) {
15030                 if (n > PTY_TBUF_SIZE - tbuf_avail)
15031                   n = PTY_TBUF_SIZE - tbuf_avail;
15032                 debug(F101,"ttptycmd net read size adjusted","",n); 
15033                 if (xlocal && netconn) {
15034                     /*
15035                       We have to use a byte loop here because ttxin()
15036                       does not decrypt or, for that matter, handle Telnet.
15037                     */
15038                     int c;
15039                     CHAR * p;
15040                     p = tbuf + tbuf_avail;
15041                     for (x = 0; x < n; x++) {
15042                         if ((c = ttinc(0)) < 0)
15043                           break;
15044                         if (!is_tn) {   /* Not Telnet - keep all bytes */
15045                             *p++ = (CHAR)c;
15046                             debug(F000,"<<< char","",c);
15047 #ifdef TNCODE
15048                         } else {        /* Telnet - must handle IAC and NVT */
15049                             debug(F000,"<<< char",ckitoa(in_state),c);
15050                             switch (c) {
15051                               case 0x00: /* NUL */
15052                                 if (in_state == HAVE_CR) {
15053                                     debug(F000,"<<< SKIP","",c);
15054                                 } else {
15055                                     *p++ = c;
15056                                     debug(F000,"<<< Keep","",c);
15057                                 }
15058                                 in_state = 0;
15059                                 break;
15060                               case 0x0d: /* CR */
15061                                 if (!TELOPT_U(TELOPT_BINARY))
15062                                   in_state = HAVE_CR;
15063                                 *p++ = c;
15064                                 debug(F000,"<<< Keep","",c);
15065                                 break;
15066 #ifdef COMMENT
15067                               case 0x0f: /* Ctrl-O */
15068                               case 0x16: /* Ctrl-V */
15069                                 *p++ = 0x16;
15070                                 *p++ = c;
15071                                 debug(F000,"<<< QUOT","",c);
15072                                 break;
15073 #endif /* COMMENT */
15074                               case 0xff: /* IAC */
15075                                 if (in_state == HAVE_IAC) {
15076                                     debug(F000,"<<< KEEP","",c);
15077                                     *p++ = c;
15078                                     in_state = 0;
15079                                 } else {
15080                                     debug(F000,"<<< SKIP","",c);
15081                                     in_state = HAVE_IAC;
15082                                 }
15083                                 break;
15084                               default:  /* All others */
15085                                 if (in_state == HAVE_IAC) {
15086 #ifdef COMMENT
15087 /*
15088   tn_doop() will consume an unknown number of bytes and we'll overshoot
15089   the for-loop.  The only Telnet command I've ever seen arrive here is
15090   a Data Mark, which comes when the remote protocol exits and the remote
15091   job returns to its shell prompt.  On the assumption it's a 1-byte command,
15092   we don't write out the IAC or the command, and we clear the state.  If
15093   we called tn_doop() we'd have no way of knowing how many bytes it took
15094   from the input stream.
15095 */
15096                                     int xx;
15097                                     xx = tn_doop((CHAR)c,duplex,ttinc);
15098                                     debug(F111,"<<< DOOP",ckctoa(c),xx);
15099 #else
15100                                     debug(F101,"<<< DOOP","",c);
15101 #endif  /* COMMENT */
15102                                     in_state = 0;
15103                                 } else {
15104                                     *p++ = c;
15105                                     debug(F000,"<<< keep","",c);
15106                                     in_state = 0;
15107                                 }
15108                             }
15109 #endif  /* TNCODE */
15110                         }
15111                     }
15112                     ckmakmsg(msgbuf,500,
15113                              "ttptycmd read net [ttinc loop] errno=",
15114                              ckitoa(errno),
15115                              " count=",
15116                              ckitoa(x));
15117                     debug(F100,msgbuf,"",0);
15118                 } else {
15119                     x = ttxin(n,tbuf+tbuf_avail);
15120                     debug(F101,"ttptycmd ttxin x","",x); 
15121                 }
15122
15123                 if (x < 0) {
15124                     debug(F101,"ttptycmd read net error","",x);
15125                     net_err++;
15126                 }
15127                 tbuf_avail += x;
15128                 read_net_bytes += x;
15129             }
15130
15131         } else
15132           tnotset++;
15133
15134         if (FD_ISSET(ptyfd, &in)) {     /* Read from pty? */
15135             pset++;
15136             debug(F100,"ttptycmd FD_ISSET ptyfd in","",0);
15137 #ifdef PTY_USE_NDELAY
15138             n = PTY_PBUF_SIZE;
15139 #else
15140             /*
15141               This does not work on nonblocking channels
15142               on certain platforms such as NetBSD.
15143             */
15144             n = pty_chk(ptyfd);
15145 #endif /* PTY_USE_NDELAY */
15146             debug(F101,"ttptycmd pty_chk() n","",n); 
15147
15148             if (n < 0)
15149               n = 0;
15150             if (n > 0) {
15151                 if (n > PTY_PBUF_SIZE - pbuf_avail)
15152                   n = PTY_PBUF_SIZE - pbuf_avail;
15153                 debug(F101,"ttptycmd pty read size adjusted","",n); 
15154                 errno = 0;
15155                 x = read(ptyfd,pbuf+pbuf_avail,n);
15156 #ifdef DEBUG
15157                 if (deblog) {
15158                     ckmakmsg(msgbuf,500,
15159                              "ttptycmd read pty errno=",
15160                              ckitoa(errno),
15161                              " count=",
15162                              ckitoa(x));
15163                     debug(F100,msgbuf,"",0);
15164                 }
15165 #endif  /* DEBUG */
15166
15167                 if (x < 0 && errno == EAGAIN)
15168                   x = 0;
15169
15170                 if (x < 0) {            /* This works on Solaris and Linux */
15171                     pty_err++;          /* but not NetBSD */
15172                     debug(F100,"TERMINATION TEST A","",0);
15173 #ifdef COMMENT
15174                     if (errno == EIO)
15175                       rc = 1;
15176 #endif  /* COMMENT */
15177                     if (pexitstat < 0) {
15178                         status = pty_get_status(ptyfd,pty_fork_pid);
15179                         debug(F101,"ttptycmd pty_get_status C","",status);
15180                         if (status > -1) pexitstat = status;
15181                     }
15182                     have_pty = 0;
15183                     x = 0;
15184                 }
15185                 if (x == 0 && !pty_err) { /* This works on NetBSD but */
15186                     debug(F100,"TERMINATION TEST B","",0);
15187                     status = pexitstat > -1 ? pexitstat :
15188                         pty_get_status(ptyfd,pty_fork_pid);
15189                     debug(F101,"ttptycmd pty_get_status D","",status);
15190                     if (status > -1) {
15191                         pexitstat = status;
15192                         pty_err++;
15193                         have_pty = 0;
15194                     } else {            /* Select() lied */
15195                         pty_err = 0;    /* pty still there but has nothing */
15196                         msleep(100);    /* sleep a bit */
15197                     }
15198                     x = 0;
15199                 } 
15200                 /* Hopefully the next two are no longer needed... */
15201                 if (!pty_err && (
15202 #ifndef PTY_USE_NDELAY
15203                     x < 1 || errno
15204 #else
15205                     errno != 0 && errno != EAGAIN
15206 #endif /* PTY_USE_NDELAY */
15207                     )) {
15208                     debug(F100,"TERMINATION TEST C","",0);
15209                     pty_err++;
15210                     debug(F101,"ttptycmd SET pty_err","",pty_err);
15211                     if (errno == EIO)   /* errno == EIO is like EOF */
15212                       rc = 1;
15213                     if (x < 0)
15214                       x = 0;
15215                 }
15216 #ifdef COMMENT
15217 #ifdef DEBUG
15218                 if (deblog) {
15219                     pbuf[pbuf_avail + x] = '\0';
15220                     debug(F111,"ttptycmd added to pty buffer",
15221                           pbuf+pbuf_avail,x);
15222                 }
15223 #endif  /* DEBUG */
15224 #endif  /* COMMENT */
15225                 pbuf_avail += x;
15226                 read_pty_bytes += x;
15227             } else {                    /* n == 0 with blocking reads */
15228                 debug(F100,
15229                       "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN",
15230                       "",0);
15231             }
15232         } else
15233           pnotset++;
15234
15235         /* If writes have caught up to reads, reset the buffers */
15236
15237         if (pbuf_written == pbuf_avail)
15238           pbuf_written = pbuf_avail = 0;
15239         if (tbuf_written == tbuf_avail)
15240           tbuf_written = tbuf_avail = 0;
15241
15242         /* See if we can exit */
15243
15244         x1 = pbuf_avail - pbuf_written; 
15245         x2 = tbuf_avail - tbuf_written;
15246
15247         debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err);
15248         debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1);
15249         debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2);
15250         debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc);
15251         debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status);
15252         debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat);
15253
15254         if (net_err) {                  /* Net error? */
15255             debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err);
15256             if (have_net) {
15257                 if (local) {
15258                     ttclos(0);
15259                     printf("?Connection closed\n");
15260                 }
15261                 have_net = 0;
15262             }
15263             debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1);
15264             if (x1 == 0)
15265               break;
15266         }
15267         if (pty_err) {                  /* Pty error? */
15268             if (have_pty) {
15269                 if (pexitstat < 0) {            
15270                     status = pty_get_status(ptyfd,pty_fork_pid);
15271                     debug(F101,"ttptycmd pty_get_status E","",status);
15272                     if (status > -1) pexitstat = status;
15273                 }
15274                 have_pty = 0;
15275             }
15276             if (x1 == 0 && x2 == 0) {   /* If buffers are caught up */
15277                 rc = 1;                 /* set preliminary return to success */
15278                 debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc);
15279                 break;                  /* and exit the loop */
15280             }
15281         }
15282     }
15283     debug(F101,"ttptycmd +++ have_pty","",have_pty);
15284     if (have_pty) {                     /* In case select() failed */
15285 #ifdef USE_CKUPTY_C
15286         end_pty();
15287         close(ptyfd);
15288 #else
15289         close(slavefd);
15290         close(masterfd);
15291 #endif /* USE_CKUPTY_C */
15292     }
15293     pty_master_fd = -1;
15294     debug(F101,"ttptycmd +++ pexitstat","",pexitstat);
15295     if (pexitstat < 0) {                /* Try one last time to get status */
15296         status = pty_get_status(ptyfd,pty_fork_pid);
15297         debug(F101,"ttptycmd pty_get_status F","",status);
15298         if (status > -1) pexitstat = status;
15299     }
15300     debug(F101,"ttptycmd +++ final pexitstat","",pexitstat);
15301     if (deblog) {                       /* Stats for debug log */
15302         debug(F101,"ttptycmd +++ pset   ","",pset);
15303         debug(F101,"ttptycmd +++ pnotset","",pnotset);
15304         debug(F101,"ttptycmd +++ tset   ","",tset);
15305         debug(F101,"ttptycmd +++ tnotset","",tnotset);
15306
15307         debug(F101,"ttptycmd +++  read_pty_bytes","",read_pty_bytes);
15308         debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes);
15309         debug(F101,"ttptycmd +++  read_net_bytes","",read_net_bytes);
15310         debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes);
15311     }
15312 /*
15313   If we got the external protocol's exit status from waitpid(), we use that
15314   to set our return code.  If not, we fall back on whatever rc was previously
15315   set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise.
15316 */
15317     if (save_sigchld) {                 /* Restore this if we changed it */
15318         (VOID) signal(SIGCHLD,save_sigchld);
15319         save_sigchld = NULL;
15320     }
15321     msleep(500);
15322     x = kill(pty_fork_pid,SIGHUP);      /* In case it's still there */
15323     pty_fork_pid = -1;
15324     debug(F101,"ttptycmd fork kill SIGHUP","",x);
15325     if (pexitstat > -1)
15326       rc = (pexitstat == 0 ? 1 : 0);
15327     debug(F101,"ttptycmd +++ rc","",rc);
15328     if (!local) {                       /* If in remote mode */
15329         conres();                       /* restore console to CBREAK mode */
15330         concb((char)escchr);
15331     }
15332     return(rc);
15333 }
15334 #endif  /* NETPTY */
15335 #endif  /* SELECT */
15336
15337 /* T T R U N C M D  --  Redirect an external command over the connection. */
15338
15339 /*
15340   TTRUNCMD is the routine that was originally used for running external
15341   protocols.  It is very simple and works fine provided (a) the connection
15342   is not encrypted, and (b) the external protocol uses standard i/o
15343   (file descriptors 0 and 1) for file transfer.
15344 */
15345
15346 int
15347 ttruncmd(s) char *s; {
15348     PID_T pid;                          /* pid of lower fork */
15349     int wstat;                          /* for wait() */
15350     int x;
15351     int statusp;
15352
15353     if (ttyfd == -1) {
15354         printf("?Sorry, device is not open\n");
15355         return(0);
15356     }
15357     if (nopush) {
15358         debug(F100,"ttruncmd fail: nopush","",0);
15359         return(0);
15360     }
15361
15362 #ifdef NETPTY
15363 /***************
15364   It might also be necessary to use the pty routine for other reasons,
15365   e.g. because the external program does not use stdio.
15366 */
15367 #ifdef NETCONN
15368 /*
15369   If we have a network connection we use a different routine because
15370   (a) if the connection is encrypted, the mechanism used here can't deal
15371   with it; and (b) it won't handle any network protocols either, e.g.
15372   Telnet, Rlogin, K5 U-to-U, etc.  However, this routine works much
15373   better (faster, more transparent) on serial connections and when
15374   C-Kermit is in remote mode (i.e. is on the far end).
15375 */
15376     /* For testing always use this */
15377     if (netconn)
15378       return(ttptycmd(s));
15379 #endif /* NETCONN */
15380
15381 /***************/
15382 #else  /* NETPTY */
15383     if (tt_is_secure()) {
15384         printf("?Sorry, \
15385 external protocols over secure connections not supported in this OS.\n"
15386               );
15387         return(0);
15388     }
15389 #endif  /* NETPTY */
15390
15391     conres();                           /* Make console normal  */
15392     pexitstat = -4;
15393     if ((pid = fork()) == 0) {          /* Make a child fork */
15394         if (priv_can())                 /* Child: turn off privs. */
15395           exit(1);
15396         dup2(ttyfd, 0);                 /* Give stdin/out to the line */
15397         dup2(ttyfd, 1);
15398         x = system(s);
15399         debug(F101,"ttruncmd system",s,x);
15400         _exit(x ? BAD_EXIT : 0);
15401     } else {
15402         SIGTYP (*istat)(), (*qstat)();
15403         if (pid == (PID_T) -1)          /* fork() failed? */
15404           return(0);
15405         istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
15406         qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
15407
15408 #ifdef COMMENT
15409         while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
15410 #else  /* Not COMMENT */
15411         while (1) {
15412             wstat = wait(&statusp);
15413             debug(F101,"ttruncmd wait","",wstat);
15414             if (wstat == pid || wstat == -1)
15415               break;
15416         }
15417 #endif /* COMMENT */
15418
15419         pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
15420         debug(F101,"ttruncmd wait statusp","",statusp);
15421         debug(F101,"ttruncmd wait pexitstat","",pexitstat);
15422         signal(SIGINT,istat);           /* Restore interrupts */
15423         signal(SIGQUIT,qstat);
15424     }
15425     concb((char)escchr);                /* Restore console to CBREAK mode */
15426     return(statusp == 0 ? 1 : 0);
15427 }
15428 #endif  /* CK_REDIR */
15429
15430 struct tm *
15431 #ifdef CK_ANSIC
15432 cmdate2tm(char * date, int gmt)         /* date as "yyyymmdd hh:mm:ss" */
15433 #else
15434 cmdate2tm(date,gmt) char * date; int gmt;
15435 #endif
15436 {
15437     /* date as "yyyymmdd hh:mm:ss" */
15438     static struct tm _tm;
15439     time_t now;
15440
15441     if (strlen(date) != 17 ||
15442         date[8] != ' ' ||
15443         date[11] != ':' ||
15444         date[14] != ':')
15445       return(NULL);
15446
15447     time(&now);
15448     if (gmt)
15449       _tm = *gmtime(&now);
15450     else
15451       _tm = *localtime(&now);
15452     _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
15453                   (date[2]-'0')*10   + (date[3]-'0')-1900;
15454     _tm.tm_mon  = (date[4]-'0')*10   + (date[5]-'0')-1;
15455     _tm.tm_mday = (date[6]-'0')*10   + (date[7]-'0');
15456     _tm.tm_hour = (date[9]-'0')*10   + (date[10]-'0');
15457     _tm.tm_min  = (date[12]-'0')*10  + (date[13]-'0');
15458     _tm.tm_sec  = (date[15]-'0')*10  + (date[16]-'0');
15459
15460     /* Should we set _tm.tm_isdst to -1 here? */
15461
15462     _tm.tm_wday = 0;
15463     _tm.tm_yday = 0;
15464
15465     return(&_tm);
15466 }
15467
15468 #ifdef OXOS
15469 #undef kill
15470 #endif /* OXOS */
15471
15472 #ifdef OXOS
15473 int
15474 priv_kill(pid, sig) int pid, sig; {
15475     int i;
15476
15477     if (priv_on())
15478         debug(F100,"priv_kill priv_on failed","",0);
15479     i = kill(pid, sig);
15480     if (priv_off())
15481         debug(F100,"priv_kill priv_off failed","",0);
15482     return(i);
15483 }
15484 #endif /* OXOS */
15485
15486 #ifdef BEOSORBEBOX
15487 /* #ifdef BE_DR_7 */
15488 /*
15489   alarm() function not supplied with Be OS DR7 - this one contributed by
15490   Neal P. Murphy.
15491 */
15492
15493 /*
15494   This should mimic the UNIX/POSIX alarm() function well enough, with the
15495   caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
15496   and wait for the alarm thread to finish.
15497 */
15498 unsigned int
15499 alarm(unsigned int seconds) {
15500     long time_left = 0;
15501
15502 /* If an alarm is active, turn it off, saving the unused time */
15503     if (alarm_thread != -1) {
15504         /* We'll be generous and count partial seconds as whole seconds. */
15505         time_left = alarm_struct.time -
15506           ((system_time() - time_started) / 1000000.0);
15507
15508         /* Kill the alarm thread */
15509         kill_thread (alarm_thread);
15510
15511         /* We need to clean up as though the alarm occured. */
15512         time_started = 0;
15513         alarm_struct.thread = -1;
15514         alarm_struct.time = 0;
15515         alarm_expired();
15516     }
15517
15518 /* Set a new alarm clock, if requested. */
15519     if (seconds > 0) {
15520         alarm_struct.thread = find_thread(NULL);
15521         alarm_struct.time = seconds;
15522         time_started = system_time();
15523         alarm_thread = spawn_thread (do_alarm,
15524                                      "alarm_thread",
15525                                      B_NORMAL_PRIORITY,
15526                                      (void *) &alarm_struct
15527                                      );
15528         resume_thread (alarm_thread);
15529     }
15530
15531 /* Now return [unused time | 0] */
15532     return ((unsigned int) time_left);
15533 }
15534
15535 /*
15536   This function is the departure from UNIX/POSIX alarm handling. In the case
15537   of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
15538   handler. When Be implements alarm(), this function call can be eliminated
15539   from user's SIGALRM signal handlers.
15540 */
15541
15542 void
15543 alarm_expired(void) {
15544     long ret_val;
15545
15546     if (alarm_thread != -1) {
15547         wait_for_thread (alarm_thread, &ret_val);
15548         alarm_thread = -1;
15549     }
15550 }
15551
15552 /*
15553   This is the function that snoozes the requisite number of seconds and then
15554   SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
15555   uses thread_id; currently they are both typdef'ed as long, but I'll do the
15556   cast anyway. This function is run in a separate thread.
15557 */
15558
15559 long
15560 do_alarm (void *alarm_struct) {
15561     snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
15562     kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
15563     time_started = 0;
15564     ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
15565     ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
15566 }
15567 /* #endif */ /* BE_DR_7 */
15568 #endif /* BEOSORBEBOX */
15569
15570 #ifdef Plan9
15571
15572 int
15573 p9ttyctl(char letter, int num, int param) {
15574     char cmd[20];
15575     int len;
15576
15577     if (ttyctlfd < 0)
15578       return -1;
15579
15580     cmd[0] = letter;
15581     if (num)
15582       len = sprintf(cmd + 1, "%d", param) + 1;
15583     else {
15584         cmd[1] = param;
15585         len = 2;
15586     }
15587     if (write(ttyctlfd, cmd, len) == len) {
15588         cmd[len] = 0;
15589         /* fprintf(stdout, "wrote '%s'\n", cmd); */
15590         return 0;
15591     }
15592     return -1;
15593 }
15594
15595 int
15596 p9ttyparity(char l) {
15597     return p9ttyctl('p', 0, l);
15598 }
15599
15600 int
15601 p9tthflow(int flow, int status) {
15602     return p9ttyctl('m', 1, status);
15603 }
15604
15605 int
15606 p9ttsspd(int cps) {
15607     if (p9ttyctl('b', 1, cps * 10) < 0)
15608       return -1;
15609     ttylastspeed = cps * 10;
15610     return 0;
15611 }
15612
15613 int
15614 p9openttyctl(char *ttname) {
15615     char name[100];
15616
15617     if (ttyctlfd >= 0) {
15618         close(ttyctlfd);
15619         ttyctlfd = -1;
15620         ttylastspeed = -1;
15621     }
15622     sprintf(name, "%sctl", ttname);
15623     ttyctlfd = open(name, 1);
15624     return ttyctlfd;
15625 }
15626
15627 int
15628 p9concb() {
15629     if (consctlfd >= 0) {
15630         if (write(consctlfd, "rawon", 5) == 5)
15631           return 0;
15632     }
15633     return -1;
15634 }
15635
15636 int
15637 p9conbin() {
15638     return p9concb();
15639 }
15640
15641 int
15642 p9conres() {
15643     if (consctlfd >= 0) {
15644         if (write(consctlfd, "rawoff", 6) == 6)
15645           return 0;
15646     }
15647     return -1;
15648 }
15649
15650 int
15651 p9sndbrk(int msec) {
15652     if (ttyctlfd >= 0) {
15653         char cmd[20];
15654         int i = sprintf(cmd, "k%d", msec);
15655         if (write(ttyctlfd, cmd, i) == i)
15656           return 0;
15657     }
15658     return -1;
15659 }
15660
15661 int
15662 conwrite(char *buf, int n) {
15663     int x;
15664     static int length = 0;
15665     static int holdingcr = 0;
15666     int normal = 0;
15667     for (x = 0; x < n; x++) {
15668         char c = buf[x];
15669         if (c == 007) {
15670             if (normal) {
15671                 write(1, buf + (x - normal), normal);
15672                 length += normal;
15673                 normal = 0;
15674             }
15675             /* write(noisefd, "1000 300", 8); */
15676             holdingcr = 0;
15677         } else if (c == '\r') {
15678             if (normal) {
15679                 write(1, buf + (x - normal), normal);
15680                 length += normal;
15681                 normal = 0;
15682             }
15683             holdingcr = 1;
15684         } else if (c == '\n') {
15685             write(1, buf + (x - normal), normal + 1);
15686             normal = 0;
15687             length = 0;
15688             holdingcr = 0;
15689         } else if (c == '\b') {
15690             if (normal) {
15691                 write(1, buf + (x - normal), normal);
15692                 length += normal;
15693                 normal = 0;
15694             }
15695             if (length) {
15696                 write(1, &c, 1);
15697                 length--;
15698             }
15699             holdingcr = 0;
15700         } else {
15701             if (holdingcr) {
15702                 char b = '\b';
15703                 while (length-- > 0)
15704                   write(1, &b, 1);
15705                 length = 0;     /* compiler bug */
15706             }
15707             holdingcr = 0;
15708             normal++;
15709         }
15710     }
15711     if (normal) {
15712         write(1, buf + (x - normal), normal);
15713         length += normal;
15714     }
15715     return n;
15716 }
15717
15718 void
15719 conprint(char *fmt, ...) {
15720     static char buf[1000];              /* not safe if on the stack */
15721
15722     va_list ap;
15723     int i;
15724
15725     va_start(ap, fmt);
15726     i = vsprintf(buf, fmt, ap);
15727     conwrite(buf, i);
15728 }
15729 #endif /* Plan9 */
15730
15731 /* fprintf, printf, perror replacements... */
15732
15733 /* f p r i n t f */
15734
15735 #ifdef UNIX
15736 #ifdef CK_ANSIC
15737 #include <stdarg.h>
15738 #else /* CK_ANSIC */
15739 #ifdef __GNUC__
15740 #include <stdarg.h>
15741 #else
15742 #include <varargs.h>
15743 #endif  /* __GNUC__ */
15744 #endif /* CK_ANSIC */
15745 #ifdef fprintf
15746 #undef fprintf
15747 static char str1[4096];
15748 static char str2[4096];
15749 int
15750 #ifdef CK_ANSIC
15751 ckxfprintf(FILE * file, const char * format, ...)
15752 #else /* CK_ANSIC */
15753 ckxfprintf(va_alist) va_dcl
15754 #endif /* CK_ANSIC */
15755 /* ckxfprintf */ {
15756     int i, j, len, got_cr;
15757     va_list args;
15758     int rc = 0;
15759
15760 #ifdef CK_ANSIC
15761     va_start(args, format);
15762 #else /* CK_ANSIC */
15763     char * format;
15764     FILE * file;
15765     va_start(args);
15766     file = va_arg(args,FILE *);
15767     format = va_arg(args,char *);
15768 #endif /* CK_ANSIC */
15769
15770     if (!inserver || (file != stdout && file != stderr && file != stdin)) {
15771         rc = vfprintf(file,format,args);
15772     } else {
15773         unsigned int c;
15774         rc = vsprintf(str1, format, args);
15775         len = strlen(str1);
15776         if (len >= sizeof(str1)) {
15777             debug(F101,"ckxfprintf() buffer overflow","",len);
15778             doexit(BAD_EXIT,1);
15779         }
15780         for (i = 0, j = 0, got_cr = 0;
15781              i < len && j < sizeof(str1)-2;
15782              i++, j++ ) {
15783             /* We can't use 255 as a case label because of signed chars */
15784             c = (unsigned)(str1[i] & 0xff);
15785 #ifdef TNCODE
15786             if (c == 255) {
15787                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15788                   str2[j++] = '\0';
15789                 str2[j++] = IAC;
15790                 str2[j] = IAC;
15791                 got_cr = 0;
15792             } else
15793 #endif /* TNCODE */
15794             switch (c) {
15795               case '\r':
15796                 if (got_cr
15797 #ifdef TNCODE
15798                     && !TELOPT_ME(TELOPT_BINARY)
15799 #endif /* TNCODE */
15800                     )
15801                   str2[j++] = '\0';
15802                 str2[j] = str1[i];
15803                 got_cr = 1;
15804                 break;
15805               case '\n':
15806                 if (!got_cr)
15807                   str2[j++] = '\r';
15808                 str2[j] = str1[i];
15809                 got_cr = 0;
15810                 break;
15811               default:
15812                 if (got_cr
15813 #ifdef TNCODE
15814                     && !TELOPT_ME(TELOPT_BINARY)
15815 #endif /* TNCODE */
15816                     )
15817                   str2[j++] = '\0';
15818                 str2[j] = str1[i];
15819                 got_cr = 0;
15820             }
15821         }
15822         if (got_cr
15823 #ifdef TNCODE
15824              && !TELOPT_ME(TELOPT_BINARY)
15825 #endif /* TNCODE */
15826              )
15827             str2[j++] = '\0';
15828 #ifdef CK_ENCRYPTION
15829 #ifdef TNCODE
15830         if (TELOPT_ME(TELOPT_ENCRYPTION))
15831           ck_tn_encrypt(str2,j);
15832 #endif /* TNCODE */
15833 #endif /* CK_ENCRYPTION */
15834 #ifdef CK_SSL
15835         if (inserver && (ssl_active_flag || tls_active_flag)) {
15836             /* Write using SSL */
15837             char * p = str2;
15838           ssl_retry:
15839             if (ssl_active_flag)
15840               rc = SSL_write(ssl_con, p, j);
15841             else
15842               rc = SSL_write(tls_con, p, j);
15843             debug(F111,"ckxfprintf","SSL_write",rc);
15844             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
15845               case SSL_ERROR_NONE:
15846                 if (rc == j)
15847                   break;
15848                 p += rc;
15849                 j -= rc;
15850                 goto ssl_retry;
15851               case SSL_ERROR_WANT_WRITE:
15852               case SSL_ERROR_WANT_READ:
15853               case SSL_ERROR_SYSCALL:
15854                 if (rc != 0)
15855                   return(-1);
15856               case SSL_ERROR_WANT_X509_LOOKUP:
15857               case SSL_ERROR_SSL:
15858               case SSL_ERROR_ZERO_RETURN:
15859               default:
15860                 rc = 0;
15861             }
15862         } else
15863 #endif /* CK_SSL */
15864         fwrite(str2,sizeof(char),j,stdout);
15865     }
15866     va_end(args);
15867     return(rc);
15868 }
15869 #endif /* fprintf */
15870
15871 /* p r i n t f */
15872
15873 #ifdef printf
15874 #undef printf
15875 int
15876 #ifdef CK_ANSIC
15877 ckxprintf(const char * format, ...)
15878 #else /* CK_ANSIC */
15879 ckxprintf(va_alist) va_dcl
15880 #endif /* CK_ANSIC */
15881 /* ckxprintf */ {
15882     int i, j, len, got_cr;
15883     va_list args;
15884     int rc = 0;
15885
15886 #ifdef CK_ANSIC
15887     va_start(args, format);
15888 #else /* CK_ANSIC */
15889     char * format;
15890     va_start(args);
15891     format = va_arg(args,char *);
15892 #endif /* CK_ANSIC */
15893
15894     if (!inserver) {
15895         rc = vprintf(format, args);
15896     } else {
15897         unsigned int c;
15898         rc = vsprintf(str1, format, args);
15899         len = strlen(str1);
15900         if (len >= sizeof(str1)) {
15901             debug(F101,"ckxprintf() buffer overflow","",len);
15902             doexit(BAD_EXIT,1);
15903         }
15904         for (i = 0, j = 0, got_cr=0;
15905              i < len && j < sizeof(str1)-2;
15906              i++, j++ ) {
15907             c = (unsigned)(str1[i] & 0xff);
15908 #ifdef TNCODE
15909             if (c == 255) {
15910                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15911                   str2[j++] = '\0';
15912                 str2[j++] = IAC;
15913                 str2[j] = IAC;
15914                 got_cr = 0;
15915             } else
15916 #endif /* TNCODE */
15917             switch (c) {
15918               case '\r':
15919                 if (got_cr
15920 #ifdef TNCODE
15921                     && !TELOPT_ME(TELOPT_BINARY)
15922 #endif /* TNCODE */
15923                     )
15924                   str2[j++] = '\0';
15925                 str2[j] = str1[i];
15926                 got_cr = 1;
15927                 break;
15928               case '\n':
15929                 if (!got_cr)
15930                   str2[j++] = '\r';
15931                 str2[j] = str1[i];
15932                 got_cr = 0;
15933                 break;
15934               default:
15935                 if (got_cr
15936 #ifdef TNCODE
15937                     && !TELOPT_ME(TELOPT_BINARY)
15938 #endif /* TNCODE */
15939                     )
15940                   str2[j++] = '\0';
15941                 str2[j] = str1[i];
15942                 got_cr = 0;
15943                 break;
15944             }
15945         }
15946         if (got_cr
15947 #ifdef TNCODE
15948              && !TELOPT_ME(TELOPT_BINARY)
15949 #endif /* TNCODE */
15950              )
15951             str2[j++] = '\0';
15952 #ifdef CK_ENCRYPTION
15953 #ifdef TNCODE
15954         if (TELOPT_ME(TELOPT_ENCRYPTION))
15955           ck_tn_encrypt(str2,j);
15956 #endif /* TNCODE */
15957 #endif /* CK_ENCRYPTION */
15958 #ifdef CK_SSL
15959         if (inserver && (ssl_active_flag || tls_active_flag)) {
15960             char * p = str2;
15961             /* Write using SSL */
15962           ssl_retry:
15963             if (ssl_active_flag)
15964               rc = SSL_write(ssl_con, p, j);
15965             else
15966               rc = SSL_write(tls_con, p, j);
15967             debug(F111,"ckxprintf","SSL_write",rc);
15968             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
15969               case SSL_ERROR_NONE:
15970                 if (rc == j)
15971                   break;
15972                 p += rc;
15973                 j -= rc;
15974                 goto ssl_retry;
15975               case SSL_ERROR_WANT_WRITE:
15976               case SSL_ERROR_WANT_READ:
15977               case SSL_ERROR_SYSCALL:
15978                 if (rc != 0)
15979                   return(-1);
15980               case SSL_ERROR_WANT_X509_LOOKUP:
15981               case SSL_ERROR_SSL:
15982               case SSL_ERROR_ZERO_RETURN:
15983               default:
15984                 rc = 0;
15985             }
15986         } else
15987 #endif /* CK_SSL */
15988           rc = fwrite(str2,sizeof(char),j,stdout);
15989     }
15990     va_end(args);
15991     return(rc);
15992 }
15993 #endif /* printf */
15994
15995 /*  p e r r o r  */
15996
15997 #ifdef perror
15998 #undef perror
15999 _PROTOTYP(char * ck_errstr,(VOID));
16000 #ifdef NEXT
16001 void
16002 #else
16003 #ifdef CK_SCOV5
16004 void
16005 #else
16006 int
16007 #endif /* CK_SCOV5 */
16008 #endif /* NEXT */
16009 #ifdef CK_ANSIC
16010 ckxperror(const char * str)
16011 #else /* CK_ANSIC */
16012 ckxperror(str) char * str;
16013 #endif /* CK_ANSIC */
16014 /* ckxperror */ {
16015     char * errstr = ck_errstr();
16016 #ifndef NEXT
16017 #ifndef CK_SCOV5
16018     return
16019 #endif /* CK_SCOV5 */
16020 #endif /* NEXT */
16021       ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
16022 }
16023 #endif /* perror */
16024 #endif /* UNIX */
16025
16026 #ifdef MINIX2
16027
16028 /* Minix doesn't have a gettimeofday call (but MINIX3 does).
16029  * We fake one here using time(2)
16030  */
16031
16032 #ifndef MINIX3
16033 int
16034 gettimeofday(struct timeval *tp, struct timezone *tzp) {
16035     tp->tv_usec = 0L;                   /* Close enough for horseshoes */
16036     if(time(&(tp->tv_sec))==-1)
16037       return(-1);
16038     return(0);
16039 }
16040 #endif  /* MINIX3 */
16041
16042 #ifndef MINIX3
16043 int
16044 readlink(const char *path, void *buf, size_t bufsiz) {
16045     errno = ENOSYS;
16046     return(-1);
16047 }
16048 #endif  /* MINIX3 */
16049
16050 #endif /* MINIX2 */