dh_installchangelogs: adjust to use ckc301.txt. changelog: explain -O1 usage
[ckermit.git] / ckutio.c
1 #define CKUTIO_C
2
3 #ifdef aegis
4 char *ckxv = "Aegis Communications support, 9.0.324, 20 June 2011";
5 #else
6 #ifdef Plan9
7 char *ckxv = "Plan 9 Communications support, 9.0.324, 20 June 2011";
8 #else
9 char *ckxv = "UNIX Communications support, 9.0.324, 20 June 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 #include <errno.h>                      /* System error numbers */
54
55 #ifdef __386BSD__
56 #define ENOTCONN 57
57 #else
58 #ifdef __bsdi__
59 #define ENOTCONN 57
60 #else
61 #ifdef __FreeBSD__
62 #define ENOTCONN 57
63 #endif /* __FreeBSD__ */
64 #endif /* __bsdi__ */
65 #endif /* __386BSD__ */
66
67 #ifdef SCO_OSR504
68 #define NBBY 8
69 #endif /* SCO_OSR504 */
70
71 #ifdef Plan9
72 #define SELECT
73 #include <sys/time.h>
74 #include <select.h>
75 #define FD_SETSIZE (3 * sizeof(long) * 8)
76 static struct timeval tv;
77 #endif /* Plan9 */
78
79 #ifdef CLIX
80 #include <sys/time.h>
81 #endif /* CLIX */
82
83 #include "ckcnet.h"                     /* Symbols for network types. */
84 #ifdef CK_SSL
85 #include "ck_ssl.h"
86 #endif /* CK_SSL */
87
88 /*
89   The directory-related includes are here because we need to test some
90   file-system-related symbols to find out which system we're being compiled
91   under.  For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
92 */
93 #ifdef SDIRENT                          /* Directory bits... */
94 #define DIRENT
95 #endif /* SDIRENT */
96
97 #ifdef XNDIR
98 #include <sys/ndir.h>
99 #else /* !XNDIR */
100 #ifdef NDIR
101 #include <ndir.h>
102 #else /* !NDIR, !XNDIR */
103 #ifdef RTU
104 #include "/usr/lib/ndir.h"
105 #else /* !RTU, !NDIR, !XNDIR */
106 #ifdef DIRENT
107 #ifdef SDIRENT
108 #include <sys/dirent.h>
109 #else
110 #include <dirent.h>
111 #endif /* SDIRENT */
112 #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
113 #include <sys/dir.h>
114 #endif /* DIRENT */
115 #endif /* RTU */
116 #endif /* NDIR */
117 #endif /* XNDIR */
118
119 #ifdef QNX
120 #include <sys/dev.h>
121 #endif /* QNX */
122
123 #ifdef HPUX5
124 #ifndef TCPSOCKET
125 /* I don't know why this is needed here since we never reference bzero(). */
126 /* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
127 void
128 bzero(s,n) char *s; int n; {
129     extern char * memset();
130     memset(s,0,n);
131 }
132 #endif /* TCPSOCKET */
133 #endif /* HPUX5 */
134
135 /* Definition of HZ, used in msleep() */
136
137 #ifdef MIPS
138 #define HZ ( 1000 / CLOCK_TICK )
139 #else  /* MIPS */
140 #ifdef ATTSV
141 #ifndef NAP
142 #ifdef TRS16
143 #define HZ ( 1000 / CLOCK_TICK )
144 #endif /* TRS16 */
145 #ifdef NAPHACK
146 #define nap(x) (void)syscall(3112, (x))
147 #define NAP
148 #endif /* NAPHACK */
149 #endif /* NAP */
150 #endif /* ATTSV */
151 #endif /* MIPS */
152
153 #ifdef M_UNIX
154 #undef NGROUPS_MAX              /* Prevent multiple definition warnings */
155 #endif /* M_UNIX */
156
157 /*
158   NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
159   library routine, so _poll comes up undefined at link time.
160 */
161 #ifdef CK_POLL
162 #ifndef AIXRS                   /* IBM AIX needs special handling */
163 #include <poll.h>               /* "standard" (SVID) i/o multiplexing, etc */
164 #else /* AIXRS */
165 #ifdef SVR4                     /* AIX 3.2 is like SVID... */
166 #include <poll.h>
167 #else                           /* But AIX 3.1 is not ... */
168 #include <sys/poll.h>           /* The include file is in include/sys */
169 #define events reqevents        /* And it does not map IBM-specific member */
170 #define revents rtnevents       /* names to the System V equivalents */
171 #endif /* SVR4 */
172 #endif /* AIXRS */
173 #endif /* CK_POLL */
174
175 #include <signal.h>                     /* Signals */
176
177 /* For setjmp and longjmp */
178
179 #ifndef ZILOG
180 #include <setjmp.h>
181 #else
182 #include <setret.h>
183 #endif /* ZILOG */
184
185 /*
186   The following test differentiates between 4.1 BSD and 4.2 & later.
187   If you have a 4.1BSD system with the DIRENT library, this test could
188   mistakenly diagnose 4.2BSD and then later enable the use of system calls
189   that aren't defined.  If indeed there are such systems, we can use some
190   other way of testing for 4.1BSD, or add yet another compile-time switch.
191 */
192 #ifdef BSD4
193 #ifdef MAXNAMLEN
194 #ifndef FT21                            /* Except for Fortune. */
195 #ifndef FT18
196 #ifndef BELLV10                         /* And Bell Labs Research UNIX V10 */
197 #define BSD42
198 #endif /* BELLV10 */
199 #endif /* FT18 */
200 #endif /* FT21 */
201 #endif /* MAXNAMLEN */
202 #endif /* BSD4 */
203
204 #ifdef SUNOS41                          /* From Christian Corti */
205 #define BSD44ORPOSIX                    /* Uni Stuttgart */
206 #define SVORPOSIX                       /* February 2010 */
207 #include <termios.h>
208 #include <sys/ioctl.h>
209 #include <unistd.h>
210 #include <limits.h>
211 #endif  /* SUNOS41 */
212
213 #ifdef SNI542
214 #include <sys/filio.h>                  /* 299 for FIONREAD */
215 #endif  /* SNI542 */
216
217 /*
218   Minix 2.0 support added by Terry McConnell,
219   Syracuse University <tmc@barnyard.syr.edu>
220   No more sgtty interface, posix compliant.
221 */
222 #ifdef MINIX2
223 #define _MINIX   /* Needed for some Minix header files */
224 #define BSD44ORPOSIX
225 #define SVORPOSIX
226 #ifndef MINIX3
227 #define DCLTIMEVAL
228 #endif  /* MINIX3 */
229 #define NOFILEH
230 #include <sys/types.h>
231 #include <sys/ioctl.h>
232 #include <termios.h>
233 #include <limits.h>
234 #undef TIOCGETC    /* defined in sys/ioctl.h, but not really supported */
235 #define TANDEM 0
236 #endif /* MINIX2 */
237
238 /*
239  MINIX 1.0 support added by Charles Hedrick,
240  Rutgers University <hedrick@aramis.rutgers.edu>.
241  MINIX also has V7 enabled.
242 */
243 #ifdef MINIX
244 #define TANDEM 0
245 #define MYREAD
246 #define NOSYSIOCTLH
247 #include <limits.h>
248 #endif /* MINIX */
249
250 #ifdef CK_REDIR         /* <sys/wait.h> needed only for REDIRECT command. */
251 /*
252   If anybody can figure out how to make this work with NeXTSTEP, be
253   my guest!  (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
254 */
255 #ifndef CK_WAIT_H                       /* If wait.h not already included... */
256 #ifdef OSF                              /* force OSF to select POSIX wait */
257 #ifdef _BSD                             /* instead of BSD (see ckcdeb.h) */
258 #define CK_OSF_BSD
259 #undef _BSD
260 #endif /* _BSD */
261 #endif /* OSF */
262 #include <sys/wait.h>                   /* Include it */
263 #ifdef OSF
264 #ifdef CK_OSF_BSD
265 #define _BSD                            /* Restore it */
266 #undef CK_OSF_BSD
267 #endif /* CK_OSF_BSD */
268 #endif /* OSF */
269 #endif /* CK_WAIT_H */
270 #endif /* CK_REDIR */
271
272 #include "ckuver.h"                     /* Version herald */
273 char *ckxsys = HERALD;
274
275 #ifdef CK_UTSNAME
276 #include <sys/utsname.h>
277
278 #ifdef TRU64                            /* Tru64 UNIX 4.0 and later */
279 /* Verified on Tru64 4.0F - might break on 4.0E or earlier */
280 #include <sys/sysinfo.h>                /* (don't know about OSF/1 or DU) */
281 #include <machine/hal_sysinfo.h>
282 #endif /* TRU64 */
283
284 #ifdef SOLARIS25                        /* Solaris 2.5 and later */
285 #include <sys/systeminfo.h>             /* (don't know about earlier ones) */
286 #endif /* SOLARIS25 */
287
288 #ifdef UW7
289 #ifndef SYS_NMLN
290 #define SYS_NMLN 257
291 #endif /* NMLN */
292 #endif /* UW7 */
293 #ifdef HPUX9PLUS
294 static int hpis800 = 0;
295 #endif /* HPUX9PLUS */
296 #ifdef SYS_NMLN
297 #define CK_SYSNMLN SYS_NMLN
298 #else
299 #ifdef _SYS_NMLN
300 #define CK_SYSNMLN _SYS_NMLN
301 #else
302 #ifdef UTSLEN
303 #define CK_SYSNMLN UTSLEN
304 #else
305 #define CK_SYSNMLN 31
306 #endif /* UTSLEN */
307 #endif /* _SYS_NMLN */
308 #endif /* SYS_NMLN */
309 char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
310 char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
311 char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
312 char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
313 char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
314 #endif /* CK_UTSNAME */
315
316 #ifdef CIE
317 #include <stat.h>                       /* For chasing symlinks, etc. */
318 #else
319 #include <sys/stat.h>
320 #endif /* CIE */
321
322 #ifdef QNX                              /* 299 */
323 #ifndef IXANY
324 #define IXANY 0
325 #endif  /* IXANY */
326 #endif  /* QNX */
327
328 /* UUCP lockfile material... */
329
330 #ifndef NOUUCP
331 #ifdef USETTYLOCK
332 #ifdef HAVE_LOCKDEV                     /* Red Hat baudboy/lockdev */
333 /*
334   Watch out: baudboy.h references open() without making sure it has been
335   declared, resulting in warnings on at least Red Hat 7.3.  It's declared in
336   fcntl.h, but we don't include that until later.  In this case only, we
337   include it here, and then the second include is harmless because in Red Hat
338   Linux (the only place where you find baudboy.h) fcntl.h is protected from
339   multiple inclusion by _FCNTL_H.   - fdc, 10 May 2004.
340
341   NOTE: Although Linux /usr/sbin/lockdev obviates the need for setuid or
342   setgid bits to access the lockfile, C-Kermit will still need them to access
343   the serial port itself unless the port is open for world read/write.
344   Normally setgid uucp does the trick.
345
346   Extra: HAVE_LOCKDEV has been added als openSuSE >= 11.3 doesn't use baudboy
347   but ttylock.  - jb, 26 Jul 2010
348 */
349 #include <fcntl.h>                      /* This has to come before baudboy */
350 #ifdef HAVE_BAUDBOY                     /* Red Hat baudboy/lockdev */
351 #include <baudboy.h>
352 #else  /* !HAVE_BAUDBOY */              /* openSuSE lock via ttylock */
353 #include <ttylock.h>
354 #endif  /* HAVE_BAUDBOY */
355 #define LOCK_DIR "/var/lock"            /* (even though we don't care) */
356
357 #else  /* !HAVE_LOCKDEV */
358
359 #ifdef USE_UU_LOCK
360 #ifdef __FreeBSD__
361 #include <libutil.h>                    /* FreeBSD */
362 #else
363 #include <util.h>                       /* OpenBSD */
364 #endif /* HAVE_LOCKDEV */
365 #endif /* __FreeBSD */
366 #endif /* USE_UU_LOCK */
367 #else  /* USETTYLOCK */
368
369 /* Name of UUCP tty device lockfile */
370
371 #ifdef LINUXFSSTND
372 #ifndef HDBUUCP
373 #define HDBUUCP
374 #endif /* HDBUUCP */
375 #endif /* LINUXFSSTND */
376
377 #ifdef ACUCNTRL
378 #define LCKDIR
379 #endif /* ACUCNTRL */
380
381 /*
382   PIDSTRING means use ASCII string to represent pid in lockfile.
383 */
384 #ifndef PIDSTRING
385 #ifdef HDBUUCP
386 #define PIDSTRING
387 #else
388 #ifdef BSD44
389 #define PIDSTRING
390 #else
391 #ifdef RTAIX
392 #define PIDSTRING
393 #else
394 #ifdef AIXRS
395 #define PIDSTRING
396 #else
397 #ifdef COHERENT
398 #define PIDSTRING
399 #endif /* COHERENT */
400 #endif /* AIXRS */
401 #endif /* RTAIX */
402 #endif /* BSD44 */
403 #endif /* HDBUUCP */
404 #endif /* PIDSTRING */
405
406 /* Now the PIDSTRING exceptions... */
407
408 #ifdef PIDSTRING
409 #ifdef HPUX
410 #undef PIDSTRING
411 #endif /* HPUX */
412 #endif /* PIDSTRING */
413
414 #ifdef __bsdi__                         /* BSDI (at least thru 1.1) */
415 #ifdef PIDSTRING
416 #undef PIDSTRING
417 #endif /* PIDSTRING */
418 #endif /* __bsdi__ */
419
420 #ifdef OSF32                            /* Digital UNIX (OSF/1) 3.2 */
421 #ifdef PIDSTRING
422 #undef PIDSTRING
423 #endif /* PIDSTRING */
424 #endif /* OSF32 */
425
426 /*
427   LOCK_DIR is the name of the lockfile directory.
428   If LOCK_DIR is already defined (e.g. on command line), we don't change it.
429 */
430
431 #ifndef LOCK_DIR
432 #ifdef MACOSX
433 #define LOCK_DIR "/var/spool/lock"
434 #endif /* MACOSX */
435 #endif/* LOCK_DIR */
436
437 #ifndef LOCK_DIR
438 #ifdef BSD44
439 #ifdef __386BSD__
440 #define LOCK_DIR "/var/spool/lock"
441 #else
442 #ifdef __FreeBSD__
443 #define LOCK_DIR "/var/spool/lock"
444 #else
445 #ifdef __NetBSD__
446 #define LOCK_DIR "/var/spool/lock"
447 #else
448 #ifdef __OpenBSD__
449 #define LOCK_DIR "/var/spool/lock"
450 #else
451 /* So which ones is this for? */
452 /* Probably original 4.4BSD on Vangogh */
453 /* Plus who knows about Mac OS X... It doesn't even have a cu program */
454 #define LOCK_DIR "/var/spool/uucp"
455 #endif /* __OpenBSD__ */
456 #endif /* __NetBSD__ */
457 #endif /* __FreeBSD__ */
458 #endif /* __386BSD__ */
459 #else
460 #ifdef DGUX430
461 #define LOCK_DIR "/var/spool/locks"
462 #else
463 #ifdef HPUX10
464 #define LOCK_DIR "/var/spool/locks"
465 #else
466 #ifdef RTAIX                            /* IBM RT PC AIX 2.2.1 */
467 #define LOCK_DIR "/etc/locks"
468 #else
469 #ifdef AIXRS
470 #define LOCK_DIR "/etc/locks"
471 #else
472 #ifdef ISIII
473 #define LOCK_DIR "/etc/locks"
474 #else
475 #ifdef HDBUUCP
476 #ifdef M_SYS5
477 #define LOCK_DIR "/usr/spool/uucp"
478 #else
479 #ifdef M_UNIX
480 #define LOCK_DIR "/usr/spool/uucp"
481 #else
482 #ifdef SVR4
483 #define LOCK_DIR "/var/spool/locks"
484 #else
485 #ifdef SUNOS4
486 #define LOCK_DIR "/var/spool/locks"
487 #else
488 #ifdef LINUXFSSTND
489 #define LOCK_DIR "/var/lock";
490 #else
491 #define LOCK_DIR "/usr/spool/locks"
492 #endif /* LINUXFSSTND */
493 #endif /* SUNOS4 */
494 #endif /* SVR4 */
495 #endif /* M_UNIX */
496 #endif /* M_SYS5 */
497 #else
498 #ifdef LCKDIR
499 #define LOCK_DIR "/usr/spool/uucp/LCK"
500 #else
501 #ifdef COHERENT
502 #define LOCK_DIR "/usr/spool/uucp"
503 #else
504 #define LOCK_DIR "/usr/spool/uucp"
505 #endif /* COHERENT */
506 #endif /* LCKDIR */
507 #endif /* HDBUUCP */
508 #endif /* ISIII */
509 #endif /* AIXRS */
510 #endif /* RTAIX */
511 #endif /* HPUX10 */
512 #endif /* DGUX430 */
513 #endif /* BSD44 */
514 #endif /* !LOCK_DIR (outside ifndef) */
515
516 #ifdef OSF2                             /* OSF/1 2.0 or later */
517 #ifdef LOCK_DIR                         /* (maybe 1.x too, who knows...) */
518 #undef LOCK_DIR
519 #define LOCK_DIR "/var/spool/locks"
520 #endif /* LOCK_DIR */
521 #endif /* OSF2 */
522
523 #ifdef COMMENT
524 /* Sorry no more lockf() -- we lock first and THEN open the device. */
525 #ifdef SVR4
526 #ifndef BSD44
527 #ifndef LOCKF
528 #define LOCKF                           /* Use lockf() on tty device in SVR4 */
529 #endif /* LOCKF */
530 #endif /* BSD44 */
531 #endif /* SVR4 */
532 #endif /* COMMENT */
533
534 #ifdef NOLOCKF                          /* But NOLOCKF cancels LOCKF */
535 #ifdef LOCKF
536 #undef LOCKF
537 #endif /* LOCKF */
538 #endif /* NOLOCKF */
539
540 /* More about this below... */
541
542 #endif /* USETTYLOCK */
543 #endif /* NOUUCP */
544
545 /*
546   MYREAD means use our internally defined nonblocking buffered read routine.
547 */
548 #ifdef ATTSV
549 #define MYREAD
550 #endif /* ATTSV */
551
552 #ifdef ATT7300
553 #ifndef MYREAD
554 #define MYREAD
555 #endif /* MYREAD */
556 /* bits for attmodem: internal modem in use, restart getty */
557 #define ISMODEM 1
558 #define DOGETY 512
559 #endif  /* ATT7300 */
560
561 #ifdef BSD42
562 #define MYREAD
563 #endif /* BSD42 */
564
565 #ifdef POSIX
566 #define MYREAD
567 #endif /* POSIX */
568 #ifdef __bsdi__
569 #ifndef O_NDELAY
570 #define O_NDELAY O_NONBLOCK
571 #endif /* O_NDELAY */
572 #endif /* __bsdi__ */
573
574 /*
575  Variables available to outside world:
576
577    dftty  -- Pointer to default tty name string, like "/dev/tty".
578    dfloc  -- 0 if dftty is console, 1 if external line.
579    dfprty -- Default parity
580    dfflow -- Default flow control
581    ckxech -- Flag for who echoes console typein:
582      1 - The program (system echo is turned off)
583      0 - The system (or front end, or terminal).
584    functions that want to do their own echoing should check this flag
585    before doing so.
586
587    flfnam  -- Name of lock file, including its path, e.g.,
588                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
589    lkflfn  -- Name of link to lock file, including its paths
590    haslock -- Flag set if this kermit established a uucp lock.
591    lockpid -- PID of other process that has desired line open, as string.
592    backgrd -- Flag indicating program executing in background ( & on
593                 end of shell command). Used to ignore INT and QUIT signals.
594    rtu_bug -- Set by stptrap().  RTU treats ^Z as EOF (but only when we handle
595                 SIGTSTP)
596
597  Functions for assigned communication line (either external or console tty):
598
599    sysinit()               -- System dependent program initialization
600    syscleanup()            -- System dependent program shutdown
601    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
602    ttclos()                -- Close & reset the tty, releasing any access lock.
603    ttsspd(cps)             -- Set the transmission speed of the tty.
604    ttgspd()                -- Get (read) the the transmission speed of the tty.
605    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
606    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
607                                 or in DIALING or CONNECTED modem control state.
608    ttres()                 -- Restore original tty modes.
609    ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
610    ttinl(dest,max,timo)    -- Timed read line from the tty.
611    ttinc(timo)             -- Timed read character from tty.
612    myread()                -- Raw mode bulk buffer read, gives subsequent
613                                 chars one at a time and simulates FIONREAD.
614    myunrd(c)               -- Places c back in buffer to be read (one only)
615    ttchk()                 -- See how many characters in tty input buffer.
616    ttxin(n,buf)            -- Read n characters from tty (untimed).
617    ttol(string,length)     -- Write a string to the tty.
618    ttoc(c)                 -- Write a character to the tty.
619    ttflui()                -- Flush tty input buffer.
620    ttsndb()                -- Send BREAK signal.
621    ttsndlb()               -- Send Long BREAK signal.
622
623    ttlock(ttname)          -- "Lock" tty device against uucp collisions.
624    ttunlck()               -- Unlock tty device.
625
626                               For ATT7300/Unix PC, System V:
627    attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
628    offgetty(ttname)        -- Turns off getty(1m) for comms line
629    ongetty(ttname)         -- Restores getty() to comms line
630 */
631
632 /*
633 Functions for console terminal:
634
635    congm()   -- Get console terminal modes.
636    concb(esc) -- Put the console in single-character wakeup mode with no echo.
637    conbin(esc) -- Put the console in binary (raw) mode.
638    conres()  -- Restore the console to mode obtained by congm().
639    conoc(c)  -- Unbuffered output, one character to console.
640    conol(s)  -- Unbuffered output, null-terminated string to the console.
641    conola(s) -- Unbuffered output, array of strings to the console.
642    conxo(n,s) -- Unbuffered output, n characters to the console.
643    conchk()  -- Check if characters available at console (bsd 4.2).
644                 Check if escape char (^\) typed at console (System III/V).
645    coninc(timo)  -- Timed get a character from the console.
646    congks(timo)  -- Timed get keyboard scan code.
647    conint()  -- Enable terminal interrupts on the console if not background.
648    connoi()  -- Disable terminal interrupts on the console if not background.
649
650 Time functions
651
652    msleep(m) -- Millisecond sleep
653    ztime(&s) -- Return pointer to date/time string
654    rtimer() --  Reset timer
655    gtimer()  -- Get elapsed time since last call to rtimer()
656 */
657
658 /* Conditional Includes */
659
660 /* Whether to include <sys/file.h> */
661
662 #ifdef RTU                              /* RTU doesn't */
663 #define NOFILEH
664 #endif /* RTU */
665
666 #ifdef CIE                              /* CIE does. */
667 #undef NOFILEH
668 #endif /* CIE */
669
670 #ifdef BSD41                            /* 4.1 BSD doesn't */
671 #define NOFILEH
672 #endif /* BSD41 */
673
674 #ifdef is68k                            /* Integrated Solutions 68000 UNIX  */
675 #define NOFILEH                         /* e.g. on Plexux P60 and Sun-1 */
676 #endif /* is68k */
677
678 #ifdef MINIX                            /* MINIX */
679 #define NOFILEH
680 #endif /* MINIX */
681
682 #ifdef COHERENT                         /* Coherent */
683 #define NOFILEH
684 #endif /* COHERENT */
685
686 #ifndef NOFILEH                         /* Now include if selected. */
687 #include <sys/file.h>
688 #endif /* NOFILEH */
689
690 /* POSIX */
691
692 #ifdef BSD44ORPOSIX                     /* POSIX uses termios.h */
693 #define TERMIOS
694 #ifdef __bsdi__
695 #ifdef POSIX
696 #undef _POSIX_SOURCE                    /* Get extra stuff from termios.h */
697 #endif /* POSIX */
698 #endif /* __bsdi__ */
699 #include <termios.h>
700 #ifdef LINUX
701 #include <sys/ioctl.h>
702 #endif /* LINUX */
703 #ifdef QNX16
704 #include <ioctl.h>
705 #else
706 #ifdef QNX6
707 #include <ioctl.h>
708 #endif /* QNX6 */
709 #endif /* QNX16 */
710 #ifdef __bsdi__
711 #ifdef POSIX
712 #define _POSIX_SOURCE
713 #endif /* POSIX */
714 #endif /* __bsdi__ */
715 #ifndef BSD44                           /* Really POSIX */
716 #ifndef CK_QNX32                        /* was CK_QNX32 */
717 #define NOSYSIOCTLH                     /* No ioctl's allowed. */
718 #undef ultrix                           /* Turn off any ultrix features. */
719 #endif /* CK_QNX32 */
720 #endif /* BSD44 */
721 #endif /* POSIX */
722
723 /* System III, System V */
724
725 #ifdef ATTSV
726 #ifndef BSD44
727 #ifndef POSIX
728 #include <termio.h>
729 #endif /* POSIX */
730 #endif /* BSD44 */
731 #ifdef TERMIOX
732 /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
733 #include <termiox.h>
734   struct termiox rctsx;
735 #else
736 #ifdef STERMIOX
737 #ifdef SCO_OSR504
738 /* Sorry, this is truly disgusting but it's SCO's fault. */
739 #ifndef _SVID3
740 #define _CK_SVID3_X
741 #define _SVID3
742 #endif /* _SVID3 */
743 #endif /* SCO_OSR504 */
744 #include <sys/termiox.h>
745   struct termiox rctsx;
746 #ifdef CK_SVID3_X
747 #undef _SVID3
748 #undef CK_SVID3_X
749 #endif /* CK_SVID3_X */
750 #endif /* STERMIOX */
751 #endif /* TERMIOX */
752 #endif /* ATTSV */
753
754 #ifdef COHERENT                 /* Use termio.h, not sgtty.h for Coherent */
755 #include <termio.h>
756 #endif /* COHERENT */
757
758 #ifdef MINIX                            /* MINIX uses ioctl's */
759 #define NOSYSIOCTLH                     /* but has no <sys/ioctl.h> */
760 #endif /* MINIX */
761
762 /* Others */
763
764 #ifndef NOSYSIOCTLH                     /* Others use ioctl() */
765 #ifdef SUN4S5
766 /*
767   This is to get rid of cpp warning messages that occur because all of
768   these symbols are defined by both termios.h and ioctl.h on the SUN.
769 */
770 #undef ECHO
771 #undef NL0
772 #undef NL1
773 #undef TAB0
774 #undef TAB1
775 #undef TAB2
776 #undef XTABS
777 #undef CR0
778 #undef CR1
779 #undef CR2
780 #undef CR3
781 #undef FF0
782 #undef FF1
783 #undef BS0
784 #undef BS1
785 #undef TOSTOP
786 #undef FLUSHO
787 #undef PENDIN
788 #undef NOFLSH
789 #endif /* SUN4S5 */
790 #include <sys/ioctl.h>
791 #endif /* NOSYSIOCTLH */
792 /*
793   We really, really, REALLY want FIONREAD, because it is the only way to find
794   out not just *if* stuff is waiting to be read, but how much, which is
795   critical to our sliding-window and streaming procedures, not to mention
796   efficiency of CONNECT, etc.
797 */
798 #ifdef BELLV10
799 #include <sys/filio.h>                  /* For FIONREAD */
800 #ifdef FIONREAD
801 #define MYREAD
802 #endif /* MYREAD */
803 #endif /* BELLV10 */
804
805 #ifndef FIONREAD
806 /* It wasn't found in ioctl.h or term*.h - try these places: */
807 #ifdef UNIXWARE
808 #include <sys/filio.h>
809 #else
810 #ifdef SOLARIS
811 #include <sys/filio.h>
812 #endif /* SOLARIS */
813 #endif /* UNIXWARE */
814 #endif /* FIONREAD */
815
816 #ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
817 /*
818   <sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
819   something.  Due to this, in_chk() uses the FIONREAD instead of RDCHK
820   and the hot keys during file transfer (X to cancel file etc) do not
821   work because FIONREAD doesn't work even though it is defined.
822
823   NOTE: This might also be true elsewhere.
824 */
825 #ifdef FIONREAD
826 #undef FIONREAD
827 #endif /* FIONREAD */
828 #endif /* XENIX */
829
830 #ifdef CK_SCOV5                         /* Ditto for SCO OpenServer 5.0 */
831 #ifndef SCO_OSR507                      /* 299 */
832 #ifdef FIONREAD
833 #undef FIONREAD
834 #endif /* FIONREAD */
835 #endif  /* SCO_OSR507 */
836 #endif /* CK_SCOV5 */
837
838 #ifdef SCO_OSR507                       /* 299 */
839 #ifdef RDCHK
840 #undef RDCHK
841 #endif  /* RDCHK */
842 #endif  /* SCO_OSR507 */
843
844 /* Whether to include <fcntl.h> */
845
846 #ifndef is68k                           /* Only a few don't have this one. */
847 #ifndef BSD41
848 #ifndef FT21
849 #ifndef FT18
850 #ifndef COHERENT
851 #include <fcntl.h>
852 #endif /* COHERENT */
853 #endif /* FT18 */
854 #endif /* FT21 */
855 #endif /* BSD41 */
856 #endif /* not is68k */
857
858 #ifdef COHERENT
859 #ifdef _I386
860 #include <fcntl.h>
861 #else
862 #include <sys/fcntl.h>
863 #endif /* _I386 */
864 #endif /* COHERENT */
865
866 #ifdef ATT7300                          /* Unix PC, internal modem dialer */
867 #include <sys/phone.h>
868 #endif /* ATT7300 */
869
870 #ifdef HPUX                             /* HP-UX variations. */
871 #define HPUXJOBCTL
872 #include <sys/modem.h>                  /* HP-UX modem signals */
873 #ifdef hp9000s500                       /* Model 500 */
874 #undef HPUXJOBCTL
875 #endif /* hp9000s500 */
876 #ifdef HPUXPRE65
877 #undef HPUXJOBCTL
878 typedef long mflag;
879 #endif /* HPUXPRE65 */
880 #ifdef HPUXJOBCTL
881 #include <sys/bsdtty.h>                 /* HP-UX Berkeley tty support */
882 #endif /* HPUXJOBCTL */
883 #endif /* HPUX */
884
885 /*
886   Which time.h files to include... See ckcdeb.h for defaults.
887   Note that 0, 1, 2, or all 3 of these can be included according to
888   the symbol definitions.
889 */
890 #ifndef NOTIMEH
891 #ifdef TIMEH
892 #include <time.h>
893 #endif /* TIMEH */
894 #endif /* NOTIMEH */
895
896 #ifndef NOSYSTIMEH
897 #ifdef SYSTIMEH
898 #include <sys/time.h>
899 #endif /* SYSTIMEH */
900 #endif /* NOSYSTIMEH */
901
902 #ifndef NOSYSTIMEBH
903 #ifdef SYSTIMEBH
904 #include <sys/timeb.h>
905 #endif /* SYSTIMEBH */
906 #endif /* NOSYSTIMEBH */
907
908 #ifndef NODCLTIMEVAL
909 #ifdef DCLTIMEVAL
910 /*
911   In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
912   define the structs we need to access the higher speeds, so we have to
913   do it ourselves.
914 */
915 struct timeval {
916     long tv_sec;
917     long tv_usec;
918 };
919 struct timezone {
920     int tz_minuteswest;
921     int tz_dsttime;
922 };
923 #endif /* DCLTIMEVAL */
924 #endif /* NODCLTIMEVAL */
925
926 #ifdef __linux__
927 /* THIS IS OBSOLETE since about Linux 0.92 */
928 #ifdef OLINUXHISPEED
929 #include <linux/serial.h>
930 #endif /* OLINUXHISPEED */
931 #ifdef __alpha__                        /* Linux on DEC Alpha */
932 #ifndef __GLIBC__                       /* But not with glibc */
933 #include <asm/termios.h>
934 #endif /* __GLIBC__ */
935 #endif /* __alpha__ */
936 #endif /* __linux__ */
937
938 #ifdef NOIEXTEN                         /* This is broken on some systems */
939 #undef IEXTEN                           /* like Convex/OS 9.1 */
940 #endif /* NOIEXTEN */
941 #ifndef IEXTEN                          /* Turn off ^O/^V processing. */
942 #define IEXTEN 0                        /* Needed, at least, on BSDI. */
943 #endif /* IEXTEN */
944 /*
945   Pick up definitions needed for select() if we don't have them already.
946   Normally they come from <sys/types.h> but some systems get them from
947   <sys/select.h>...  Rather than hardwire all of them into the source, we
948   include it if SELECT_H is defined in compile-time CFLAGS.
949 */
950 #ifndef SCO_OSR504
951 #ifdef SELECT_H
952 #include <sys/select.h>
953 #endif /* SELECT_H */
954 #endif /* SCO_OSR504 */
955
956 #ifdef aegis
957 #include "/sys/ins/base.ins.c"
958 #include "/sys/ins/error.ins.c"
959 #include "/sys/ins/ios.ins.c"
960 #include "/sys/ins/sio.ins.c"
961 #include "/sys/ins/pad.ins.c"
962 #include "/sys/ins/time.ins.c"
963 #include "/sys/ins/pfm.ins.c"
964 #include "/sys/ins/pgm.ins.c"
965 #include "/sys/ins/ec2.ins.c"
966 #include "/sys/ins/type_uids.ins.c"
967 #include <default_acl.h>
968 #undef TIOCEXCL
969 #undef FIONREAD
970 #endif /* aegis */
971
972 #ifdef sxaE50                           /* PFU Compact A SX/A TISP V10/L50 */
973 #undef FIONREAD
974 #endif /* sxaE50 */
975
976 /* The following #defines are catch-alls for those systems */
977 /* that didn't have or couldn't find <file.h>... */
978
979 #ifndef FREAD
980 #define FREAD 0x01
981 #endif /* FREAD */
982
983 #ifndef FWRITE
984 #define FWRITE 0x10
985 #endif /* FWRITE */
986
987 #ifndef O_RDONLY
988 #define O_RDONLY 000
989 #endif /* O_RDONLY */
990
991 /* This is for ancient Unixes that don't have these tty symbols defined. */
992
993 #ifndef PENDIN
994 #define PENDIN ICANON
995 #endif /* PENDIN */
996 #ifndef FLUSHO
997 #define FLUSHO ICANON
998 #endif /* FLUSHO */
999 #ifndef EXTPROC
1000 #define EXTPROC ICANON
1001 #endif /* EXTPROC */
1002
1003 #ifdef SVORPOSIX
1004 /*
1005   Modem signals are also forbidden in the POSIX world.  But some POSIX-based
1006   platforms let us at them anyway if we know where to look.
1007 */
1008 #ifndef NEEDMDMDEFS
1009 /* Doesn't work for Linux */
1010 #ifdef UNIXWARE7
1011 #define NEEDMDMDEFS
1012 #endif /* UNIXWARE7 */
1013 #endif /* NEEDMDMDEFS */
1014
1015 #ifdef NEEDMDMDEFS
1016 #ifndef TIOCMGET
1017 #define TIOCMGET (('t'<<8)|29)
1018 #endif /* TIOCMGET */
1019
1020 #ifndef TIOCM_DTR
1021 #define TIOCM_DTR 0x0002
1022 #endif /* TIOCM_DTR */
1023 #ifndef TIOCM_RTS
1024 #define TIOCM_RTS 0x0004
1025 #endif /* TIOCM_RTS */
1026 #ifndef TIOCM_CTS
1027 #define TIOCM_CTS 0x0020
1028 #endif /* TIOCM_CTS */
1029 #ifndef TIOCM_CAR
1030 #define TIOCM_CAR 0x0040
1031 #endif /* TIOCM_CAR */
1032 #ifndef TIOCM_RNG
1033 #define TIOCM_RNG 0x0080
1034 #endif /* TIOCM_RNG */
1035 #ifndef TIOCM_DSR
1036 #define TIOCM_DSR 0x0100
1037 #endif /* TIOCM_DSR */
1038 #endif /* NEEDMDMDEFS */
1039 #endif /* SVORPOSIX */
1040
1041 /* Declarations */
1042
1043 #ifdef OXOS
1044 #undef TCGETA
1045 #undef TCSETA
1046 #undef TCSETAW
1047 #undef TCSETAF
1048 #define TCGETA TCGETS
1049 #define TCSETA TCSETS
1050 #define TCSETAW TCSETSW
1051 #define TCSETAF TCSETSF
1052 #define termio termios
1053 #endif /* OXOS */
1054
1055 #ifdef SVORPOSIX                        /* AT&T Sys V or POSIX */
1056 #ifdef UNIXWAREPOSIX                    /* UnixWare 7 POSIX build */
1057 /*
1058   In Unixware POSIX builds, <[sys/]time.h> refuses to define the
1059   structs we need to access the higher speeds, so we have to do it
1060   ourselves.
1061 */
1062 struct timeval {
1063     long tv_sec;
1064     long tv_usec;
1065 };
1066 struct timezone {
1067     int tz_minuteswest;
1068     int tz_dsttime;
1069 };
1070 #endif /* UNIXWAREPOSIX */
1071 #endif /* SVORPOSIX */
1072
1073 #ifdef __GNUC__
1074 #ifdef XENIX
1075 /*
1076   Because Xenix <time.h> doesn't declare time() if we're using gcc.
1077 */
1078 time_t time();
1079 #endif /* XENIX */
1080 #endif /* __GNUC__ */
1081
1082 /* Special stuff for V7 input buffer peeking */
1083
1084 #ifdef  V7
1085 int kmem[2] = { -1, -1};
1086 char *initrawq(), *qaddr[2]={0,0};
1087 #define CON 0
1088 #define TTY 1
1089 #endif /* V7 */
1090
1091 /* dftty is the device name of the default device for file transfer */
1092 /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
1093
1094 #ifdef BEOS
1095     char * dftty = NULL;
1096     char * dfmdm = "none";
1097     int dfloc = 0;                  /* that goes in local mode by default */
1098 #else
1099 #ifndef DFTTY
1100 #ifdef PROVX1
1101     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
1102     char *dfmdm = "none";
1103     int dfloc = 1;                  /* that goes in local mode by default */
1104 #else
1105     char *dftty = CTTNAM;               /* Remote by default, use normal */
1106     char *dfmdm = "none";
1107     int dfloc = 0;                      /* controlling terminal name. */
1108 #endif /* PROVX1 */
1109 #else
1110     char *dftty = DFTTY;                /* Default location specified on */
1111     char *dfmdm = "none";               /* command line. */
1112     int dfloc = 1;                      /* controlling terminal name. */
1113 #endif /* DFTTY */
1114 #endif /* BEOS */
1115
1116 #define CON_RES 0                       /* Console state is "reset" */
1117 #define CON_CB  1                       /* Console state is CBREAK */
1118 #define CON_BIN 2                       /* Console state is binary */
1119     static int constate = CON_RES;
1120
1121 #define CONI_RES 0                      /* Console interrupts are "reset" */
1122 #define CONI_INT 1                      /* Console intterupts are set */
1123 #define CONI_NOI 2                      /* Console intterupts are disabled */
1124     static int conistate = CONI_RES;
1125
1126 #ifdef CK_SMALL
1127 #define CONBUFSIZ 15
1128 #else
1129 #define CONBUFSIZ 255
1130 #endif /* CK_SMALL */
1131     static char conbuf[CONBUFSIZ];      /* Console readahead buffer */
1132     static int  conbufn = 0;            /* Chars in readahead buffer */
1133     static char *conbufp = conbuf;      /* Next char in readahead buffer */
1134
1135     char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
1136
1137 #ifdef RTU
1138     int rtu_bug = 0;                /* set to 1 when returning from SIGTSTP */
1139 #endif /* RTU */
1140
1141     int dfprty = DEFPAR;                /* Default parity (0 = none) */
1142     int ttprty = 0;                     /* The parity that is in use. */
1143     static int ttpmsk = 0xff;           /* Parity stripping mask. */
1144     int ttmdm = 0;                      /* Modem in use. */
1145     int ttcarr = CAR_AUT;               /* Carrier handling mode. */
1146     int dfflow = FLO_NONE;              /* Default flow control is NONE */
1147     int backgrd = 0;                    /* Assume in foreground (no '&' ) */
1148 #ifdef F_SETFL
1149     int iniflags = -1;                  /* fcntl flags for ttyfd */
1150 #endif /* F_SETFL */
1151     int fdflag = 0;                     /* Flag for redirected stdio */
1152     int ttfdflg = 0;                    /* Open File descriptor was given */
1153     int tvtflg = 0;                     /* Flag that ttvt has been called */
1154     long ttspeed = -1L;                 /* For saving speed */
1155     int ttflow = -9;                    /* For saving flow */
1156     int ttld = -1;                      /* Line discipline */
1157
1158 #ifdef sony_news
1159     static int km_con = -1;             /* Kanji mode for console tty */
1160     static int km_ext = -1;             /* Kanji mode for external device */
1161 #endif /* sony_news */
1162
1163 #ifdef PARSENSE
1164     static int needpchk = 1;            /* Need parity check */
1165 #else
1166     static int needpchk = 0;
1167 #endif /* PARSENSE */
1168
1169     extern int stopbits;                /* Stop bits */
1170 #ifdef HWPARITY
1171 /*
1172   Unfortunately we must do this with global variables rather than through the
1173   tt...() APIs to avoid changing the APIs and the many modules that use them.
1174   If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
1175   bits + parity or 8 data bits and no parity, and overrides the regular parity
1176   variable, which is communicated to this module thru ttpkt(), and represented
1177   locally by the ttprty variable.
1178 */
1179     extern int hwparity;                /* Hardware parity */
1180 #endif /* HWPARITY */
1181
1182 #ifdef TCPSOCKET
1183 #ifdef TCP_NODELAY
1184 static int nodelay_sav = -1;
1185 #endif /* TCP_NODELAY */
1186 #endif /* TCPSOCKET */
1187
1188 static int sigint_ign = 0;              /* SIGINT is ignored */
1189
1190 /*
1191   Having this module rely on external globals is bad, but fixing this
1192   requires overhaul of the ck*tio.c modules for all the different operating
1193   systems supported by C-Kermit.  Left for a future release.
1194 */
1195 extern int ttnproto;                    /* Defined in ckcnet.c */
1196 extern int ttnet;                       /* Defined in ckcnet.c */
1197 extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
1198 extern int xsuspend, wasclosed;
1199 extern int inserver, local;
1200
1201 int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
1202
1203 int ckmaxfiles = 0;                     /* Max number of open files */
1204
1205 #ifdef CK_ENCRYPTION                    /* Kerberos */
1206 #include "ckuath.h"
1207 extern int me_encrypt, u_encrypt;
1208 #endif /* CK_ENCRYPTION */
1209
1210 /* Declarations of variables global within this module */
1211
1212 #ifdef TTLEBUF                          /* See ckcnet.h */
1213 int ttpush = -1;
1214 #define LEBUFSIZ 4096
1215 static CHAR le_buf[LEBUFSIZ];
1216 static int le_start = 0, le_end = 0, le_data = 0;
1217 #endif /* TTLEBUF */
1218
1219 #define MSGBUF_SIZE 1024                /* For debugging */
1220 static char msgbuf[MSGBUF_SIZE];
1221
1222 static int gotsigs = 0;
1223
1224 static time_t tcount = (time_t)0;       /* Elapsed time counter */
1225
1226 static SIGTYP (*saval)()     = NULL;    /* For saving alarm() handler */
1227 static SIGTYP (*savquit)()   = NULL;    /* and other signal handlers */
1228 #ifdef SIGUSR1
1229 static SIGTYP (*savusr1)()   = NULL;
1230 #endif /* SIGUSR1 */
1231 #ifdef SIGUSR2
1232 static SIGTYP (*savusr2)()   = NULL;
1233 #endif /* SIGUSR2 */
1234 #ifdef SIGPIPE
1235 static SIGTYP (*savpipe)()   = NULL;
1236 #endif /* SIGPIPE */
1237 #ifdef SIGDANGER
1238 static SIGTYP (*savdanger)() = NULL;
1239 #endif /* SIGDANGER */
1240
1241 #ifndef NOJC
1242 static SIGTYP (*jchdlr)()    = NULL;    /* For checking suspend handler */
1243 #endif /* NOJC */
1244 static int jcshell = -1;                /* And flag for result */
1245
1246 /*
1247   BREAKNULS is defined for systems that simulate sending a BREAK signal
1248   by sending a bunch of NUL characters at low speed.
1249 */
1250 #ifdef PROVX1
1251 #ifndef BREAKNULS
1252 #define BREAKNULS
1253 #endif /* BREAKNULS */
1254 #endif /* PROVX1 */
1255
1256 #ifdef V7
1257 #ifndef BREAKNULS
1258 #define BREAKNULS
1259 #endif /* BREAKNULS */
1260 #endif /* V7 */
1261
1262 #ifdef BREAKNULS
1263 static char                             /* A string of nulls */
1264 *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";
1265 #endif /* BREAKNULS */
1266
1267 #ifdef CK_POSIX_SIG                     /* Longjump buffers */
1268 static sigjmp_buf sjbuf;                /* POSIX signal handling */
1269 #else
1270 static jmp_buf sjbuf;
1271 #endif /* CK_POSIX_SIG */
1272
1273 #ifdef V7
1274 static jmp_buf jjbuf;
1275 #endif /* V7 */
1276
1277 /* static */                            /* (Not static any more) */
1278 int ttyfd = -1;                         /* TTY file descriptor */
1279
1280 int ttpipe = 0;                         /* NETCMD: Use pipe instead of ttyfd */
1281 int ttpty  = 0;                         /* NETPTY: Use pty instead of ttfyd */
1282
1283 #ifdef NETPTY                           /* These are in ckupty.c */
1284 extern PID_T pty_fork_pid;
1285 extern int pty_master_fd, pty_slave_fd;
1286 #endif  /* NETPTY */
1287
1288 #ifdef NETCMD
1289 #ifdef NETCONN
1290 static int pipe0[2], pipe1[2];          /* Pipes for net i/o */
1291 #endif /* NETCONN */
1292 static PID_T ttpid = 0;                 /* Process ID for fork */
1293 static int fdin, fdout;                 /* File descriptors for pipe */
1294 static FILE * ttout = NULL;             /* File pointer for output pipe */
1295 #ifdef DCLFDOPEN
1296 /* fdopen() needs declaring because it's not declared in <stdio.h> */
1297 _PROTOTYP( FILE * fdopen, (int, char *) );
1298 #endif /* DCLFDOPEN */
1299 #endif /* NETCMD */
1300
1301 extern int pexitstat, quiet;
1302
1303 #ifdef Plan9
1304 int ttyctlfd  = -1;   /* TTY control channel - What? UNIX doesn't have one? */
1305 int consctlfd = -1;                     /* Console control channel */
1306 int noisefd = -1;                       /* tone channel */
1307 static int ttylastspeed = -1;           /* So we can lie about the speed */
1308 #endif /* Plan9 */
1309
1310 int telnetfd = 0;                       /* File descriptor is for telnet */
1311 #ifdef NETCONN
1312 int x25fd = 0;                          /* File descriptor is for X.25 */
1313 #endif /* NETCONN */
1314
1315 char lockpid[16] = { '\0', '\0' };      /* PID stored in lockfile, as string */
1316
1317 static int lkf = 0,                     /* Line lock flag */
1318     cgmf = 0,                           /* Flag that console modes saved */
1319     xlocal = 0,                         /* Flag for tty local or remote */
1320     curcarr = 0;                        /* Carrier mode: require/ignore. */
1321
1322 static int netconn = 0;                 /* 1 if network connection active */
1323
1324 static char escchr;                     /* Escape or attn character */
1325
1326 #ifdef CK_SCO32V4
1327 #include <sys/time.h>
1328 #endif /* CK_SCO32V4 */
1329
1330 #ifdef HAVE_TV
1331     static struct timeval tv;           /* For getting time, from sys/time.h */
1332 #endif /* HAVE_TV */
1333 #ifdef HAVE_TZ
1334     static struct timezone tz;
1335 #endif /* HAVE_TZ */
1336
1337 #ifdef OSF
1338     static struct timeb ftp;            /* And from sys/timeb.h */
1339 #endif /* OSF */
1340
1341 #ifdef BSD29
1342     static long xclock;                 /* For getting time from sys/time.h */
1343     static struct timeb ftp;            /* And from sys/timeb.h */
1344 #endif /* BSD29 */
1345
1346 #ifdef BSD41
1347     static long xclock;                 /* For getting time from sys/time.h */
1348     static struct timeb ftp;            /* And from sys/timeb.h */
1349 #endif /* BSD41 */
1350
1351 #ifdef BELLV10
1352     static long xclock;                 /* For getting time from sys/time.h */
1353     static struct timeb ftp;            /* And from sys/timeb.h */
1354 #endif /* BELLV10 */
1355
1356 #ifdef FT21
1357     static long xclock;                 /* For getting time from sys/time.h */
1358     static struct timeb ftp;            /* And from sys/timeb.h */
1359 #endif /* FT21 */
1360
1361 #ifdef TOWER1
1362     static long xclock;                 /* For getting time from sys/time.h */
1363     static struct timeb ftp;            /* And from sys/timeb.h */
1364 #endif /* TOWER1 */
1365
1366 #ifdef COHERENT
1367     static long xclock;                 /* For getting time from sys/time.h */
1368     static struct timeb ftp;            /* And from sys/timeb.h */
1369 #endif /* COHERENT */
1370
1371 #ifdef V7
1372     static long xclock;
1373 #endif /* V7 */
1374
1375 /* sgtty/termio information... */
1376
1377 #ifdef BSD44ORPOSIX                     /* POSIX or BSD44 */
1378   static struct termios
1379     ttold, ttraw, tttvt, ttcur,
1380     ccold, ccraw, cccbrk;
1381 #else                                   /* BSD, V7, etc */
1382
1383 #ifdef COHERENT                         /* Hack alert... */
1384 #define ATTSV
1385 #endif /* COHERENT */
1386
1387 #ifdef ATTSV
1388   static struct termio ttold = {0};     /* Init'd for word alignment, */
1389   static struct termio ttraw = {0};     /* which is important for some */
1390   static struct termio tttvt = {0};     /* systems, like Zilog... */
1391   static struct termio ttcur = {0};
1392   static struct termio ccold = {0};
1393   static struct termio ccraw = {0};
1394   static struct termio cccbrk = {0};
1395 #else
1396   static struct sgttyb                  /* sgtty info... */
1397     ttold, ttraw, tttvt, ttcur,         /* for communication line */
1398     ccold, ccraw, cccbrk;               /* and for console */
1399 #ifdef BELLV10
1400   static struct ttydevb                 /* Device info... */
1401     tdold, tdcur;                       /* for communication device */
1402 #endif /* BELLV10 */
1403 #ifdef TIOCGETC
1404   static struct tchars tchold, tchnoi;
1405
1406   static int tcharf;
1407 #endif /* TIOCGETC */
1408 #ifdef TIOCGLTC
1409   static struct ltchars ltchold, ltchnoi;
1410   static int ltcharf;
1411 #endif /* TIOCGLTC */
1412   int lmodef = 0;                       /* Local modes */
1413   int lmode = 0;
1414 #endif /* ATTSV */
1415 #endif /* BSD44ORPOSIX */
1416
1417 #ifdef COMMENT
1418 /* It picks up the speeds but they don't work */
1419 #ifdef UNIXWARE                         /* For higher serial speeds */
1420 #ifdef UW7                              /* in Unixware 7.0 */
1421 #include <sys/asyc.h>                   /* This picks up 57600 and 115200 */
1422 #endif /* UW7 */
1423 #endif /* UNIXWARE */
1424 #endif /* COMMENT */
1425
1426 #ifdef PROVX1
1427   static struct sgttyb ttbuf;
1428 #endif /* PROVX1 */
1429
1430 #ifdef ultrix
1431 /* do we really need this? */
1432   static struct sgttyb vanilla;
1433 #endif /* ultrix */
1434
1435 #ifdef ATT7300
1436 static int attmodem = 0;                /* ATT7300 internal-modem status */
1437 struct updata dialer = {0};             /* Condition dialer for data call */
1438 #endif /* ATT7300 */
1439
1440 #ifndef NOUUCP
1441 #define FLFNAML 128
1442 #ifndef USETTYLOCK
1443 #ifdef RTAIX
1444 char lkflfn[FLFNAML] = { '\0', '\0' };  /* and possible link to it */
1445 #endif /* RTAIX */
1446 char lock2[FLFNAML] =  { '\0', '\0' };  /* Name of second lockfile */
1447 #endif /* USETTYLOCK */
1448 #else
1449 #define FLFNAML 7
1450 #endif /* NOUUCP */
1451 char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
1452
1453 int haslock = 0;                        /* =1 if this kermit locked uucp */
1454
1455 #ifndef OXOS
1456 #ifdef SVORPOSIX
1457 static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
1458 #else
1459 #ifdef V7
1460 static int conesc = 0;
1461 #else
1462 #ifdef C70
1463 static int conesc = 0;
1464 #endif /* C70 */
1465 #endif /* V7 */
1466 #endif /* SVORPOSIX */
1467 #endif /* OXOS */
1468
1469 /* Local copy of comm device name or network host */
1470 static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
1471 #ifdef USETTYLOCK
1472 static char lockname[DEVNAMLEN+1];      /* Ditto, the part after "/dev/". */
1473 #endif /* USETTYLOCK */
1474
1475 #ifdef aegis
1476 static status_$t st;                    /* error status return value */
1477 static short concrp = 0;                /* true if console is CRP pad */
1478 static uid_$t ttyuid;                   /* tty type uid */
1479 static uid_$t conuid;                   /* stdout type uid */
1480
1481 /* APOLLO Aegis main()
1482  * establish acl usage and cleanup handling
1483  *    this makes sure that CRP pads
1484  *    get restored to a usable mode
1485  */
1486 main(argc,argv) int argc; char **argv; {
1487         status_$t status;
1488         pfm_$cleanup_rec dirty;
1489
1490         PID_T pid = getpid();
1491
1492         /* acl usage according to invoking environment */
1493         default_acl(USE_DEFENV);
1494
1495         /* establish a cleanup continuation */
1496         status = pfm_$cleanup(dirty);
1497         if (status.all != pfm_$cleanup_set) {
1498                 /* only handle faults for the original process */
1499                 if (pid == getpid() && status.all > pgm_$max_severity) {
1500                     /* blew up in main process */
1501                     status_$t quo;
1502                     pfm_$cleanup_rec clean;
1503
1504                     /* restore the console in any case */
1505                     conres();
1506
1507                     /* attempt a clean exit */
1508                     debug(F101, "cleanup fault status", "", status.all);
1509
1510                     /* doexit(), then send status to continuation */
1511                     quo = pfm_$cleanup(clean);
1512                     if (quo.all == pfm_$cleanup_set)
1513                       doexit(pgm_$program_faulted,-1);
1514                     else if (quo.all > pgm_$max_severity)
1515                       pfm_$signal(quo); /* blew up in doexit() */
1516                 }
1517                 /* send to the original continuation */
1518                 pfm_$signal(status);
1519                 /*NOTREACHED*/
1520             }
1521         return(ckcmai(argc, argv));
1522 }
1523 #endif /* aegis */
1524
1525 /* ANSI-style prototypes for internal functions. */
1526 /* Functions used outside this module are prototyped in ckcker.h. */
1527
1528 #ifdef apollo
1529 _PROTOTYP( SIGTYP timerh, () );
1530 _PROTOTYP( SIGTYP cctrap, () );
1531 _PROTOTYP( SIGTYP esctrp, () );
1532 _PROTOTYP( SIGTYP sig_ign, () );
1533 #else
1534 _PROTOTYP( SIGTYP timerh, (int) );
1535 _PROTOTYP( SIGTYP cctrap, (int) );
1536 _PROTOTYP( SIGTYP esctrp, (int) );
1537 #endif /* apollo */
1538 _PROTOTYP( int do_open, (char *) );
1539 _PROTOTYP( static int in_chk, (int, int) );
1540 _PROTOTYP( static int ttrpid, (char *) );
1541 _PROTOTYP( static int ttchkpid, (char *) );
1542 _PROTOTYP( static int ttlock, (char *) );
1543 _PROTOTYP( static int ttunlck, (void) );
1544 _PROTOTYP( static VOID sigchld_handler, (int) );
1545 _PROTOTYP( int mygetbuf, (void) );
1546 _PROTOTYP( int myfillbuf, (void) );
1547 _PROTOTYP( VOID conbgt, (int) );
1548 #ifdef ACUCNTRL
1549 _PROTOTYP( VOID acucntrl, (char *, char *) );
1550 #endif /* ACUCNTRL */
1551
1552 #ifdef BSD44ORPOSIX
1553 _PROTOTYP( int carrctl, (struct termios *, int) );
1554 #else
1555 #ifdef ATTSV
1556 _PROTOTYP( int carrctl, (struct termio *, int) );
1557 #else
1558 _PROTOTYP( int carrctl, (struct sgttyb *, int) );
1559 #endif /* ATTSV */
1560 #endif /* BSD44ORPOSIX */
1561
1562 #ifdef ATT7300
1563 _PROTOTYP( int attdial, (char *, long, char *) );
1564 _PROTOTYP( int offgetty, (char *) );
1565 _PROTOTYP( int ongetty, (char *) );
1566 #endif /* ATT7300 */
1567
1568 #ifdef BEOSORBEBOX
1569 #ifdef SELECT
1570     /* BeOS is not capable of using SELECT on anything but sockets */
1571 #undef SELECT
1572 #endif /* SELECT */
1573 #include <kernel/OS.h>
1574 /* #ifdef BE_DR_7 */
1575 static double time_started = 0.0;
1576 struct ALARM_STRUCT {
1577     thread_id thread;
1578     int time;
1579 };
1580 static thread_id alarm_thread = -1;
1581 static struct ALARM_STRUCT alarm_struct;
1582 _PROTOTYP( long do_alarm, (void *) );
1583 _PROTOTYP( unsigned int alarm, (unsigned int) );
1584 _PROTOTYP( void alarm_expired, (void) );
1585 /* #endif */ /* BE_DR_7 */
1586 #endif /* BEOSORBEBOX */
1587
1588 #ifndef xunchar
1589 #define xunchar(ch) (((ch) - 32 ) & 0xFF )      /* Character to number */
1590 #endif /* xunchar */
1591
1592 #ifdef CK_ANSIC
1593 static char *
1594 xxlast(char *s, char c)
1595 #else
1596 static char *
1597 xxlast(s,c) char *s; char c;
1598 #endif /* CK_ANSIC */
1599 /* xxlast */ {          /*  Last occurrence of character c in string s. */
1600     int i;
1601     for (i = (int)strlen(s); i > 0; i--)
1602       if (s[i-1] == c ) return(s + (i - 1));
1603     return(NULL);
1604 }
1605
1606 /* Timeout handler for communication line input functions */
1607
1608 /*ARGSUSED*/
1609 SIGTYP
1610 timerh(foo) int foo; {
1611     ttimoff();
1612 #ifdef BEOSORBEBOX
1613 /* #ifdef BE_DR_7 */
1614     alarm_expired();
1615 /* #endif */ /* BE_DR_7 */
1616 #endif /* BEOSORBEBOX */
1617 #ifdef CK_POSIX_SIG
1618     siglongjmp(sjbuf,1);
1619 #else
1620     longjmp(sjbuf,1);
1621 #endif /* CK_POSIX_SIG */
1622 }
1623
1624 /*ARGSUSED*/
1625 SIGTYP
1626 xtimerh(foo) int foo; {                 /* Like timerh() but does */
1627 #ifdef BEOSORBEBOX                      /* not reset the timer itself */
1628 /* #ifdef BE_DR_7 */
1629     alarm_expired();
1630 /* #endif */ /* BE_DR_7 */
1631 #endif /* BEOSORBEBOX */
1632 #ifdef CK_POSIX_SIG
1633     siglongjmp(sjbuf,1);
1634 #else
1635     longjmp(sjbuf,1);
1636 #endif /* CK_POSIX_SIG */
1637 }
1638
1639
1640 /* Control-C trap for communication line input functions */
1641
1642 int cc_int;                             /* Flag */
1643 SIGTYP (* occt)();                      /* For saving old SIGINT handler */
1644
1645 /*ARGSUSED*/
1646 SIGTYP
1647 cctrap(foo) int foo; {                  /* Needs arg for ANSI C */
1648   cc_int = 1;                           /* signal() prototype. */
1649   return;
1650 }
1651
1652 /*  S Y S I N I T  --  System-dependent program initialization.  */
1653
1654 /*
1655  * ttgwsiz() returns:
1656  *      1    tt_rows and tt_cols are known, both altered, both > 0
1657  *      0    tt_rows and/or tt_cols are known, both altered, one or both <= 0
1658  *      -1   tt_rows and tt_cols are unknown and unaltered
1659  */
1660
1661 extern int tt_rows, tt_cols;
1662
1663 static int
1664 xttgwsiz() {
1665     char *p;
1666     int rows = 0, cols = 0;
1667     p = getenv("LINES");
1668     debug(F110,"xttgwsiz LINES",p,0);
1669     if (p) {
1670         rows = atol(p);
1671         if (rows > 0) {
1672             p = getenv("COLUMNS");
1673             debug(F110,"xttgwsiz COLUMNS",p,0);
1674             if (p) {
1675                 cols = atol(p);
1676                 if (cols > 0) {
1677                     tt_rows = rows;
1678                     tt_cols = cols;
1679                     return(1);
1680                 }
1681                 return(0);
1682             }
1683         }
1684     }
1685     return(-1);
1686 }
1687
1688 #ifdef TTLEBUF
1689 VOID
1690 le_init() {                             /* LocalEchoInit() */
1691     int i;
1692     for (i = 0; i < LEBUFSIZ; i++)
1693       le_buf[i] = '\0';
1694     le_start = 0;
1695     le_end = 0;
1696     le_data = 0;
1697 }
1698
1699 VOID
1700 le_clean() {                            /* LocalEchoCleanup() */
1701     le_init();
1702     return;
1703 }
1704
1705 int
1706 le_inbuf() {
1707     int rc = 0;
1708     if (le_start != le_end) {
1709         rc = (le_end -
1710               le_start +
1711               LEBUFSIZ) % LEBUFSIZ;
1712     }
1713     debug(F111,"le_inbuf","chars waiting",rc);
1714     return(rc);
1715 }
1716
1717 int
1718 #ifdef CK_ANSIC
1719 le_putchar(CHAR ch)
1720 #else
1721 le_putchar(ch) CHAR ch;
1722 #endif /* CK_ANSIC */
1723 /* le_putchar */ {
1724 #ifdef COMMENT
1725     /* In UNIX we do not have another thread taking chars out of the buffer */
1726     while ((le_start - le_end == 1) ||
1727             (le_start == 0 && le_end == LEBUFSIZ - 1)) {
1728         /* Buffer is full */
1729         debug(F111,"le_putchar","Buffer is Full",ch);
1730         ReleaseLocalEchoMutex() ;
1731         msleep(250);
1732         RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
1733     }
1734 #else
1735     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
1736         debug(F110,"le_putchar","buffer is full",0);
1737         return(-1);
1738     }
1739 #endif /* COMMENT */
1740     le_buf[le_end++] = ch;
1741     if (le_end == LEBUFSIZ)
1742       le_end = 0;
1743     le_data = 1;
1744     return(0);
1745 }
1746
1747 int
1748 #ifdef CK_ANSIC
1749 le_puts(CHAR * s, int n)
1750 #else
1751 le_puts(s,n) CHAR * s; int n;
1752 #endif /* CK_ANSIC */
1753 /* le_puts */ {
1754     int rc = 0;
1755     int i = 0;
1756     CHAR * p = (CHAR *)"le_puts";
1757     ckhexdump(p,s,n);
1758     for (i = 0; i < n; i++)
1759       rc = le_putchar((char)s[i]);
1760     debug(F101,"le_puts","",rc);
1761     return(rc);
1762 }
1763
1764 int
1765 #ifdef CK_ANSIC
1766 le_putstr(CHAR * s)
1767 #else
1768 le_putstr(s) CHAR * s;
1769 #endif /* CK_ANSIC */
1770 /* le_puts */ {
1771     CHAR * p;
1772     int rc = 0;
1773     p = (CHAR *)"le_putstr";
1774     ckhexdump(p,s,(int)strlen((char *)s));
1775     for (p = s; *p && !rc; p++)
1776       rc = le_putchar(*p);
1777     return(rc);
1778 }
1779
1780 int
1781 #ifdef CK_ANSIC
1782 le_getchar(CHAR * pch)
1783 #else /* CK_ANSIC */
1784 le_getchar(pch) CHAR * pch;
1785 #endif /* CK_ANSIC */
1786 /* le_gatchar */ {
1787     int rc = 0;
1788     if (le_start != le_end) {
1789         *pch = le_buf[le_start];
1790         le_buf[le_start] = 0;
1791         le_start++;
1792
1793         if (le_start == LEBUFSIZ)
1794           le_start = 0;
1795
1796         if (le_start == le_end) {
1797             le_data = 0;
1798         }
1799         rc++;
1800     } else {
1801         *pch = 0;
1802     }
1803     return(rc);
1804 }
1805 #endif /* TTLEBUF */
1806
1807 #ifdef COMMENT
1808 /*
1809   Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
1810   But as far as I know, whenever TIOCGSIZE is defined, it is
1811   equated to TIOCGWINSZ.  For cases where this is not done, try this:
1812 */
1813 #ifndef TIOCGWINSZ
1814 #ifdef TIOCGSIZE
1815 #define TIOCGWINSZ TIOCGSIZE
1816 #endif /* TIOCGSIZE */
1817 #endif /* TIOCGWINSZ */
1818 #endif /* COMMENT */
1819
1820 static int tt_xpixel = 0, tt_ypixel = 0;
1821
1822 int
1823 ttgwsiz() {
1824     int x = 0;
1825 #ifndef NONAWS
1826 #ifdef QNX
1827 /*
1828   NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
1829   This code works for both the 16- and 32-bit versions.
1830 */
1831     extern int dev_size(int, int, int, int *, int *);
1832     int r, c;
1833
1834     if (dev_size(0, -1, -1, &r, &c) == 0) {
1835         debug(F101,"ttgwsiz QNX r","",r);
1836         debug(F101,"ttgwsiz QNX c","",c);
1837         tt_rows = r;
1838         tt_cols = c;
1839         return ((r > 0 && c > 0) ? 1 : 0);
1840     } else return(xttgwsiz());
1841 #else /* QNX */
1842 #ifdef TIOCGWINSZ
1843
1844 /* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
1845 #ifdef XENIX                            /* SCO UNIX 3.2v4.0 */
1846 #include <sys/stream.h>                 /* typedef mblk_t needed by ptem.h */
1847 #include <sys/ptem.h>                   /* for ttgwsiz() */
1848 #endif /* XENIX */
1849
1850 #ifdef I386IX                           /* Ditto for Interactive */
1851 #include <sys/stream.h>
1852 #include <sys/ptem.h>
1853 #endif /* I386IX */
1854
1855 /* Note, the above might be needed for some other older SVR3 Intel makes... */
1856
1857     struct winsize w;
1858     tt_xpixel = 0;
1859     tt_ypixel = 0;
1860
1861 #ifdef IKSD
1862     if (inserver)
1863       return(xttgwsiz());
1864 #endif /* IKSD */
1865     x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
1866     debug(F101,"ttgwsiz TIOCGWINSZ","",x);
1867     if (x < 0) {
1868         return(xttgwsiz());
1869     } else if (w.ws_row > 0 && w.ws_col > 0) {
1870         tt_rows = w.ws_row;
1871         tt_cols = w.ws_col;
1872         tt_xpixel = w.ws_xpixel;
1873         tt_ypixel = w.ws_ypixel;
1874         debug(F101,"ttgwsiz tt_rows","",tt_rows);
1875         debug(F101,"ttgwsiz tt_cols","",tt_cols);
1876         return(1);
1877     } else {
1878         debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
1879         return(xttgwsiz());
1880     }
1881 #else
1882     return(xttgwsiz());
1883 #endif /* TIOCGWINSZ */
1884 #endif /* QNX */
1885 #endif /* NONAWS */
1886 }
1887
1888
1889 #ifdef RLOGCODE
1890 _PROTOTYP( int rlog_naws, (void) );
1891 #endif  /* RLOGCODE */
1892
1893 #ifndef NOSIGWINCH
1894 #ifdef SIGWINCH
1895 SIGTYP
1896 winchh(foo) int foo; {                  /* SIGWINCH handler */
1897     int x = 0;
1898 #ifdef CK_TTYFD
1899 #ifndef VMS
1900     extern int ttyfd;
1901 #endif /* VMS */
1902 #endif /* CK_TTYFD */
1903     extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
1904 #ifdef DEBUG
1905     if (deblog) {
1906         debug(F100,"***************","",0);
1907         debug(F100,"SIGWINCH caught","",0);
1908         debug(F100,"***************","",0);
1909 #ifdef NETPTY
1910         debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
1911 #endif /* NETPTY */
1912     }
1913 #endif /* DEUB */
1914     signal(SIGWINCH,winchh);            /* Re-arm the signal */
1915     x = ttgwsiz();                      /* Get new window size */
1916     cmd_rows = tt_rows;                 /* Adjust command screen too */
1917     cmd_cols = tt_cols;
1918
1919 #ifdef CK_TTYFD
1920     if                                  /* If we don't have a connection */
1921 #ifdef VMS                              /* we're done. */
1922       (vmsttyfd() == -1)
1923 #else
1924       (ttyfd == -1)
1925 #endif /* VMS */
1926 #else
1927       (!local)
1928 #endif /* CK_TTYFD */
1929         return;
1930
1931 #ifdef NETPTY
1932     if (pty_fork_pid > -1) {            /* "set host" to a PTY? */
1933         int x;
1934
1935 #ifdef TIOCSWINSZ
1936         struct winsize w;               /* Resize the PTY */
1937         errno = 0;
1938         w.ws_col = tt_cols;
1939         w.ws_row = tt_rows;
1940         w.ws_xpixel = tt_xpixel;
1941         w.ws_ypixel = tt_ypixel;
1942         x = ioctl(ttyfd,TIOCSWINSZ,&w);
1943         debug(F101,"winchh TIOCSWINSZ","",x);
1944         debug(F101,"winchh TIOCSWINSZ errno","",errno);
1945 #endif /* TIOCSWINSZ */
1946
1947         errno = 0;
1948         x = kill(pty_fork_pid,SIGWINCH);
1949         debug(F101,"winchh kill","",x);
1950         debug(F101,"winchh kill errno","",errno);
1951     }
1952 #endif /* NETPTY */
1953
1954 /*
1955   This should be OK.  It might seem that sending this from
1956   interrupt level could interfere with another TELNET IAC string
1957   that was in the process of being sent.  But we always send
1958   TELNET strings with a single write(), which should prevent mixups.
1959   blah_snaws() should protect themselves from being called on the
1960   wrong kind of connection.
1961 */
1962 #ifdef TCPSOCKET
1963 #ifndef NOTTGWSIZ
1964     if (x > 0 && tt_rows > 0 && tt_cols > 0) {
1965         tn_snaws();
1966 #ifdef RLOGCODE
1967         rlog_naws();
1968 #endif /* RLOGCODE */
1969     }
1970 #endif /* NOTTGWSIZ */
1971 #endif /* TCPSOCKET */
1972     SIGRETURN;
1973 }
1974 #endif /* SIGWINCH */
1975 #endif /* NOSIGWINCH */
1976
1977 SIGTYP
1978 sighup(foo) int foo; {                  /* SIGHUP handler */
1979     backgrd = 1;
1980     debug(F100,"***************","",0);
1981     debug(F100,"SIGHUP received","",0);
1982     debug(F100,"***************","",0);
1983     doexit(BAD_EXIT,-1);
1984     /*NOTREACHED*/
1985     SIGRETURN;                          /* Shut picky compilers up... */
1986 }
1987
1988 #ifdef CK_SCO32V4
1989 /* Exists but there is no prototype in the header files */
1990 _PROTOTYP( char * ttyname, (int) );
1991 #else
1992 #ifdef SV68R3V6
1993 _PROTOTYP( char * ttyname, (int) );
1994 #else
1995 #ifdef ultrix
1996 _PROTOTYP( char * ttyname, (int) );
1997 #else
1998 #ifdef HPUX6
1999 _PROTOTYP( char * ttyname, (int) );
2000 #else
2001 #ifdef HPUX5
2002 _PROTOTYP( char * ttyname, (int) );
2003 #else
2004 #ifdef PS2AIX10
2005 _PROTOTYP( char * ttyname, (int) );
2006 #else
2007 #ifdef BSD42
2008 _PROTOTYP( char * ttyname, (int) );
2009 #endif /* BSD42 */
2010 #endif /* PS2AIX10 */
2011 #endif /* HPUX5 */
2012 #endif /* HPUX6 */
2013 #endif /* ultrix */
2014 #endif /* SV68R3V6 */
2015 #endif /* CK_SCO32V4 */
2016
2017 #ifndef SIGUSR1                         /* User-defined signals */
2018 #define SIGUSR1 30
2019 #endif /* SIGUSR1 */
2020
2021 #ifndef SIGUSR2
2022 #define SIGUSR2 31
2023 #endif /* SIGUSR2 */
2024
2025 /*
2026   ignorsigs() sets certain signals to SIG_IGN.  But when a signal is
2027   ignored, it remains ignored across exec(), so we have to restore these
2028   signals before exec(), which is the purpose of restorsigs().
2029 */
2030 static VOID
2031 ignorsigs() {                           /* Ignore these signals */
2032     savquit = signal(SIGQUIT,SIG_IGN);  /* Ignore Quit signal */
2033
2034 #ifdef SIGDANGER                        /* Ignore danger signals */
2035 /*
2036   This signal is sent when the system is low on swap space.  Processes
2037   that don't handle it are candidates for termination.  If swap space doesn't
2038   clear out enough, we still might be terminated via kill() -- nothing we can
2039   do about that!  Conceivably, this could be improved by installing a real
2040   signal handler that warns the user, but that would be pretty complicated,
2041   since we are not always in control of the screen -- e.g. during remote-mode
2042   file transfer.
2043 */
2044     savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
2045 #endif /* SIGDANGER */
2046 #ifdef SIGPIPE
2047 /*
2048   This one comes when a TCP/IP connection is broken by the remote.
2049   We prefer to catch this situation by examining error codes from write().
2050 */
2051     savpipe = signal(SIGPIPE,SIG_IGN);
2052 #endif /* SIGPIPE */
2053     savusr1 = signal(SIGUSR1,SIG_IGN);  /* Ignore user-defined signals */
2054     savusr2 = signal(SIGUSR2,SIG_IGN);
2055 }
2056
2057 VOID
2058 restorsigs() {                          /* Restore these signals */
2059     (VOID) signal(SIGQUIT,savquit);     /* (used in ckufio.c) */
2060 #ifdef SIGDANGER
2061     (VOID) signal(SIGDANGER,savdanger);
2062 #endif /* SIGDANGER */
2063 #ifdef SIGPIPE
2064     (VOID) signal(SIGPIPE,savpipe);
2065 #endif /* SIGPIPE */
2066     (VOID) signal(SIGUSR1,savusr1);
2067     (VOID) signal(SIGUSR2,savusr2);
2068 }
2069
2070 int
2071 sysinit() {
2072     int x;
2073     char * s;
2074 #ifdef CK_UTSNAME
2075     struct utsname name;
2076 #endif /* CK_UTSNAME */
2077
2078     extern char startupdir[];
2079 /*
2080   BEFORE ANYTHING ELSE: Initialize the setuid package.
2081   Change to the user's real user and group ID.
2082   If this can't be done, don't run at all.
2083 */
2084     x = priv_ini();
2085 #ifdef SUIDDEBUG
2086     fprintf(stderr,"PRIV_INI=%d\n",x);
2087 #endif /* SUIDDEBUG */
2088     if (x) {
2089         if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
2090         if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
2091         if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
2092         exit(1);
2093     }
2094     signal(SIGINT,SIG_IGN);             /* Ignore interrupts at first */
2095     signal(SIGFPE,SIG_IGN);             /* Ignore floating-point exceptions */
2096     signal(SIGHUP,sighup);              /* Catch SIGHUP */
2097 #ifndef NOSIGWINCH
2098 #ifdef SIGWINCH
2099     signal(SIGWINCH,winchh);            /* Catch window-size change */
2100 #endif /* SIGWINCH */
2101 #endif /* NOSIGWINCH */
2102
2103 #ifdef SIGXFSZ
2104     signal(SIGXFSZ,SIG_IGN);            /* Ignore writing past file limit */ 
2105 #endif  /* SIGXFSZ */
2106
2107 #ifndef NOJC
2108 /*
2109   Get the initial job control state.
2110   If it is SIG_IGN, that means the shell does not support job control,
2111   and so we'd better not suspend ourselves.
2112 */
2113 #ifdef SIGTSTP
2114     jchdlr = signal(SIGTSTP,SIG_IGN);
2115     if (jchdlr == SIG_IGN) {
2116         jcshell = 0;
2117         debug(F100,"sysinit jchdlr: SIG_IGN","",0);
2118     } else if (jchdlr == SIG_DFL) {
2119         debug(F100,"sysinit jchdlr: SIG_DFL","",0);
2120         jcshell = 1;
2121     } else {
2122         debug(F100,"sysinit jchdlr: other","",0);
2123         jcshell = 3;
2124     }
2125     (VOID) signal(SIGTSTP,jchdlr);      /* Put it back... */
2126 #endif /* SIGTSTP */
2127 #endif /* NOJC */
2128
2129     conbgt(0);                          /* See if we're in the background */
2130     congm();                            /* Get console modes */
2131
2132     (VOID) signal(SIGALRM,SIG_IGN);     /* Ignore alarms */
2133
2134     ignorsigs();                        /* Ignore some other signals */
2135
2136 #ifdef F_SETFL
2137     iniflags = fcntl(0,F_GETFL,0);      /* Get stdin flags */
2138 #endif /* F_SETFL */
2139
2140 #ifdef ultrix
2141     gtty(0,&vanilla);                   /* Get sgtty info */
2142 #else
2143 #ifdef AUX
2144     set42sig();                         /* Don't ask! (hakanson@cs.orst.edu) */
2145 #endif /* AUX */
2146 #endif /* ultrix */
2147 /*
2148   Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
2149   never closes it.  If it is called often enough, we run out of file
2150   descriptors and subsequent open()'s of other devices or files can fail.
2151 */
2152     s = NULL;
2153 #ifndef MINIX
2154     if (isatty(0))                      /* Name of controlling terminal */
2155       s = ttyname(0);
2156     else if (isatty(1))
2157       s = ttyname(1);
2158     else if (isatty(2))
2159       s = ttyname(2);
2160     debug(F110,"sysinit ttyname(0)",s,0);
2161 #endif /* MINIX */
2162
2163 #ifdef BEOS
2164     if (!dftty)
2165       makestr(&dftty,s);
2166 #endif /* BEOS */
2167
2168     if (s)
2169       ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
2170 #ifdef SVORPOSIX
2171     if (!cttnam[0])
2172       ctermid(cttnam);
2173 #endif /* SVORPOSIX */
2174     if (!cttnam[0])
2175       ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
2176     debug(F110,"sysinit CTTNAM",CTTNAM,0);
2177     debug(F110,"sysinit cttnam",cttnam,0);
2178
2179     ttgwsiz();                          /* Get window (screen) dimensions. */
2180
2181 #ifndef NOSYSCONF
2182 #ifdef _SC_OPEN_MAX
2183     ckmaxfiles = sysconf(_SC_OPEN_MAX);
2184 #endif /* _SC_OPEN_MAX */
2185 #endif /* NOSYSCONF */
2186
2187 #ifdef Plan9
2188     if (!backgrd) {
2189         consctlfd = open("/dev/consctl", O_WRONLY);
2190         /*noisefd = open("/dev/noise", O_WRONLY)*/
2191     }
2192     ckxech = 1;
2193 #endif /* Plan9 */
2194
2195 #ifdef CK_UTSNAME
2196     if (uname(&name) > -1) {
2197         ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
2198         ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
2199         ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
2200         ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
2201 #ifdef DEBUG
2202         if (deblog) {
2203             debug(F110,"sysinit uname machine",unm_mch,0);
2204             debug(F110,"sysinit uname sysname",unm_nam,0);
2205             debug(F110,"sysinit uname release",unm_rel,0);
2206             debug(F110,"sysinit uname version",unm_ver,0);
2207         }
2208 #endif /* DEBUG */
2209
2210 #ifdef HPUX9PLUS
2211         if (name.machine[5] == '8')
2212           hpis800 = 1;
2213         else
2214           hpis800 = 0;
2215         debug(F101,"sysinit hpis800","",hpis800);
2216 #endif /* HPUX9PLUS */
2217 #ifdef TRU64
2218         getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
2219         debug(F110,"sysinit getsysinfo model",unm_mod,0);
2220 #endif /* TRU64 */
2221 #ifdef SOLARIS25
2222         sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
2223         debug(F110,"sysinit sysinfo model",unm_mod,0);
2224 #endif /* SOLARIS25 */
2225     }
2226 #endif /* CK_UTSNAME */
2227
2228 #ifdef CK_ENVIRONMENT
2229     {
2230 #ifdef TNCODE
2231         extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
2232         tn_env_prnt[], tn_env_sys[];
2233 #endif /* TNCODE */
2234         extern char uidbuf[];
2235         extern char * whoami();
2236         char *p;
2237 #ifdef CKSENDUID
2238         uidbuf[0] = '\0';
2239 #ifdef IKSD
2240         if (!inserver) {
2241 #endif /* IKSD */
2242             p = getenv("USER");
2243             debug(F110,"sysinit uidbuf from USER",uidbuf,0);
2244             if (!p) p = "";
2245             if (!*p) {
2246                 p = getenv("LOGNAME");
2247                 debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
2248             }
2249             if (!p) p = "";
2250             if (!*p) {
2251                 p = whoami();
2252                 debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
2253             }
2254             if (!p) p = "";
2255             ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
2256 #ifdef IKSD
2257         }
2258 #endif /* IKSD */
2259         debug(F110,"sysinit final uidbuf",uidbuf,0);
2260 #endif /* CKSENDUID */
2261
2262 #ifdef TNCODE
2263         if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
2264         if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
2265         if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
2266         if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
2267 #ifdef aegis
2268         ckstrncpy(tn_env_sys,"Aegis",64);
2269 #else
2270 #ifdef Plan9
2271         ckstrncpy(tn_env_sys,"Plan9",64);
2272 #else
2273         ckstrncpy(tn_env_sys,"UNIX",64);
2274 #endif /* Plan9 */
2275 #endif /* aegis */
2276 #endif /* TNCODE */
2277     }
2278 #endif /* CK_ENVIRONMENT */
2279 #ifdef CK_SNDLOC
2280     {
2281         extern char * tn_loc;
2282         char *p;
2283         if (p = getenv("LOCATION"))
2284           if (tn_loc = (char *)malloc((int)strlen(p)+1))
2285             strcpy(tn_loc,p);           /* safe */
2286     }
2287 #endif /* CK_SNDLOC */
2288
2289     ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
2290     startupdir[CKMAXPATH] = '\0';
2291     x = strlen(startupdir);
2292     if (x <= 0) {
2293         startupdir[0] = '/';
2294         startupdir[1] = '\0';
2295     } else if (startupdir[x-1] != '/') {
2296         startupdir[x] = '/';
2297         startupdir[x+1] = '\0';
2298     }
2299     debug(F110,"sysinit startupdir",startupdir,0);
2300 #ifdef TTLEBUF
2301     le_init();
2302 #endif /* TTLEBUF */
2303 #ifdef BSD44ORPOSIX
2304     /* This should catch the ncurses platforms */
2305     /* Some platforms don't have putenv(), like NeXTSTEP */
2306     putenv("NCURSES_NO_SETBUF=1");
2307 #endif /* BSD44ORPOSIX */
2308     return(0);
2309 }
2310
2311 /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
2312
2313 int
2314 syscleanup() {
2315 #ifdef F_SETFL
2316     if (iniflags > -1)
2317       fcntl(0,F_SETFL,iniflags);        /* Restore stdin flags */
2318 #endif /* F_SETFL */
2319 #ifdef ultrix
2320     stty(0,&vanilla);                   /* Get sgtty info */
2321 #endif /* ultrix */
2322 #ifdef NETCMD
2323     if (ttpid) kill(ttpid,9);
2324 #endif /* NETCMD */
2325     return(0);
2326 }
2327
2328 /*  T T O P E N  --  Open a tty for exclusive access.  */
2329
2330 /*
2331   Call with:
2332     ttname: character string - device name or network host name.
2333     lcl:
2334   If called with lcl < 0, sets value of lcl as follows:
2335   0: the terminal named by ttname is the job's controlling terminal.
2336   1: the terminal named by ttname is not the job's controlling terminal.
2337   But watch out: if a line is already open, or if requested line can't
2338   be opened, then lcl remains (and is returned as) -1.
2339     modem:
2340   Less than zero: ttname is a network host name.
2341   Zero or greater: ttname is a terminal device name.
2342   Zero means a local connection (don't use modem signals).
2343   Positive means use modem signals.
2344    timo:
2345   0 = no timer.
2346   nonzero = number of seconds to wait for open() to return before timing out.
2347
2348   Returns:
2349     0 on success
2350    -5 if device is in use
2351    -4 if access to device is denied
2352    -3 if access to lock directory denied
2353    -2 upon timeout waiting for device to open
2354    -1 on other error
2355 */
2356 static int ttotmo = 0;                  /* Timeout flag */
2357 /* Flag kept here to avoid being clobbered by longjmp.  */
2358
2359 int
2360 ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
2361
2362 #ifdef BSD44
2363 #define ctermid(x) strcpy(x,"")
2364 #else
2365 #ifdef SVORPOSIX
2366 #ifndef CIE
2367     extern char *ctermid();             /* Wish they all had this! */
2368 #else                                   /* CIE Regulus */
2369 #define ctermid(x) strcpy(x,"")
2370 #endif /* CIE */
2371 #endif /* SVORPOSIX */
2372 #endif /* BSD44 */
2373
2374 #ifdef ultrix
2375     int temp = 0;
2376 #endif /* ultrix */
2377
2378 #ifndef OPENFIRST
2379     char fullname[DEVNAMLEN+1];
2380 #endif /* OPENFIRST */
2381
2382     char * fnam;                        /* Full name after expansion */
2383
2384     int y;
2385
2386 #ifndef pdp11
2387 #define NAMEFD   /* Feature to allow name to be an open file descriptor */
2388 #endif /* pdp11 */
2389
2390 #ifdef NAMEFD
2391     char *p;
2392     debug(F101,"ttopen telnetfd","",telnetfd);
2393 #endif /* NAMEFD */
2394
2395     debug(F110,"ttopen ttname",ttname,0);
2396     debug(F110,"ttopen ttnmsv",ttnmsv,0);
2397     debug(F101,"ttopen modem","",modem);
2398     debug(F101,"ttopen netconn","",netconn);
2399     debug(F101,"ttopen ttyfd","",ttyfd);
2400     debug(F101,"ttopen *lcl","",*lcl);
2401     debug(F101,"ttopen ttmdm","",ttmdm);
2402     debug(F101,"ttopen ttnet","",ttnet);
2403
2404     ttpmsk = 0xff;
2405     lockpid[0] = '\0';
2406
2407     if (ttyfd > -1) {                   /* If device already opened */
2408         if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
2409           return(0);                    /* Yes, nothing to do - just return */
2410         ttnmsv[0] = '\0';               /* No, clear out old name */
2411         ttclos(ttyfd);                  /* close old connection.  */
2412     }
2413     wasclosed = 0;                      /* New connection, not closed yet. */
2414     ttpipe = 0;                         /* Assume it's not a pipe */
2415     ttpty = 0;                          /* or a pty... */
2416
2417 #ifdef NETCONN
2418 /*
2419   This is a bit tricky...  Suppose that previously Kermit had dialed a telnet
2420   modem server ("set host xxx:2001, set modem type usr, dial ...").  Then the
2421   connection was closed (ttyfd = -1), and then a REDIAL command was given.  At
2422   this point we've obliterated the negative modem type hack, and so would
2423   treat the IP hostname as a device name, and would then fail because of "No
2424   such device or directory".  But the previous connection has left behind some
2425   clues, so let's use them...
2426 */
2427     if (ttyfd < 0) {                    /* Connection is not open */
2428         if (!strcmp(ttname,ttnmsv)) {   /* Old and new names the same? */
2429             if (((netconn > 0) && (ttmdm < 0)) ||
2430                 ((ttnet > 0) &&
2431                  (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
2432                 ) {
2433                 int x, rc;
2434                 x = (ttmdm < 0) ? -ttmdm : ttnet;
2435                 rc = netopen(ttname, lcl, x);
2436                 debug(F111,"ttopen REOPEN netopen",ttname,rc);
2437                 if (rc > -1) {
2438                     netconn = 1;
2439                     xlocal = *lcl = 1;
2440                 } else {
2441                     netconn = 0;
2442                 }
2443                 gotsigs = 0;
2444                 return(rc);
2445             }
2446         }
2447     }
2448 #endif /* NETCONN */
2449
2450 #ifdef MAXNAMLEN
2451     debug(F100,"ttopen MAXNAMLEN defined","",0);
2452 #else
2453     debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
2454 #endif
2455
2456 #ifdef BSD4
2457     debug(F100,"ttopen BSD4 defined","",0);
2458 #else
2459     debug(F100,"ttopen BSD4 *NOT* defined","",0);
2460 #endif /* BSD4 */
2461
2462 #ifdef BSD42
2463     debug(F100,"ttopen BSD42 defined","",0);
2464 #else
2465     debug(F100,"ttopen BSD42 *NOT* defined","",0);
2466 #endif /* BSD42 */
2467
2468 #ifdef MYREAD
2469     debug(F100,"ttopen MYREAD defined","",0);
2470 #else
2471     debug(F100,"ttopen MYREAD *NOT* defined","",0);
2472 #endif /* MYREAD */
2473
2474 #ifdef  NETCONN
2475     if (modem < 0) {                    /* modem < 0 = code for network */
2476         int x;
2477         ttmdm = modem;
2478         modem = -modem;                 /* Positive network type number */
2479         fdflag = 0;                     /* Stdio not redirected. */
2480         netconn = 1;                    /* And it's a network connection */
2481         debug(F111,"ttopen net",ttname,modem);
2482 #ifdef NAMEFD
2483         for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
2484         if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
2485             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2486             ttfdflg = 1;                /* We got an open file descriptor */
2487             debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
2488             debug(F101,"ttopen net ttyfd","",ttyfd);
2489             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2490             x = 1;                      /* Return code is "good". */
2491             if (telnetfd) {
2492                 ttnet = NET_TCPB;
2493                 if (ttnproto != NP_TCPRAW)
2494                   ttnproto = NP_TELNET;
2495 #ifdef SUNX25
2496             } else if (x25fd) {
2497                 ttnet = NET_SX25;
2498                 ttnproto = NP_NONE;
2499 #endif /* SUNX25 */
2500             }
2501         } else {                        /* Host name or address given */
2502 #ifdef NETPTY
2503             if (modem == NET_PTY) {
2504                 int x;
2505                 if (nopush) {
2506                     debug(F100,"ttopen PTY: nopush","",0);
2507                     return(-1);
2508                 }
2509                 ttnet = NET_PTY;
2510                 ttnproto = NP_NONE;
2511                 netconn = 1;            /* but we don't use network i/o */
2512                 ttpty = 1;
2513                 debug(F110,"ttopen PTY",ttname,0);
2514                 x = do_pty(&ttyfd,ttname,0);
2515                 if (x > -1) {
2516                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2517                     xlocal = *lcl = 1;  /* It's local */
2518                 } else {
2519                     ttpty = 0;
2520                     netconn = 0;
2521                 }
2522                 gotsigs = 0;
2523                 return(x);
2524             }
2525 #endif /* NETPTY */
2526 #ifdef NETCMD
2527 /*
2528   dup2() is not available on older System V platforms like AT&T 3Bx.  For
2529   those systems we punt by not defining NETCMD, but we might be able to do
2530   better -- see workarounds for this problem in ckufio.c (search for dup2).
2531 */
2532             if (modem == NET_CMD) {
2533                 if (nopush) {
2534                     debug(F100,"ttopen pipe: nopush","",0);
2535                     return(-1);
2536                 }
2537                 if (pipe(pipe0) || pipe(pipe1)) {
2538                     perror("Pipe error");
2539                     return(-1);
2540                 }
2541                 ttpid = fork();         /* Make a fork */
2542
2543                 switch (ttpid) {
2544                   case -1:              /* Error making fork */
2545                     close(pipe0[0]);
2546                     close(pipe0[1]);
2547                     close(pipe1[0]);
2548                     close(pipe1[1]);
2549                     perror("Fork error");
2550                     return(-1);
2551                   case 0:               /* Child. */
2552                     close(pipe0[0]);
2553                     close(pipe1[1]);
2554                     dup2(pipe0[1], 1);
2555                     close(pipe0[1]);
2556                     dup2(pipe1[0], 0);
2557                     close(pipe1[0]);
2558                     system(ttname);
2559                     _exit(0);
2560                   default:              /* Parent */
2561                     close(pipe0[1]);
2562                     close(pipe1[0]);
2563                     fdin = pipe0[0];    /* Read from pipe */
2564                     fdout = pipe1[1];   /* Write to pipe */
2565                     ttout = fdopen(fdout,"w"); /* Get stream so we can */
2566                     if (!ttout) {       /* make it unbuffered. */
2567                         perror("fdopen failure");
2568                         return(-1);
2569                     }
2570                     setbuf(ttout,NULL);
2571                     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2572                     xlocal = *lcl = 1;  /* It's local */
2573                     netconn = 1;        /* Call it a network connection */
2574                     ttmdm = modem;      /* Remember network type */
2575                     ttyfd = fdin;
2576                     ttpipe = 1;
2577                     gotsigs = 0;
2578                     return(0);
2579                 }
2580             }
2581 #endif /* NETCMD */
2582 #endif /* NAMEFD */
2583             x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
2584             if (x > -1) {
2585                 ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
2586             } else netconn = 0;
2587 #ifdef NAMEFD
2588         }
2589 #endif /* NAMEFD */
2590
2591 #ifdef sony_news                        /* Sony NEWS */
2592         if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
2593             perror("ttopen error getting Kanji mode (network)");
2594             debug(F111,"ttopen error getting Kanji mode","network",0);
2595             km_ext = -1;                /* Make sure this stays undefined. */
2596         }
2597 #endif /* sony_news */
2598
2599         xlocal = *lcl = 1;              /* Network connections are local. */
2600         debug(F101,"ttopen net x","",x);
2601 #ifdef COMMENT
2602 /* Let netopen() do this */
2603         if (x > -1 && !x25fd)
2604           x = tn_ini();                 /* Initialize TELNET protocol */
2605 #endif /* COMMENT */
2606         gotsigs = 0;
2607         return(x);
2608     } else {                            /* Terminal device */
2609 #endif  /* NETCONN */
2610
2611 #ifdef NAMEFD
2612 /*
2613   This code lets you give Kermit an open file descriptor for a serial
2614   communication device, rather than a device name.  Kermit assumes that the
2615   line is already open, locked, conditioned with the right parameters, etc.
2616 */
2617         for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
2618         if (*p == '\0') {
2619             ttyfd = atoi(ttname);       /* Is there a way to test it's open? */
2620             debug(F111,"ttopen got open fd",ttname,ttyfd);
2621             ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
2622             if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
2623               xlocal = *lcl = 0;        /* we're in remote mode */
2624             else                        /* otherwise */
2625               xlocal = *lcl = 1;        /* local mode. */
2626             netconn = 0;                /* Assume it's not a network. */
2627             tvtflg = 0;                 /* Might need to initialize modes. */
2628             ttmdm = modem;              /* Remember modem type. */
2629             fdflag = 0;                 /* Stdio not redirected. */
2630             ttfdflg = 1;                /* Flag we were opened this way. */
2631             debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
2632             debug(F101,"ttopen non-net ttyfd","",ttyfd);
2633
2634 #ifdef sony_news                        /* Sony NEWS */
2635             /* Get device Kanji mode */
2636             if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
2637                 perror("ttopen error getting Kanji mode");
2638                 debug(F101,"ttopen error getting Kanji mode","",0);
2639                 km_ext = -1;            /* Make sure this stays undefined. */
2640             }
2641 #endif /* sony_news */
2642             gotsigs = 0;
2643             return(0);                  /* Return success */
2644         }
2645 #endif /* NAMEFD */
2646 #ifdef NETCONN
2647     }
2648 #endif /* NETCONN */
2649
2650 /* Here we have to open a serial device of the given name. */
2651
2652     netconn = 0;                        /* So it's not a network connection */
2653     occt = signal(SIGINT, cctrap);      /* Set Control-C trap, save old one */
2654     sigint_ign = 0;
2655
2656     tvtflg = 0;                 /* Flag for use by ttvt(). */
2657                                 /* 0 = ttvt not called yet for this device */
2658
2659     fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
2660     debug(F101,"ttopen fdflag","",fdflag);
2661
2662     ttmdm = modem;                      /* Make this available to other fns */
2663     xlocal = *lcl;                      /* Make this available to other fns */
2664
2665 /* Code for handling bidirectional tty lines goes here. */
2666 /* Use specified method for turning off logins and suppressing getty. */
2667
2668 #ifdef ACUCNTRL
2669     /* Should put call to priv_on() here, but that would be very risky! */
2670     acucntrl("disable",ttname);         /* acucntrl() program. */
2671     /* and priv_off() here... */
2672 #else
2673 #ifdef ATT7300
2674     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
2675       attmodem |= offgetty(ttname);     /* Remember response.  */
2676 #endif /* ATT7300 */
2677 #endif /* ACUCNTRL */
2678
2679 #ifdef OPENFIRST
2680 /*
2681  1985-2001: opens device first then gets lock; reason:
2682  Kermit usually has to run setuid or setgid in order to create a lockfile.
2683  If you give a SET LINE command for a device that happens to be your job's
2684  controlling terminal, Kermit doesn't have to create a lockfile, and in fact
2685  should not create one, and would fail if it tried to if it did not have the
2686  required privileges.  But you can't find out if two tty device names are
2687  equivalent until you have a file descriptor that you can give to ttyname().
2688  But this can cause a race condition between Kermit and [m]getty.  So see
2689  the [#]else part...
2690 */ 
2691
2692 /*
2693  In the following section, we open the tty device for read/write.
2694  If a modem has been specified via "set modem" prior to "set line"
2695  then the O_NDELAY parameter is used in the open, provided this symbol
2696  is defined (e.g. in fcntl.h), so that the program does not hang waiting
2697  for carrier (which in most cases won't be present because a connection
2698  has not been dialed yet).  O_NDELAY is removed later on in ttopen().  It
2699  would make more sense to first determine if the line is local before
2700  doing this, but because ttyname() requires a file descriptor, we have
2701  to open it first.  See do_open().
2702
2703  Now open the device using the desired treatment of carrier.
2704  If carrier is REQUIRED, then open could hang forever, so an optional
2705  timer is provided.  If carrier is not required, the timer should never
2706  go off, and should do no harm...
2707 */
2708     ttotmo = 0;                         /* Flag no timeout */
2709     debug(F101,"ttopen timo","",timo);
2710     debug(F101,"ttopen xlocal","",xlocal);
2711     if (timo > 0) {
2712         int xx;
2713         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2714         xx = alarm(timo);               /* Timed open() */
2715         debug(F101,"ttopen alarm","",xx);
2716         if (
2717 #ifdef CK_POSIX_SIG
2718             sigsetjmp(sjbuf,1)
2719 #else
2720             setjmp(sjbuf)
2721 #endif /* CK_POSIX_SIG */
2722             ) {
2723             ttotmo = 1;                 /* Flag timeout. */
2724         } else ttyfd = do_open(ttname);
2725         ttimoff();
2726         debug(F111,"ttopen","modem",modem);
2727         debug(F101,"ttopen ttyfd","",ttyfd);
2728         debug(F101,"ttopen alarm return","",ttotmo);
2729     } else {
2730         errno = 0;
2731         ttyfd = do_open(ttname);
2732     }
2733     debug(F111,"ttopen ttyfd",ttname,ttyfd);
2734     if (ttyfd < 0) {                    /* If couldn't open, fail. */
2735         debug(F101,"ttopen errno","",errno);
2736         if (errno > 0 && !quiet)
2737           perror(ttname);               /* Print message */
2738
2739 #ifdef ATT7300
2740         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
2741           ongetty(ttnmsv);              /* yes, restart on tty line */
2742         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
2743 #else
2744 #ifdef ACUCNTRL
2745         /* Should put call to priv_on() here, but that would be risky! */
2746         acucntrl("enable",ttname);      /* acucntrl() program. */
2747         /* and priv_off() here... */
2748 #endif /* ACUNTRL */
2749 #endif /* ATT7300 */
2750
2751         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
2752         if (errno == EACCES) {          /* Device is protected against user */
2753             debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
2754             return(-4);
2755         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
2756     }
2757
2758 #ifdef QNX
2759     {
2760         extern int qnxportlock;
2761         x = qnxopencount();
2762         debug(F101,"ttopen qnxopencount","",x);
2763         debug(F101,"ttopen qnxportlock","",qnxportlock);
2764         if (x < 0 && qnxportlock) {
2765             ttclos(0);
2766             printf("?Can't get port open count\n");
2767             printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
2768             return(-1);                 /* Indicate device is in use */
2769         }
2770         if (x > 1) {                    /* 1 == me */
2771             if (qnxportlock)
2772               ttclos(0);
2773               return(-2);               /* Indicate device is in use */
2774             else if (!quiet)
2775               printf("WARNING: \"%s\" looks busy...\n",ttdev);
2776         }
2777     }
2778 #endif /* QNX */
2779
2780 #ifdef Plan9
2781     /* take this opportunity to open the control channel */
2782     if (p9openttyctl(ttname) < 0)
2783 #else
2784     /* Make sure it's a real tty. */
2785     if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
2786 #endif /* Plan9 */
2787       {
2788         fprintf(stderr,"%s is not a terminal device\n",ttname);
2789         debug(F111,"ttopen not a tty",ttname,errno);
2790         close(ttyfd);
2791         ttyfd = -1;
2792         wasclosed = 1;
2793         signal(SIGINT,occt);
2794         return(-1);
2795     }
2796
2797 #ifdef aegis
2798         /* Apollo C runtime claims that console pads are tty devices, which
2799          * is reasonable, but they aren't any good for packet transfer. */
2800         ios_$inq_type_uid((short)ttyfd, ttyuid, st);
2801         if (st.all != status_$ok) {
2802             fprintf(stderr, "problem getting tty object type: ");
2803             error_$print(st);
2804         } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
2805             close(ttyfd); ttyfd = -1;
2806             wasclosed = 1;
2807             errno = ENOTTY; perror(ttname);
2808             signal(SIGINT,occt);
2809             return(-1);
2810         }
2811 #endif /* aegis */
2812
2813     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2814
2815     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
2816
2817 /* Caller wants us to figure out if line is controlling tty */
2818
2819     if (*lcl < 0) {
2820         if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
2821             xlocal = 0;
2822             debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
2823         } else if (strcmp(ttname,cttnam) == 0) {
2824             xlocal = 0;
2825             debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
2826         } else if (cttnam[0]) {
2827 #ifdef BEBOX_DR7
2828             x = ttnmsv;                 /* ttyname() is broken */
2829 #else
2830             x = ttyname(ttyfd);         /* Get real name of ttname. */
2831 #endif /* BEBOX_DR7 */
2832             if (!x) x = "";
2833             if (*x)
2834               xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
2835             else
2836               xlocal = 1;
2837             debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
2838         }
2839     }
2840
2841 #ifndef NOFDZERO
2842 /* Note, the following code was added so that Unix "idle-line" snoopers */
2843 /* would not think Kermit was idle when it was transferring files, and */
2844 /* maybe log people out. */
2845     if (xlocal == 0) {                  /* Remote mode */
2846         if (fdflag == 0) {              /* Standard i/o is not redirected */
2847             debug(F100,"ttopen setting ttyfd = 0","",0);
2848 #ifdef LYNXOS
2849             /* On Lynx OS, fd 0 is open for read only. */
2850             dup2(ttyfd,0);
2851 #endif /* LYNXOS */
2852             close(ttyfd);               /* Use file descriptor 0 */
2853             ttyfd = 0;
2854         } else {                        /* Standard i/o is redirected */
2855             debug(F101,"ttopen stdio redirected","",ttyfd);
2856         }
2857     }
2858 #endif /* NOFDZERO */
2859
2860 /* Now check if line is locked -- if so fail, else lock for ourselves */
2861 /* Note: After having done this, don't forget to delete the lock if you */
2862 /* leave ttopen() with an error condition. */
2863
2864     lkf = 0;                            /* Check lock */
2865     if (xlocal > 0) {
2866         int xx; int xpid;
2867         if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
2868             debug(F111,"ttopen ttlock fails",ttname,xx);
2869             /* WARNING - This close() can hang if tty is an empty socket... */
2870             close(ttyfd);               /* Close the device. */
2871             ttyfd = -1;                 /* Erase its file descriptor. */
2872             wasclosed = 1;
2873             signal(SIGINT,occt);        /* Put old SIGINT back. */
2874             sigint_ign = (occt == SIG_IGN) ? 1 : 0;
2875             if (xx == -2) {             /* If lockfile says device in use, */
2876 #ifndef NOUUCP
2877                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2878                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2879                 if (xpid > -1) {        /* If we got a pid */
2880                     if (!quiet)
2881                       printf("Locked by process %d\n",xpid); /* tell them. */
2882                     sprintf(lockpid,"%d",xpid); /* Record it too */
2883                     debug(F110,"ttopen lockpid",lockpid,0);
2884                 } else if (*flfnam) {
2885                     extern char *DIRCMD;
2886                     char *p = NULL;
2887                     int x;
2888                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2889                     p = malloc(x);      /* Print a directory listing. */
2890 /*
2891   Note: priv_on() won't help here, because we do not pass privs along to
2892   to inferior processes, in this case ls.  So if the real user does not have
2893   directory-listing access to the lockfile directory, this will result in
2894   something like "not found".  That's why we try this only as a last resort.
2895 */
2896                     if (p) {            /* If we got the space... */
2897                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2898                         zsyscmd(p);     /* Get listing. */
2899                         if (p) {        /* free the space */
2900                             free(p);
2901                             p = NULL;
2902                         }
2903                     }
2904                 }
2905 #endif /* NOUUCP */
2906                 return(-5);             /* Code for device in use */
2907             } else return(-3);          /* Access denied */
2908         } else lkf = 1;
2909     }
2910 #else  /* OPENFIRST */
2911
2912 /*
2913   27 Oct 2001: New simpler code that gets the lock first and then opens the
2914   device, which eliminates the race condition.  The downside is you can no
2915   longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
2916   terminal, without trying to create a lockfile, which fails if C-Kermit lacks
2917   privs, and if it succeeds, it has created a lockfile where it didn't create
2918   one before.
2919 */
2920     xlocal = *lcl;                      /* Is the device my login terminal? */
2921     debug(F111,"ttopen xlocal","A",xlocal);
2922     fnam = ttname;
2923     if (strcmp(ttname,CTTNAM) && netconn == 0) {
2924         if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
2925             if ((int)strlen(fullname) > 0)
2926               fnam = fullname;
2927         }
2928     }
2929     debug(F110,"ttopen fnam",fnam,0);
2930     if (xlocal < 0) {
2931         xlocal = (strcmp(fnam,CTTNAM) != 0);
2932     }
2933     debug(F111,"ttopen xlocal","B",xlocal);
2934
2935     lkf = 0;                            /* No lock yet */
2936     if (xlocal > 0) {                   /* If not... */
2937         int xx; int xpid;
2938         xx = ttlock(fnam);              /* Try to lock it. */
2939         debug(F101,"ttopen ttlock","",xx);
2940         if (xx < 0) {                   /* Can't lock it. */
2941             debug(F111,"ttopen ttlock fails",fnam,xx);
2942             if (xx == -2) {             /* If lockfile says device in use, */
2943 #ifndef NOUUCP
2944                 debug(F111,"ttopen reading lockfile pid",flfnam,xx);
2945                 xpid = ttrpid(flfnam);  /* Try to read pid from lockfile */
2946                 if (xpid > -1) {        /* If we got a pid */
2947                     if (!quiet)
2948                       printf("Locked by process %d\n",xpid); /* tell them. */
2949                     ckstrncpy(lockpid,ckitoa(xpid),16);
2950                     debug(F110,"ttopen lockpid",lockpid,0);
2951 #ifndef NOPUSH
2952                 } else if (flfnam[0] && !nopush) {
2953                     extern char *DIRCMD;
2954                     char *p = NULL;
2955                     int x;
2956                     x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
2957                     p = malloc(x);      /* Print a directory listing. */
2958 /*
2959   Note: priv_on() won't help here, because we do not pass privs along to
2960   to inferior processes, in this case ls.  So if the real user does not have
2961   directory-listing access to the lockfile directory, this will result in
2962   something like "not found".  That's why we try this only as a last resort.
2963 */
2964                     if (p) {            /* If we got the space... */
2965                         ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
2966                         zsyscmd(p);     /* Get listing. */
2967                         if (p) {        /* free the space */
2968                             free(p);
2969                             p = NULL;
2970                         }
2971                     }
2972 #endif /* NOPUSH */
2973                 }
2974 #endif /* NOUUCP */
2975                 return(-5);             /* Code for device in use */
2976             } else return(-3);          /* Access denied */
2977         } else lkf = 1;
2978     }
2979     /* Have lock -- now it's safe to open the device */
2980
2981     debug(F101,"ttopen lkf","",lkf);
2982     debug(F101,"ttopen timo","",timo);
2983
2984     ttotmo = 0;                         /* Flag no timeout */
2985     if (timo > 0) {
2986         int xx;
2987         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
2988         xx = alarm(timo);               /* Timed open() */
2989         debug(F101,"ttopen alarm","",xx);
2990         if (
2991 #ifdef CK_POSIX_SIG
2992             sigsetjmp(sjbuf,1)
2993 #else
2994             setjmp(sjbuf)
2995 #endif /* CK_POSIX_SIG */
2996             ) {
2997             ttotmo = 1;                 /* Flag timeout. */
2998         } else {
2999             ttyfd = do_open(fnam);
3000         }
3001         ttimoff();
3002         debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
3003     } else {
3004         errno = 0;
3005         ttyfd = do_open(fnam);
3006         debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
3007     }
3008     if (ttyfd < 0) {                    /* If couldn't open, fail. */
3009         debug(F111,"ttopen errno",fnam,errno);
3010         debug(F111,"ttopen xlocal","C",xlocal);
3011         if (xlocal == 0) {
3012             debug(F100,"ttopen substituting 0","",0);
3013             ttyfd = 0;
3014         } else {
3015             if (errno > 0 && !quiet) {
3016                 debug(F111,"ttopen perror",fnam,errno);
3017                 perror(fnam);           /* Print message */
3018             }
3019             if (ttunlck())                  /* Release the lock file */
3020               fprintf(stderr,"Warning, problem releasing lock\r\n");
3021         }
3022     }
3023
3024     if (ttyfd < 0) {                    /* ttyfd is still < 0? */
3025 #ifdef ATT7300
3026         if (attmodem & DOGETY)          /* was getty(1m) running before us? */
3027           ongetty(ttnmsv);              /* yes, restart on tty line */
3028         attmodem &= ~DOGETY;            /* no phone in use, getty restored */
3029 #else
3030 #ifdef ACUCNTRL
3031         /* Should put call to priv_on() here, but that would be risky! */
3032         acucntrl("enable",fnam);        /* acucntrl() program. */
3033         /* and priv_off() here... */
3034 #endif /* ACUNTRL */
3035 #endif /* ATT7300 */
3036
3037         signal(SIGINT,occt);            /* Put old Ctrl-C trap back. */
3038         if (errno == EACCES) {          /* Device is protected against user */
3039             debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
3040             return(-4);
3041         } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
3042     }
3043
3044 /* Make sure it's a real tty. */
3045
3046 #ifdef Plan9
3047     /* take this opportunity to open the control channel */
3048     if (p9openttyctl(fnam) < 0)       
3049 #else
3050       if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
3051 #endif /* Plan9 */
3052         {
3053             fprintf(stderr,"%s is not a terminal device\n",fnam);
3054             debug(F111,"ttopen not a tty",fnam,errno);
3055             if (ttunlck())              /* Release the lock file */
3056               fprintf(stderr,"Warning, problem releasing lock\r\n");
3057             close(ttyfd);
3058             ttyfd = -1;
3059             wasclosed = 1;
3060             signal(SIGINT,occt);
3061             return(-1);
3062         }
3063
3064 #ifdef aegis
3065     /*
3066       Apollo C runtime claims that console pads are tty devices, which
3067       is reasonable, but they aren't any good for packet transfer.
3068     */
3069     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
3070     if (st.all != status_$ok) {
3071         fprintf(stderr, "problem getting tty object type: ");
3072         error_$print(st);
3073     } else if (ttyuid != sio_$uid) {    /* Reject non-SIO lines */
3074         close(ttyfd); ttyfd = -1;
3075         wasclosed = 1;
3076         errno = ENOTTY; perror(fnam);
3077         signal(SIGINT,occt);
3078         return(-1);
3079     }
3080 #endif /* aegis */
3081
3082     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3083
3084     ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
3085
3086 /* Caller wants us to figure out if line is controlling tty */
3087
3088     if (*lcl < 0) {
3089         char * s;
3090         if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
3091             xlocal = 0;
3092             debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
3093         } else if (strcmp(fnam,cttnam) == 0) {
3094             xlocal = 0;
3095             debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
3096         } else if (cttnam[0]) {
3097 #ifdef BEBOX_DR7
3098             s = ttnmsv;                 /* ttyname() is broken */
3099 #else
3100             s = ttyname(ttyfd);         /* Get real name of ttname. */
3101 #endif /* BEBOX_DR7 */
3102             if (!s) s = "";
3103             if (*s)
3104               xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
3105             else
3106               xlocal = 1;
3107             debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
3108         }
3109     }
3110
3111 #ifndef NOFDZERO
3112 /* Note, the following code was added so that Unix "idle-line" snoopers */
3113 /* would not think Kermit was idle when it was transferring files, and */
3114 /* maybe log people out. */
3115     if (xlocal == 0) {                  /* Remote mode */
3116         if (fdflag == 0) {              /* Standard i/o is not redirected */
3117             debug(F100,"ttopen setting ttyfd = 0","",0);
3118 #ifdef LYNXOS
3119             /* On Lynx OS, fd 0 is open for read only. */
3120             dup2(ttyfd,0);
3121 #endif /* LYNXOS */
3122             close(ttyfd);               /* Use file descriptor 0 */
3123             ttyfd = 0;
3124         } else {                        /* Standard i/o is redirected */
3125             debug(F101,"ttopen stdio redirected","",ttyfd);
3126         }
3127     }
3128 #endif /* NOFDZERO */
3129 #endif /* OPENFIRST */
3130
3131 /* Got the line, now set the desired value for local. */
3132
3133     if (*lcl != 0) *lcl = xlocal;
3134
3135 /* Some special stuff for v7... */
3136
3137 #ifdef  V7
3138 #ifndef MINIX
3139     if (kmem[TTY] < 0) {                /*  If open, then skip this.  */
3140         qaddr[TTY] = initrawq(ttyfd);   /* Init the queue. */
3141         if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
3142             fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
3143             perror("/dev/kmem");
3144             exit(1);
3145         }
3146     }
3147 #endif /* !MINIX */
3148 #endif /* V7 */
3149
3150 /* No failure returns after this point */
3151
3152 #ifdef ultrix
3153     ioctl(ttyfd, TIOCMODEM, &temp);
3154 #ifdef TIOCSINUSE
3155     if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
3156         if (!quiet)
3157           perror(fnam);
3158     }
3159 #endif /* TIOCSINUSE */
3160 #endif /* ultrix */
3161
3162 /* Get tty device settings  */
3163
3164 #ifdef BSD44ORPOSIX                     /* POSIX */
3165     tcgetattr(ttyfd,&ttold);
3166     debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
3167     tcgetattr(ttyfd,&ttraw);
3168     debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
3169     tcgetattr(ttyfd,&tttvt);
3170     debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
3171 #else                                   /* BSD, V7, and all others */
3172 #ifdef ATTSV                            /* AT&T UNIX */
3173     ioctl(ttyfd,TCGETA,&ttold);
3174     debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
3175     ioctl(ttyfd,TCGETA,&ttraw);
3176     ioctl(ttyfd,TCGETA,&tttvt);
3177 #else
3178 #ifdef BELLV10
3179     ioctl(ttyfd,TIOCGETP,&ttold);
3180     debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
3181     ioctl(ttyfd,TIOCGDEV,&tdold);
3182     debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
3183 #else
3184     gtty(ttyfd,&ttold);
3185     debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
3186 #endif /* BELLV10 */
3187
3188 #ifdef sony_news                        /* Sony NEWS */
3189     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
3190         perror("ttopen error getting Kanji mode");
3191         debug(F101,"ttopen error getting Kanji mode","",0);
3192         km_ext = -1;                    /* Make sure this stays undefined. */
3193     }
3194 #endif /* sony_news */
3195
3196 #ifdef TIOCGETC
3197     debug(F100,"ttopen TIOCGETC","",0);
3198     tcharf = 0;                         /* In remote mode, also get */
3199     if (xlocal == 0) {                  /* special characters */
3200         if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
3201             debug(F100,"ttopen TIOCGETC failed","",0);
3202         } else {
3203             tcharf = 1;                 /* It worked. */
3204             ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
3205             debug(F100,"ttopen TIOCGETC ok","",0);
3206         }
3207     }
3208 #else
3209     debug(F100,"ttopen TIOCGETC not defined","",0);
3210 #endif /* TIOCGETC */
3211
3212 #ifdef TIOCGLTC
3213     debug(F100,"ttopen TIOCGLTC","",0);
3214     ltcharf = 0;                        /* In remote mode, also get */
3215     if (xlocal == 0) {                  /* local special characters */
3216         if (ioctl(ttyfd,TIOCGLTC,&ltchold) < 0) {
3217             debug(F100,"ttopen TIOCGLTC failed","",0);
3218         } else {
3219             ltcharf = 1;                /* It worked. */
3220             ioctl(ttyfd,TIOCGLTC,&ltchnoi); /* Get another copy */
3221             debug(F100,"ttopen TIOCGLTC ok","",0);
3222         }
3223     }
3224 #else
3225     debug(F100,"ttopen TIOCGLTC not defined","",0);
3226 #endif /* TIOCGLTC */
3227
3228 #ifdef TIOCLGET
3229     debug(F100,"ttopen TIOCLGET","",0);
3230     lmodef = 0;
3231     if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
3232         debug(F100,"ttopen TIOCLGET failed","",0);
3233     } else {
3234         lmodef = 1;
3235         debug(F100,"ttopen TIOCLGET ok","",0);
3236     }
3237 #endif /* TIOCLGET */
3238
3239 #ifdef BELLV10
3240     ioctl(ttyfd,TIOCGETP,&ttraw);
3241     ioctl(ttyfd,TIOCGETP,&tttvt);
3242 #else
3243     gtty(ttyfd,&ttraw);                 /* And a copy of it for packets*/
3244     gtty(ttyfd,&tttvt);                 /* And one for virtual tty service */
3245 #endif /* BELLV10 */
3246
3247 #endif /* ATTSV */
3248 #endif /* BSD44ORPOSIX */
3249
3250 /* Section for changing line discipline.  It's restored in ttres(). */
3251
3252 #ifdef AIXRS
3253 #ifndef AIX41
3254     { union txname ld_name; int ld_idx = 0;
3255       ttld = 0;
3256         do {
3257           ld_name.tx_which = ld_idx++;
3258           ioctl(ttyfd, TXGETCD, &ld_name);
3259           if (!strncmp(ld_name.tx_name, "rts", 3))
3260             ttld |= 1;
3261         } while (*ld_name.tx_name);
3262         debug(F101,"AIX line discipline","",ttld);
3263       }
3264 #endif /* AIX41 */
3265 #endif /* AIXRS */
3266
3267 #ifdef BSD41
3268 /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
3269     { int k;
3270       ioctl(ttyfd, TIOCGETD, &ttld);    /* Get and save line discipline */
3271       debug(F101,"4.1bsd line discipline","",ttld);
3272       k = OTTYDISC;                     /* Switch to "old" discipline */
3273       k = ioctl(ttyfd, TIOCSETD, &k);
3274       debug(F101,"4.1bsd tiocsetd","",k);
3275     }
3276 #endif /* BSD41 */
3277
3278 #ifdef aegis
3279     /* This was previously done before the last two TCGETA or gtty above,
3280      * in both the ATTSV and not-ATTSV case.  If it is not okay to have only
3281      * one copy if it here instead, give us a shout!
3282      */
3283     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
3284     if (xlocal) {       /* ignore breaks from local line */
3285         sio_$control((short)ttyfd, sio_$int_enable, false, st);
3286         sio_$control((short)ttyfd, sio_$quit_enable, false, st);
3287     }
3288 #endif /* aegis */
3289
3290 #ifdef VXVE
3291     ttraw.c_line = 0;                   /* STTY line 0 for VX/VE */
3292     tttvt.c_line = 0;                   /* STTY line 0 for VX/VE */
3293     ioctl(ttyfd,TCSETA,&ttraw);
3294 #endif /* vxve */
3295
3296 /* If O_NDELAY was used during open(), then remove it now. */
3297
3298 #ifdef O_NDELAY
3299     debug(F100,"ttopen O_NDELAY","",0);
3300     if (xlocal > 0) {
3301       if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
3302         debug(F100,"ttopen fcntl O_NDELAY","",0);
3303 #ifndef aegis
3304         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
3305             debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
3306             perror("Can't unset O_NDELAY");
3307         }
3308 #endif /* aegis */
3309         /* Some systems, notably Xenix (don't know how common this is in
3310          * other systems), need special treatment to get rid of the O_NDELAY
3311          * behaviour on read() with respect to carrier presence (i.e. read()
3312          * returning 0 when carrier absent), even though the above fcntl()
3313          * is enough to make read() wait for input when carrier is present.
3314          * This magic, in turn, requires CLOCAL for working when the carrier
3315          * is absent. But if xlocal == 0, presumably you already have CLOCAL
3316          * or you have a carrier, otherwise you wouldn't be running this.
3317          */
3318         debug(F101,"ttopen xlocal","",xlocal);
3319 #ifdef ATTSV
3320 #ifdef BSD44ORPOSIX
3321 #ifdef COMMENT                          /* 12 Aug 1997 */
3322 #ifdef __bsdi__
3323         if (xlocal)
3324           ttraw.c_cflag |= CLOCAL;
3325 #else
3326 #ifdef __FreeBSD__
3327         if (xlocal)
3328           ttraw.c_cflag |= CLOCAL;
3329 #endif /* __FreeBSD__ */
3330 #endif /* __bsdi__ */
3331 #else /* Not COMMENT */
3332 #ifdef CLOCAL
3333         if (xlocal)                     /* Unset this if it's defined. */
3334           ttraw.c_cflag |= CLOCAL;
3335 #endif /* CLOCAL */
3336 #endif /* COMMENT */
3337         debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
3338         if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
3339             debug(F100,"ttopen POSIX tcseattr fails","",0);
3340             perror("tcsetattr");
3341         }
3342 #else /* !BSD44ORPOSIX */
3343         if (xlocal) {
3344             ttraw.c_cflag |= CLOCAL;
3345             debug(F100,"ttopen calling ioctl(TCSETA)","",0);
3346             errno = 0;
3347             if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
3348                 debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
3349                 perror("ioctl(TCSETA)");
3350             }
3351         }
3352 #endif /* BSD44ORPOSIX */
3353 #endif /* ATTSV */
3354 #ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
3355 /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
3356         debug(F100,"ttopen executing close/open","",0);
3357         close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
3358 #endif /* NOCOTFMC */
3359       }
3360     }
3361 #endif /* O_NDELAY */
3362
3363 /* Instruct the system how to treat the carrier, and set a few other tty
3364  * parameters.
3365  *
3366  * This also undoes the temporary setting of CLOCAL that may have been done
3367  * for the close(open()) above (except in Xenix).  Also throw in ~ECHO, to
3368  * prevent the other end of the line from sitting there talking to itself,
3369  * producing garbage when the user performs a connect.
3370  *
3371  * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
3372  * Now it thinks CLOCAL is always on. It seems the only real solution for
3373  * Xenix is to switch between the lower and upper case device names.
3374  *
3375  * This section may at some future time expand into setting a complete
3376  * collection of tty parameters, or call a function shared with ttpkt()/
3377  * ttvt() that does so.  On the other hand, the initial parameters are not
3378  * that important, since ttpkt() or ttvt() should always fix that before
3379  * any communication is done.  Well, we'll see...
3380  */
3381     if (xlocal) {
3382         curcarr = -2;
3383         debug(F100,"ttopen calling carrctl","",0);
3384         carrctl(&ttraw, ttcarr == CAR_ON);
3385         debug(F100,"ttopen carrctl ok","",0);
3386
3387 #ifdef COHERENT
3388 #define SVORPOSIX
3389 #endif /* COHERENT */
3390
3391 #ifdef SVORPOSIX
3392         ttraw.c_lflag &= ~ECHO;
3393         ttold.c_lflag &= ~ECHO;
3394 #ifdef BSD44ORPOSIX
3395         y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
3396         debug(F101,"ttopen tcsetattr","",y);
3397 #else
3398         y = ioctl(ttyfd, TCSETA, &ttraw);
3399         debug(F100,"ttopen ioctl","",y);
3400 #endif /* BSD44ORPOSIX */
3401
3402 #else /* BSD, etc */
3403         ttraw.sg_flags &= ~ECHO;
3404         ttold.sg_flags &= ~ECHO;
3405 #ifdef BELLV10
3406         y = ioctl(ttyfd,TIOCSETP,&ttraw);
3407         debug(F100,"ttopen ioctl","",y);
3408 #else
3409         y = stty(ttyfd,&ttraw);
3410         debug(F100,"ttopen stty","",y);
3411 #endif /* BELLV10 */
3412 #endif /* SVORPOSIX */
3413
3414 #ifdef COHERENT
3415 #undef SVORPOSIX
3416 #endif /* COHERENT */
3417
3418         /* ttflui(); */  /*  This fails for some reason.  */
3419     }
3420
3421     /* Get current speed */
3422
3423 #ifndef BEBOX
3424     ttspeed = ttgspd();
3425 #else
3426     ttspeed = 19200;
3427 #endif /* !BEBOX */
3428     debug(F101,"ttopen ttspeed","",ttspeed);
3429
3430     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
3431
3432     debug(F101,"ttopen ttyfd","",ttyfd);
3433     debug(F101,"ttopen *lcl","",*lcl);
3434     debug(F111,"ttopen lock file",flfnam,lkf);
3435     signal(SIGINT,occt);
3436     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
3437     gotsigs = 0;
3438     return(0);
3439 }
3440
3441
3442 /*  D O _ O P E N  --  Do the right kind of open() call for the tty. */
3443
3444 int
3445 do_open(ttname) char *ttname; {
3446     int flags;
3447
3448 #ifdef QNX6
3449     /* O_NONBLOCK on /dev/tty makes open() fail */
3450     return(priv_opn(ttname, O_RDWR |
3451                     (
3452                      ((int)strcmp(ttname,"/dev/tty") == 0) ?
3453                      0 :
3454                      (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
3455                     )
3456            ); 
3457 #else  /* !QNX6 */
3458
3459 #ifndef O_NDELAY                        /* O_NDELAY not defined */
3460     return(priv_opn(ttname,2));
3461 #else                                   /* O_NDELAY defined */
3462
3463 #ifdef ATT7300
3464 /*
3465  Open comms line without waiting for carrier so initial call does not hang
3466  because state of "modem" is likely unknown at the initial call  -jrd.
3467  If this is needed for the getty stuff to work, and the open would not work
3468  without O_NDELAY when getty is still on, then this special case is ok.
3469  Otherwise, get rid of it. -ske
3470 */
3471     return(priv_opn(ttname, O_RDWR | O_NDELAY));
3472
3473 #else   /* !ATT7300 */
3474
3475     /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
3476     flags = O_RDWR;
3477     debug(F101,"do_open xlocal","",xlocal);
3478     debug(F111,"do_open flags A",ttname,flags);
3479     if (xlocal && (ttcarr != CAR_ON))
3480       flags |= O_NDELAY;
3481     debug(F111,"do_open flags B",ttname,flags);
3482     return(priv_opn(ttname, flags));
3483 #endif /* !ATT7300 */
3484 #endif /* O_NDELAY */
3485 #endif /* QNX6 */
3486 }
3487
3488 /*  T T C L O S  --  Close the TTY, releasing any lock.  */
3489
3490 static int ttc_state = 0;               /* ttclose() state */
3491 static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
3492
3493 int
3494 ttclos(foo) int foo; {                  /* Arg req'd for signal() prototype */
3495     int xx, x = 0;
3496     extern int exithangup;
3497
3498     debug(F101,"ttclos ttyfd","",ttyfd);
3499     debug(F101,"ttclos netconn","",netconn);
3500     debug(F101,"ttclos xlocal","",xlocal);
3501 #ifdef NOFDZERO
3502     debug(F100,"ttclos NOFDZERO","",0);
3503 #endif /* NOFDZERO */
3504
3505 #ifdef COMMENT
3506 #ifdef TTLEBUF
3507     le_init();                          /* No need for any of this */
3508 #endif /* TTLEBUF */
3509 #endif /* COMMENT */
3510
3511     if (ttyfd < 0)                      /* Wasn't open. */
3512       return(0);
3513
3514     if (ttfdflg)                        /* If we inherited ttyfd from */
3515       return(0);                        /* another process, don't close it. */
3516
3517     tvtflg = 0;                         /* (some day get rid of this...) */
3518     gotsigs = 0;
3519
3520 #ifdef IKSD
3521     if (inserver) {
3522 #ifdef TNCODE
3523           tn_push();                    /* Place any waiting data into input*/
3524           tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
3525           TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
3526           tn_reset();                   /* The Reset Telnet Option table.  */
3527 #endif /* TNCODE */
3528 #ifdef CK_SSL
3529           if (ssl_active_flag) {
3530               if (ssl_debug_flag)
3531                 BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
3532               SSL_shutdown(ssl_con);
3533               SSL_free(ssl_con);
3534               ssl_con = NULL;
3535               ssl_active_flag = 0;
3536           }
3537           if (tls_active_flag) {
3538               if (ssl_debug_flag)
3539                 BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
3540               SSL_shutdown(tls_con);
3541               SSL_free(tls_con);
3542               tls_con = NULL;
3543               tls_active_flag = 0;
3544           }
3545 #endif /* CK_SSL */
3546     }
3547 #endif /* IKSD */
3548 #ifdef NETCMD
3549     if (ttpipe) {                       /* We've been using a pipe */
3550         /* ttpipe = 0; */
3551         if (ttpid > 0) {
3552             int wstat;
3553             int statusp;
3554             close(fdin);                /* Close these. */
3555             close(fdout);
3556             fdin = fdout = -1;
3557             kill(ttpid,1);              /* Kill fork with SIGHUP */
3558             while (1) {
3559                 wstat = wait(&statusp);
3560                 if (wstat == ttpid || wstat == -1)
3561                   break;
3562                 pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
3563             }
3564             ttpid = 0;
3565         }
3566         netconn = 0;
3567         wasclosed = 1;
3568         ttyfd = -1;
3569         return(0);
3570     }
3571 #endif /* NETCMD */
3572 #ifdef NETPTY
3573     if (ttpty) {
3574 #ifndef NODOPTY
3575         end_pty();
3576 #endif /* NODOPTY */
3577         close(ttyfd);
3578         netconn = 0;
3579         wasclosed = 1;
3580         ttpty = 0;
3581         ttyfd = -1;
3582         return(0);
3583     }
3584 #endif /* NETPTY */
3585
3586 #ifdef  NETCONN
3587     if (netconn) {                      /* If it's a network connection. */
3588         debug(F100,"ttclos closing net","",0);
3589         netclos();                      /* Let the network module close it. */
3590         netconn = 0;                    /* No more network connection. */
3591         debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
3592         return(0);
3593     }
3594 #endif  /* NETCONN */
3595
3596     if (xlocal) {                       /* We're closing a SET LINE device */
3597 #ifdef FT21                             /* Fortune 2.1-specific items ... */
3598         ioctl(ttyfd,TIOCHPCL, NULL);
3599 #endif /* FT21 */
3600 #ifdef ultrix                           /* Ultrix-specific items ... */
3601 #ifdef TIOCSINUSE
3602         /* Unset the INUSE flag that we set in ttopen() */
3603         ioctl(ttyfd, TIOCSINUSE, NULL);
3604 #endif /* TIOCSINUSE */
3605         ioctl(ttyfd, TIOCNMODEM, &x);
3606 #ifdef COMMENT
3607         /* What was this? */
3608         ioctl(ttyfd, TIOCNCAR, NULL);
3609 #endif /* COMMENT */
3610 #endif /* ultrix */
3611     }
3612
3613     /* This is to prevent us from sticking in tthang() or close(). */
3614
3615 #ifdef O_NDELAY
3616 #ifndef aegis
3617     if (ttyfd > 0) {                    /* But skip it on stdin. */
3618         debug(F100,"ttclos setting O_NDELAY","",0);
3619         x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
3620 #ifdef DEBUG
3621         if (deblog && x == -1) {
3622             perror("Warning - Can't set O_NDELAY");
3623             debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
3624         }
3625 #endif /* DEBUG */
3626     }
3627 #endif /* aegis */
3628 #endif /* O_NDELAY */
3629
3630     x = 0;
3631     ttc_state = 0;
3632     if (xlocal
3633 #ifdef NOFDZERO
3634         || ttyfd > 0
3635 #endif /* NOFDZERO */
3636         ) {
3637         saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
3638         xx = alarm(8);                  /* Allow 8 seconds. */
3639         debug(F101,"ttclos alarm","",xx);
3640         if (
3641 #ifdef CK_POSIX_SIG
3642             sigsetjmp(sjbuf,1)
3643 #else
3644             setjmp(sjbuf)
3645 #endif /* CK_POSIX_SIG */
3646             ) {                         /* Timer went off? */
3647             x = -1;
3648 #ifdef DEBUG
3649             debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
3650             printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
3651 #endif /* DEBUG */
3652         }
3653         /* Hang up the device (drop DTR) */
3654
3655         errno = 0;
3656         debug(F111,"ttclos A",ckitoa(x),ttc_state);
3657         if (ttc_state < 1) {
3658             ttc_state = 1;
3659             debug(F101,"ttclos exithangup","",exithangup);
3660             if (exithangup) {
3661                 alarm(8);               /* Re-arm the timer */
3662                 debug(F101,"ttclos calling tthang()","",x);
3663                 x = tthang();           /* Hang up first, then... */
3664                 debug(F101,"ttclos tthang()","",x);
3665             }
3666 #ifndef CK_NOHUPCL
3667 /*
3668   Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF.
3669   Suggested by Soewono Effendi.
3670 */
3671 #ifdef HUPCL
3672             else {
3673                 ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */
3674 #ifdef BSD44ORPOSIX
3675                 tcsetattr(ttyfd,TCSANOW,&ttold);
3676 #else /* !BSD44ORPOSIX */
3677 #ifdef ATTSV
3678                 ioctl(ttyfd,TCSETAW,&ttold);            
3679 #else  /* !ATTSV */
3680                 stty(ttyfd,&ttold);
3681 #endif  /* ATTSV */
3682 #endif  /* BSD44ORPOSIX */
3683             }
3684 #endif  /* HUPCL */
3685 #endif  /* CK_NOHUPCL */
3686         }
3687         /* Put back device modes as we found them */
3688
3689         errno = 0;
3690         debug(F111,"ttclos B",ckitoa(x),ttc_state);
3691         if (ttc_state < 2) {
3692             ttc_state = 2;
3693             /* Don't try to mess with tty modes if tthang failed() */
3694             /* since it probably won't work. */
3695             if (x > -1) {
3696                 debug(F101,"ttclos calling ttres()","",x);
3697                 signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
3698                 alarm(8);               /* Re-arm the timer */
3699                 x = ttres();            /* Reset device modes. */
3700                 debug(F101,"ttclos ttres()","",x);
3701                 alarm(0);
3702             }
3703         }
3704         /* Close the device */
3705
3706         errno = 0;
3707         debug(F101,"ttclos C","",ttc_state);
3708         if (ttc_state < 3) {
3709             ttc_state = 3;
3710             errno = 0;
3711             debug(F101,"ttclos calling close","",x);
3712             signal(SIGALRM,xtimerh);    /* Re-enable alarm. */
3713             alarm(8);                   /* Re-arm the timer */
3714             x = close(ttyfd);           /* Close the device. */
3715             debug(F101,"ttclos close()","",x);
3716             if (x > -1)
3717               ttc_state = 3;
3718         }
3719         debug(F101,"ttclos D","",ttc_state);
3720         ttimoff();                      /* Turn off timer. */
3721         if (x < 0) {
3722             printf("?WARNING - close failed: %s\n",ttnmsv);
3723 #ifdef DEBUG
3724             if (deblog) {
3725                 printf("errno = %d\n", errno);
3726                 debug(F101,"ttclos failed","",errno);
3727             }
3728 #endif /* DEBUG */
3729         }
3730         /* Unlock after closing but before any getty mumbo jumbo */
3731
3732         debug(F100,"ttclos about to call ttunlck","",0);
3733         if (ttunlck())                  /* Release uucp-style lock */
3734           fprintf(stderr,"Warning, problem releasing lock\r\n");
3735     }
3736
3737 /* For bidirectional lines, restore getty if it was there before. */
3738
3739 #ifdef ACUCNTRL                         /* 4.3BSD acucntrl() method. */
3740     if (xlocal) {
3741         debug(F100,"ttclos ACUCNTRL","",0);
3742         acucntrl("enable",ttnmsv);      /* Enable getty on the device. */
3743     }
3744 #else
3745 #ifdef ATT7300                          /* ATT UNIX PC (3B1, 7300) method. */
3746     if (xlocal) {
3747         debug(F100,"ttclos ATT7300 ongetty","",0);
3748         if (attmodem & DOGETY)          /* Was getty(1m) running before us? */
3749           ongetty(ttnmsv);              /* Yes, restart getty on tty line */
3750         attmodem &= ~DOGETY;            /* No phone in use, getty restored */
3751     }
3752 #endif /* ATT7300 */
3753 #endif /* System-dependent getty-restoring methods */
3754
3755 #ifdef sony_news
3756     km_ext = -1;                        /* Invalidate device's Kanji-mode */
3757 #endif /* sony_news */
3758
3759     ttyfd = -1;                         /* Invalidate the file descriptor. */
3760     wasclosed = 1;
3761     debug(F100,"ttclos done","",0);
3762     return(0);
3763 }
3764
3765 /*  T T H A N G  --  Hangup phone line or network connection.  */
3766 /*
3767   Returns:
3768   0 if it does nothing.
3769   1 if it believes that it hung up successfully.
3770  -1 if it believes that the hangup attempt failed.
3771 */
3772
3773 #define HUPTIME 500                     /* Milliseconds for hangup */
3774
3775 #ifdef COMMENT
3776 /* The following didn't work but TIOCSDTR does work */
3777 #ifdef UNIXWARE
3778 /* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
3779 #ifndef POSIX                           /* Such as Unixware 1.x, 2.x */
3780 #ifndef HUP_POSIX
3781 #define HUP_POSIX
3782 #endif /* HUP_POSIX */
3783 #endif /* POSIX */
3784 #endif /* UNIXWARE */
3785 #endif /* COMMENT */
3786
3787 #ifndef USE_TIOCSDTR
3788 #ifdef __NetBSD__
3789 /* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
3790 #ifdef TIOCSDTR
3791 #ifdef TIOCCDTR
3792 #define USE_TIOCSDTR
3793 #endif /* TIOCCDTR */
3794 #endif /* TIOCSDTR */
3795 #endif /* __NetBSD__ */
3796 #endif /* USE_TIOCSDTR */
3797
3798 #ifndef HUP_CLOSE_POSIX
3799 #ifdef OU8
3800 #define HUP_CLOSE_POSIX
3801 #else
3802 #ifdef CK_SCOV5
3803 #define HUP_CLOSE_POSIX
3804 #endif /* CK_SCOV5 */
3805 #endif /* OU8 */
3806 #endif /* HUP_CLOSE_POSIX */
3807
3808 #ifdef NO_HUP_CLOSE_POSIX
3809 #ifdef HUP_CLOSE_POSIX
3810 #undef HUP_CLOSE_POSIX
3811 #endif /* HUP_CLOSE_POSIX */
3812 #endif /* NO_HUP_CLOSE_POSIX */
3813
3814 int
3815 tthang() {
3816 #ifdef NOLOCAL
3817     return(0);
3818 #else
3819     int x = 0;                          /* Sometimes used as return code. */
3820 #ifndef POSIX
3821     int z;                              /* worker */
3822 #endif /* POSIX */
3823
3824 #ifdef COHERENT
3825 #define SVORPOSIX
3826 #endif /* COHERENT */
3827
3828 #ifdef SVORPOSIX                        /* AT&T, POSIX, HPUX declarations. */
3829     int spdsav;                         /* for saving speed */
3830 #ifdef HUP_POSIX
3831     int spdsavi;
3832 #else
3833 #ifdef BSD44ORPOSIX
3834     int spdsavi;
3835 #endif /* BSD44ORPOSIX */
3836 #endif /* HUP_POSIX */
3837 #ifdef HPUX
3838 /*
3839   Early versions of HP-UX omitted the mflag typedef.  If you get complaints
3840   about it, just change it to long (or better still, unsigned long).
3841 */
3842     mflag
3843       dtr_down = 00000000000,
3844       modem_rtn,
3845       modem_sav;
3846     char modem_state[64];
3847 #endif /* HPUX */
3848     int flags;                          /* fcntl flags */
3849     unsigned short ttc_save;
3850 #endif /* SVORPOSIX */
3851
3852     if (ttyfd < 0) return(0);           /* Don't do this if not open  */
3853     if (xlocal < 1) return(0);          /* Don't do this if not local */
3854
3855 #ifdef NETCMD
3856     if (ttpipe)
3857       return((ttclos(0) < 0) ? -1 : 1);
3858 #endif /* NETCMD */
3859 #ifdef NETPTY
3860     if (ttpty)
3861       return((ttclos(0) < 0) ? -1 : 1);
3862 #endif /* NETPTY */
3863 #ifdef NETCONN
3864     if (netconn) {                      /* Network connection. */
3865 #ifdef TN_COMPORT
3866         if (istncomport()) {
3867             int rc = tnc_set_dtr_state(0);
3868             if (rc >= 0) {
3869                 msleep(HUPTIME);
3870                 rc = tnc_set_dtr_state(1);
3871             }
3872             return(rc >= 0 ? 1 : -1);
3873         } else
3874 #endif /* TN_COMPORT */
3875           return((netclos() < 0) ? -1 : 1); /* Just close it. */
3876   }
3877 #endif /* NETCONN */
3878
3879 /* From here down, we handle real tty devices. */
3880 #ifdef HUP_POSIX
3881 /*
3882   e.g. for Unixware 2, where we don't have a full POSIX build, we
3883   still have to use POSIX-style hangup.  Thus the duplication of this
3884   and the next case, the only difference being we use a local termios
3885   struct here, since a different model is used elsewhere.
3886
3887   NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
3888   even though it compiles and executes without error, doesn't actually
3889   work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
3890 */
3891     {
3892         struct termios ttcur;
3893         int x;
3894         debug(F100,"tthang HUP_POSIX style","",0);
3895         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3896         debug(F111,"tthang tcgetattr",ckitoa(errno),x);
3897         if (x < 0) return(-1);
3898         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
3899         debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
3900         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
3901         debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
3902         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
3903         debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
3904         if (x < 0) return(-1);
3905         x = cfsetispeed(&ttcur,B0);
3906         debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
3907         if (x < 0) return(-1);
3908         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3909         debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
3910         if (x < 0) return(-1);
3911         msleep(HUPTIME);                /* Sleep 0.5 sec */
3912         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
3913         if (x < 0) return(-1);
3914         debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
3915         x = cfsetispeed(&ttcur,spdsavi);
3916         debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
3917         if (x < 0) return(-1);
3918         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3919         debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
3920         if (x < 0) return(-1);
3921         return(1);
3922     }
3923 #else
3924 #ifdef BSD44ORPOSIX
3925 #ifdef QNX
3926     {
3927         int x;
3928         x = tcdropline(ttyfd,500);
3929         debug(F101,"tthang QNX tcdropline","",x);
3930         ttcur.c_cflag |= CLOCAL;
3931         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
3932         debug(F101,"tthang QNX tcsetattr restore","",x);
3933         if (x < 0) {
3934             debug(F101,"tthang QNX tcsetattr restore errno","",errno);
3935             return(-1);
3936         }
3937         /* Fix flags - ensure O_NONBLOCK is off */
3938
3939         errno = 0;
3940         debug(F101,"tthang QNX iniflags","",iniflags);
3941         if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
3942             debug(F101,"tthang QNX F_SETFL errno","",errno);
3943             return(-1);
3944         }
3945         return(x);
3946     }
3947 #else  /* QNX */
3948     {
3949         int x;
3950 #ifdef USE_TIOCSDTR
3951         debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
3952         errno = 0;
3953         x = ioctl(ttyfd, TIOCCDTR, NULL);
3954         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
3955         if (x < 0) return(-1);
3956         msleep(HUPTIME);                /* Sleep 0.5 sec */
3957         errno = 0;
3958         x = ioctl(ttyfd, TIOCSDTR, NULL);
3959         debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
3960         if (x < 0) return(-1);
3961 #else  /* USE_TIOCSDTR */
3962
3963 #ifdef HUP_CLOSE_POSIX
3964 /*
3965   In OSR5 versions where TIOCSDTR is not defined (up to and including at
3966   least 5.0.6a) the POSIX APIs in the "#else" part below are available but
3967   don't work, and no other APIs are available that do work.  In this case
3968   we have to drop DTR by brute force: close and reopen the port.  This
3969   code actually works, but all the steps are crucial: setting CLOCAL, the
3970   O_NDELAY manipulations, etc.
3971 */
3972         debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
3973         debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
3974         debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
3975         errno = 0;
3976         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
3977         debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
3978         if (x < 0) {
3979             debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
3980             return(-1);
3981         }
3982         errno = 0;
3983
3984         x = close(ttyfd);               /* Close without releasing lock */
3985         if (x < 0) {
3986             debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
3987             return(-1);
3988         }
3989         errno = 0;
3990         x = msleep(500);                /* Pause half a second */
3991         if (x < 0) {                    /* Or if that doesn't work, 1 sec */
3992             debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
3993             sleep(1);
3994         }
3995         errno = 0;
3996         ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
3997         debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
3998         if (ttyfd < 0) {
3999             debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
4000             return(-1);
4001         }
4002         debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
4003
4004         /* Restore previous attributes */
4005
4006         errno = 0;
4007         tvtflg = 0;
4008         ttcur.c_cflag |= CLOCAL;
4009         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4010         debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
4011         if (x < 0) {
4012             debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
4013                   "",errno);
4014             return(-1);
4015         }
4016         /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
4017
4018         errno = 0;
4019         if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
4020             debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
4021             return(-1);
4022         }
4023         debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4024         errno = 0;
4025         x &= ~(O_NONBLOCK|O_NDELAY);
4026         debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
4027         debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
4028         if (fcntl(ttyfd, F_SETFL, x) == -1) {
4029             debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
4030             return(-1);
4031         }
4032 #ifdef DEBUG
4033         if (deblog) {
4034             if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
4035                 debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
4036                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
4037                       "",x&O_NONBLOCK);
4038                 debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
4039                       "",x&O_NDELAY);
4040             }
4041         }
4042 #endif /* DEBUG */
4043
4044 #else  /* HUP_CLOSE_POSIX */
4045         
4046         /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
4047
4048         debug(F100,"tthang BSD44ORPOSIX B0","",0);
4049         x = tcgetattr(ttyfd, &ttcur);   /* Get current attributes */
4050         debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
4051         if (x < 0) return(-1);
4052         spdsav = cfgetospeed(&ttcur);   /* Get current speed */
4053         debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
4054         spdsavi = cfgetispeed(&ttcur);  /* Get current speed */
4055         debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
4056         x = cfsetospeed(&ttcur,B0);     /* Replace by 0 */
4057         debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
4058         if (x < 0) return(-1);
4059         x = cfsetispeed(&ttcur,B0);
4060         debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
4061         if (x < 0) return(-1);
4062         /* This gets EINVAL on NetBSD 1.4.1 because of B0... */
4063         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4064         debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
4065         if (x < 0) return(-1);
4066         msleep(HUPTIME);                /* Sleep 0.5 sec */
4067         debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
4068         x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
4069         debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
4070         if (x < 0) return(-1);
4071         debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
4072         x = cfsetispeed(&ttcur,spdsavi);
4073         debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
4074         if (x < 0) return(-1);
4075         ttcur.c_cflag |= CLOCAL;        /* Don't expect CD after hangup */
4076         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
4077         debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
4078         if (x < 0) return(-1);
4079
4080 #endif /* HUP_CLOSE_POSIX */
4081 #endif /* USE_TIOCSDTR */
4082
4083         return(1);
4084     }
4085
4086 #endif /* QNX */
4087 #else /* BSD44ORPOSIX */
4088
4089 #ifdef aegis                            /* Apollo Aegis */
4090     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
4091     msleep(HUPTIME);                                    /* pause */
4092     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
4093     return(1);
4094 #endif /* aegis */
4095
4096 #ifdef ANYBSD                           /* Any BSD version. */
4097 #ifdef TIOCCDTR                         /* Except those that don't have this */
4098     debug(F100,"tthang BSD style","",0);
4099     if (ioctl(ttyfd,TIOCCDTR,0) < 0) {  /* Clear DTR. */
4100         debug(F101,"tthang TIOCCDTR fails","",errno);
4101         return(-1);
4102     }
4103     msleep(HUPTIME);                    /* For about 1/2 sec */
4104     errno = 0;
4105     x = ioctl(ttyfd,TIOCSDTR,0);        /* Restore DTR */
4106     if (x < 0) {
4107         /*
4108           For some reason, this tends to fail with "no such device or address"
4109           but the operation still works, probably because of the close/open
4110           later on.  So let's not scare the user unnecessarily here.
4111         */
4112         debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
4113         x = 1;                          /* Pretend we succeeded */
4114     } else if (x == 0) x = 1;           /* Success */
4115 #ifdef COMMENT
4116 #ifdef FT21
4117     ioctl(ttyfd, TIOCSAVEMODES, 0);
4118     ioctl(ttyfd, TIOCHPCL, 0);
4119     close(ttyfd);                       /* Yes, must do this twice */
4120     if ((ttyfd = open(ttnmsv,2)) < 0)   /* on Fortune computers... */
4121       return(-1);                       /* (but why?) */
4122     else x = 1;
4123 #endif /* FT21 */
4124 #endif /* COMMENT */
4125 #endif /* TIOCCDTR */
4126     close(do_open(ttnmsv));             /* Clear i/o error condition */
4127     errno = 0;
4128 #ifdef COMMENT
4129 /* This is definitely dangerous.  Why was it here? */
4130     z = ttvt(ttspeed,ttflow);           /* Restore modes. */
4131     debug(F101,"tthang ttvt returns","",z);
4132     return(z < 0 ? -1 : 1);
4133 #else
4134     return(x);
4135 #endif /* COMMENT */
4136 #endif /* ANYBSD */
4137
4138 #ifdef ATTSV
4139 /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
4140
4141 #ifdef HPUX
4142 /* Hewlett Packard allows explicit manipulation of modem signals. */
4143
4144 #ifdef COMMENT
4145 /* Old way... */
4146     debug(F100,"tthang HP-UX style","",0);
4147     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0)        /* lower DTR */
4148       return(-1);                                  /* oops, can't. */
4149     msleep(HUPTIME);                               /* Pause half a second. */
4150     x = 1;                                         /* Set return code */
4151     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) {     /* Get line status. */
4152         if ((modem_rtn & MDCD) != 0)               /* Check if CD is low. */
4153           x = -1;                                  /* CD didn't drop, fail. */
4154     } else x = -1;
4155
4156     /* Even if above calls fail, RTS & DTR should be turned back on. */
4157     modem_rtn = MRTS | MDTR;
4158     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
4159     return(x);
4160 #else
4161 /* New way, from Hellmuth Michaelis */
4162     debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
4163     if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
4164         debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
4165         return(-1);
4166     }
4167     sprintf(modem_state,"%#lx",modem_rtn);
4168     debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
4169     modem_sav = modem_rtn;              /* Save current modem signals */
4170     modem_rtn &= ~MDTR;                 /* Turn DTR bit off */
4171     sprintf(modem_state,"%#lx",modem_rtn);
4172     debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
4173     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
4174         debug(F100,"tthang HP-UX: can't lower DTR!","",0);
4175         return(-1);                     /* oops, can't. */
4176     }
4177     msleep(HUPTIME);                    /* Pause half a second. */
4178     x = 1;                              /* Set return code */
4179     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
4180         sprintf(modem_state,"%#lx",modem_rtn);
4181         debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
4182         if ((modem_rtn & MDCD) != 0) {  /* Check if CD is low. */
4183             debug(F100,"tthang HP-UX: DCD not down","",0);
4184             x = -1;                     /* CD didn't drop, fail. */
4185         } else {
4186             debug(F100,"tthang HP-UX: DCD down","",0);
4187         }
4188     } else {
4189         x = -1;
4190         debug(F100,"tthang HP-UX: can't get DCD status !","",0);
4191     }
4192
4193     /* Even if above calls fail, DTR should be turned back on. */
4194
4195     modem_sav |= MDTR;
4196     if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
4197         x = -1;
4198         debug(F100,"tthang HP-UX: can't set saved state","",0);
4199     } else {
4200         sprintf(modem_state,"%#lx",modem_sav);
4201         debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
4202     }
4203     return(x);
4204 #endif /* COMMENT */
4205
4206 #else /* AT&T but not HP-UX */
4207
4208 /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
4209 /* It is not known how many, if any, systems actually implement them, */
4210 /* so we include them here in ifdef's. */
4211
4212 /*
4213   Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
4214   gives error 22 (invalid argument).
4215 */
4216 #ifndef _IBMR2
4217 /*
4218   No modem-signal twiddling for IBM RT PC or RS/6000.
4219   In AIX 3.1 and earlier, the ioctl() call is broken.
4220   This code could be activated for AIX 3.1 with PTF 2006 or later
4221   (e.g. AIX 3.2), but close/open does the job too, so why bother.
4222 */
4223 #ifdef TIOCMBIS                         /* Bit Set */
4224 #ifdef TIOCMBIC                         /* Bit Clear */
4225 #ifdef TIOCM_DTR                        /* DTR */
4226
4227 /* Clear DTR, sleep 300 msec, turn it back on. */
4228 /* If any of the ioctl's return failure, go on to the next section. */
4229
4230     z = TIOCM_DTR;                      /* Code for DTR. */
4231 #ifdef COMMENT
4232 /*
4233   This was the cause of the troubles with the Solaris Port Monitor.
4234   The problem is: RTS never comes back on.  Moral: Don't do it!
4235   (But why doesn't it come back on?  See the TIOCMBIS call...)
4236 */
4237 #ifdef TIOCM_RTS                        /* Lower RTS too if symbol is known. */
4238     z |= TIOCM_RTS;
4239 #endif /* TIOCM_RTS */
4240 #endif /* COMMENT */
4241
4242     debug(F101,"tthang TIOCM signal mask","",z);
4243     if (ioctl(ttyfd,TIOCMBIC,&z) > -1) {   /* Try to lower DTR. */
4244         debug(F100,"tthang TIOCMBIC ok","",0);
4245         msleep(HUPTIME);                   /* Pause half a second. */
4246         if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
4247             debug(F100,"tthang TIOCMBIS ok","",0);
4248 #ifndef CLSOPN
4249             return(1);                  /* Success, done. */
4250 #endif /* CLSOPN */
4251         } else {                        /* Couldn't raise, continue. */
4252             debug(F101,"tthang TIOCMBIS errno","",errno);
4253         }
4254     } else {                            /* Couldn't lower, continue. */
4255         debug(F101,"tthang TIOCMBIC errno","",errno);
4256     }
4257 #endif /* TIOCM_DTR */
4258 #endif /* TIOCMBIC */
4259 #endif /* TIOCMBIS */
4260 #endif /* _IBMR2 */
4261
4262 /*
4263   General AT&T UNIX case, not HPUX.  The following code is highly suspect.  No
4264   two AT&T-based systems seem to do this the same way.  The object is simply
4265   to turn off DTR and then turn it back on.  SVID says the universal method
4266   for turning off DTR is to set the speed to zero, and this does seem to do
4267   the trick in all cases.  But neither SVID nor any known man pages say how to
4268   turn DTR back on again.  Some variants, like most Xenix implementations,
4269   raise DTR again when the speed is restored to a nonzero value.  Others
4270   require the device to be closed and opened again, but this is risky because
4271   getty could seize the device during the instant it is closed.
4272 */
4273
4274 /* Return code for ioctl failures... */
4275 #ifdef ATT6300
4276     x = 1;                              /* ATT6300 doesn't want to fail... */
4277 #else
4278     x = -1;
4279 #endif /* ATT6300 */
4280
4281     debug(F100,"tthang get settings","",0);
4282     if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
4283       return(x);                        /* Fail if this doesn't work. */
4284     if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
4285       return(x);
4286     ttc_save = ttcur.c_cflag;           /* Remember current speed. */
4287     spdsav = ttc_save & CBAUD;
4288     debug(F101,"tthang speed","",spdsav);
4289
4290 #ifdef O_NDELAY
4291     debug(F100,"tthang turning O_NDELAY on","",0);
4292     fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
4293 #endif /* O_NDELAY */
4294
4295 #ifdef ATT7300 /* This is the way it is SUPPOSED to work */
4296     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4297 #else
4298 #ifdef RTAIX
4299     ttcur.c_cflag &= ~CBAUD;            /* Change the speed to zero.  */
4300 #else          /* This way really works but may be dangerous */
4301 #ifdef u3b2
4302     ttcur.c_cflag = ~(CBAUD|CLOCAL);    /* Special for AT&T 3B2s */
4303                                         /* (CLOCAL must be OFF) */
4304 #else
4305 #ifdef SCO3R2                           /* SCO UNIX 3.2 */
4306 /*
4307   This is complete nonsense, but an SCO user claimed this change made
4308   hanging up work.  Comments from other SCO UNIX 3.2 users would be
4309   appreciated.
4310 */
4311     ttcur.c_cflag = CBAUD|B0;
4312 #else
4313 #ifdef AIXRS                            /* AIX on RS/6000 */
4314 /*
4315   Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
4316   even though you can do it on the built-in port and the 8- and 16-port
4317   adapters.  (Untested on 128-port adapter.)
4318 */
4319     ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
4320 #else                                   /* None of the above */
4321 /*
4322   Set everything, including the speed, to zero, except for the CLOCAL
4323   and HUPCL bits.
4324 */
4325     ttcur.c_cflag = CLOCAL|HUPCL;
4326 #endif /* AIXRS */
4327 #endif /* SCO3R2 */
4328 #endif /* u3b2 */
4329 #endif /* RTAIX */
4330 #endif /* ATT7300 */
4331
4332 #ifdef COMMENT
4333     /* and if none of those work, try one of these... */
4334     ttcur.c_cflag = 0;
4335     ttcur.c_cflag = CLOCAL;
4336     ttcur.c_cflag &= ~(CBAUD|HUPCL);
4337     ttcur.c_cflag &= ~(CBAUD|CREAD);
4338     ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
4339     /* or other combinations */
4340 #endif /* COMMENT */
4341
4342 #ifdef TCXONC
4343     debug(F100,"tthang TCXONC","",0);
4344     if (ioctl(ttyfd, TCXONC, 1) < 0) {
4345         debug(F101,"tthang TCXONC failed","",errno);
4346     }
4347 #endif /* TCXONC */
4348
4349 #ifdef TIOCSTART
4350     debug(F100,"tthang TIOCSTART","",0);
4351     if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
4352         debug(F101,"tthang TIOCSTART failed","",errno);
4353     }
4354 #endif /* TIOCSTART */
4355
4356     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
4357         debug(F101,"tthang TCSETAF failed","",errno);
4358         fcntl(ttyfd, F_SETFL, flags);   /* Restore flags */
4359         return(-1);                     /* before returning. */
4360     }
4361     msleep(300);                        /* Give modem time to notice. */
4362
4363 #ifndef NOCOTFMC
4364
4365 /* Now, even though it doesn't say this in SVID or any man page, we have */
4366 /* to close and reopen the device.  This is not necessary for all systems, */
4367 /* but it's impossible to predict which ones need it and which ones don't. */
4368
4369 #ifdef ATT7300
4370 /*
4371   Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
4372   related ioctl's for their internal modems.  attmodem has getty status and
4373   modem-in-use bit.  Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
4374   but also ruins the file descriptor, and no other phone(7) ioctl call can fix
4375   it.  Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
4376   The only way to undo the damage is to close the fd and then reopen it.
4377 */
4378     if (attmodem & ISMODEM) {
4379         debug(F100,"tthang attmodem close/open","",0);
4380         ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
4381         ioctl(ttyfd,PIOCDISC,&dialer);  /* Disconnect phone. */
4382         close(ttyfd);                   /* Close and reopen the fd. */
4383         ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
4384         attmodem &= ~ISMODEM;           /* Phone no longer in use. */
4385     }
4386 #else /* !ATT7300 */
4387 /* It seems we have to close and open the device for other AT&T systems */
4388 /* too, and this is the place to do it.  The following code does the */
4389 /* famous close(open(...)) magic by default.  If that doesn't work for you, */
4390 /* then try uncommenting the following statement or putting -DCLSOPN in */
4391 /* the makefile CFLAGS. */
4392
4393 /* #define CLSOPN */
4394
4395 #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
4396
4397 #ifdef O_NDELAY
4398 #define OPENFLGS O_RDWR | O_NDELAY
4399 #else
4400 #define OPENFLGS O_RDWR
4401 #endif
4402
4403 #ifndef CLSOPN
4404 /* This method is used by default, i.e. unless CLSOPN is defined. */
4405 /* It is thought to be safer because there is no window where getty */
4406 /* can seize control of the device.  The drawback is that it might not work. */
4407
4408     debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
4409     close(priv_opn(ttnmsv, OPENFLGS));
4410
4411 #else
4412 /* This method is used if you #define CLSOPN.  It is more likely to work */
4413 /* than the previous method, but it's also more dangerous. */
4414
4415     debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
4416     close(ttyfd);
4417     msleep(10);
4418     ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */
4419 #endif /* CLSOPN */
4420 #undef OPENFLGS
4421
4422 #endif /* SCO32 */
4423 #endif /* ATT7300 */
4424
4425 #endif /* NOCOTFMC */
4426
4427 /* Now put all flags & modes back the way we found them. */
4428 /* (Does the order of ioctl & fcntl matter ? ) */
4429
4430     debug(F100,"tthang restore settings","",0);
4431     ttcur.c_cflag = ttc_save;           /* Get old speed back. */
4432     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
4433       return(-1);
4434 #ifdef O_NDELAY
4435 /*
4436   This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
4437   After closing a modem line, the modem will probably not be asserting
4438   carrier any more, so we should not require carrier any more.  If this
4439   causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
4440   than O_NDELAY.
4441 */
4442     flags &= ~O_NDELAY;                 /* Don't require carrier on reopen */
4443 #endif /* O_NDELAY */
4444     if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */
4445       return(-1);
4446
4447     return(1);
4448 #endif /* not HPUX */
4449 #endif /* ATTSV */
4450 #endif /* BSD44ORPOSIX */
4451 #endif /* HUP_POSIX */
4452 #endif /* NOLOCAL */
4453 }
4454
4455 /*
4456   Major change in 5A(174).  We used to use LPASS8, if it was defined, to
4457   allow 8-bit data and Xon/Xoff flow control at the same time.  But this
4458   LPASS8 business seems to have been causing trouble for everybody but me!
4459   For example, Annex terminal servers, commonly used with Encore computers,
4460   do not support LPASS8 even though the Encore itself does.  Ditto for many
4461   other terminal servers, TELNET connections, rlogin connections, etc etc.
4462   Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
4463   serial lines, even though LPASS8 is a feature of 4.3BSD.  So let's turn it
4464   off for everybody.  That means we goes back to using raw mode, with no
4465   flow control.  Phooey.
4466
4467   NOTE: This must be done before the first reference to LPASS8 in this file,
4468   and after the last #include statment.
4469 */
4470 #ifdef LPASS8
4471 #undef LPASS8
4472 #endif /* LPASS8 */
4473
4474 /*  T T R E S  --  Restore terminal to "normal" mode.  */
4475
4476 /* ske@pkmab.se: There are two choices for what this function should do.
4477  * (1) Restore the tty to current "normal" mode, with carrier treatment
4478  * according to ttcarr, to be used after every kermit command. (2) Restore
4479  * the tty to the state it was in before kermit opened it. These choices
4480  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
4481  * is currently being called as in choice (1), but ttold basically holds
4482  * the initial parameters, as in (2), and the description at the beginning
4483  * of this file says (2).
4484  *
4485  * I don't think restoring tty parameters after all kermit commands makes
4486  * much of a difference.  Restoring them upon exit from kermit may be of
4487  * some use in some cases (when the line is not restored automatically on
4488  * close, by the operating system).
4489  *
4490  * I can't choose which one it should be, so I haven't changed it. It
4491  * probably works as it is, too. It would probably even work even with
4492  * ttres() entirely deleted...
4493  *
4494  * (from fdc: Actually, this function operates in remote mode too, so
4495  * it restores the console (command) terminal to whatever mode it was
4496  * in before packet operations began, so that commands work right again.)
4497  */
4498 int
4499 ttres() {                               /* Restore the tty to normal. */
4500     int x;
4501
4502     if (ttyfd < 0) return(-1);          /* Not open. */
4503
4504     if (ttfdflg) return(0);             /* Don't mess with terminal modes if */
4505                                         /* we got ttyfd from another process */
4506 #ifdef  NETCONN
4507     if (netconn) {                      /* Network connection */
4508         tvtflg = 0;
4509 #ifdef TCPSOCKET
4510 #ifdef TCP_NODELAY
4511         {
4512             extern int tcp_nodelay;     /* Just put this back if necessary */
4513             if (ttnet == NET_TCPB) {
4514                 if (nodelay_sav > -1) {
4515                     no_delay(ttyfd,nodelay_sav);
4516                     nodelay_sav = -1;
4517                 }
4518             }
4519         }
4520 #endif /* TCP_NODELAY */
4521 #ifdef TN_COMPORT
4522         if (istncomport()) {
4523             int rc = -1;
4524             if ((rc = tnsetflow(ttflow)) < 0)
4525               return(rc);
4526             if (ttspeed <= 0) 
4527               ttspeed = tnc_get_baud();
4528             else if ((rc = tnc_set_baud(ttspeed)) < 0)
4529               return(rc);
4530             tnc_set_datasize(8);
4531             tnc_set_stopsize(stopbits);
4532
4533 #ifdef HWPARITY
4534             if (hwparity) {
4535                 switch (hwparity) {
4536                   case 'e':                     /* Even */
4537                     debug(F100,"ttres 8 bits + even parity","",0);
4538                     tnc_set_parity(3);
4539                     break;
4540                   case 'o':                     /* Odd */
4541                     debug(F100,"ttres 8 bits + odd parity","",0);
4542                     tnc_set_parity(2);
4543                     break;
4544                   case 'm':                     /* Mark */
4545                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
4546                     tnc_set_parity(4);
4547                     break;
4548                   case 's':                     /* Space */
4549                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
4550                     tnc_set_parity(5);
4551                     break;
4552                 }
4553             } else
4554 #endif /* HWPARITY */
4555             {
4556                 tnc_set_parity(1);              /* None */
4557             }
4558             tvtflg = 0;
4559             return(0);
4560         }
4561 #endif /* TN_COMPORT */
4562 #endif /* TCPSOCKET */
4563         return(0);
4564     }
4565 #endif  /* NETCONN */
4566 #ifdef NETCMD
4567     if (ttpipe) return(0);
4568 #endif /* NETCMD */
4569 #ifdef NETPTY
4570     if (ttpty) return(0);
4571 #endif /* NETPTY */
4572
4573 /* Real terminal device, so restore its original modes */
4574
4575 #ifdef BSD44ORPOSIX                     /* For POSIX like this */
4576     debug(F100,"ttres BSD44ORPOSIX","",0);
4577     x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
4578 #else                                   /* For all others... */
4579 #ifdef ATTSV                            /* For AT&T versions... */
4580     debug(F100,"ttres ATTSV","",0);
4581     x = ioctl(ttyfd,TCSETAW,&ttold);    /* Restore tty modes this way. */
4582 #else
4583 /* Here we restore the modes for BSD */
4584
4585 #ifdef LPASS8                           /* Undo "pass8" if it were done */
4586     if (lmodef) {
4587         if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4588           debug(F100,"ttres TIOCLSET failed","",0);
4589         else
4590           debug(F100,"ttres TIOCLSET ok","",0);
4591     }
4592 #endif /* LPASS8 */
4593
4594 #ifdef CK_DTRCTS                   /* Undo hardware flow if it were done */
4595     if (lmodef) {
4596         if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
4597           debug(F100,"ttres TIOCLSET failed","",0);
4598         else
4599           debug(F100,"ttres TIOCLSET ok","",0);
4600     }
4601 #endif /* CK_DTRCTS */
4602
4603 #ifdef TIOCGETC                         /* Put back special characters */
4604     if (tcharf && (xlocal == 0)) {
4605         if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
4606           debug(F100,"ttres TIOCSETC failed","",0);
4607         else
4608           debug(F100,"ttres TIOCSETC ok","",0);
4609     }
4610 #endif /* TIOCGETC */
4611
4612 #ifdef TIOCGLTC                         /* Put back local special characters */
4613     if (ltcharf && (xlocal == 0)) {
4614         if (ioctl(ttyfd,TIOCSLTC,&ltchold) < 0)
4615           debug(F100,"ttres TIOCSLTC failed","",0);
4616         else
4617           debug(F100,"ttres TIOCSLTC ok","",0);
4618     }
4619 #endif /* TIOCGLTC */
4620
4621 #ifdef BELLV10
4622     debug(F100,"ttres BELLV10","",0);
4623     x = ioctl(ttyfd,TIOCSETP,&ttold);   /* Restore both structs */
4624     x = ioctl(ttyfd,TIOCSDEV,&tdold);
4625 #else
4626     debug(F100,"ttres stty","",0);
4627     x = stty(ttyfd,&ttold);             /* Restore tty modes the old way. */
4628 #endif /* BELLV10 */
4629
4630     if (!xlocal)
4631       msleep(100);                      /* This replaces sleep(1)... */
4632                                         /* Put back sleep(1) if tty is */
4633                                         /* messed up after close. */
4634 #endif /* ATTSV */
4635 #endif /* BSD44ORPOSIX */
4636
4637     debug(F101,"ttres result","",x);
4638 #ifndef QNX
4639     if (x < 0) debug(F101,"ttres errno","",errno);
4640 #endif /* QNX */
4641
4642 #ifdef AIXRS
4643 #ifndef AIX41
4644     x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
4645     debug(F101,"ttres AIX line discipline rts restore","",x);
4646 #endif /* AIX41 */
4647 #endif /* AIXRS */
4648
4649 #ifdef BSD41
4650     if (ttld > -1) {                    /* Put back line discipline */
4651         x = ioctl(ttyfd, TIOCSETD, &ttld);
4652         debug(F101,"ttres BSD41 line discipline restore","",x);
4653         if (x < 0) debug(F101,"...ioctl errno","",errno);
4654         ttld = -1;
4655     }
4656 #endif /* BSD41 */
4657
4658 #ifdef sony_news
4659     x = xlocal ? km_ext : km_con;       /* Restore Kanji mode. */
4660     if (x != -1) {                      /* Make sure we know original modes. */
4661         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
4662             perror("ttres can't set Kanji mode");
4663             debug(F101,"ttres error setting Kanji mode","",x);
4664             return(-1);
4665         }
4666     }
4667     debug(F100,"ttres set Kanji mode ok","",0);
4668 #endif /* sony_news */
4669
4670     tvtflg = 0;                         /* Invalidate terminal mode settings */
4671     debug(F101,"ttres return code","",x);
4672     return(x);
4673 }
4674
4675 #ifndef NOUUCP
4676
4677 /*  T T C H K P I D  --  Check lockfile pid  */
4678 /*
4679   Read pid from lockfile named f, check that it's still valid.
4680   If so, return 1.
4681   On failure to read pid, return 1.
4682   Otherwise, try to delete lockfile f and return 0 if successful, else 1.
4683 */
4684 static int
4685 ttchkpid(f) char *f; {
4686     int pid, mypid, x;
4687     pid = ttrpid(f);                    /* Read pid from file. */
4688     if (pid > -1) {                     /* If we were able to read the pid.. */
4689         debug(F101,"ttchkpid lock pid","",pid);
4690         errno = 0;                      /* See if process still exists. */
4691         mypid = (int)getpid();          /* Get my own pid. */
4692         debug(F101,"ttchkpid my pid","",mypid);
4693         if (pid == mypid) {             /* It's me! */
4694             x = -1;                     /* So I can delete it */
4695             errno = ESRCH;              /* pretend it's invalid */
4696         } else {                        /* It's not me */
4697             x = kill((PID_T)pid, 0);    /* See if it's a live process */
4698             debug(F101,"ttchkpid kill errno","",errno);
4699         }
4700         debug(F101,"ttchkpid pid test","",x);
4701         if (x < 0 && errno == ESRCH) { /* pid is invalid */
4702             debug(F111,"removing stale lock",f,pid);
4703             if (!backgrd)
4704               printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
4705             priv_on();
4706             x = unlink(f);              /* Remove the lockfile. */
4707             priv_off();
4708             debug(F111,"ttchkpid unlink",f,x);
4709             if (x > -1)
4710               return(0);                /* Device is not locked after all */
4711             else if (!backgrd)
4712               perror(f);
4713         }
4714         return(1);
4715     }
4716     return(1);                          /* Failure to read pid */
4717 }
4718
4719 #ifdef HPUX
4720
4721 /* Aliases (different drivers) for HP-UX dialout devices: */
4722
4723 static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
4724 static int ttydexists = 0;
4725
4726 #endif /* HPUX */
4727
4728 /*  T T R P I D  --  Read pid from lockfile "name" */
4729
4730 static int
4731 ttrpid(name) char *name; {
4732     long len;
4733     int x, fd, pid;
4734     short spid;
4735     char buf[32];
4736
4737     debug(F110,"ttrpid",name,0);
4738     if (!name) return(-1);
4739     if (!*name) return(-1);
4740     priv_on();
4741     len = zchki(name);                  /* Get file length */
4742     priv_off();
4743     debug(F101,"ttrpid zchki","",len);
4744     if (len < 0)
4745       return(-1);
4746     if (len > 31)
4747       return(-1);
4748     priv_on();
4749     fd = open(name,O_RDONLY);           /* Try to open lockfile. */
4750     priv_off();
4751     debug(F101,"ttrpid fd","",fd);
4752     if (fd <= 0)
4753       return(-1);
4754 /*
4755   Here we try to be flexible and allow for all different binary and string
4756   formats at runtime, rather than a specific format for each configuration
4757   hardwired at compile time.
4758 */
4759     pid = -1;
4760 #ifndef COHERENT
4761 /*
4762   COHERENT uses a string PID but without leading spaces or 0's, so there is
4763   no way to tell from the file's length whether it contains a string or binary
4764   pid.  So for COHERENT only, we only allow string pids.  For all others, we
4765   decide based on the size of the lockfile.
4766 */
4767     if (len > 4) {                      /* If file > 4 bytes it's a string */
4768 #endif /* COHERENT */
4769         x = read(fd,buf,(int)len);
4770         debug(F111,"ttrpid string read",buf,x);
4771         if (x < 0) {
4772             pid = -1;
4773         } else {
4774             buf[31] = '\0';
4775             x = sscanf(buf,"%d",&pid);  /* Get the integer pid from it. */
4776         }
4777 #ifndef COHERENT
4778     } else if (len == 4) {              /* 4 bytes so binary */
4779         x = read(fd, (char *)&pid, 4);  /* Read the bytes into an int */
4780         debug(F101,"ttrpid integer read","",x);
4781         if (x < 4)
4782           pid = -1;
4783     } else if (len == 2) {              /* 2 bytes binary */
4784         x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */
4785         debug(F101,"ttrpid short read","",x);
4786         if (x < 2)
4787           pid = -1;
4788         else
4789           pid = spid;
4790     } else
4791       pid = -1;
4792 #endif /* COHERENT */
4793     close(fd);                          /* Close the lockfile */
4794     debug(F101,"ttrpid pid","",pid);
4795     return(pid);
4796 }
4797 #endif /* NOUUCP */
4798
4799 /*  T T L O C K  */
4800
4801 /*
4802   This function attempts to coordinate use of the communication device with
4803   other copies of Kermit and any other program that follows the UUCP
4804   device-locking conventions, which, unfortunately, vary among different UNIX
4805   implementations.  The idea is to look for a file of a certain name, the
4806   "lockfile", in a certain directory.  If such a file is found, then the line
4807   is presumed to be in use, and Kermit should not use it.  If no such file is
4808   found, Kermit attempts to create one so that other programs will not use the
4809   same line at the same time.  Because the lockfile and/or the directory it's
4810   in might lack write permission for the person running Kermit, Kermit could
4811   find itself running setuid to uucp or other user that does have the
4812   necessary permissions.  At startup, Kermit has changed its effective uid to
4813   the user's real uid, and so ttlock() must switch back to the original
4814   effective uid in order to create the lockfile, and then back again to the
4815   real uid to prevent unauthorized access to other directories or files owned
4816   by the user the program is setuid to.
4817
4818   Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
4819   based on suggestions from Warren Tucker.  Call with pointer to name of
4820   tty device.  Returns:
4821
4822    0 on success
4823   -1 on failure
4824
4825   Note: Once privileges are turned on using priv_on(), it is essential that
4826   they are turned off again before this function returns.
4827 */
4828 #ifdef SVR4                             /* Lockfile uses device numbers. */
4829 /*
4830   Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
4831   it is the behavior of the "reference version" of SVR4, i.e. the Intel
4832   port from UNIX Systems Laboratories, then called Univel UnixWare,
4833   then called Novell UnixWare, then called SCO Unixware, then called Caldera
4834   Open UNIX...  It also makes much more sense than device-name-based lockfiles
4835   since there can be multiple names for the same device, symlinks, etc.
4836 */
4837 #ifndef NOLFDEVNO
4838 #ifndef LFDEVNO                         /* Define this for SVR4 */
4839 #ifndef AIXRS                           /* But not for RS/6000 AIX 3.2, etc. */
4840 #ifndef BSD44                           /* If anybody else needs it... */
4841 #ifndef __386BSD__
4842 #ifndef __FreeBSD__
4843 #ifndef HPUX10
4844 #ifndef IRIX51                          /* SGI IRIX 5.1 or later */
4845 #ifndef CK_SCOV5                        /* SCO Open Server 5.0 */
4846 #define LFDEVNO
4847 #endif /* CK_SCOV5 */
4848 #endif /* IRIX51 */
4849 #endif /* HPUX10 */
4850 #endif /* __FreeBSD__ */
4851 #endif /* __386BSD__ */
4852 #endif /* BSD44 */
4853 #endif /* AIXRS */
4854 #endif /* LFDEVNO */                    /* ... define it here or on CC */
4855 #endif /* NOLFDEVNO */
4856 #endif /* SVR4 */                       /* command line. */
4857
4858 #ifdef COHERENT
4859 #define LFDEVNO
4860 #endif /* COHERENT */
4861
4862 /*
4863   For platforms where the lockfile name is made from device/major/minor
4864   device number, as in SVR4.  Which, if we must have lockfiles at all, is
4865   by far the best format, since it eliminates all the confusion that stems
4866   from multiple names (or drivers) for the same port, not to mention
4867   symlinks.  It might even be a good idea to start using this form even
4868   on platforms where it's not supported, alongside the normal forms for those
4869   platforms, in order to get people used to it...
4870 */
4871 #ifdef LFDEVNO
4872 #ifndef major                           /* If we didn't find it */
4873 #ifdef SVR4                             /* then for Sys V R4 */
4874 #include <sys/mkdev.h>                  /* look here */
4875 #else                                   /* or for SunOS versions */
4876 #ifdef SUNOS4                           /* ... */
4877 #include <sys/sysmacros.h>              /* look here */
4878 #else                                   /* Otherwise take a chance: */
4879 #define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
4880 #define minor(dev) ( (int) ( (dev) & 0xff))
4881 #endif /* SUNOS4 */
4882 #endif /* SVR4 */
4883 #endif /* major */
4884 #endif /* LFDEVNO */
4885
4886 /* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
4887
4888 #ifdef LOCKF
4889 #ifndef F_TLOCK
4890 #undef LOCKF
4891 #ifndef NOLOCKF
4892 #define NOLOCKF
4893 #endif /* NOLOCKF */
4894 #endif /* F_TLOCK */
4895 #endif /* LOCKF */
4896
4897 #ifdef LOCKF
4898 #ifndef F_ULOCK
4899 #undef LOCKF
4900 #ifndef NOLOCKF
4901 #define NOLOCKF
4902 #endif /* NOLOCKF */
4903 #endif /* F_ULOCK */
4904 #endif /* LOCKF */
4905
4906 static char linkto[DEVNAMLEN+1];
4907 static char * linkdev = NULL;
4908
4909 #ifndef NOUUCP
4910 #ifdef USETTYLOCK
4911 #ifdef LOCK_DIR
4912 char * uucplockdir = LOCK_DIR;
4913 #else
4914 char * uucplockdir = "";
4915 #endif /* LOCK_DIR */
4916 #else
4917 #ifdef LOCK_DIR
4918 char * uucplockdir = LOCK_DIR;
4919 #else
4920 char * uucplockdir = "";
4921 #endif /* LOCK_DIR */
4922 #endif /* USETTYLOCK */
4923 #else
4924 char * uucplockdir = "";
4925 #endif /* NOUUCP */
4926
4927 #ifdef QNX                              /* Only for QNX4 */
4928 int                                     /* Visible to outside world */
4929 qnxopencount() {                        /* Get QNX device open count */
4930     struct _dev_info_entry info;
4931     int x;
4932
4933     x = -1;                             /* Unknown */
4934     if (ttyfd > -1) {
4935         if (!dev_info(ttyfd, &info)) {
4936             debug(F101,"ttlock QNX open_count","",info.open_count);
4937             x = info.open_count;
4938         }
4939     }
4940     return(x);
4941 }
4942 #endif /* QNX */
4943
4944 char *
4945 ttglckdir() {                           /* Get Lockfile directory name */
4946 #ifdef __OpenBSD__
4947     return("/var/spool/lock");
4948 #else /* __OpenBSD__ */
4949 #ifdef __FreeBSD__
4950     return("/var/spool/lock");
4951 #else  /* __FreeBSD__ */
4952 #ifdef LOCK_DIR
4953     char * s = LOCK_DIR;
4954 #endif /* LOCK_DIR */
4955 #ifdef NOUUCP
4956     return("");
4957 #else  /* NOUUCP */
4958 #ifdef LOCK_DIR
4959     return(s);
4960 #else  /* LOCK_DIR */
4961     return("");
4962 #endif /* LOCK_DIR */
4963 #endif /* NOUUCP */
4964 #endif /* __FreeBSD__ */
4965 #endif /* __OpenBSD__ */
4966 }
4967
4968 static int
4969 ttlock(ttdev) char *ttdev; {
4970
4971     int x, n;
4972     int islink = 0;
4973
4974 #ifdef NOUUCP
4975     debug(F100,"ttlock NOUUCP","",0);
4976     ckstrncpy(flfnam,"NOLOCK",FLFNAML);
4977     haslock = 1;
4978     return(0);
4979 #else /* !NOUUCP */
4980
4981 #ifdef USETTYLOCK
4982     haslock = 0;                        /* Not locked yet. */
4983     *flfnam = '\0';                     /* Lockfile name is empty. */
4984     if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
4985       ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
4986     else
4987       ckstrncpy(lockname,ttdev,DEVNAMLEN);
4988 /*
4989   This might be overkill, but it's not clear from the man pages whether
4990   ttylock() can be called without calling ttylocked() first, since the doc
4991   says that ttylocked() removes any stale lockfiles, but it does not say this
4992   about ttylock().  Also the docs don't say what ttylocked() returns in the
4993   case when it finds and removes a stale lockfile.  So one or both calls to
4994   to ttylocked() might be superfluous, but they should do no harm.  Also I'm
4995   assuming that we have to do all the same ID swapping, etc, with these
4996   routines as we do without them.  Thus the priv_on/off() sandwich.
4997 */
4998 #ifdef USE_UU_LOCK
4999     priv_on();                          /* Turn on privs */
5000     x = uu_lock(lockname);              /* Try to set the lock */
5001     priv_off();                         /* Turn privs off */
5002     debug(F111,"ttlock uu_lock",lockname,x);
5003     switch (x) {
5004       case UU_LOCK_INUSE:
5005         return(-2);
5006       case UU_LOCK_OK:
5007 #ifdef BSD44
5008         ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
5009 #endif /* BSD44 */
5010         haslock = 1;
5011         return(0);
5012       default:
5013         return(-1);
5014     }
5015 #else  /* USE_UU_LOCK */
5016     priv_on();                          /* Turn on privs */
5017     if (ttylocked(lockname)) {          /* This should remove any stale lock */
5018         if (ttylocked(lockname)) {      /* so check again. */
5019             priv_off();
5020             return(-5);                 /* Still locked, fail. */
5021         }
5022     }
5023     x = ttylock(lockname);              /* Lock it. */
5024     priv_off();                         /* Turn off privs */
5025
5026     debug(F111,"ttlock lockname",lockname,x);
5027     if (x > -1) {
5028         /*
5029           We don't really know the name of the lockfile, but
5030           this is what the man page says it is.  In USETTYLOCK
5031           builds, it is used only for display by SHOW COMM.
5032         */
5033         ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
5034         haslock = 1;
5035     }
5036     return(x);
5037 #endif /* USE_UU_LOCK */
5038 #else  /* Systems that don't have ttylock()... */
5039
5040 #ifndef HPUX
5041
5042     int lockfd;                         /* File descriptor for lock file. */
5043     PID_T pid;                          /* Process id of this process. */
5044     int tries;                          /* How many times we've tried... */
5045     struct stat devbuf;                 /* For device numbers (SVR4). */
5046
5047 #ifdef PIDSTRING
5048     char pid_str[32];                   /* My pid in string format. */
5049 #endif /* PIDSTRING */
5050
5051     char *device, *devname;
5052
5053 #define LFNAML 256                      /* Max length for lock file name. */
5054     char lockfil[LFNAML];               /* Lock file name */
5055 #ifdef RTAIX
5056     char lklockf[LFNAML];               /* Name for link to lock file  */
5057 #endif /* RTAIX */
5058 #ifdef CKSYMLINK
5059     char symlock[LFNAML];               /* Name for symlink lockfile name */
5060 #endif /* CKSYMLINK */
5061     char tmpnam[LFNAML+30];             /* Temporary lockfile name. */
5062     char *lockdir = LOCK_DIR;           /* Defined near top of this file, */
5063                                         /* or on cc command line. */
5064     haslock = 0;                        /* Not locked yet. */
5065     *flfnam = '\0';                     /* Lockfile name is empty. */
5066     lock2[0] = '\0';                    /* Clear secondary lockfile name. */
5067     pid = getpid();                     /* Get id of this process. */
5068
5069 /*  Construct name of lockfile and temporary file */
5070
5071 /*  device  = name of tty device without the path, e.g. "ttyh8" */
5072 /*  lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
5073
5074     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5075
5076     if (stat(ttdev,&devbuf) < 0)
5077       return(-1);
5078
5079 #ifdef CKSYMLINK
5080     islink = 1;                         /* Assume it's a symlink */
5081     linkto[0] = '\0';                   /* But we don't know to what */
5082 #ifdef COMMENT
5083 /*
5084   This is undependable.  If it worked it would save the readlink call if
5085   we knew the device name was not a link.
5086 */
5087 #ifdef S_ISLNK
5088     islink = S_ISLNK(devbuf.st_mode);
5089     debug(F101,"ttlock stat S_ISLNK","",islink);
5090 #endif /* S_ISLNK */
5091 #endif /* COMMENT */
5092     if (islink) {
5093         n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
5094         debug(F111,"ttlock readlink",ttdev,n);
5095         if (n > -1)                     /* It is */
5096           linkto[n] = '\0';
5097         else                            /* It's not */
5098           islink = 0;
5099         debug(F111,"ttlock link",linkto,islink);
5100     }
5101     if (islink) {
5102         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5103         debug(F110,"ttlock linkdev",linkdev,0);
5104     }
5105 #endif /* CKSYMLINK */
5106
5107 /*
5108   On SCO platforms, if we don't have a symlink, then let's pretend the
5109   name given for the device is a symlink, because later we will change
5110   the name if it contains any uppercase characters.
5111 */
5112 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5113     if (!islink) {
5114         islink = 1;
5115         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5116         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5117         debug(F110,"ttlock linkdev",linkdev,0);
5118     }
5119 #else
5120 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5121     if (!islink) {
5122         islink = 1;
5123         ckstrncpy(linkto,ttdev,DEVNAMLEN);
5124         linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
5125         debug(F110,"ttlock linkdev",linkdev,0);
5126     }
5127 #endif /* M_XENIX */
5128 #endif /* CK_SCOV5 */
5129
5130 #ifdef ISIII                            /* Interactive System III, PC/IX */
5131     ckstrncpy(lockfil, device, DEVNAMLEN);
5132 #else  /* not ISIII */
5133 #ifdef LFDEVNO                          /* Lockfilename has device numbers. */
5134 #ifdef COHERENT
5135     sprintf(lockfil,"LCK..%d.%d",       /* SAFE */
5136             major(devbuf.st_rdev),         /* major device number */
5137             0x1f & minor(devbuf.st_rdev)); /* minor device number */
5138 #else
5139     /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
5140     /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
5141     sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
5142             major(devbuf.st_dev),       /* device */
5143             major(devbuf.st_rdev),      /* major device number */
5144             minor(devbuf.st_rdev));     /* minor device number */
5145 #endif /* COHERENT */
5146 #else  /* Not LFDEVNO */
5147 #ifdef PTX                              /* Dynix PTX */
5148     if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
5149         if ((int)strlen(device) + 8 < LFNAML)
5150           sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
5151         else
5152           ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5153     } else
5154 #endif /* PTX */
5155       if ((int)strlen(device) + 5 < LFNAML)
5156         sprintf(lockfil,"LCK..%s", device);
5157       else
5158         ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
5159 #ifdef RTAIX
5160     ckstrncpy(lklockf,device,DEVNAMLEN);
5161 #endif /* RTAIX */
5162 #ifdef CKSYMLINK
5163     symlock[0] = '\0';
5164     if (islink)
5165       ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
5166 #endif /* CKSYMLINK */
5167 #endif /* LFDEVNO */
5168 #endif /* ISIII */
5169
5170 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
5171     {
5172         /* Lowercase the entire filename. */
5173         /* SCO says we must do this in V5.0 and later. */
5174         /* BUT... watch out for devices -- like Digiboard Portserver */
5175         /* That can have hundreds of ports... */
5176         char *p = (char *)(lockfil + 5);
5177         while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
5178     }
5179 #ifdef CKSYMLINK
5180     if (islink) {                       /* If no change */
5181         if (!strcmp(lockfil,symlock)) { /* then no second lockfile needed */
5182             islink = 0;
5183             symlock[0] = '\0';
5184         }
5185     }
5186 #endif /* CKSYMLINK */
5187 #else
5188 #ifdef M_XENIX                          /* SCO Xenix or UNIX */
5189     {
5190         int x; char c;
5191         x = (int)strlen(lockfil) - 1;   /* Get last letter of device name. */
5192         if (x > 0) {                    /* If it's uppercase, lower it. */
5193             c = lockfil[x];
5194             if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
5195         }
5196     }
5197 #ifdef CKSYMLINK
5198     if (islink) {
5199         if (!strcmp(lockfil,symlock)) { /* No change */
5200             islink = 0;                 /* so no second lockfile */
5201             symlock[0] = '\0';
5202         }
5203     }
5204 #endif /* CKSYMLINK */
5205 #endif /* M_XENIX */
5206 #endif /* CK_SCOV5 */
5207
5208 /*  flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
5209 /*  tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
5210
5211     ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
5212
5213 #ifdef RTAIX
5214     ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
5215 #endif /* RTAIX */
5216
5217 #ifndef LFDEVNO
5218 #ifdef CKSYMLINK
5219     /* If it's a link then also make a lockfile for the real name */
5220     debug(F111,"ttlock link symlock",symlock,islink);
5221     if (islink && symlock[0]) {
5222         /* But only if the lockfile names would be different. */
5223         /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
5224         ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
5225         debug(F110,"ttlock lock2",lock2,0);
5226         if (!strcmp(lock2,flfnam)) {    /* Are lockfile names the same? */
5227             debug(F100,"ttlock lock2 cleared","",0);
5228             lock2[0] = '\0';            /* Clear secondary lockfile name. */
5229         }
5230     }
5231 #endif /* CKSYMLINK */
5232 #endif /* LFDEVNO */
5233
5234     sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
5235     debug(F110,"ttlock flfnam",flfnam,0);
5236     debug(F110,"ttlock tmpnam",tmpnam,0);
5237
5238     priv_on();                          /* Turn on privileges if possible. */
5239     lockfd = creat(tmpnam, 0444);       /* Try to create temp lock file. */
5240     if (lockfd < 0) {                   /* Create failed. */
5241         debug(F111,"ttlock creat failed",tmpnam,errno);
5242         if (errno == ENOENT) {
5243             perror(lockdir);
5244             printf("UUCP not installed or Kermit misconfigured\n");
5245         } else {
5246             if (!quiet)
5247               perror(lockdir);
5248             unlink(tmpnam);             /* Get rid of the temporary file. */
5249         }
5250         priv_off();                     /* Turn off privileges!!! */
5251         return(-1);                     /* Return failure code. */
5252     }
5253 /* Now write the pid into the temp lockfile in the appropriate format */
5254
5255 #ifdef PIDSTRING                        /* For Honey DanBer UUCP, */
5256     sprintf(                            /* write PID as decimal string */
5257             pid_str,
5258 #ifdef LINUXFSSTND                      /* The "Linux File System Standard" */
5259 #ifdef FSSTND10                         /* Version 1.0 calls for */
5260             "%010d\n",                  /* leading zeros */
5261 #else                                   /* while version 1.2 calls for */
5262             "%10d\n",                   /* leading spaces */
5263 #endif /* FSSTND10 */
5264 #else
5265 #ifdef COHERENT
5266             "%d\n",                     /* with leading nothing */
5267 #else
5268             "%10d\n",                   /* with leading blanks */
5269 #endif /* COHERENT */
5270 #endif /* LINUXFSSTND */
5271             (int) pid
5272             );                          /* safe */
5273     write(lockfd, pid_str, 11);
5274     debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
5275
5276 #else /* Not PIDSTRING, use integer PID */
5277
5278     write(lockfd, (char *)&pid, sizeof(pid) );
5279     debug(F101,"ttlock pid","",(int) pid);
5280
5281 #endif /* PIDSTRING */
5282
5283 /* Now try to rename the temp file to the real lock file name. */
5284 /* This will fail if a lock file of that name already exists.  */
5285
5286     close(lockfd);                      /* Close the temp lockfile. */
5287     chmod(tmpnam,0444);                 /* Permission for a valid lock. */
5288     tries = 0;
5289     while (!haslock && tries++ < 2) {
5290         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5291         if (haslock) {                        /* If we got the lockfile */
5292 #ifdef RTAIX
5293             link(flfnam,lkflfn);
5294 #endif /* RTAIX */
5295 #ifdef CKSYMLINK
5296 #ifndef LFDEVNO
5297             if (islink && lock2[0])
5298               link(flfnam,lock2);
5299 #endif /* LFDEVNO */
5300 #endif /* CKSYMLINK */
5301
5302 #ifdef COMMENT
5303 /* Can't do this any more because device is not open yet so no ttyfd. */
5304 #ifdef LOCKF
5305 /*
5306   Advisory file locking works on SVR4, so we use it.  In fact, it is
5307   necessary in some cases, e.g. when SLIP is involved.  But it still doesn't
5308   seem to prevent multiple users accessing the same device by different names.
5309 */
5310             while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
5311                 debug(F111, "ttlock lockf returns errno", "", errno);
5312                 if ((++tries >= 3) || (errno != EAGAIN)) {
5313                     x = unlink(flfnam); /* remove the lockfile */
5314 #ifdef RTAIX
5315                     unlink(lkflfn);     /* And any links to it... */
5316 #endif /* RTAIX */
5317 #ifdef CKSYMLINK
5318 #ifndef LFDEVNO
5319                     if (islink && lock2[0])
5320                       unlink(lock2);    /* ditto... */
5321 #endif /* LFDEVNO */
5322 #endif /* CKSYMLINK */
5323                     debug(F111,"ttlock unlink",flfnam,x);
5324                     haslock = 0;
5325                     break;
5326                 }
5327                 sleep(2);
5328             }
5329             if (haslock)                /* If we got an advisory lock */
5330 #endif /* LOCKF */
5331 #endif /* COMMENT */
5332               break;                    /* We're done. */
5333
5334         } else {                        /* We didn't create a new lockfile. */
5335             priv_off();
5336             if (ttchkpid(flfnam)) {     /* Check existing lockfile */
5337                 priv_on();              /* cause ttchkpid turns priv_off... */
5338                 unlink(tmpnam);         /* Delete the tempfile */
5339                 debug(F100,"ttlock found tty locked","",0);
5340                 priv_off();             /* Turn off privs */
5341                 return(-2);             /* Code for device is in use. */
5342             }
5343             priv_on();
5344         }
5345     }
5346     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5347     priv_off();                         /* Turn off privs */
5348     return(haslock ? 0 : -1);           /* Return link's return code. */
5349
5350 #else /* HPUX */
5351
5352 /*
5353   HP-UX gets its own copy of this routine, modeled after the observed behavior
5354   of the HP-UX 'cu' program.  HP-UX serial device names consist of a base name
5355   such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
5356   designator which is a string of digits, possibly containing an imbedded
5357   letter "p".  Examples (for base name "tty"):
5358
5359      /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
5360
5361   According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
5362   used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
5363   on other models.  In HP-UX 10.00, "0p0" notation was adopted for all models.
5364   However, we make and enforce no such distinctions; either notation is
5365   accepted on any model or HP-UX version as a valid unit designator.
5366
5367   If a valid unit is specified (as opposed to a designer name or symlink), we
5368   check for all aliases of the given unit according to the devprefix[] array.
5369   If no lockfiles are found for the given unit, we can have the device; we
5370   create a lockfile LCK..name in the lockfile directory appropriate for the
5371   HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
5372   9.xx and earlier).  If it is a "cua" or "cul" device, a second lockfile is
5373   created with the "ttyd" prefix.  This is exactly what cu does.
5374
5375   If the "set line" device does not have a valid unit designator, then it is
5376   used literally and no synomyms are searched for and only one lockfile is
5377   created.
5378
5379   -fdc, March 1998.
5380 */
5381 #define LFNAML 80                       /* Max length for lock file name. */
5382
5383     int lockfd;                         /* File descriptor for lock file. */
5384     PID_T pid;                          /* Process ID of this process. */
5385     int fpid;                           /* pid found in existing lockfile. */
5386     int tries;                          /* How many times we've tried... */
5387     int i, k;                           /* Workers */
5388
5389     char *device, *devname;             /* "/dev/xxx", "xxx" */
5390     char *unit, *p;                     /* <instance>p<port> part of xxx */
5391
5392     char lockfil[LFNAML];               /* Lockfile name (no path) */
5393     char tmpnam[LFNAML];                /* Temporary lockfile name. */
5394
5395 #ifdef HPUX10                           /* Lockfile directory */
5396     char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */
5397 #else  /* HP-UX 9.xx and below */
5398 #ifdef LOCK_DIR
5399     char *lockdir = LOCK_DIR;           /* Defined near top of this file */
5400 #else
5401     char *lockdir = "/usr/spool/uucp";  /* or not... */
5402 #endif /* LOCK_DIR */
5403 #endif /* HPUX10 */
5404
5405     haslock = 0;                        /* Not locked yet. */
5406     *flfnam = '\0';                     /* Lockfile name is empty. */
5407     lock2[0] = '\0';                    /* Second one too. */
5408     pid = getpid();                     /* Get my process ID */
5409 /*
5410   Construct name of lockfile and temporary file...
5411   device  = name of tty device without the path, e.g. "tty0p0"
5412   lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
5413 */
5414     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
5415     debug(F110,"TTLOCK device",device,0);
5416     ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
5417
5418     k = 0;                              /* Assume device is not locked */
5419     n = 0;                              /* Digit counter */
5420     unit = device;                      /* Unit = <instance>p<port> */
5421     while (*unit && !isdigit(*unit))    /* Search for digit... */
5422       unit++;
5423     p = unit;                           /* Verify <num>p<num> format... */
5424     debug(F110,"TTLOCK unit 1",unit,0);
5425 /*
5426   The unit number is recognized as:
5427   (a) any sequence of digits that runs to the end of the string.
5428   (b) any (a) that includes one and only one letter "p", with at least
5429       one digit before and after it.
5430 */
5431     while (isdigit(*p)) p++, n++;       /* Get a run of digits */
5432     if (*p && n > 0) {                  /* Have a "p"? */
5433         if (*p == 'p' && isdigit(*(p+1))) {
5434             p++;
5435             n = 0;
5436             while (isdigit(*p)) p++, n++;
5437         }
5438     }
5439     if (n == 0 || *p) unit = "";
5440     debug(F110,"TTLOCK unit 2",unit,0);
5441
5442     if (*unit) {                        /* Device name has unit number. */
5443         /* The following loop not only searches for the various lockfile    */
5444         /* synonyms, but also removes all -- not just one -- stale lockfile */
5445         /* for the device, should there be more than one.  See ttchkpid().  */
5446         ttydexists = 0;
5447         for (i = 0; *devprefix[i]; i++) { /* For each driver... */
5448             /* Make device name */
5449             ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
5450             priv_on();                  /* Privs on */
5451             k = zchki(lock2) != -1;     /* See if device exists */
5452             priv_off();                 /* Privs off */
5453             debug(F111,"TTLOCK exist",lock2,k);
5454             if (k) {
5455                 if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
5456                   ttydexists = 1;
5457                 /* Make lockfile name */
5458                 ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
5459                 debug(F110,"TTLOCK checking",lock2,0);
5460                 priv_on();              /* Privs on */
5461                 k = zchki(lock2) != -1; /* See if lockfile exists */
5462                 priv_off();             /* Privs off */
5463                 debug(F111,"TTLOCK check for lock A",lock2,k);
5464                 if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
5465                     ckstrncpy(flfnam,lock2,FLFNAML);
5466                     return(-2);
5467                 }
5468             }
5469         }
5470     } else {                            /* Some other device-name format */
5471         /* This takes care of symbolic links, etc... */
5472         /* But does not chase them down! */
5473         ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
5474         priv_on();
5475         k = zchki(lock2) != -1;         /* Check for existing lockfile */
5476         priv_off();
5477         debug(F111,"TTLOCK check for lock B",lock2,k);
5478         if (k) if (ttchkpid(lock2)) {   /* Check pid from lockfile */
5479             ckstrncpy(flfnam,lock2,FLFNAML);
5480             debug(F110,"TTLOCK in use",device,0);
5481             debug(F101,"TTLOCK returns","",-2);
5482             return(-2);
5483         }
5484     }
5485 /*
5486   Get here only if there is no (more) lockfile, so now we make one (or two)...
5487   flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
5488   tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
5489 */
5490     ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
5491
5492     /* If dialout device, also make one for corresponding dialin device */
5493     lock2[0] = '\0';
5494     if (!strncmp(device,"cu",2) && *unit && ttydexists)
5495       ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
5496
5497     if ((int)strlen(lockdir)+12 < LFNAML)
5498       sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
5499 #ifdef DEBUG
5500     if (deblog) {
5501         debug(F110,"TTLOCK flfnam",flfnam,0);
5502         debug(F110,"TTLOCK lock2",lock2,0);
5503         debug(F110,"TTLOCK tmpnam",tmpnam,0);
5504     }
5505 #endif /* DEBUG */
5506 /*
5507    Lockfile permissions...
5508    444 is standard, HP-UX 10.00 uses 664.  It doesn't matter.
5509    Kermit uses 444; the difference lets us tell whether Kermit created
5510    the lock file.
5511 */
5512     priv_on();                          /* Turn on privileges. */
5513     lockfd = creat(tmpnam, 0444);       /* Try to create temporary file. */
5514     if (lockfd < 0) {                   /* Create failed. */
5515         debug(F111,"TTLOCK creat failed",tmpnam,errno);
5516         if (errno == ENOENT) {
5517             perror(lockdir);
5518             printf("UUCP not installed or Kermit misconfigured\n");
5519         } else {
5520             if (!quiet)
5521               perror(lockdir);
5522             unlink(tmpnam);             /* Get rid of the temporary file. */
5523         }
5524         priv_off();                     /* Turn off privileges!!! */
5525         debug(F101,"TTLOCK returns","",-1);
5526         return(-1);                     /* Return failure code. */
5527     }
5528     debug(F110,"TTLOCK temp ok",tmpnam,0);
5529
5530 /* Now write our pid into the temp lockfile in integer format. */
5531
5532     i = write(lockfd, (char *)&pid, sizeof(pid));
5533
5534 #ifdef DEBUG
5535     if (deblog) {
5536         debug(F101,"TTLOCK pid","",pid);
5537         debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
5538         debug(F101,"TTLOCK write pid returns","",i);
5539     }
5540 #endif /* DEBUG */
5541
5542 /*
5543   Now try to rename the temporary file to the real lockfile name.
5544   This will fail if a lock file of that name already exists, which
5545   will catch race conditions with other users.
5546 */
5547     close(lockfd);                      /* Close the temp lockfile. */
5548     chmod(tmpnam,0444);
5549
5550     tries = 0;
5551     while (!haslock && tries++ < 2) {
5552         haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
5553         debug(F101,"TTLOCK link","",haslock);
5554         if (haslock) {                  /* If we made the lockfile... */
5555
5556 #ifdef COMMENT
5557 /* We can't do this any more because we don't have a file descriptor yet. */
5558 #ifdef LOCKF                            /* Can be canceled with -DNOLOCKF */
5559 /*
5560   Create an advisory lock on the device through its file descriptor.
5561   This code actually seems to work.  If it is executed, and then another
5562   process tries to open the same device under a different name to circumvent
5563   the lockfile, they get a "device busy" error.
5564 */
5565             debug(F100,"TTLOCK LOCKF code...","",0);
5566             while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
5567                 debug(F111, "TTLOCK lockf error", "", errno);
5568                 if ((++tries >= 3) || (errno != EAGAIN)) {
5569                     x = unlink(flfnam); /* Remove the lockfile */
5570                     if (errno == EACCES && !quiet)
5571                       printf("Device already locked by another process\n");
5572                     haslock = 0;
5573                     break;
5574                 }
5575                 sleep(2);
5576             }
5577 #endif /* LOCKF */
5578 #endif /* COMMENT */
5579
5580             if (haslock) {              /* If we made the lockfile ... */
5581                 if (lock2[0]) {         /* if there is to be a 2nd lockfile */
5582                     lockfd = creat(lock2, 0444); /* Create it */
5583                     debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
5584                     if (lockfd > -1) {  /* Created OK, write pid. */
5585                         write(lockfd, (char *)&pid, sizeof(pid) );
5586                         close(lockfd);  /* Close and */
5587                         chmod(lock2, 0444); /* set permissions. */
5588                     } else {             /* Not OK, but don't fail. */
5589                         lock2[0] = '\0'; /* Just remember it's not there. */
5590                     }
5591                 }
5592                 break;                  /* and we're done. */
5593             }
5594         }
5595     }
5596     unlink(tmpnam);                     /* Unlink (remove) the temp file. */
5597     priv_off();                         /* Turn off privs */
5598     i = haslock ? 0 : -1;               /* Our return value */
5599     debug(F101,"TTLOCK returns","",i);
5600     return(i);
5601 #endif /* HPUX */
5602 #endif /* USETTYLOCK */
5603 #endif /* !NOUUCP */
5604 }
5605
5606 /*  T T U N L O C K  */
5607
5608 static int
5609 ttunlck() {                             /* Remove UUCP lockfile(s). */
5610 #ifndef NOUUCP
5611     int x;
5612
5613     debug(F111,"ttunlck",flfnam,haslock);
5614
5615 #ifdef USETTYLOCK
5616
5617     if (haslock && *flfnam) {
5618         int x;
5619         priv_on();                      /* Turn on privs */
5620 #ifdef USE_UU_LOCK
5621         x = uu_unlock(lockname);
5622 #else  /* USE_UU_LOCK */
5623         x = ttyunlock(lockname);        /* Try to unlock */
5624 #endif /* USE_UU_LOCK */
5625         priv_off();                     /* Turn off privs */
5626         if (x < 0 && !quiet)
5627           printf("Warning - Can't remove lockfile: %s\n", flfnam);
5628
5629         *flfnam = '\0';                 /* Erase the name. */
5630         haslock = 0;
5631         return(0);
5632     }
5633
5634 #else  /* No ttylock()... */
5635
5636     if (haslock && *flfnam) {
5637         /* Don't remove lockfile if we didn't make it ourselves */
5638         if ((x = ttrpid(flfnam)) != (int)getpid()) {
5639             debug(F111,"ttunlck lockfile seized",flfnam,x);
5640             printf("Warning - Lockfile %s seized by pid %d\n",
5641                    flfnam,
5642                    x
5643                    );
5644             return(0);
5645         }
5646         priv_on();                      /* Turn privileges on.  */
5647         errno = 0;
5648         x = unlink(flfnam);             /* Remove the lockfile. */
5649         debug(F111,"ttunlck unlink",flfnam,x);
5650         if (x < 0) {
5651             if (errno && !quiet)
5652               perror(ttnmsv);
5653             printf("Warning - Can't remove lockfile: %s\n", flfnam);
5654         }
5655         haslock = 0;
5656         *flfnam = '\0';                 /* Erase the name. */
5657
5658 #ifdef RTAIX
5659         errno = 0;
5660         x = unlink(lkflfn);             /* Remove link to lockfile */
5661         debug(F111,"ttunlck AIX link unlink",lkflfn,x);
5662         if (x < 0) {
5663             if (errno && !quiet)
5664               perror(ttnmsv);
5665             printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
5666         }
5667         *lkflfn = '\0';
5668 #else
5669         if (lock2[0]) {                 /* If there is a second lockfile, */
5670             errno = 0;
5671             x = unlink(lock2);          /*  remove it too. */
5672             debug(F111,"ttunlck lock2 unlink",lock2,x);
5673             if (x < 0) {
5674                 if (errno && !quiet)
5675                   perror(ttnmsv);
5676                 printf("Warning - Can't remove secondary lockfile: %s\n",
5677                        lock2
5678                        );
5679             }
5680             lock2[0] = '\0';            /* Forget its name. */
5681         }
5682 #endif /* RTAIX */
5683
5684 #ifdef COMMENT
5685 #ifdef LOCKF
5686         (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
5687 #endif /* LOCKF */
5688 #endif /* COMMENT */
5689
5690         priv_off();                     /* Turn privileges off. */
5691     }
5692 #endif /* USETTYLOCK */
5693 #endif /* !NOUUCP */
5694     return(0);
5695 }
5696
5697 /*
5698   4.3BSD-style UUCP line direction control.
5699   (Stan Barber, Rice U, 1980-something...)
5700 */
5701 #ifndef NOUUCP
5702 #ifdef ACUCNTRL
5703 VOID
5704 acucntrl(flag,ttname) char *flag, *ttname; {
5705     char x[DEVNAMLEN+32], *device, *devname;
5706
5707     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
5708       return;                           /* just return. */
5709     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
5710     if (strncmp(device,"LCK..",4) == 0) device += 5;
5711     ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
5712     debug(F110,"called ",x,0);
5713     zsyscmd(x);
5714 }
5715 #endif /* ACUCNTRL */
5716 #endif /* NOUUCP */
5717
5718 /*
5719   T T H F L O W  --  Set or Reset hardware flow control.
5720
5721   This is an attempt to collect all hardware-flow-control related code
5722   into a single module.  Thanks to Rick Sladkey and John Kohl for lots of
5723   help here.  Overview:
5724
5725   Hardware flow control is not supported in many UNIX implementions.  Even
5726   when it is supported, there is no (ha ha) "standard" for the programming
5727   interface.  In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
5728   SunOS, AIX, etc, have totally different methods.  (And, not strictly
5729   relevant here, the programming interface often brings one only to a no-op
5730   in the device driver!)
5731
5732   Among all these, we have two major types of APIs: those in which hardware
5733   flow control is determined by bits in the same termio/termios/sgtty mode
5734   word(s) that are used for controlling such items as CBREAK vs RAW mode, and
5735   which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
5736   for changing terminal modes.  And those that use entirely different
5737   mechanisms.
5738
5739   In the first category, it is important that any change in the mode bits be
5740   reflected in the relevant termio(s)/sgtty structure, so that subsequent
5741   changes to that structure do not wipe out the effects of this routine.  That
5742   is why a pointer, attrs, to the appropriate structure is passed as a
5743   parameter to this routine.
5744
5745   The second category should give us no worries, since any changes to hardware
5746   flow control accomplished by this routine should not affect the termio(s)/
5747   sgtty structures, and therefore will not be undone by later changes to them.
5748
5749   The second argument, status, means to turn on hardware flow control if
5750   nonzero, and to turn it off if zero.
5751
5752   Returns: 0 on apparent success, -1 on probable failure.
5753 */
5754
5755 /*
5756   The following business is for BSDI, where it was discovered that two
5757   separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
5758   but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
5759   bits, so hwfc only works in one direction if you use CRTSCTS to control it.
5760   Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
5761   define CRTSCTS correctly.
5762 */
5763 #ifdef FIXCRTSCTS
5764 #ifdef CRTSCTS
5765 #ifdef CCTS_OFLOW
5766 #ifdef CRTS_IFLOW
5767 #undef CRTSCTS
5768 #define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
5769 #endif /* CRTS_IFLOW */
5770 #endif /* CCTS_OFLOW */
5771 #endif /* CRTSCTS */
5772 #endif /* FIXCRTSCTS */
5773
5774 static int
5775 tthflow(flow, status, attrs)
5776     int flow,                           /* Type of flow control (ckcdeb.h) */
5777     status;                             /* Nonzero = turn it on */
5778                                         /* Zero = turn it off */
5779 #ifdef BSD44ORPOSIX                     /* POSIX or BSD44 */
5780     struct termios *attrs;
5781 #else                                   /* System V */
5782 #ifdef ATTSV
5783 #ifdef ATT7300
5784 #ifdef UNIX351M
5785 /* AT&T UNIX 3.51m can set but not test for hardware flow control */
5786 #define RTSFLOW CTSCD
5787 #define CTSFLOW CTSCD
5788 #endif /* ATT7300 */
5789 #endif /* UNIX351M */
5790     struct termio *attrs;
5791 #else                                   /* BSD, V7, etc */
5792     struct sgttyb *attrs;               /* sgtty info... */
5793 #endif /* ATTSV */
5794 #endif /* BSD44ORPOSIX */
5795 /* tthflow */ {
5796
5797     int x = 0;                          /* tthflow() return code */
5798
5799 #ifdef Plan9
5800     return p9tthflow(flow, status);
5801 #else
5802
5803 #ifndef OXOS                            /* NOT Olivetti X/OS... */
5804 /*
5805   For SunOS 4.0 and later in the BSD environment ...
5806
5807   The declarations are copied and interpreted from the System V header files,
5808   so we don't actually have to pull in all the System V junk when building
5809   C-Kermit for SunOS in the BSD environment, which would be dangerous because
5810   having those symbols defined would cause us to take the wrong paths through
5811   the code.  The code in this section is used in both the BSD and Sys V SunOS
5812   versions.
5813 */
5814 #ifdef SUNOS41
5815 /*
5816   In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
5817   because GNU CC uses different formats for the _IOxxx macros than regular CC;
5818   the POSIX forms work for both.  But the POSIX calls are not available in
5819   SunOS 4.0.
5820 */
5821 #define CRTSCTS 0x80000000              /* RTS/CTS flow control */
5822 #define TCSANOW 0                       /* Do it now */
5823
5824     struct termios {
5825         unsigned long c_iflag;          /* Input modes */
5826         unsigned long c_oflag;          /* Output modes */
5827         unsigned long c_cflag;          /* Control modes */
5828         unsigned long c_lflag;          /* Line discipline modes */
5829         char c_line;
5830         CHAR c_cc[17];
5831     };
5832     struct termios temp;
5833
5834 _PROTOTYP( int tcgetattr, (int, struct termios *) );
5835 _PROTOTYP( int tcsetattr, (int, int, struct termios *) );
5836 /*
5837   When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
5838   asserted.  So we don't set CRTSCTS unless CD is up.  This should be OK,
5839   since we don't need RTS/CTS during dialing, and after dialing is complete,
5840   we should have CD.  If not, we still communicate, but without RTS/CTS.
5841 */
5842     int mflags;                         /* Modem signal flags */
5843
5844 #ifdef NETCMD
5845     if (ttpipe) return(0);
5846 #endif /* NETCMD */
5847 #ifdef NETPTY
5848     if (ttpty) return(0);
5849 #endif /* NETPTY */
5850
5851     debug(F101,"tthflow SUNOS41 entry status","",status);
5852     if (!status) {                      /* Turn hard flow off */
5853         if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5854             (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5855             temp.c_cflag &= ~CRTSCTS;   /* It's there, remove it */
5856             x = tcsetattr(ttyfd,TCSANOW,&temp);
5857         }
5858     } else {                            /* Turn hard flow on */
5859         if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
5860             (mflags & TIOCM_CAR)) {             /* Check for CD */
5861             debug(F100,"tthflow SunOS has CD","",0);
5862             if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
5863                 !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
5864                 temp.c_cflag |= CRTSCTS;        /* Not there, add it */
5865                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5866             }
5867         } else {
5868             x = -1;
5869             debug(F100,"tthflow SunOS no CD","",0);
5870         }
5871     }
5872 #else
5873 #ifdef QNX
5874     struct termios temp;
5875 #ifdef NETCMD
5876     if (ttpipe) return(0);
5877 #endif /* NETCMD */
5878 #ifdef NETPTY
5879     if (ttpty) return(0);
5880 #endif /* NETPTY */
5881     debug(F101,"tthflow QNX entry status","",status);
5882     if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
5883         if (!status) {                  /* Turn hard flow off */
5884             if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
5885                 temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
5886                 attrs->c_cflag &= ~(IHFLOW|OHFLOW);
5887                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5888             }
5889         } else {                        /* Turn hard flow on */
5890             if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
5891                 temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
5892                 temp.c_iflag &= ~(IXON|IXOFF);   /* Bye to IXON/IXOFF */
5893                 ttraw.c_lflag |= IEXTEN;         /* Must be on */
5894                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5895                 attrs->c_cflag |= (IHFLOW|OHFLOW);
5896                 attrs->c_iflag &= ~(IXON|IXOFF);
5897             }
5898         }
5899     } else {
5900         x = -1;
5901         debug(F100, "tthflow QNX getattr fails", "", 0);
5902     }
5903 #else
5904 #ifdef POSIX_CRTSCTS
5905 /*
5906   POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
5907   Note: Do not assume CRTSCTS is a one-bit field!
5908 */
5909     struct termios temp;
5910 #ifdef NETCMD
5911     if (ttpipe) return(0);
5912 #endif /* NETCMD */
5913 #ifdef NETPTY
5914     if (ttpty) return(0);
5915 #endif /* NETPTY */
5916     debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
5917     errno = 0;
5918     x = tcgetattr(ttyfd, &temp);
5919     debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
5920     errno = 0;
5921     if (x < 0) {
5922         x = -1;
5923     } else {
5924         if (!status) {                  /* Turn hard flow off */
5925             if (
5926 #ifdef COMMENT
5927                 /* This can fail because of sign extension */
5928                 /* e.g. in Linux where it's Bit 31 */
5929                 (temp.c_cflag & CRTSCTS) == CRTSCTS
5930 #else
5931                 (temp.c_cflag & CRTSCTS) != 0
5932 #endif /* COMMENT */
5933                 ) {
5934                 temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
5935                 attrs->c_cflag &= ~CRTSCTS;
5936                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5937                 debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
5938                       ckitoa(x),errno);
5939             } else {                    /* John Dunlap 2010-01-26 */
5940                 debug(F001,
5941                       "tthflow before forcing off attrs CRTSCTS",
5942                       "",
5943                       attrs->c_cflag&CRTSCTS
5944                       );
5945                 attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */
5946                 debug(F001,
5947                       "tthflow after forcing off attrs CRTSCTS",
5948                       "",
5949                       attrs->c_cflag&CRTSCTS
5950                       );
5951                 }
5952         } else {                        /* Turn hard flow on */
5953             if (
5954 #ifdef COMMENT
5955                 /* This can fail because of sign extension */
5956                 (temp.c_cflag & CRTSCTS) != CRTSCTS
5957 #else
5958                 (temp.c_cflag & CRTSCTS) == 0
5959 #endif /* COMMENT */
5960                 ) {
5961                 temp.c_cflag |= CRTSCTS; /* Not there, add it */
5962                 temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
5963                 x = tcsetattr(ttyfd,TCSANOW,&temp);
5964                 debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
5965                       ckitoa(x),errno);
5966                 attrs->c_cflag |= CRTSCTS;
5967                 attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
5968             }
5969         }
5970     }
5971 #else
5972 #ifdef SUNOS4
5973 /*
5974   SunOS 4.0 (and maybe earlier?).  This code is dangerous because it
5975   prevents compilation with GNU gcc, which uses different formats for the
5976   _IORxxx macros than regular cc.  SunOS 4.1 and later can use the POSIX
5977   routines above, which work for both cc and gcc.
5978 */
5979 #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
5980 #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
5981 #define CRTSCTS 0x80000000                /* RTS/CTS flow control */
5982
5983     struct termios {
5984         unsigned long c_iflag;          /* Input modes */
5985         unsigned long c_oflag;          /* Output modes */
5986         unsigned long c_cflag;          /* Control modes */
5987         unsigned long c_lflag;          /* Line discipline modes */
5988         char c_line;
5989         CHAR c_cc[17];
5990     };
5991     struct termios temp;
5992 #ifdef NETCMD
5993     if (ttpipe) return(0);
5994 #endif /* NETCMD */
5995 #ifdef NETPTY
5996     if (ttpty) return(0);
5997 #endif /* NETPTY */
5998     debug(F101,"tthflow entry status","",status);
5999     if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
6000         if (status) {                   /* Turn hard flow on */
6001             temp.c_cflag |= CRTSCTS;    /* Add RTS/CTS to them. */
6002             x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
6003             attrs->c_cflag |= CRTSCTS;  /* Add to global info. */
6004         } else {                        /* Turn hard flow off */
6005             temp.c_cflag &= ~CRTSCTS;
6006             x = ioctl(ttyfd,TCSETS,&temp);
6007             attrs->c_cflag &= ~CRTSCTS;
6008         }
6009     }
6010 #else                                   /* Not SunOS 4.0 or later */
6011 #ifdef AIXRS                            /* IBM AIX RS/6000 */
6012 #ifndef AIX41                           /* But only pre-4.x == SVR4 */
6013 #ifdef NETCMD
6014     if (ttpipe) return(0);
6015 #endif /* NETCMD */
6016 #ifdef NETPTY
6017     if (ttpty) return(0);
6018 #endif /* NETPTY */
6019     if (status) {
6020         if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
6021           debug(F100,"hardflow TXADDCD (rts) error", "", 0);
6022     } else {
6023         if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
6024           debug(F100,"hardflow TXDELCD (rts) error", "", 0);
6025     }
6026 #endif /* AIX41 */
6027 #else                                   /* Not AIX RS/6000 */
6028
6029 #ifdef ATTSV                            /* System V... */
6030
6031 #ifdef CK_SCOV5                         /* SCO Open Server 5.0 */
6032 #define CK_SCOUNIX
6033 #else
6034 #ifdef M_UNIX                           /* SCO UNIX 3.2v4.x or earlier */
6035 #define CK_SCOUNIX
6036 #endif /* M_UNIX */
6037 #endif /* CK_SCOV5 */
6038
6039 #ifdef SCO_FORCE_RTSXOFF
6040 #ifdef CK_SCOUNIX                       /* But not SCO OpenServer 5.0.4 */
6041 #ifdef SCO_OSR504                       /* or later... */
6042 #undef CK_SCOUNIX
6043 #endif /* SCO_OSR504 */
6044 #endif /* CK_SCOUNIX */
6045 #endif /* SCO_FORCE_RTSXOFF */
6046
6047 #ifdef CK_SCOUNIX
6048 #ifdef POSIX
6049     struct termios temp;
6050 #ifdef NETCMD
6051     if (ttpipe) return(0);
6052 #endif /* NETCMD */
6053 #ifdef NETPTY
6054     if (ttpty) return(0);
6055 #endif /* NETPTY */
6056     debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
6057     errno = 0;
6058     x = tcgetattr(ttyfd, &temp);
6059     debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
6060 #else /* POSIX */
6061     struct termio temp;
6062 #ifdef NETCMD
6063     if (ttpipe) return(0);
6064 #endif /* NETCMD */
6065 #ifdef NETPTY
6066     if (ttpty) return(0);
6067 #endif /* NETPTY */
6068     debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
6069     x = ioctl(ttyfd, TCGETA, &temp);
6070     debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
6071 #endif /* POSIX */
6072 /*
6073   This is not really POSIX, since POSIX does not deal with hardware flow
6074   control, but we are using the POSIX APIs.  In fact, RTSFLOW and CTSFLOW
6075   are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif.  So
6076   let's try forcing their definitions here.
6077 */
6078 #ifndef CTSFLOW
6079 #define CTSFLOW 0020000
6080     debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
6081 #else
6082     debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
6083 #endif /* CTSFLOW */
6084 #ifndef RTSFLOW
6085 #define RTSFLOW 0040000
6086     debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
6087 #else
6088     debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
6089 #endif /* RTSFLOW */
6090 #ifndef ORTSFL
6091 #define ORTSFL 0100000
6092     debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
6093 #else
6094     debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
6095 #endif /* ORTSFL */
6096
6097     if (x != -1) {
6098         if (status) {                   /* Turn it ON */
6099             temp.c_cflag |= RTSFLOW|CTSFLOW;
6100             attrs->c_cflag |= RTSFLOW|CTSFLOW;
6101 #ifdef ORTSFL
6102             temp.c_cflag &= ~ORTSFL;
6103             attrs->c_cflag &= ~ORTSFL;
6104 #endif /* ORTSFL */
6105             temp.c_iflag &= ~(IXON|IXOFF|IXANY);
6106             attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
6107         } else {                        /* Turn it OFF */
6108 #ifdef ORTSFL
6109             temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6110             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
6111 #else  /* ORTSFL */
6112             temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
6113             attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
6114 #endif /* ORTSFL */
6115         }
6116 #ifdef POSIX
6117         x = tcsetattr(ttyfd, TCSADRAIN, &temp);
6118 #else
6119         x = ioctl(ttyfd, TCSETA, &temp);
6120 #endif /* POSIX */
6121         debug(F101,"tthflow SCO set modes","",x);
6122     }
6123 #else /* Not SCO UNIX */
6124 #ifdef NETCMD
6125     if (ttpipe) return(0);
6126 #endif /* NETCMD */
6127 #ifdef NETPTY
6128     if (ttpty) return(0);
6129 #endif /* NETPTY */
6130     if (!status) {                      /* Turn it OFF */
6131 #ifdef RTSXOFF
6132         debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
6133         rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
6134 #ifdef TCSETX
6135         x = ioctl(ttyfd,TCSETX,&rctsx);
6136         debug(F101,"tthflow ATTSV TCSETX OFF","",x);
6137 #else
6138         x = -1
6139         debug(F100,"tthflow TCSETX not defined","",0);
6140 #endif /* TCSETX */
6141 #else
6142         debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
6143 #endif /* RTSXOFF */
6144 #ifdef DTRXOFF
6145         debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
6146         rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6147         x = ioctl(ttyfd,TCSETX,&rctsx);
6148         debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
6149 #else
6150         debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6151 #endif /* DTRXOFF */
6152     } else {                            /* Turn it ON. */
6153         if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */
6154             debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
6155 #ifdef RTSXOFF
6156             /* This is the preferred way, according to SVID3 */
6157 #ifdef TCGETX
6158             x = ioctl(ttyfd,TCGETX,&rctsx);
6159             debug(F101,"tthflow TCGETX","",x);
6160             if (x > -1) {
6161                 rctsx.x_hflag |= RTSXOFF | CTSXON;
6162                 x = ioctl(ttyfd,TCSETX,&rctsx);
6163                 debug(F100,"tthflow ATTSV ioctl","",x);
6164             }
6165 #else
6166             debug(F100,"tthflow TCGETX not defined","",0);
6167             x = -1
6168 #endif /* TCGETX */
6169 #else
6170             debug(F100,"tthflow RTSXOFF not defined","",0);
6171             x = -1;
6172 #endif /* RTSXOFF */
6173         } else if (flow == FLO_DTRC) {  /* DTR/CD Flow control... */
6174             debug(F100,"tthflow ATTSV DTR/CD ON","",0);
6175 #ifdef DTRXOFF
6176             /* This is straight out of SVID R4 */
6177             if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
6178                 rctsx.x_hflag &= ~(DTRXOFF|CDXON);
6179                 x = ioctl(ttyfd,TCSETX,&rctsx);
6180             }
6181 #else
6182             debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
6183             x = -1;
6184 #endif /* DTRXOFF */
6185         }
6186     }
6187 #endif /* CK_SCOUNIX */
6188
6189 #else /* not System V... */
6190
6191 #ifdef CK_DTRCTS
6192 #ifdef LDODTR
6193 #ifdef LDOCTS
6194 #ifdef NETCMD
6195     if (ttpipe) return(0);
6196 #endif /* NETCMD */
6197 #ifdef NETPTY
6198     if (ttpty) return(0);
6199 #endif /* NETPTY */
6200     x = LDODTR | LDOCTS;                /* Found only on UTEK? */
6201     if (flow == FLO_DTRT && status) {   /* Use hardware flow control */
6202         if (lmodef) {
6203             x = ioctl(ttyfd,TIOCLBIS,&x);
6204             if (x < 0) {
6205                 debug(F100,"hardflow TIOCLBIS error","",0);
6206             } else {
6207                 lmodef++;
6208                 debug(F100,"hardflow TIOCLBIS ok","",0);
6209             }
6210         }
6211     } else {
6212         if (lmodef) {
6213             x = ioctl(ttyfd,TIOCLBIC,&x);
6214             if (x < 0) {
6215                 debug(F100,"hardflow TIOCLBIC error","",0);
6216             } else {
6217                 lmodef++;
6218                 debug(F100,"hardflow TIOCLBIC ok","",0);
6219             }
6220         }
6221     }
6222 #endif /* LDODTR */
6223 #endif /* LDOCTS */
6224 #endif /* CK_DTRCTS */
6225 #endif /* ATTSV */
6226 #endif /* AIXRS */
6227 #endif /* SUNOS4 */
6228 #endif /* QNX */
6229 #endif /* POSIX_CRTSCTS */
6230 #endif /* SUNOS41 */
6231
6232 #else /* OXOS */
6233
6234     struct termios temp;                /* Olivetti X/OS ... */
6235
6236 #ifdef NETCMD
6237     if (ttpipe) return(0);
6238 #endif /* NETCMD */
6239 #ifdef NETPTY
6240     if (ttpty) return(0);
6241 #endif /* NETPTY */
6242     x = ioctl(ttyfd,TCGETS,&temp);
6243     if (x == 0) {
6244         temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
6245         if (status) {
6246             switch (flow) {
6247               case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
6248                 break;
6249               case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
6250                 break;
6251             }
6252         }
6253         x = ioctl(ttyfd,TCSETS,&temp);
6254     }
6255 #endif /* OXOS */
6256     return(x);
6257
6258 #endif /* Plan9 */
6259 }
6260
6261 /*  T T P K T  --  Condition the communication line for packets */
6262 /*                 or for modem dialing */
6263
6264 /*
6265   If called with speed > -1, also set the speed.
6266   Returns 0 on success, -1 on failure.
6267
6268   NOTE: the "xflow" parameter is supposed to be the currently selected
6269   type of flow control, but for historical reasons, this parameter is also
6270   used to indicate that we are dialing.  Therefore, when the true flow
6271   control setting is needed, we access the external variable "flow", rather
6272   than trusting our "xflow" argument.
6273 */
6274 int
6275 #ifdef CK_ANSIC
6276 ttpkt(long speed, int xflow, int parity)
6277 #else
6278 ttpkt(speed,xflow,parity) long speed; int xflow, parity;
6279 #endif /* CK_ANSIC */
6280 /* ttpkt */ {
6281 #ifndef NOLOCAL
6282     int s2;
6283     int s = -1;
6284 #endif /* NOLOCAL */
6285     int x;
6286     extern int flow;                    /* REAL flow-control setting */
6287
6288     if (ttyfd < 0) return(-1);          /* Not open. */
6289
6290     debug(F101,"ttpkt parity","",parity);
6291     debug(F101,"ttpkt xflow","",xflow);
6292     debug(F101,"ttpkt speed","",(int) speed);
6293
6294     ttprty = parity;                    /* Let other tt functions see these. */
6295     ttspeed = speed;                    /* Make global copy for this module */
6296     ttpmsk = ttprty ? 0177 : 0377;      /* Parity stripping mask */
6297 #ifdef PARSENSE
6298     needpchk = ttprty ? 0 : 1;          /* Parity check needed? */
6299 #else
6300     needpchk = 0;
6301 #endif /* PARSENSE */
6302
6303     debug(F101,"ttpkt ttpmsk","",ttpmsk);
6304     debug(F101,"ttpkt netconn","",netconn);
6305
6306 #ifdef NETCONN                          /* No mode-changing for telnet */
6307     if (netconn) {
6308 #ifdef TCPSOCKET
6309 #ifdef TCP_NODELAY
6310         if (ttnet == NET_TCPB) {        /* But turn off Nagle */
6311             extern int tcp_nodelay;
6312             nodelay_sav = tcp_nodelay;
6313             no_delay(ttyfd,1);
6314         }
6315 #endif /* TCP_NODELAY */
6316 #ifdef TN_COMPORT
6317         if (istncomport()) {
6318             int rc = -1;
6319             if (tvtflg == 0 && speed == ttspeed && flow == ttflow
6320                  /* && ttcarr == curcarr */ ) {
6321                 debug(F100,"ttpkt modes already set, skipping...","",0);
6322                 return(0);              /* Already been called. */
6323             }
6324             if (flow != ttflow) {
6325                 if ((rc = tnsetflow(flow)) < 0)
6326                   return(rc);
6327                 ttflow = flow;
6328             }
6329             if (speed != ttspeed) {
6330                 if (speed <= 0) 
6331                   speed = tnc_get_baud();
6332                 else if ((rc = tnc_set_baud(speed)) < 0)
6333                   return(rc);
6334                 ttspeed = speed;
6335             }
6336             tnc_set_datasize(8);
6337             tnc_set_stopsize(stopbits);
6338
6339 #ifdef HWPARITY
6340             if (hwparity) {
6341                 switch (hwparity) {
6342                   case 'e':                     /* Even */
6343                     debug(F100,"ttres 8 bits + even parity","",0);
6344                     tnc_set_parity(3);
6345                     break;
6346                   case 'o':                     /* Odd */
6347                     debug(F100,"ttres 8 bits + odd parity","",0);
6348                     tnc_set_parity(2);
6349                     break;
6350                   case 'm':                     /* Mark */
6351                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
6352                     tnc_set_parity(4);
6353                     break;
6354                   case 's':                     /* Space */
6355                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
6356                     tnc_set_parity(5);
6357                     break;
6358                 }
6359             } else 
6360 #endif /* HWPARITY */
6361             {
6362                 tnc_set_parity(1);              /* None */
6363             }
6364             tvtflg = 0;
6365             return(0);
6366         }
6367 #endif /* TN_COMPORT */
6368 #endif /* TCPSOCKET */
6369         tvtflg = 0;
6370         return(0);
6371     }
6372 #endif /* NETCONN */
6373 #ifdef NETCMD
6374     if (ttpipe) return(0);
6375 #endif /* NETCMD */
6376 #ifdef NETPTY
6377     if (ttpty) return(0);
6378 #endif /* NETPTY */
6379
6380 #ifndef Plan9
6381     if (ttfdflg && !isatty(ttyfd)) return(0);
6382 #endif /* Plan9 */
6383
6384 #ifdef COHERENT
6385 #define SVORPOSIX
6386 #endif /* COHERENT */
6387
6388 #ifndef SVORPOSIX                       /* Berkeley, V7, etc. */
6389 #ifdef LPASS8
6390 /*
6391  For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
6392  after having previously set it to NONE without closing and reopening the
6393  device.  Unless there's something I overlooked below...
6394 */
6395     if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
6396         debug(F101,"ttpkt executing horrible flow kludge","",0);
6397         ttclos(0);                      /* Close it */
6398         x = 0;
6399         ttopen(ttnmsv,&x,ttmdm,0);      /* Open it again */
6400     }
6401 #endif /* LPASS8 */
6402 #endif /* SVORPOSIX */
6403
6404 #ifdef COHERENT                         /* This must be vestigial since we */
6405 #undef SVORPOSIX                        /* reverse it a few lines below... */
6406 #endif /* COHERENT */
6407
6408     if (xflow != FLO_DIAL && xflow != FLO_DIAX)
6409       ttflow = xflow;                   /* Now make this available too. */
6410
6411 #ifndef NOLOCAL
6412     if (xlocal) {
6413         s2 = (int) (speed / 10L);       /* Convert bps to cps */
6414         debug(F101,"ttpkt calling ttsspd","",s2);
6415         s = ttsspd(s2);                 /* Check and set the speed */
6416         debug(F101,"ttpkt ttsspd result","",s);
6417         carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
6418                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
6419         tvtflg = 0;                     /* So ttvt() will work next time */
6420     }
6421 #endif /* NOLOCAL */
6422
6423 #ifdef COHERENT
6424 #define SVORPOSIX
6425 #endif /* COHERENT */
6426
6427 #ifndef SVORPOSIX                       /* BSD section */
6428     if (flow == FLO_RTSC ||             /* Hardware flow control */
6429         flow == FLO_DTRC ||
6430         flow == FLO_DTRT) {
6431         tthflow(flow, 1, &ttraw);
6432         debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
6433         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6434         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6435     } else if (flow == FLO_NONE) {      /* No flow control */
6436         debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
6437         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6438         tthflow(flow, 0, &ttraw);       /* Turn off any hardware f/c too */
6439         ttraw.sg_flags |= RAW;          /* Enter raw mode */
6440     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
6441         debug(F100,"ttpkt keeping original TANDEM","",0);
6442         ttraw.sg_flags &= ~TANDEM;
6443         ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
6444         /* NOTE: We should also handle hardware flow control here! */
6445     }
6446
6447 /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
6448
6449     if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
6450         debug(F100,"ttpkt turning on TANDEM","",0);
6451         ttraw.sg_flags |= TANDEM;       /* So ask for it. */
6452
6453 #ifdef LPASS8                           /* Can pass 8-bit data through? */
6454 /* If the LPASS8 local mode is available, then flow control can always  */
6455 /* be used, even if parity is none and we are transferring 8-bit data.  */
6456 /* But we only need to do all this if Xon/Xoff is requested. */
6457 /* BUT... this tends not to work through IP or LAT connections, terminal */
6458 /* servers, telnet, rlogin, etc, so it is currently disabled. */
6459         x = LPASS8;                     /* If LPASS8 defined, then */
6460         debug(F100,"ttpkt executing LPASS8 code","",0);
6461         if (lmodef) {                   /* TIOCLBIS must be too. */
6462             x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
6463             if (x < 0) {
6464                 debug(F100,"ttpkt TIOCLBIS error","",0);
6465             } else {
6466                 lmodef++;
6467                 debug(F100,"ttpkt TIOCLBIS ok","",0);
6468             }
6469         }
6470 /*
6471  But if we use LPASS8 mode, we must explicitly turn off
6472  terminal interrupts of all kinds.
6473 */
6474 #ifdef TIOCGETC                         /* Not rawmode, */
6475         if (tcharf && (xlocal == 0)) {  /* must turn off */
6476             tchnoi.t_intrc = -1;        /* interrupt character */
6477             tchnoi.t_quitc = -1;        /* and quit character. */
6478             tchnoi.t_startc = 17;       /* Make sure xon */
6479             tchnoi.t_stopc = 19;        /* and xoff not ignored. */
6480 #ifndef NOBRKC
6481             tchnoi.t_eofc = -1;         /* eof character. */
6482             tchnoi.t_brkc = -1;         /* brk character. */
6483 #endif /* NOBRKC */
6484             if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6485                 debug(F100,"ttpkt TIOCSETC failed","",0);
6486             } else {
6487                 tcharf = 1;
6488                 debug(F100,"ttpkt TIOCSETC ok","",0);
6489             }
6490 #ifdef COMMENT
6491 /* only for paranoid debugging */
6492             if (tcharf) {
6493                 struct tchars foo;
6494                 char tchbuf[100];
6495                 ioctl(0,TIOCGETC,&foo);
6496                 sprintf(tchbuf,
6497                     "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
6498                     foo.t_intrc, foo.t_quitc, foo.t_startc,
6499                     foo.t_stopc, foo.t_eofc,  foo.t_brkc);
6500                 debug(F110,"ttpkt chars",tchbuf,0);
6501             }
6502 #endif /* COMMENT */
6503         }
6504         ttraw.sg_flags |= CBREAK;       /* Needed for unknown reason */
6505 #endif /* TIOCGETC */
6506
6507 /* Prevent suspend during packet mode */
6508 #ifdef TIOCGLTC                         /* Not rawmode, */
6509         if (ltcharf && (xlocal == 0)) { /* must turn off */
6510             ltchnoi.t_suspc = -1;       /* suspend character */
6511             ltchnoi.t_dsuspc = -1;      /* and delayed suspend character */
6512             if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6513                 debug(F100,"ttpkt TIOCSLTC failed","",0);
6514             } else {
6515                 ltcharf = 1;
6516                 debug(F100,"ttpkt TIOCSLTC ok","",0);
6517             }
6518         }
6519 #endif /* TIOCGLTC */
6520
6521 #else /* LPASS8 not defined */
6522
6523 /* Previously, BSD-based implementations always */
6524 /* used rawmode for packets.  Now, we use rawmode only if parity is NONE. */
6525 /* This allows the flow control requested above to actually work, but only */
6526 /* if the user asks for parity (which also means they get 8th-bit quoting). */
6527
6528         if (parity) {                   /* If parity, */
6529             ttraw.sg_flags &= ~RAW;     /* use cooked mode */
6530 #ifdef COMMENT
6531 /* WHY??? */
6532             if (xlocal)
6533 #endif /* COMMENT */
6534               ttraw.sg_flags |= CBREAK;
6535             debug(F101,"ttpkt cooked, cbreak, parity","",parity);
6536 #ifdef TIOCGETC                         /* Not rawmode, */
6537             if (tcharf && (xlocal == 0)) { /* must turn off */
6538                 tchnoi.t_intrc = -1;    /* interrupt character */
6539                 tchnoi.t_quitc = -1;    /* and quit character. */
6540                 tchnoi.t_startc = 17;   /* Make sure xon */
6541                 tchnoi.t_stopc = 19;    /* and xoff not ignored. */
6542 #ifndef NOBRKC
6543                 tchnoi.t_eofc = -1;     /* eof character. */
6544                 tchnoi.t_brkc = -1;     /* brk character. */
6545 #endif /* NOBRKC */
6546                 if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
6547                     debug(F100,"ttpkt TIOCSETC failed","",0);
6548                 } else {
6549                     tcharf = 1;
6550                     debug(F100,"ttpkt TIOCSETC ok","",0);
6551                 }
6552             }
6553 #endif /* TIOCGETC */
6554 #ifdef TIOCGLTC                         /* Not rawmode, */
6555 /* Prevent suspend during packet mode */
6556             if (ltcharf && (xlocal == 0)) { /* must turn off */
6557                 ltchnoi.t_suspc = -1;   /* suspend character */
6558                 ltchnoi.t_dsuspc = -1;  /* and delayed suspend character */
6559                 if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
6560                     debug(F100,"ttpkt TIOCSLTC failed","",0);
6561                 } else {
6562                     ltcharf = 1;
6563                     debug(F100,"ttpkt TIOCSLTC ok","",0);
6564                 }
6565             }
6566 #endif /* TIOCGLTC */
6567         } else {                        /* If no parity, */
6568             ttraw.sg_flags |= RAW;      /* must use 8-bit raw mode. */
6569             debug(F101,"ttpkt setting rawmode, parity","",parity);
6570         }
6571 #endif /* LPASS8 */
6572     } /* End of Xon/Xoff section */
6573
6574     /* Don't echo, don't map CR to CRLF on output, don't fool with case */
6575 #ifdef LCASE
6576     ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
6577 #else
6578     ttraw.sg_flags &= ~(ECHO|CRMOD);
6579 #endif /* LCASE */
6580
6581 #ifdef TOWER1
6582     ttraw.sg_flags &= ~ANYP;            /* Must set this on old Towers */
6583 #endif /* TOWER1 */
6584
6585 #ifdef BELLV10
6586     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
6587       return(-1);
6588 #else
6589     errno = 0;
6590     if (stty(ttyfd,&ttraw) < 0) {       /* Set the new modes. */
6591         debug(F101,"ttpkt stty failed","",errno);
6592         return(-1);
6593     }
6594 #endif /* BELLV10 */
6595     debug(F100,"ttpkt stty ok","",0);
6596
6597 #ifdef sony_news
6598     x = xlocal ? km_ext : km_con;       /* Put line in ASCII mode. */
6599     if (x != -1) {                      /* Make sure we know original modes. */
6600         x &= ~KM_TTYPE;
6601         x |= KM_ASCII;
6602         if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
6603             perror("ttpkt can't set ASCII mode");
6604             debug(F101,"ttpkt error setting ASCII mode","",x);
6605             return(-1);
6606         }
6607     }
6608     debug(F100,"ttpkt set ASCII mode ok","",0);
6609 #endif /* sony_news */
6610
6611     if (xlocal == 0) {                  /* Turn this off so we can read */
6612         signal(SIGINT,SIG_IGN);         /* Ctrl-C chars typed at console */
6613         sigint_ign = 1;
6614     }
6615     tvtflg = 0;                         /* So ttvt() will work next time */
6616     debug(F100,"ttpkt success","",0);
6617     return(0);
6618
6619 #endif /* Not ATTSV or POSIX */
6620
6621 /* AT&T UNIX and POSIX */
6622
6623 #ifdef COHERENT
6624 #define SVORPOSIX
6625 #endif /* COHERENT */
6626
6627 #ifdef SVORPOSIX
6628     if (flow == FLO_XONX) {             /* Xon/Xoff */
6629         ttraw.c_iflag |= (IXON|IXOFF);
6630         tthflow(flow, 0, &ttraw);
6631     } else if (flow == FLO_NONE) {      /* None */
6632         /* NOTE: We should also turn off hardware flow control here! */
6633         ttraw.c_iflag &= ~(IXON|IXOFF);
6634         tthflow(flow, 0, &ttraw);
6635     } else if (flow == FLO_KEEP) {      /* Keep */
6636         ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
6637         ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
6638         /* NOTE: We should also handle hardware flow control here! */
6639 #ifdef POSIX_CRTSCTS
6640 /* In Linux case, we do this, which is unlikely to be portable */
6641         ttraw.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
6642         ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
6643 #endif /* POSIX_CRTSCTS */
6644     } else if (flow == FLO_RTSC ||      /* Hardware */
6645                flow == FLO_DTRC ||
6646                flow == FLO_DTRT) {
6647         ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */
6648         tthflow(flow, 1, &ttraw);
6649     }
6650     ttraw.c_lflag &= ~(ICANON|ECHO);
6651     ttraw.c_lflag &= ~ISIG;             /* Do NOT check for interrupt chars */
6652
6653 #ifndef OXOS
6654 #ifdef QNX
6655     if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
6656 #endif /* QNX */
6657 #ifndef COHERENT
6658       ttraw.c_lflag &= ~IEXTEN;         /* Turn off ^O/^V processing */
6659 #endif /* COHERENT */
6660 #else /* OXOS */
6661     ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
6662 #endif /* OXOS */
6663     ttraw.c_lflag |= NOFLSH;            /* Don't flush */
6664     ttraw.c_iflag |= IGNPAR;            /* Ignore parity errors */
6665 #ifdef ATTSV
6666 #ifdef BSD44
6667     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
6668 #else
6669     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
6670 #endif /* BSD44 */
6671 #else /* POSIX */
6672     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
6673 #endif /* ATTSV */
6674     ttraw.c_oflag &= ~OPOST;
6675     ttraw.c_cflag &= ~(CSIZE);
6676     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
6677
6678 #ifdef CSTOPB
6679     if (xlocal) {
6680         if (stopbits == 2) {
6681             ttraw.c_cflag |= CSTOPB;    /* 2 stop bits */
6682             debug(F100,"ttpkt 2 stopbits","",0);
6683         } else if (stopbits == 1) {
6684             ttraw.c_cflag &= ~(CSTOPB); /* 1 stop bit */
6685             debug(F100,"ttpkt 1 stopbit","",0);
6686         }
6687     }
6688 #endif /* CSTOPB */
6689
6690 #ifdef HWPARITY
6691     if (hwparity && xlocal) {           /* Hardware parity */
6692         ttraw.c_cflag |= PARENB;        /* Enable parity */
6693 #ifdef COMMENT
6694 /* Uncomment this only if needed -- I don't think it is */
6695         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
6696         ttraw.c_cflag |= CS8;           /* And set it to 8 */
6697 #endif /* COMMENT */
6698 #ifdef IGNPAR
6699         ttraw.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
6700         debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
6701 #endif /* IGNPAR */
6702         switch (hwparity) {
6703           case 'e':                     /* Even */
6704             ttraw.c_cflag &= ~(PARODD);
6705             debug(F100,"ttpkt 8 bits + even parity","",0);
6706             break;
6707           case 'o':                     /* Odd */
6708             ttraw.c_cflag |= PARODD;
6709             debug(F100,"ttpkt 8 bits + odd parity","",0);
6710             break;
6711           case 'm':                     /* Mark */
6712           case 's':                     /* Space */
6713             /* PAREXT is mentioned in SVID but the details are not given. */
6714             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
6715             debug(F100,"ttpkt 8 bits + invalid parity","",0);
6716             break;
6717         }
6718     } else {                            /* We handle parity ourselves */
6719 #endif /* HWPARITY */
6720         ttraw.c_cflag &= ~(PARENB);     /* Don't enable parity */
6721 #ifdef HWPARITY
6722     }
6723 #endif /* HWPARITY */
6724
6725 #ifdef IX370
6726     ttraw.c_cc[4] = 48;  /* So Series/1 doesn't interrupt on every char */
6727     ttraw.c_cc[5] = 1;
6728 #else
6729 #ifndef VEOF                            /* for DGUX this is VEOF, not VMIN */
6730     ttraw.c_cc[4] = 1;   /* [VMIN]  return max of this many characters or */
6731 #else
6732 #ifndef OXOS
6733 #ifdef VMIN
6734     ttraw.c_cc[VMIN] = 1;
6735 #endif /* VMIN */
6736 #else /* OXOS */
6737     ttraw.c_min = 1;
6738 #endif /* OXOS */
6739 #endif /* VEOF */
6740 #ifndef VEOL                            /* for DGUX this is VEOL, not VTIME */
6741     ttraw.c_cc[5] = 0;   /* [VTIME] when this many secs/10 expire w/no input */
6742 #else
6743 #ifndef OXOS
6744 #ifdef VTIME
6745     ttraw.c_cc[VTIME] = 0;
6746 #endif /* VTIME */
6747 #else /* OXOS */
6748     ttraw.c_time = 0;
6749 #endif /* OXOS */
6750 #endif /* VEOL */
6751 #endif /* IX370 */
6752
6753 #ifdef VINTR                            /* Turn off interrupt character */
6754     if (xlocal == 0)                    /* so ^C^C can break us out of */
6755       ttraw.c_cc[VINTR] = 0;            /* packet mode. */
6756 #endif /* VINTR */
6757
6758 #ifdef Plan9
6759     if (p9ttyparity('n') < 0)
6760         return -1;
6761 #else
6762 #ifdef BSD44ORPOSIX
6763     errno = 0;
6764 #ifdef BEOSORBEBOX
6765     ttraw.c_cc[VMIN] = 0;               /* DR7 can only poll. */
6766 #endif /* BEOSORBEBOX */
6767
6768 #define TESTING234
6769 #ifdef TESTING234
6770     if (1) {
6771         debug(F100,"ttpkt TESTING234 rawmode","",0);
6772
6773         /* iflags */
6774         ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
6775         ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF);
6776         ttraw.c_iflag |= IGNBRK;
6777 #ifdef IMAXBEL
6778         ttraw.c_iflag &= ~IMAXBEL;
6779 #endif  /* IMAXBEL */
6780 #ifdef IXANY
6781         ttraw.c_iflag &= ~IXANY;
6782 #endif  /* IXANY */
6783 #ifdef IUCLC
6784         ttraw.c_iflag &= ~IUCLC;
6785 #endif /* IUCLC */
6786
6787         /* oflags */
6788         ttraw.c_oflag &= ~OPOST;
6789 #ifdef OXTABS
6790         ttraw.c_oflag &= ~OXTABS;
6791 #endif /* OXTABS */
6792 #ifdef ONOCR
6793         ttraw.c_oflag &= ~ONOCR;
6794 #endif /* ONOCR */
6795 #ifdef ONLRET
6796         ttraw.c_oflag &= ~ONLRET;
6797 #endif /* ONLRET */
6798 #ifdef ONLCR
6799         ttraw.c_oflag &= ~ONLCR;
6800 #endif /* ONLCR */
6801
6802         /* lflags */
6803         ttraw.c_lflag &= ~ECHO;
6804 #ifdef ECHOE
6805         ttraw.c_lflag &= ~ECHOE;
6806 #endif /* ECHOE */
6807 #ifdef ECHONL
6808         ttraw.c_lflag &= ~ECHONL;
6809 #endif /* ECHONL */
6810 #ifdef ECHOPRT
6811         ttraw.c_lflag &= ~ECHOPRT;
6812 #endif /* ECHOPRT */
6813 #ifdef ECHOKE
6814         ttraw.c_lflag &= ~ECHOKE;
6815 #endif /* ECHOKE */
6816 #ifdef ECHOCTL
6817         ttraw.c_lflag &= ~ECHOCTL;
6818 #endif /* ECHOCTL */
6819 #ifdef ALTWERASE
6820         ttraw.c_lflag &= ~ALTWERASE;
6821 #endif /* ALTWERASE */
6822 #ifdef EXTPROC
6823         ttraw.c_lflag &= ~EXTPROC;
6824 #endif /* EXTPROC */
6825         ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
6826 #ifdef NOKERNINFO
6827         ttraw.c_lflag |= NOKERNINFO;
6828 #endif  /* NOKERNINFO */
6829         /* ttraw.c_lflag |= NOFLSH; */
6830         ttraw.c_lflag &= ~NOFLSH;
6831
6832         /* cflags */
6833         ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD);
6834         ttraw.c_cflag |= CS8|CREAD;
6835 #ifdef VMIN
6836         ttraw.c_cc[VMIN] = 1;           /* Supposedly needed for AIX */
6837 #endif  /* VMIN */
6838
6839     }
6840 #endif /* TESTING234 */
6841
6842     debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
6843     x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
6844     debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
6845     if (x < 0) {
6846         debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
6847         return(-1);
6848     }
6849 #else /* BSD44ORPOSIX */
6850     x = ioctl(ttyfd,TCSETAW,&ttraw);
6851     debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
6852     if (x < 0) {  /* set new modes . */
6853         debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
6854         return(-1);
6855     }
6856 #endif /* BSD44ORPOSIX */
6857 #endif /* Plan9 */
6858     tvtflg = 0;
6859     debug(F100,"ttpkt ok","",0);
6860     return(0);
6861 #endif /* ATTSV */
6862
6863 #ifdef COHERENT
6864 #undef SVORPOSIX
6865 #endif /* COHERENT */
6866
6867 }
6868
6869 /*  T T S E T F L O W  --  Set flow control immediately.  */
6870
6871 #ifdef COHERENT
6872 #define SVORPOSIX
6873 #endif /* COHERENT */
6874
6875 int
6876 ttsetflow(flow) int flow; {
6877     if (ttyfd < 0)                      /* A channel must be open */
6878       return(-1);
6879
6880     debug(F101,"ttsetflow flow","",flow);
6881
6882 #ifdef TN_COMPORT
6883     if (netconn && istncomport()) {
6884         debug(F101,"ttsetflow net modem","",ttmdm);
6885         return(tnsetflow(flow));
6886     }
6887 #endif /* TN_COMPORT */
6888 #ifdef NETCMD
6889     if (ttpipe) return(0);
6890 #endif /* NETCMD */
6891 #ifdef NETPTY
6892     if (ttpty) return(0);
6893 #endif /* NETPTY */
6894
6895 #ifdef COMMENT
6896     /* This seems to hurt... */
6897     if (flow == FLO_KEEP)
6898       return(0);
6899 #endif /* COMMENT */
6900
6901     if (flow == FLO_RTSC ||             /* Hardware flow control... */
6902         flow == FLO_DTRC ||
6903         flow == FLO_DTRT) {
6904         tthflow(flow, 1, &ttraw);
6905 #ifndef SVORPOSIX
6906         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6907 #else
6908         ttraw.c_iflag &= ~(IXON|IXOFF);
6909 #endif /* SVORPOSIX */
6910
6911     } else if (flow == FLO_XONX) {      /* Xon/Xoff... */
6912
6913 #ifndef SVORPOSIX
6914         ttraw.sg_flags |= TANDEM;
6915 #else
6916         ttraw.c_iflag |= (IXON|IXOFF);
6917 #endif /* SVORPOSIX */
6918         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off hardware flow control */
6919
6920     } else if (flow == FLO_NONE) {      /* No flow control */
6921
6922 #ifndef SVORPOSIX
6923         ttraw.sg_flags &= ~TANDEM;      /* Turn off software flow control */
6924 #else
6925         ttraw.c_iflag &= ~(IXON|IXOFF);
6926 #endif /* SVORPOSIX */
6927         tthflow(FLO_RTSC, 0, &ttraw);   /* Turn off any hardware f/c too */
6928     }
6929
6930 /* Set the new modes... */
6931
6932 #ifndef SVORPOSIX                       /* BSD and friends */
6933 #ifdef BELLV10
6934     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
6935       return(-1);
6936 #else
6937 #ifndef MINIX2
6938     if (stty(ttyfd,&ttraw) < 0)
6939       return(-1);
6940 #endif /* MINIX2 */
6941 #endif /* BELLV10 */
6942 #else
6943 #ifdef BSD44ORPOSIX                     /* POSIX */
6944     if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
6945       return(-1);
6946 #else                                   /* System V */
6947     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
6948       return(-1);
6949 #endif /* BSD44ORPOSIX */
6950 #endif /* SVORPOSIX */
6951     return(0);
6952 }
6953 #ifdef COHERENT
6954 #undef SVORPOSIX
6955 #endif /* COHERENT */
6956
6957 /*  T T V T -- Condition communication device for use as virtual terminal. */
6958
6959 int
6960 #ifdef CK_ANSIC
6961 ttvt(long speed, int flow)
6962 #else
6963 ttvt(speed,flow) long speed; int flow;
6964 #endif /* CK_ANSIC */
6965 /* ttvt */ {
6966     int s, s2, x;
6967
6968     debug(F101,"ttvt ttyfd","",ttyfd);
6969     debug(F101,"ttvt tvtflg","",tvtflg);
6970     debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
6971     debug(F111,"ttvt flow",ckitoa(ttflow),flow);
6972     debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
6973
6974 /* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
6975 /* Maybe it would be simpler to use it... */
6976
6977     ttpmsk = 0xff;
6978 #ifdef NOLOCAL
6979     return(conbin((char)escchr));
6980 #else
6981     if (ttyfd < 0) {                    /* Not open. */
6982         if (ttchk() < 0)
6983           return(-1);
6984         else                            /* But maybe something buffered. */
6985           return(0);
6986     }
6987 #ifdef NETCMD
6988     if (ttpipe) return(0);
6989 #endif /* NETCMD */
6990 #ifdef NETPTY
6991     if (ttpty) return(0);
6992 #endif /* NETPTY */
6993 #ifdef NETCONN
6994     if (netconn) {
6995 #ifdef TCPSOCKET
6996 #ifdef TCP_NODELAY
6997         {
6998             extern int tcp_nodelay;
6999             if (ttnet == NET_TCPB) {
7000                 if (nodelay_sav > -1) {
7001                     no_delay(ttyfd,nodelay_sav);
7002                     nodelay_sav = -1;
7003                 }
7004             }
7005         }
7006 #endif /* TCP_NODELAY */
7007 #ifdef TN_COMPORT
7008         if (istncomport()) {
7009             int rc = -1;
7010             if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7011                  /* && ttcarr == curcarr */ ) {
7012                 debug(F100,"ttvt modes already set, skipping...","",0);
7013                 return(0);                      /* Already been called. */
7014             }
7015             if (flow != ttflow) {
7016                 if ((rc = tnsetflow(flow)) < 0)
7017                   return(rc);
7018                 ttflow = flow;
7019             }
7020             if (speed != ttspeed) {
7021                 if (speed <= 0) 
7022                   speed = tnc_get_baud();
7023                 else if ((rc = tnc_set_baud(speed)) < 0)
7024                   return(rc);
7025                 ttspeed = speed;
7026             }
7027             tnc_set_datasize(8);
7028             tnc_set_stopsize(stopbits);
7029
7030 #ifdef HWPARITY
7031             if (hwparity) {
7032                 switch (hwparity) {
7033                   case 'e':             /* Even */
7034                     debug(F100,"ttres 8 bits + even parity","",0);
7035                     tnc_set_parity(3);
7036                     break;
7037                   case 'o':             /* Odd */
7038                     debug(F100,"ttres 8 bits + odd parity","",0);
7039                     tnc_set_parity(2);
7040                     break;
7041                   case 'm':             /* Mark */
7042                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
7043                     tnc_set_parity(4);
7044                     break;
7045                   case 's':             /* Space */
7046                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
7047                     tnc_set_parity(5);
7048                     break;
7049                 }
7050             } else
7051 #endif /* HWPARITY */
7052             {
7053                 tnc_set_parity(1);      /* None */
7054             }
7055             tvtflg = 1;
7056             return(0);
7057         }
7058 #endif /* TN_COMPORT */
7059 #endif /* TCPSOCKET */
7060         tvtflg = 1;                     /* Network connections... */
7061         debug(F100,"ttvt network connection, skipping...","",0);
7062         return(0);                      /* ... require no special setup */
7063     }
7064 #endif /* NETCONN */
7065
7066     if (tvtflg != 0 && speed == ttspeed && flow == ttflow
7067         /* && ttcarr == curcarr */ )
7068       {
7069           debug(F100,"ttvt modes already set, skipping...","",0);
7070           return(0);                    /* Already been called. */
7071       }
7072
7073     if (ttfdflg
7074 #ifndef Plan9
7075         && !isatty(ttyfd)
7076 #endif /* Plan9 */
7077         ) {
7078         debug(F100,"ttvt using external fd, skipping...","",0);
7079         return(0);
7080     }
7081
7082     debug(F100,"ttvt setting modes...","",0);
7083
7084     if (xlocal) {                       /* For external lines... */
7085         s2 = (int) (speed / 10L);
7086         s = ttsspd(s2);                 /* Check/set the speed */
7087         carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
7088                 && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
7089     } else
7090       s = s2 = -1;
7091
7092 #ifdef COHERENT
7093 #define SVORPOSIX
7094 #endif /* COHERENT */
7095
7096 #ifndef SVORPOSIX
7097     /* Berkeley, V7, etc */
7098     if (flow == FLO_RTSC ||             /* Hardware flow control */
7099         flow == FLO_DTRC ||
7100         flow == FLO_DTRT) {
7101         tthflow(flow, 1, &tttvt);
7102         debug(F100,"ttvt hard flow, TANDEM off","",0);
7103         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
7104     } else if (flow == FLO_XONX) {      /* Xon/Xoff flow control */
7105         debug(F100,"ttvt TANDEM on","",0);
7106         tttvt.sg_flags |= TANDEM;       /* Ask for it. */
7107         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7108     } else if (flow == FLO_NONE) {
7109         debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
7110         tttvt.sg_flags &= ~TANDEM;      /* Turn off software flow control */
7111         tthflow(flow, 0, &tttvt);       /* Turn off any hardware f/c too */
7112         tttvt.sg_flags |= RAW;          /* Enter raw mode */
7113     } else if (flow == FLO_KEEP) {      /* Keep device's original setting */
7114         debug(F100,"ttvt keeping original TANDEM","",0);
7115         tttvt.sg_flags &= ~TANDEM;
7116         tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
7117         /* NOTE: We should also handle hardware flow control here! */
7118     }
7119     tttvt.sg_flags |= RAW;              /* Raw mode in all cases */
7120 #ifdef TOWER1
7121     tttvt.sg_flags &= ~(ECHO|ANYP);     /* No echo or parity */
7122 #else
7123     tttvt.sg_flags &= ~ECHO;            /* No echo */
7124 #endif /* TOWER1 */
7125
7126 #ifdef BELLV10
7127     if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
7128       return(-1);
7129 #else
7130     if (stty(ttyfd,&tttvt) < 0)         /* Set the new modes */
7131       return(-1);
7132 #endif /* BELLV10 */
7133
7134 #else /* It is ATTSV or POSIX */
7135
7136     if (flow == FLO_XONX) {             /* Software flow control */
7137         tttvt.c_iflag |= (IXON|IXOFF);  /* On if requested. */
7138         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7139         debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
7140     } else if (flow == FLO_NONE) {      /* NONE */
7141         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */
7142         tthflow(flow, 0, &tttvt);       /* Turn off hardware f/c */
7143         debug(F100,"ttvt SVORPOSIX flow NONE","",0);
7144     } else if (flow == FLO_KEEP) {
7145         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
7146         tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
7147 #ifdef POSIX_CRTSCTS
7148         tttvt.c_cflag &= ~CRTSCTS;      /* Turn off RTS/CTS flag */
7149         tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
7150 #endif /* POSIX_CRTSCTS */
7151         debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
7152     } else if (flow == FLO_RTSC ||      /* Hardware flow control */
7153                flow == FLO_DTRC ||
7154                flow == FLO_DTRT) {
7155         tttvt.c_iflag &= ~(IXON|IXOFF); /* (196) */
7156         tthflow(flow, 1, &tttvt);
7157         debug(F100,"ttvt SVORPOSIX flow HARD","",0);
7158     }
7159 #ifndef OXOS
7160 #ifdef COHERENT
7161     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7162 #else
7163     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
7164 #endif /* COHERENT */
7165 #ifdef QNX
7166     /* Needed for hwfc */
7167     if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
7168       tttvt.c_lflag |= IEXTEN;
7169 #endif /* QNX */
7170 #else /* OXOS */
7171     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
7172     tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
7173 #endif /* OXOS */
7174
7175     tttvt.c_iflag |= (IGNBRK|IGNPAR);
7176
7177 /* Stop bits */
7178
7179 #ifdef CSTOPB
7180     if (xlocal) {
7181         if (stopbits == 2) {
7182             tttvt.c_cflag |= CSTOPB;    /* 2 stop bits */
7183             debug(F100,"ttvt 2 stopbits","",0);
7184         } else if (stopbits == 1) {
7185             tttvt.c_cflag &= ~(CSTOPB); /* 1 stop bit */
7186             debug(F100,"ttvt 1 stopbit","",0);
7187         }
7188     }
7189 #endif /* CSTOPB */
7190
7191 /* Parity */
7192
7193 #ifdef HWPARITY
7194     if (hwparity && xlocal) {           /* Hardware parity */
7195 #ifdef COMMENT
7196 /* Uncomment this only if needed -- I don't think it is */
7197         ttraw.c_cflag &= ~(CSIZE);      /* Clear out character-size mask */
7198         ttraw.c_cflag |= CS8;           /* And set it to 8 */
7199 #endif /* COMMENT */
7200 #ifdef IGNPAR
7201         debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
7202         tttvt.c_iflag |= IGNPAR;        /* Don't discard incoming bytes */
7203 #endif /* IGNPAR */
7204         tttvt.c_cflag |= PARENB;        /* Enable parity */
7205
7206         switch (hwparity) {
7207           case 'e':                     /* Even */
7208             tttvt.c_cflag &= ~(PARODD);
7209             debug(F100,"ttvt 8 bits + even parity","",0);
7210             break;
7211           case 'o':                     /* Odd */
7212             tttvt.c_cflag |= PARODD;
7213             debug(F100,"ttvt 8 bits + odd parity","",0);
7214             break;
7215           case 'm':                     /* Mark */
7216           case 's':                     /* Space */
7217             /* PAREXT is mentioned in SVID but the details are not given. */
7218             /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
7219             debug(F100,"ttvt 8 bits + invalid parity","",0);
7220             break;
7221         }
7222     } else {                            /* We handle parity ourselves */
7223 #endif /* HWPARITY */
7224         tttvt.c_cflag &= ~(PARENB);     /* Don't enable parity */
7225 #ifdef HWPARITY
7226     }
7227 #endif /* HWPARITY */
7228
7229 #ifdef ATTSV
7230 #ifdef BSD44
7231     /* Things not to do... */
7232     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
7233 #else
7234     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
7235 #endif /* BSD44 */
7236 #else /* POSIX */
7237     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
7238 #endif /* ATTSV */
7239     tttvt.c_cflag &= ~(CSIZE);          /* Zero out the char size field */
7240     tttvt.c_cflag |= (CS8|CREAD|HUPCL); /* Char size 8, enable receiver, hup */
7241     tttvt.c_oflag &= ~OPOST;            /* Don't postprocess output */
7242 #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
7243     tttvt.c_cc[4] = 1;
7244 #else
7245 #ifndef OXOS
7246 #ifdef VMIN
7247     tttvt.c_cc[VMIN] = 1;
7248 #endif /* VMIN */
7249 #else /* OXOS */
7250     tttvt.c_min = 1;
7251 #endif /* OXOS */
7252 #endif /* VEOF */
7253 #ifndef VEOL    /* DGUX termio has VEOL at entry 5, see comment above */
7254     tttvt.c_cc[5] = 0;
7255 #else
7256 #ifndef OXOS
7257 #ifdef VTIME
7258     tttvt.c_cc[VTIME] = 0;
7259 #endif /* VTIME */
7260 #else /* OXOS */
7261     tttvt.c_time = 0;
7262 #endif /* OXOS */
7263 #endif /* VEOL */
7264
7265 #ifdef Plan9
7266     if (p9ttyparity('n') < 0)
7267       return -1;
7268 #else
7269 #ifdef BSD44ORPOSIX
7270     errno = 0;
7271 #ifdef BEOSORBEBOX
7272     tttvt.c_cc[VMIN] = 0;               /* DR7 can only poll. */
7273 #endif /* BEOSORBEBOX */
7274
7275     x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
7276     debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
7277     if (x < 0) {
7278         debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
7279         return(-1);
7280     }
7281 #else /* ATTSV */
7282     x = ioctl(ttyfd,TCSETAW,&tttvt);
7283     debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
7284     if (x < 0) {                        /* set new modes . */
7285         debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
7286         return(-1);     
7287     }
7288 #endif /* BSD44ORPOSIX */
7289 #endif /* Plan9 */
7290 #endif /* ATTSV */
7291
7292     ttspeed = speed;                    /* Done, remember how we were */
7293     ttflow = flow;                      /* called, so we can decide how to */
7294     tvtflg = 1;                         /* respond next time. */
7295     debug(F100,"ttvt ok","",0);
7296     return(0);
7297
7298 #ifdef COHERENT
7299 #undef SVORPOSIX
7300 #endif /* COHERENT */
7301
7302 #endif /* NOLOCAL */
7303 }
7304
7305 #ifndef NOLOCAL
7306
7307 /* Serial speed department . . . */
7308
7309 /*
7310   SCO OSR5.0.x might or might not support high speeds.  Sometimes they are not
7311   defined in the header files but they are supported (e.g. when building with
7312   UDK compiler rather than /bin/cc), sometimes vice versa.  Even though 5.0.4
7313   was the first release that came with high serial speeds standard, releases
7314   back to 5.0.0 could use them if certain patches (or "supplements") were
7315   applied to the SIO driver.  Plus a lot of SCO installations run third-party
7316   drivers.
7317 */
7318 #ifdef CK_SCOV5
7319 #ifndef B38400
7320 #define B38400  0000017
7321 #endif /* B38400 */
7322 #ifndef B57600
7323 #define B57600  0000021
7324 #endif /* B57600 */
7325 #ifndef B76800
7326 #define B76800  0000022
7327 #endif /* B76800 */
7328 #ifndef B115200
7329 #define B115200 0000023
7330 #endif /* B115200 */
7331 #ifndef B230400
7332 #define B230400 0000024
7333 #endif /* B230400 */
7334 #ifndef B460800
7335 #define B460800 0000025
7336 #endif /* B460800 */
7337 #ifndef B921600
7338 #define B921600 0000026
7339 #endif /* B921600 */
7340 #endif /* CK_SCOV5 */
7341 /*
7342   Plan 9's native speed setting interface lets you set anything you like,
7343   but will fail if the hardware doesn't like it, so we allow all the common
7344   speeds.
7345 */
7346 #ifdef Plan9
7347 #ifndef B50
7348 #define B50 50
7349 #endif /* B50 */
7350 #ifndef B75
7351 #define B75 75
7352 #endif /* B75 */
7353 #ifndef B110
7354 #define B110 110
7355 #endif /* B110 */
7356 #ifndef B134
7357 #define B134 134
7358 #endif /* B134 */
7359 #ifndef B200
7360 #define B200 200
7361 #endif /* B200 */
7362 #ifndef B300
7363 #define B300 300
7364 #endif /* B300 */
7365 #ifndef B1200
7366 #define B1200 1200
7367 #endif /* B1200 */
7368 #ifndef B1800
7369 #define B1800 1800
7370 #endif /* B1800 */
7371 #ifndef B2400
7372 #define B2400 2400
7373 #endif /* B2400 */
7374 #ifndef B4800
7375 #define B4800 4800
7376 #endif /* B4800 */
7377 #ifndef B9600
7378 #define B9600 9600
7379 #endif /* B9600 */
7380 #ifndef B14400
7381 #define B14400 14400
7382 #endif /* B14400 */
7383 #ifndef B19200
7384 #define B19200 19200
7385 #endif /* B19200 */
7386 #ifndef B28800
7387 #define B28800 28800
7388 #endif /* B28800 */
7389 #ifndef B38400
7390 #define B38400 38400
7391 #endif /* B38400 */
7392 #ifndef B57600
7393 #define B57600 57600
7394 #endif /* B57600 */
7395 #ifndef B76800
7396 #define B76800 76800
7397 #endif /* B76800 */
7398 #ifndef B115200
7399 #define B115200 115200
7400 #endif /* B115200 */
7401 #ifndef B230400
7402 #define B230400 230400
7403 #endif /* B230400 */
7404 #ifndef B460800
7405 #define B460800 460800
7406 #endif /* B460800 */
7407 #ifndef B921600
7408 #define B921600 921600
7409 #endif /* B921600 */
7410 #endif /* Plan9 */
7411
7412 /*  T T S S P D  --  Checks and sets transmission rate.  */
7413
7414 /*  Call with speed in characters (not bits!) per second. */
7415 /*  Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
7416
7417 #ifdef USETCSETSPEED
7418 /*
7419   The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
7420   to be used as a speed to be set, rather than forcing a choice from a
7421   predefined list.  It seems to be peculiar to UnixWare 7.
7422
7423   These are the function codes to be passed to tc[gs]etspeed(),
7424   but for some reason they don't seem to be picked up from termios.h.
7425 */
7426 #ifndef TCS_ALL
7427 #define TCS_ALL 0
7428 #endif /* TCS_ALL */
7429 #ifndef TCS_IN
7430 #define TCS_IN 1
7431 #endif /* TCS_IN */
7432 #ifndef TCS_OUT
7433 #define TCS_OUT 2
7434 #endif /* TCS_OUT */
7435 #endif /* USETCSETSPEED */
7436
7437 int
7438 ttsspd(cps) int cps; {
7439     int x;
7440 #ifdef POSIX
7441 /* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
7442     speed_t
7443 #else
7444     int
7445 #endif /* POSIX */
7446       s, s2;
7447     int ok = 1;                         /* Speed check result, assume ok */
7448
7449 #ifdef OLINUXHISPEED
7450     unsigned int spd_flags = 0;
7451     struct serial_struct serinfo;
7452 #endif /* OLINUXHISPEED */
7453
7454     debug(F101,"ttsspd cps","",cps);
7455     debug(F101,"ttsspd ttyfd","",ttyfd);
7456     debug(F101,"ttsspd xlocal","",xlocal);
7457
7458     if (ttyfd < 0 || xlocal == 0)       /* Don't set speed on console */
7459       return(0);
7460
7461 #ifdef  NETCONN
7462     if (netconn) {
7463 #ifdef TN_COMPORT
7464         if (istncomport())
7465           return(tnc_set_baud(cps * 10));
7466         else
7467 #endif /* TN_COMPORT */
7468         return(0);
7469   }
7470 #endif  /* NETCONN */
7471 #ifdef NETCMD
7472     if (ttpipe) return(0);
7473 #endif /* NETCMD */
7474 #ifdef NETPTY
7475     if (ttpty) return(0);
7476 #endif /* NETPTY */
7477
7478     if (cps < 0) return(-1);
7479     s = s2 = 0;                         /* NB: s and s2 might be unsigned */
7480
7481 #ifdef USETCSETSPEED
7482
7483     s = cps * 10L;
7484
7485     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
7486     debug(F101,"ttsspd tcgetattr","",x);
7487     if (x < 0)
7488       return(-1);
7489     debug(F101,"ttsspd TCSETSPEED speed","",s);
7490
7491     errno = 0;
7492     if (s == 8880L) {                   /* 75/1200 split speed requested */
7493         tcsetspeed(TCS_IN, &ttcur, 1200L);
7494         tcsetspeed(TCS_OUT, &ttcur, 75L);
7495     } else
7496       tcsetspeed(TCS_ALL, &ttcur, s);   /* Put new speed in structs */
7497 #ifdef DEBUG
7498     if (errno & deblog) {
7499         debug(F101,"ttsspd TCSETSPEED errno","",errno);
7500     }
7501 #endif /* DEBUG */
7502
7503 #ifdef COMMENT
7504     tcsetspeed(TCS_ALL, &ttraw, s);
7505     tcsetspeed(TCS_ALL, &tttvt, s);
7506     tcsetspeed(TCS_ALL, &ttold, s);
7507 #else
7508     if (s == 8880L) {                   /* 75/1200 split speed requested */
7509         tcsetspeed(TCS_IN, &ttraw, 1200L);
7510         tcsetspeed(TCS_OUT, &ttraw, 75L);
7511         tcsetspeed(TCS_IN, &tttvt, 1200L);
7512         tcsetspeed(TCS_OUT, &tttvt, 75L);
7513         tcsetspeed(TCS_IN, &ttold, 1200L);
7514         tcsetspeed(TCS_OUT, &ttold, 75L);
7515     } else {
7516         tcsetspeed(TCS_ALL, &ttraw, s);
7517         tcsetspeed(TCS_ALL, &tttvt, s);
7518         tcsetspeed(TCS_ALL, &ttold, s);
7519     }
7520 #endif /* COMMENT */
7521
7522     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
7523     debug(F101,"ttsspd tcsetattr","",x);
7524     if (x < 0)
7525       return(-1);
7526
7527 #else  /* Not USETCSETSPEED */
7528
7529     /* First check that the given speed is valid. */
7530
7531     switch (cps) {
7532 #ifndef MINIX
7533       case 0:   s = B0;    break;
7534       case 5:   s = B50;   break;
7535       case 7:   s = B75;   break;
7536 #endif /* MINIX */
7537       case 11:  s = B110;  break;
7538 #ifndef MINIX
7539       case 13:  s = B134;  break;
7540       case 15:  s = B150;  break;
7541       case 20:  s = B200;  break;
7542 #endif /* MINIX */
7543       case 30:  s = B300;  break;
7544 #ifndef MINIX
7545       case 60:  s = B600;  break;
7546 #endif /* MINIX */
7547       case 120: s = B1200; break;
7548 #ifndef MINIX
7549       case 180: s = B1800; break;
7550 #endif /* MINIX */
7551       case 240: s = B2400; break;
7552       case 480: s = B4800; break;
7553 #ifndef MINIX
7554       case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
7555 #endif /* MINIX */
7556 #ifdef B7200
7557       case 720: s = B7200; break;
7558 #endif /* B7200 */
7559       case 960: s = B9600; break;
7560 #ifdef B14400
7561       case 1440: s = B14400; break;
7562 #endif /* B14400 */
7563 #ifdef B19200
7564       case 1920: s = B19200; break;
7565 #else
7566 #ifdef EXTA
7567       case 1920: s = EXTA; break;
7568 #endif /* EXTA */
7569 #endif /* B19200 */
7570 #ifdef B28800
7571       case 2880: s = B28800; break;
7572 #endif /* B28800 */
7573 #ifdef B38400
7574       case 3840: s = B38400;
7575 #ifdef OLINUXHISPEED
7576         spd_flags = ~ASYNC_SPD_MASK;    /* Nonzero, but zero flags */
7577 #endif /* OLINUXHISPEED */
7578         break;
7579 #else /* B38400 not defined... */
7580 #ifdef EXTB
7581       case 3840: s = EXTB; break;
7582 #endif /* EXTB */
7583 #endif /* B38400 */
7584
7585 #ifdef HPUX
7586 #ifdef _B57600
7587       case 5760: s = _B57600; break;
7588 #endif /* _B57600 */
7589 #ifdef _B115200
7590       case 11520: s = _B115200; break;
7591 #endif /* _B115200 */
7592 #else
7593 #ifdef OLINUXHISPEED
7594 /*
7595   This bit from <carlo@sg.tn.tudelft.nl>:
7596   "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
7597   setting the speed to 38400 will set the custom speed (and ttgspd returns
7598   38400), but speeds 57600 and 115200 won't work any more because I didn't
7599   want to mess up the speed flags when someone is doing sophisticated stuff
7600   like custom speeds..."
7601 */
7602       case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
7603       case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
7604 #else
7605 #ifdef B57600
7606       case 5760: s = B57600; break;
7607 #endif /* B57600 */
7608 #ifdef B76800
7609       case 7680: s = B76800; break;
7610 #endif /* B76800 */
7611 #ifdef B115200
7612       case 11520: s = B115200; break;
7613 #endif /* B115200 */
7614 #endif /* OLINUXHISPEED */
7615 #ifdef B153600
7616       case 15360: s = B153600; break;
7617 #endif /* B153600 */
7618 #ifdef B230400
7619       case 23040: s = B230400; break;
7620 #endif /* B230400 */
7621 #ifdef B307200
7622       case 30720: s = B307200; break;
7623 #endif /* B307200 */
7624 #ifdef B460800
7625       case 46080: s = B460800; break;
7626 #endif /* 460800 */
7627 #ifdef B921600
7628       case 92160: s = B921600; break;
7629 #endif /* B921600 */
7630 #endif /* HPUX */
7631       default:
7632         ok = 0;                         /* Good speed not found, so not ok */
7633         break;
7634     }
7635     debug(F101,"ttsspd ok","",ok);
7636     debug(F101,"ttsspd s","",s);
7637
7638     if (!ok) {
7639         debug(F100,"ttsspd fails","",0);
7640         return(-1);
7641     } else {
7642         if (!s2) s2 = s;                /* Set input speed */
7643 #ifdef Plan9
7644         if (p9ttsspd(cps) < 0)
7645           return(-1);
7646 #else
7647 #ifdef BSD44ORPOSIX
7648         x = tcgetattr(ttyfd,&ttcur);    /* Get current speed */
7649         debug(F101,"ttsspd tcgetattr","",x);
7650         if (x < 0)
7651           return(-1);
7652 #ifdef OLINUXHISPEED
7653         debug(F101,"ttsspd spd_flags","",spd_flags);
7654         if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
7655             if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
7656                 debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
7657                 return(-1);
7658             } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
7659             serinfo.flags &= ~ASYNC_SPD_MASK;
7660             serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
7661             if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
7662               return(-1);
7663         }
7664 #endif /* OLINUXHISPEED */
7665         cfsetospeed(&ttcur,s);
7666         cfsetispeed(&ttcur,s2);
7667         cfsetospeed(&ttraw,s);
7668         cfsetispeed(&ttraw,s2);
7669         cfsetospeed(&tttvt,s);
7670         cfsetispeed(&tttvt,s2);
7671         cfsetospeed(&ttold,s);
7672         cfsetispeed(&ttold,s2);
7673         x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
7674         debug(F101,"ttsspd tcsetattr","",x);
7675         if (x < 0) return(-1);
7676 #else
7677 #ifdef ATTSV
7678         if (cps == 888) return(-1);     /* No split speeds, sorry. */
7679         x = ioctl(ttyfd,TCGETA,&ttcur);
7680         debug(F101,"ttsspd TCGETA ioctl","",x);
7681         if (x < 0) return(-1);
7682         ttcur.c_cflag &= ~CBAUD;
7683         ttcur.c_cflag |= s;
7684         tttvt.c_cflag &= ~CBAUD;
7685         tttvt.c_cflag |= s;
7686         ttraw.c_cflag &= ~CBAUD;
7687         ttraw.c_cflag |= s;
7688         ttold.c_cflag &= ~CBAUD;
7689         ttold.c_cflag |= s;
7690         x = ioctl(ttyfd,TCSETAW,&ttcur);
7691         debug(F101,"ttsspd TCSETAW ioctl","",x);
7692         if (x < 0) return(-1);
7693 #else
7694 #ifdef BELLV10
7695         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
7696         debug(F101,"ttsspd TIOCGDEV ioctl","",x);
7697         if (x < 0) return(-1);
7698         tdcur.ispeed = s2;
7699         tdcur.ospeed = s;
7700         errno = 0;
7701         ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
7702         debug(F101,"ttsspd BELLV10 ioctl","",ok);
7703         if (ok < 0) {
7704             perror(ttnmsv);
7705             debug(F101,"ttsspd BELLV10 errno","",ok);
7706             return(-1);
7707         }
7708 #else
7709         x = gtty(ttyfd,&ttcur);
7710         debug(F101,"ttsspd gtty","",x);
7711         if (x < 0) return(-1);
7712         ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
7713         tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
7714         ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
7715         ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
7716         x = stty(ttyfd,&ttcur);
7717         debug(F101,"ttsspd stty","",x);
7718         if (x < 0) return(-1);
7719 #endif /* BELLV10 */
7720 #endif /* ATTSV */
7721 #endif /* BSD44ORPOSIX */
7722 #endif /* Plan9 */
7723     }
7724     return(1);                          /* Return 1 = success. */
7725 #endif /* USETCSETSPEED */
7726 }
7727
7728 #endif /* NOLOCAL */
7729
7730 /* C O N G S P D  -  Get speed of console terminal  */
7731
7732 long
7733 congspd() {
7734 /*
7735   This is a disgusting hack.  The right way to do this would be to pass an
7736   argument to ttgspd(), but then we'd need to change the Kermit API and
7737   all of the ck?tio.c modules.  (Currently used only for rlogin.)
7738 */
7739     int t1;
7740     long spd;
7741 #ifdef NETCONN
7742     int t2 = netconn;
7743     netconn = 0;
7744 #endif /* NETCONN */
7745     t1 = ttyfd;
7746     ttyfd = -1;
7747     spd = ttgspd();
7748     debug(F101,"congspd","",spd);
7749 #ifdef NETCONN
7750     netconn = t2;
7751 #endif /* NETCONN */
7752     ttyfd = t1;
7753     return(spd);
7754 }
7755
7756 /*  T T S P D L I S T  -- Get list of serial speeds allowed on this platform */
7757
7758 #define NSPDLIST 64
7759 static long spdlist[NSPDLIST];
7760 /*
7761   As written, this picks up the speeds known at compile time, and thus
7762   apply to the system where C-Kermit was built, rather than to the one where
7763   it is running.  Suggestions for improvement are always welcome.
7764 */
7765 long *
7766 ttspdlist() {
7767     int i;
7768     for (i = 0; i < NSPDLIST; i++)      /* Initialize the list */
7769       spdlist[i] = -1L;
7770     i = 1;
7771
7772 #ifdef USETCSETSPEED                    /* No way to find out what's legal */
7773     debug(F100,"ttspdlist USETCSETSPEED","",0);
7774     spdlist[i++] = 50L;
7775 #ifndef UW7
7776     spdlist[i++] = 75L;
7777 #endif /* UW7 */
7778     spdlist[i++] = 110L;
7779 #ifndef UW7
7780     spdlist[i++] = 134L;
7781 #endif /* UW7 */
7782     spdlist[i++] = 150L;
7783     spdlist[i++] = 200L;
7784     spdlist[i++] = 300L;
7785     spdlist[i++] = 600L;
7786     spdlist[i++] = 1200L;
7787     spdlist[i++] = 1800L;
7788     spdlist[i++] = 2400L;
7789     spdlist[i++] = 4800L;
7790     spdlist[i++] = 8880L;
7791     spdlist[i++] = 9600L;
7792     spdlist[i++] = 14400L;
7793     spdlist[i++] = 19200L;
7794     spdlist[i++] = 28800L;
7795 #ifndef UW7
7796     spdlist[i++] = 33600L;
7797 #endif /* UW7 */
7798     spdlist[i++] = 38400L;
7799     spdlist[i++] = 57600L;
7800     spdlist[i++] = 76800L;
7801     spdlist[i++] = 115200L;
7802 #ifndef UW7
7803     spdlist[i++] = 153600L;
7804     spdlist[i++] = 230400L;
7805     spdlist[i++] = 307200L;
7806     spdlist[i++] = 460800L;
7807     spdlist[i++] = 921600L;
7808 #endif /* UW7 */
7809
7810 #else  /* USETCSETSPEED */
7811
7812     debug(F100,"ttspdlist no USETCSETSPEED","",0);
7813
7814 #ifdef B50
7815     debug(F101,"ttspdlist B50","",B50);
7816     spdlist[i++] = 50L;
7817 #endif /* B50 */
7818 #ifdef B75
7819     debug(F101,"ttspdlist B75","",B75);
7820     spdlist[i++] = 75L;
7821 #endif /* B75 */
7822 #ifdef B110
7823     debug(F101,"ttspdlist B110","",B110);
7824     spdlist[i++] = 110L;
7825 #endif /* B110 */
7826 #ifdef B134
7827     debug(F101,"ttspdlist B134","",B134);
7828     spdlist[i++] = 134L;
7829 #endif /* B134 */
7830 #ifdef B150
7831     debug(F101,"ttspdlist B150","",B150);
7832     spdlist[i++] = 150L;
7833 #endif /* B150 */
7834 #ifdef B200
7835     debug(F101,"ttspdlist B200","",B200);
7836     spdlist[i++] = 200L;
7837 #endif /* B200 */
7838 #ifdef B300
7839     debug(F101,"ttspdlist B300","",B300);
7840     spdlist[i++] = 300L;
7841 #endif /* B300 */
7842 #ifdef B600
7843     debug(F101,"ttspdlist B600","",B600);
7844     spdlist[i++] = 600L;
7845 #endif /* B600 */
7846 #ifdef B1200
7847     debug(F101,"ttspdlist B1200","",B1200);
7848     spdlist[i++] = 1200L;
7849 #endif /* B1200 */
7850 #ifdef B1800
7851     debug(F101,"ttspdlist B1800","",B1800);
7852     spdlist[i++] = 1800L;
7853 #endif /* B1800 */
7854 #ifdef B2400
7855     debug(F101,"ttspdlist B2400","",B2400);
7856     spdlist[i++] = 2400L;
7857 #endif /* B2400 */
7858 #ifdef B4800
7859     debug(F101,"ttspdlist B4800","",B4800);
7860     spdlist[i++] = 4800L;
7861 #endif /* B4800 */
7862 #ifdef B9600
7863     debug(F101,"ttspdlist B9600","",B9600);
7864     spdlist[i++] = 9600L;
7865 #endif /* B9600 */
7866 #ifdef B14400
7867     debug(F101,"ttspdlist B14400","",B14400);
7868     spdlist[i++] = 14400L;
7869 #endif /* B14400 */
7870 #ifdef B19200
7871     debug(F101,"ttspdlist B19200","",B19200);
7872     spdlist[i++] = 19200L;
7873 #else
7874 #ifdef EXTA
7875     debug(F101,"ttspdlist EXTA","",EXTA);
7876     spdlist[i++] = 19200L;
7877 #endif /* EXTA */
7878 #endif /* B19200 */
7879 #ifdef B28800
7880     debug(F101,"ttspdlist B28800","",B28800);
7881     spdlist[i++] = 28800L;
7882 #endif /* B28800 */
7883 #ifdef B33600
7884     debug(F101,"ttspdlist B33600","",B33600);
7885     spdlist[i++] = 33600L;
7886 #endif /* B33600 */
7887 #ifdef B38400
7888     debug(F101,"ttspdlist B38400","",B38400);
7889     spdlist[i++] = 38400L;
7890 #else
7891 #ifdef EXTB
7892     debug(F101,"ttspdlist EXTB","",EXTB);
7893     spdlist[i++] = 38400L;
7894 #endif /* EXTB */
7895 #endif /* B38400 */
7896 #ifdef _B57600
7897     debug(F101,"ttspdlist _B57600","",_B57600);
7898     spdlist[i++] = 57600L;
7899 #else
7900 #ifdef B57600
7901     debug(F101,"ttspdlist B57600","",B57600);
7902     spdlist[i++] = 57600L;
7903 #endif /* B57600 */
7904 #endif /* _B57600 */
7905 #ifdef B76800
7906     debug(F101,"ttspdlist B76800","",B76800);
7907     spdlist[i++] = 76800L;
7908 #endif /* B76800 */
7909 #ifdef _B115200
7910     debug(F101,"ttspdlist _B115200","",_B115200);
7911     spdlist[i++] = 115200L;
7912 #else
7913 #ifdef B115200
7914     debug(F101,"ttspdlist B115200","",B115200);
7915     spdlist[i++] = 115200L;
7916 #endif /* B115200 */
7917 #endif /* _B115200 */
7918 #ifdef B153600
7919     debug(F101,"ttspdlist B153600","",B153600);
7920     spdlist[i++] = 153600L;
7921 #endif /* B153600 */
7922 #ifdef B230400
7923     debug(F101,"ttspdlist B230400","",B230400);
7924     spdlist[i++] = 230400L;
7925 #endif /* B230400 */
7926 #ifdef B307200
7927     debug(F101,"ttspdlist B307200","",B307200);
7928     spdlist[i++] = 307200L;
7929 #endif /* B307200 */
7930 #ifdef B460800
7931     debug(F101,"ttspdlist B460800","",B460800);
7932     spdlist[i++] = 460800L;
7933 #endif /* B460800 */
7934 #ifdef B921600
7935     debug(F101,"ttspdlist B921600","",B921600);
7936     spdlist[i++] = 921600L;
7937 #endif /* B921600 */
7938 #endif /* USETCSETSPEED */
7939     spdlist[0] = i - 1;                 /* Return count in 0th element */
7940     debug(F111,"ttspdlist spdlist","0",spdlist[0]);
7941     return((long *)spdlist);
7942 }
7943
7944 /* T T G S P D  -  Get speed of currently selected tty line  */
7945
7946 /*
7947   Unreliable.  After SET LINE, it returns an actual speed, but not necessarily
7948   the real speed.  On some systems, it returns the line's nominal speed, from
7949   /etc/ttytab.  Even if you SET SPEED to something else, this function might
7950   not notice.
7951 */
7952 long
7953 ttgspd() {                              /* Get current serial device speed */
7954 #ifdef NOLOCAL
7955     return(-1L);
7956 #else
7957 #ifdef POSIX
7958     speed_t                             /* Should be unsigned */
7959 #else
7960     int                                 /* Isn't unsigned */
7961 #endif /* POSIX */
7962       s;
7963     int x;
7964     long ss;
7965 #ifdef OLINUXHISPEED
7966     unsigned int spd_flags = 0;
7967     struct serial_struct serinfo;
7968 #endif /* OLINUXHISPEED */
7969
7970 #ifdef NETCONN
7971     if (netconn) {
7972 #ifdef TN_COMPORT
7973         if (istncomport())
7974           return(tnc_get_baud());
7975         else
7976 #endif /* TN_COMPORT */
7977           return(-1);                   /* -1 if network connection */
7978     }
7979 #endif /* NETCONN */
7980 #ifdef NETCMD
7981     if (ttpipe) return(-1);
7982 #endif /* NETCMD */
7983 #ifdef NETPTY
7984     if (ttpty) return(-1);
7985 #endif /* NETPTY */
7986
7987     debug(F101,"ttgspd ttyfd","",ttyfd);
7988
7989 #ifdef USETCSETSPEED
7990
7991     x = tcgetattr(ttyfd,&ttcur);        /* Get current speed */
7992     debug(F101,"ttgspd tcgetattr","",x);
7993     if (x < 0)
7994       return(-1);
7995     errno = 0;
7996     s = tcgetspeed(TCS_ALL, &ttcur);
7997     debug(F101,"ttsspd TCGETSPEED speed","",s);
7998     if (s == 0) {
7999         long s1, s2;
8000         s1 = tcgetspeed(TCS_IN, &ttcur);
8001         s2 = tcgetspeed(TCS_OUT, &ttcur);
8002         if (s1 == 1200L && s2 == 75L)
8003           return(8880L);
8004     }
8005 #ifdef DEBUG
8006     if (errno & deblog) {
8007         debug(F101,"ttsspd TCGETSPEED errno","",errno);
8008     }
8009 #endif /* DEBUG */
8010     return(s);
8011
8012 #else  /* Not USETCSETSPEED */
8013
8014 #ifdef Plan9
8015     if (ttyfd < 0)
8016       ss = -1;
8017     else
8018       ss = ttylastspeed;
8019 #else
8020 #ifdef OLINUXHISPEED
8021     debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
8022 #endif /* OLINUXHISPEED */
8023
8024     if (ttyfd < 0) {
8025 #ifdef BSD44ORPOSIX
8026         s = cfgetospeed(&ccold);
8027         debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
8028 #else
8029 #ifdef ATTSV
8030         s = ccold.c_cflag & CBAUD;
8031         debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
8032 #else
8033         s = ccold.sg_ospeed;            /* (obtained by congm()) */
8034         debug(F101,"ttgspd sg_ospeed 1","",s);
8035 #endif /* ATTSV */
8036 #endif /* BSD44POSIX */
8037
8038     } else {
8039 #ifdef BSD44ORPOSIX
8040         if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
8041         s = cfgetospeed(&ttcur);
8042         debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
8043 #ifdef OLINUXHISPEED
8044         if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
8045           spd_flags = serinfo.flags & ASYNC_SPD_MASK;
8046         debug(F101,"ttgspd spd_flags","",spd_flags);
8047 #endif /* OLINUXHISPEED */
8048 #else
8049 #ifdef ATTSV
8050         x = ioctl(ttyfd,TCGETA,&ttcur);
8051         debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
8052         debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
8053         if (x < 0) return(-1);
8054         s = ttcur.c_cflag & CBAUD;
8055         debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
8056 #else
8057 #ifdef BELLV10
8058         x = ioctl(ttyfd,TIOCGDEV,&tdcur);
8059         debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
8060         if (x < 0) return(-1);
8061         s = tdcur.ospeed;
8062         debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
8063 #else
8064         x = gtty(ttyfd,&ttcur);
8065         debug(F101,"ttgspd gtty 2 x","",x);
8066         debug(F101,"ttgspd gtty 2 errno","",errno);
8067         if (x < 0) return(-1);
8068         s = ttcur.sg_ospeed;
8069         debug(F101,"ttgspd gtty 2 speed","",s);
8070 #endif /* BELLV10 */
8071 #endif /* ATTSV */
8072 #endif /* BSD44ORPOSIX */
8073     }
8074     debug(F101,"ttgspd code","",s);
8075 #ifdef OLINUXHISPEED
8076     debug(F101,"ttgspd spd_flags","",spd_flags);
8077 #endif /* OLINUXHISPEED */
8078     switch (s) {
8079 #ifdef B0
8080       case B0:    ss = 0L; break;
8081 #endif /* B0 */
8082
8083 #ifndef MINIX
8084 /*
8085  MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
8086  etc, making for many "duplicate case in switch" errors, which are fatal.
8087 */
8088 #ifdef B50
8089       case B50:   ss = 50L; break;
8090 #endif /* B50 */
8091 #ifdef B75
8092       case B75:   ss = 75L; break;
8093 #endif /* B75 */
8094 #endif /* MINIX */
8095
8096 #ifdef B110
8097       case B110:  ss = 110L; break;
8098 #endif /* B110 */
8099
8100 #ifndef MINIX
8101 #ifdef B134
8102       case B134:  ss = 134L; break;
8103 #endif /* B134 */
8104 #ifdef B150
8105       case B150:  ss = 150L; break;
8106 #endif /* B150 */
8107 #endif /* MINIX */
8108
8109 #ifdef B200
8110       case B200:  ss = 200L; break;
8111 #endif /* B200 */
8112
8113 #ifdef B300
8114       case B300:  ss = 300L; break;
8115 #endif /* B300 */
8116
8117 #ifdef B600
8118       case B600:  ss = 600L; break;
8119 #endif /* B600 */
8120
8121 #ifdef B1200
8122       case B1200: ss = 1200L; break;
8123 #endif /* B1200 */
8124
8125 #ifdef B1800
8126       case B1800: ss = 1800L; break;
8127 #endif /* B1800 */
8128
8129 #ifdef B2400
8130       case B2400: ss = 2400L; break;
8131 #endif /* B2400 */
8132
8133 #ifdef B4800
8134       case B4800: ss = 4800L; break;
8135 #endif /* B4800 */
8136
8137 #ifdef B7200
8138       case B7200: ss = 7200L; break;
8139 #endif /* B7200 */
8140
8141 #ifdef B9600
8142       case B9600: ss = 9600L; break;
8143 #endif /* B9600 */
8144
8145 #ifdef B19200
8146       case B19200: ss = 19200L; break;
8147 #else
8148 #ifdef EXTA
8149       case EXTA: ss = 19200L; break;
8150 #endif /* EXTA */
8151 #endif /* B19200 */
8152
8153 #ifndef MINIX
8154 #ifdef B38400
8155       case B38400:
8156         ss = 38400L;
8157 #ifdef OLINUXHISPEED
8158         switch(spd_flags) {
8159           case ASYNC_SPD_HI:  ss =  57600L; break;
8160           case ASYNC_SPD_VHI: ss = 115200L; break;
8161         }
8162 #endif /* OLINUXHISPEED */
8163         break;
8164 #else
8165 #ifdef EXTB
8166       case EXTB: ss = 38400L; break;
8167 #endif /* EXTB */
8168 #endif /* B38400 */
8169 #endif /* MINIX */
8170
8171 #ifdef HPUX
8172 #ifdef _B57600
8173       case _B57600: ss = 57600L; break;
8174 #endif /* _B57600 */
8175 #ifdef _B115200
8176       case _B115200: ss = 115200L; break;
8177 #endif /* _B115200 */
8178 #else
8179 #ifdef B57600
8180       case B57600: ss = 57600L; break;
8181 #endif /* B57600 */
8182 #ifdef B76800
8183       case B76800: ss = 76800L; break;
8184 #endif /* B76800 */
8185 #ifdef B115200
8186       case B115200: ss = 115200L; break;
8187 #endif /* B115200 */
8188 #ifdef B153600
8189       case B153600: ss = 153600L; break;
8190 #endif /* B153600 */
8191 #ifdef B230400
8192       case B230400: ss = 230400L; break;
8193 #endif /* B230400 */
8194 #ifdef B307200
8195       case B307200: ss = 307200L; break;
8196 #endif /* B307200 */
8197 #ifdef B460800
8198       case B460800: ss = 460800L; break;
8199 #endif /* B460800 */
8200 #endif /* HPUX */
8201 #ifdef B921600
8202       case B921600: ss = 921600L; break;
8203 #endif /* B921600 */
8204       default:
8205         ss = -1; break;
8206     }
8207 #endif /* Plan9 */
8208     debug(F101,"ttgspd speed","",ss);
8209     return(ss);
8210
8211 #endif /* USETCSETSPEED */
8212 #endif /* NOLOCAL */
8213 }
8214 #ifdef MINIX2                           /* Another hack alert */
8215 #define MINIX
8216 #endif /* MINIX2 */
8217
8218 /*
8219   FIONREAD data type...  This has been defined as "long" for many, many
8220   years, and it worked OK until 64-bit platforms appeared.  Thus we use
8221   int for 64-bit platforms, but keep long for the others.  If we changed
8222   the default PEEKTYPE to int, this would probably break 16-bit builds
8223   (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
8224   of which we have no way of testing any more.  Therefore, do not change
8225   the default definition of PEEKTYPE -- only add exceptions to it as needed.
8226 */
8227 #ifdef COHERENT
8228 #ifdef FIONREAD
8229 #undef FIONREAD
8230 #endif /* FIONREAD */
8231 /* #define FIONREAD TIOCQUERY */
8232 /* #define PEEKTYPE int */
8233 #else  /* Not COHERENT... */
8234
8235 #ifdef OSF32                            /* Digital UNIX 3.2 or higher */
8236 #define PEEKTYPE int
8237 #else
8238 #define PEEKTYPE long                   /* Elsewhere (see notes above) */
8239 #endif /* OSF32 */
8240 #endif /* COHERENT */
8241
8242 /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
8243
8244 #ifdef MYREAD
8245
8246 /* Private buffer for myread() and its companions.  Not for use by anything
8247  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
8248  * allowed to read my_count.
8249  *
8250  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
8251  *
8252  * A global parity mask variable could be useful too.  We could use it to
8253  * let myread() strip the parity on its own, instead of stripping sign
8254  * bits as it does now.
8255  */
8256 #ifdef BIGBUFOK
8257 #define MYBUFLEN 32768
8258 #else
8259 #ifdef pdp11
8260 #define MYBUFLEN 256
8261 #else
8262 #define MYBUFLEN 1024
8263 #endif /* pdp11 */
8264 #endif /* BIGBUFOK */
8265
8266 #ifdef ANYX25
8267 #undef MYBUFLEN
8268 #define MYBUFLEN 256
8269 /*
8270   On X.25 connections, there is an extra control byte at the beginning.
8271 */
8272 static CHAR x25buf[MYBUFLEN+1];         /* Communication device input buffer */
8273 static CHAR  *mybuf = x25buf+1;
8274 #else
8275 static CHAR mybuf[MYBUFLEN];
8276 #endif /* ANYX25 */
8277
8278 static int my_count = 0;                /* Number of chars still in mybuf */
8279 static int my_item = -1;                /* Last index read from mybuf[]   */
8280
8281 /*  T T P E E K  --  Peek into our internal communications input buffers. */
8282
8283 /*
8284   NOTE: This routine is peculiar to UNIX, and is used only by the
8285   select()-based CONNECT module, ckucns.c.  It need not be replicated in
8286   the ck?tio.c of other platforms.
8287 */
8288 int
8289 ttpeek() {
8290 #ifdef TTLEBUF
8291     int rc = 0;
8292     if (ttpush >= 0)
8293       rc++;
8294     rc += le_inbuf();
8295     if (rc > 0)
8296       return(rc);
8297     else
8298 #endif /* TTLEBUF */
8299
8300 #ifdef MYREAD
8301     return(my_count);
8302 #else
8303     return(0);
8304 #endif /* MYREAD */
8305 }
8306
8307 /* myread() -- Efficient read of one character from communications line.
8308  *
8309  * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw
8310  * bytes from connection, so when the connection is encrypted, these bytes
8311  * must be decrypted.
8312  *
8313  * Uses a private buffer to minimize the number of expensive read() system
8314  * calls.  Essentially performs the equivalent of read() of 1 character, which
8315  * is then returned.  By reading all available input from the system buffers
8316  * to the private buffer in one chunk, and then working from this buffer, the
8317  * number of system calls is reduced in any case where more than one character
8318  * arrives during the processing of the previous chunk, for instance high
8319  * baud rates or network type connections where input arrives in packets.
8320  * If the time needed for a read() system call approaches the time for more
8321  * than one character to arrive, then this mechanism automatically compensates
8322  * for that by performing bigger read()s less frequently.  If the system load
8323  * is high, the same mechanism compensates for that too.
8324  *
8325  * myread() is a macro that returns the next character from the buffer.  If the
8326  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
8327  * returns.
8328  *
8329  * This should be efficient enough for any one-character-at-a-time loops.
8330  * For even better efficiency you might use memcpy()/bcopy() or such between
8331  * buffers (since they are often better optimized for copying), but it may not
8332  * be worth it if you have to take an extra pass over the buffer to strip
8333  * parity and check for CTRL-C anyway.
8334  *
8335  * Note that if you have been using myread() from another program module, you
8336  * may have some trouble accessing this macro version and the private variables
8337  * it uses.  In that case, just add a function in this module, that invokes the
8338  * macro.
8339  */
8340 #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
8341
8342 /* Specification: Push back up to one character onto myread()'s queue.
8343  *
8344  * This implementation: Push back characters into mybuf. At least one character
8345  * must have been read through myread() before myunrd() may be used.  After
8346  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
8347  * one character can be pushed back, but only one character is guaranteed.
8348  * Since a previous myread() must have read its character out of mybuf[],
8349  * that guarantees that there is space for at least one character.  If push
8350  * back was really needed after EOF, a small addition could provide that.
8351  *
8352  * As of 02/2007 myunrd() is used by ttinl().
8353  */
8354 VOID
8355 #ifdef CK_ANSIC
8356 myunrd(CHAR ch)
8357 #else
8358 myunrd(ch) CHAR ch;
8359 #endif  /* CK_ANSIC */
8360 {
8361     if (my_item >= 0) {
8362         mybuf[my_item--] = ch;
8363         ++my_count;
8364     }
8365 }
8366
8367 /*  T T P U S H B A C K  --  Put n bytes back into the myread buffer */
8368
8369 static CHAR * pushbuf = NULL;
8370 /* static int pushed = 0; */
8371
8372 int
8373 ttpushback(s,n) CHAR * s; int n; {
8374     debug(F101,"ttpushback n","",n);
8375     if (pushbuf || n > MYBUFLEN || n < 1)
8376       return(-1);
8377     debug(F101,"ttpushback my_count","",my_count);
8378     if (my_count > 0) {
8379         if (!(pushbuf = (CHAR *)malloc(n+1)))
8380           return(-1);
8381         memcpy(pushbuf,mybuf,my_count);
8382         /* pushed = my_count; */ /* (set but never used) */
8383     }
8384     memcpy(mybuf,s,n);
8385     my_count = n;
8386     my_item = -1;
8387     return(0);
8388 }
8389
8390 /* mygetbuf() -- Fill buffer for myread() and return first character.
8391  *
8392  * This function is what myread() uses when it can't get the next character
8393  * directly from its buffer.  First, it calls a system dependent myfillbuf()
8394  * to read at least one new character into the buffer, and then it returns
8395  * the first character just as myread() would have done.  This function also
8396  * is responsible for all error conditions that myread() can indicate.
8397  *
8398  * Returns: When OK     => a positive character, 0 or greater.
8399  *          When EOF    => -2.
8400  *          When error  => -3, error code in errno.
8401  *
8402  * Older myread()s additionally returned -1 to indicate that there was nothing
8403  * to read, upon which the caller would call myread() again until it got
8404  * something.  The new myread()/mygetbuf() always gets something.  If it
8405  * doesn't, then make it do so!  Any program that actually depends on the old
8406  * behaviour will break.
8407  *
8408  * The older version also used to return -2 both for EOF and other errors,
8409  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
8410  * other errors now return different results, although Kermit currently never
8411  * checks to see which it was.  It just disconnects in both cases.
8412  *
8413  * Kermit lets the user use the quit key to perform some special commands
8414  * during file transfer.  This causes read(), and thus also mygetbuf(), to
8415  * finish without reading anything and return the EINTR error.  This should
8416  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
8417  * but if there is nothing to read, this could delay Kermit's reaction to
8418  * the command, and make Kermit appear unresponsive.
8419  *
8420  * The debug() call should be removed for optimum performance.
8421  */
8422 int
8423 mygetbuf() {
8424     int x;
8425     errno = 0;
8426 #ifdef DEBUG
8427     if (deblog && my_count > 0)
8428       debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
8429 #endif /* DEBUG */
8430     if (my_count <= 0)
8431       my_count = myfillbuf();
8432
8433 #ifdef DEBUG
8434 #ifdef COMMENT
8435     if (deblog) debug(F101, "mygetbuf read", "", my_count);
8436 #else /* COMMENT */
8437     ckhexdump("mygetbuf read", mybuf, my_count);
8438 #endif /* COMMENT */
8439 #endif /* DEBUG */
8440     x = my_count;
8441     if (my_count <= 0) {
8442         my_count = 0;
8443         my_item = -1;
8444         debug(F101,"mygetbuf errno","",errno);
8445 #ifdef TCPSOCKET
8446         if (netconn && ttnet == NET_TCPB && errno != 0) {
8447             if (errno != EINTR) {
8448                 debug(F101,"mygetbuf TCP error","",errno);
8449                 ttclos(0);              /* Close the connection. */
8450             }
8451             return(-3);
8452         }
8453 #endif /* TCPSOCKET */
8454         if (!netconn && xlocal && errno) {
8455             if (errno != EINTR) {
8456                 debug(F101,"mygetbuf SERIAL error","",errno);
8457                 x = -3;
8458                 ttclos(0);              /* Close the connection. */
8459             }
8460         }
8461         return((x < 0) ? -3 : -2);
8462     }
8463     --my_count;
8464     return((unsigned)(0xff & mybuf[my_item = 0]));
8465 }
8466
8467 /* myfillbuf():
8468  * System-dependent read() into mybuf[], as many characters as possible.
8469  *
8470  * Returns: OK => number of characters read, always more than zero.
8471  *          EOF => 0
8472  *          Error => -1, error code in errno.
8473  *
8474  * If there is input available in the system's buffers, all of it should be
8475  * read into mybuf[] and the function return immediately.  If no input is
8476  * available, it should wait for a character to arrive, and return with that
8477  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
8478  * character, but be aware that any such delay lengthens the packet turnaround
8479  * time during kermit file transfers.  Should never return with zero characters
8480  * unless EOF or irrecoverable read error.
8481  *
8482  * Correct functioning depends on the correct tty parameters being used.
8483  * Better control of current parameters is required than may have been the
8484  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
8485  * no longer be sometimes off and sometimes on like it used to, unless a
8486  * special myfillbuf() is written to handle that.  Otherwise the ordinary
8487  * myfillbuf()s may think they have come to EOF.
8488  *
8489  * If your system has a facility to directly perform the functioning of
8490  * myfillbuf(), then use it.  If the system can tell you how many characters
8491  * are available in its buffers, then read that amount (but not less than 1).
8492  * If the system can return a special indication when you try to read without
8493  * anything to read, while allowing you to read all there is when there is
8494  * something, you may loop until there is something to read, but probably that
8495  * is not good for the system load.
8496  */
8497
8498 #ifdef SVORPOSIX
8499         /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
8500          * and CLOCAL set any way you like.  This way, read() will do exactly
8501          * what is required by myfillbuf(): If there is data in the buffers
8502          * of the O.S., all available data is read into mybuf, up to the size
8503          * of mybuf.  If there is none, the first character to arrive is
8504          * awaited and returned.
8505          */
8506 int
8507 myfillbuf() {
8508     int fd, n;
8509 #ifdef NETCMD
8510     if (ttpipe)
8511       fd = fdin;
8512     else
8513 #endif /* NETCMD */
8514       fd = ttyfd;
8515
8516 #ifdef sxaE50
8517     /* From S. Dezawa at Fujifilm in Japan.  I don't know why this is */
8518     /* necessary for the sxa E50, but it is. */
8519     return read(fd, mybuf, 255);
8520 #else
8521 #ifdef BEOSORBEBOX
8522     while (1) {
8523 #ifdef NETCONN
8524         if (netconn) {
8525             n = netxin(sizeof(mybuf), (char *)mybuf);
8526             debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
8527         }
8528         else
8529 #endif /* NETCONN */
8530           n = read(fd, mybuf, sizeof(mybuf));
8531         debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
8532         if (n > 0)
8533           return(n);
8534         snooze(1000.0);
8535     }
8536 #else /* BEOSORBEBOX */
8537     errno = 0;
8538     /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */
8539 #ifdef IBMX25
8540     if (netconn && (nettype == NET_IX25)) {
8541         /* can't use sizeof because mybuf is a pointer, and not an array! */
8542         n = x25xin( MYBUFLEN, mybuf );
8543     } else
8544 #endif /* IBMX25 */
8545
8546 #ifdef CK_SSL
8547       if (ssl_active_flag || tls_active_flag) {
8548           int error, n = 0;
8549           debug(F100,"myfillbuf calling SSL_read() fd","",0);
8550           while (n == 0) {
8551               if (ssl_active_flag)
8552                 n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8553               else if (tls_active_flag)
8554                 n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8555               else
8556                 break;
8557               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8558                 case SSL_ERROR_NONE:
8559                   if (n > 0)
8560                     return(n);
8561                   if (n < 0)
8562                     return(-2);
8563                   msleep(50);
8564                   break;
8565                 case SSL_ERROR_WANT_WRITE:
8566                 case SSL_ERROR_WANT_READ:
8567                   return(-1);
8568                 case SSL_ERROR_SYSCALL:
8569                   if (n != 0)
8570                     return(-1);
8571                 case SSL_ERROR_WANT_X509_LOOKUP:
8572                 case SSL_ERROR_SSL:
8573                 case SSL_ERROR_ZERO_RETURN:
8574                 default:
8575                   ttclos(0);
8576                   return(-3);
8577             }
8578         }
8579     }
8580 #endif /* CK_SSL */
8581 #ifdef CK_KERBEROS
8582 #ifdef KRB4
8583 #ifdef RLOGCODE
8584     if (ttnproto == NP_EK4LOGIN) {
8585         debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd);
8586         if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8587           return(-3);
8588         else
8589           return(n);
8590     }
8591 #endif /* RLOGCODE */
8592 #endif /* KRB4 */
8593 #ifdef KRB5
8594 #ifdef RLOGCODE
8595     if (ttnproto == NP_EK5LOGIN) {
8596         debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd);
8597         if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0)
8598           return(-3);
8599         else
8600           return(n);
8601     }
8602 #endif /* RLOGCODE */
8603 #ifdef KRB5_U2U
8604     if (ttnproto == NP_K5U2U) {
8605         debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd);
8606         if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
8607           return(-3);
8608         else
8609           return(n);
8610     }
8611 #endif /* KRB5_U2U */
8612 #endif /* KRB5 */
8613 #endif /* CK_KERBEROS */
8614
8615 #ifdef NETPTY
8616 #ifdef HAVE_PTYTRAP
8617     /* Special handling for HP-UX pty i/o */
8618   ptyread:
8619     if (ttpty && pty_trap_pending(ttyfd) > 0) {
8620         debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd);
8621         if (pty_trap_handler(ttyfd) > 0) {
8622             ttclos(0);
8623             return(-3);
8624         }
8625     }
8626 #endif /* HAVE_PTYTRAP */
8627 #endif /* NETPTY */
8628     debug(F101,"myfillbuf calling read() fd","",ttyfd);
8629     n = read(fd, mybuf, sizeof(mybuf));
8630     debug(F101,"SVORPOSIX myfillbuf read","",n);
8631     debug(F101,"SVORPOSIX myfillbuf errno","",errno);
8632     debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
8633     if (n < 1) {
8634 #ifdef NETPTY
8635 #ifdef HAVE_PTYTRAP
8636         /* When we have a PTY trap in place the connection cannot */
8637         /* be closed until the trap receives a close indication.  */
8638         if (n == 0 && ttpty)
8639             goto ptyread;
8640 #endif /* HAVE_PTYTRAP */
8641 #endif /* NETPTY */
8642         return(-3);
8643     }
8644     return(n);
8645 #endif /* BEOSORBEBOX */
8646 #endif /* sxaE50 */
8647 }
8648
8649 #else /* not AT&T or POSIX */
8650
8651 #ifdef aegis
8652         /* This is quoted from the old myread().  The semantics seem to be
8653          * alright, but maybe errno would not need to be set even when
8654          * there is no error?  I don't know aegis.
8655          */
8656 int
8657 myfillbuf() {
8658     int count;
8659 #ifdef NETCMD
8660     if (ttpipe)
8661       fd = fdin;
8662     else
8663 #endif /* NETCMD */
8664       fd = ttyfd;
8665
8666     count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
8667     errno = EIO;
8668     if (st.all == ios_$get_conditional_failed) /* get at least one */
8669       count = ios_$get((short)fd, 0, mybuf, 1L, st);
8670     if (st.all == ios_$end_of_file)
8671       return(-3);
8672     else if (st.all != status_$ok) {
8673         errno = EIO;
8674         return(-1);
8675     }
8676     return(count > 0 ? count : -3);
8677 }
8678 #else /* !aegis */
8679
8680 #ifdef FIONREAD
8681         /* This is for systems with FIONREAD.  FIONREAD returns the number
8682          * of characters available for reading. If none are available, wait
8683          * until something arrives, otherwise return all there is.
8684          */
8685 int
8686 myfillbuf() {
8687     PEEKTYPE avail = 0;
8688     int x, fd;
8689 #ifdef NETCMD
8690     if (ttpipe)
8691       fd = fdin;
8692     else
8693 #endif /* NETCMD */
8694       fd = ttyfd;
8695
8696 #ifdef SUNX25
8697 /*
8698   SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
8699   Depends on SunOS having FIONREAD, not because we use it, but just so this
8700   code is grouped correctly within the #ifdefs.  Let's hope Solaris keeps it.
8701
8702   We call x25xin() instead of read() so that Q-Bit packets, which contain
8703   X.25 service-level information (e.g. PAD parameter changes), can be processed
8704   transparently to the upper-level code.  This is a blocking read, and so
8705   we depend on higher-level code (such as ttinc()) to set any necessary alarms.
8706 */
8707     extern int nettype;
8708     if (netconn && nettype == NET_SX25) {
8709         while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
8710         return(x - 1);          /* "-1" compensates for extra status byte */
8711     }
8712 #endif /* SUNX25 */
8713
8714 #ifdef CK_SSL
8715     if (ssl_active_flag || tls_active_flag) {
8716         int error, n = 0;
8717         while (n == 0) {
8718             if (ssl_active_flag)
8719               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8720             else
8721               n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8722             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8723               case SSL_ERROR_NONE:
8724                 if (n > 0)
8725                   return(n);
8726                 if (n < 0)
8727                   return(-2);
8728                 msleep(50);
8729                 break;
8730               case SSL_ERROR_WANT_WRITE:
8731               case SSL_ERROR_WANT_READ:
8732                 return(-1);
8733               case SSL_ERROR_SYSCALL:
8734                 if (n != 0)
8735                   return(-1);
8736               case SSL_ERROR_WANT_X509_LOOKUP:
8737               case SSL_ERROR_SSL:
8738               case SSL_ERROR_ZERO_RETURN:
8739               default:
8740                 ttclos(0);
8741                 return(-2);
8742             }
8743         }
8744     }
8745 #endif /* CK_SSL */
8746 #ifdef CK_KERBEROS
8747 #ifdef KRB4
8748 #ifdef RLOGCODE
8749     if (ttnproto == NP_EK4LOGIN) {
8750         if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8751           return(-1);
8752         else
8753           return(x);
8754     }
8755 #endif /* RLOGCODE */
8756 #endif /* KRB4 */
8757 #ifdef KRB5
8758 #ifdef RLOGCODE
8759     if (ttnproto == NP_EK5LOGIN) {
8760         if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8761           return(-1);
8762         else
8763           return(x);
8764     }
8765 #endif /* RLOGCODE */
8766 #ifdef KRB5_U2U
8767     if (ttnproto == NP_K5U2U) {
8768         if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8769           return(-1);
8770         else
8771           return(x);
8772     }
8773 #endif /* KRB5_U2U */
8774 #endif /* KRB5 */
8775 #endif /* CK_KERBEROS */
8776
8777     errno = 0;
8778     debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
8779     x = ioctl(fd, FIONREAD, &avail);
8780 #ifdef DEBUG
8781     if (deblog) {
8782         debug(F101,"myfillbuf FIONREAD","",x);
8783         debug(F101,"myfillbuf FIONREAD avail","",avail);
8784         debug(F101,"myfillbuf FIONREAD errno","",errno);
8785     }
8786 #endif /* DEBUG */
8787     if (x < 0 || avail == 0)
8788       avail = 1;
8789
8790     if (avail > MYBUFLEN)
8791       avail = MYBUFLEN;
8792
8793     errno = 0;
8794
8795     x = read(fd, mybuf, (int) avail);
8796 #ifdef DEBUG
8797     if (deblog) {
8798         debug(F101,"myfillbuf avail","",avail);
8799         debug(F101,"myfillbuf read","",x);
8800         debug(F101,"myfillbuf read errno","",errno);
8801         if (x > 0)
8802           ckhexdump("myfillbuf mybuf",mybuf,x);
8803     }
8804 #endif /* DEBUG */
8805     if (x < 1) x = -3;                  /* read 0 == connection loss */
8806     return(x);
8807 }
8808
8809 #else /* !FIONREAD */
8810 /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
8811 /* When there is no other possibility, read 1 character at a time. */
8812 int
8813 myfillbuf() {
8814     int x;
8815
8816 #ifdef CK_SSL
8817     if (ssl_active_flag || tls_active_flag) {
8818         int error, n = 0;
8819         while (n == 0) {
8820             if (ssl_active_flag)
8821               n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
8822             else
8823               count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
8824             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
8825               case SSL_ERROR_NONE:
8826                 if (n > 0)
8827                   return(n);
8828                 if (n < 0)
8829                   return(-2);
8830                 msleep(50);
8831                 break;
8832               case SSL_ERROR_WANT_WRITE:
8833               case SSL_ERROR_WANT_READ:
8834                 return(-1);
8835               case SSL_ERROR_SYSCALL:
8836                 if (n != 0)
8837                   return(-1);
8838               case SSL_ERROR_WANT_X509_LOOKUP:
8839               case SSL_ERROR_SSL:
8840               case SSL_ERROR_ZERO_RETURN:
8841               default:
8842                 ttclos(0);
8843                 return(-2);
8844             }
8845         }
8846     }
8847 #endif /* CK_SSL */
8848 #ifdef CK_KERBEROS
8849 #ifdef KRB4
8850 #ifdef RLOGCODE
8851     if (ttnproto == NP_EK4LOGIN) {
8852         if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8853           return(-1);
8854         else
8855           return(len);
8856     }
8857 #endif /* RLOGCODE */
8858 #endif /* KRB4 */
8859 #ifdef KRB5
8860 #ifdef RLOGCODE
8861     if (ttnproto == NP_EK5LOGIN) {
8862         if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
8863           return(-1);
8864         else
8865           return(len);
8866     }
8867 #endif /* RLOGCODE */
8868 #ifdef KRB5_U2U
8869     if (ttnproto == NP_K5U2U) {
8870         if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
8871           return(-1);
8872         else
8873           return(len);
8874     }
8875 #endif /* KRB5_U2U */
8876 #endif /* KRB5 */
8877 #endif /* CK_KERBEROS */
8878
8879 #ifdef NETCMD
8880     if (ttpipe)
8881       fd = fdin;
8882     else
8883 #endif /* NETCMD */
8884       fd = ttyfd;
8885     x = read(fd, mybuf, 1);
8886     return(x > 0 ? x : -3);
8887 }
8888
8889 #endif /* !FIONREAD */
8890 #endif /* !aegis */
8891 #endif /* !ATTSV */
8892
8893 #endif /* MYREAD */
8894
8895 /*  T T _ T N O P T  --  Handle Telnet negotions in incoming data */
8896 /*
8897   Call with the IAC that was encountered.
8898   Returns:
8899    -3: If connection has dropped or gone bad.
8900    -2: On Telnet protocol error resulting in inconsistent states.
8901     0: If negotiation OK and caller has nothing to do.
8902     1: If packet start character has changed (new value is in global stchr).
8903   255: If there was a quoted IAC as data.
8904    or: Not at all if we got a legitimate Telnet Logout request.
8905 */
8906 #ifdef TCPSOCKET
8907 static int
8908 tt_tnopt(n) int n; {                    /* Handle Telnet options */
8909     /* In case caller did not already check these conditions...  */
8910     if (n == IAC &&
8911         ((xlocal && netconn && IS_TELNET()) ||
8912          (!xlocal && sstelnet))) {
8913         extern int server;
8914         int tx = 0;
8915         debug(F100,"ttinl calling tn_doop()","",0);
8916         tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
8917         debug(F111,"ttinl tn_doop() returned","tx",tx);
8918         switch (tx) {
8919           case 0:
8920             return(0);
8921           case -1:                      /* I/O error */
8922             ttimoff();                  /* Turn off timer */
8923             return(-3);
8924           case -2:                      /* Connection failed. */
8925           case -3:
8926             ttimoff();                  /* Turn off timer */
8927             ttclos(0);
8928             return(-3);
8929           case 1:                       /* ECHO change */
8930             duplex = 1;
8931             return(0);
8932           case 2:                       /* ECHO change */
8933             duplex = 0;
8934             return(0);
8935           case 3:                       /* Quoted IAC */
8936             n = 255;
8937             return((unsigned)255);
8938 #ifdef IKS_OPTION
8939           case 4: {
8940               if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
8941 #ifdef IKSD
8942                   && !inserver
8943 #endif /* IKSD */
8944                   ) {                   /* Remote in Server mode */
8945                   ttimoff();            /* Turn off timer */
8946                   debug(F100,"u_start and !inserver","",0);
8947                   return(-2);           /* End server mode */
8948               } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
8949                          server
8950                          ) {            /* I'm no longer in Server Mode */
8951                   debug(F100,"me_start and server","",0);
8952                   ttimoff();
8953                   return(-2);
8954               }
8955               return(0);
8956           }
8957           case 5: {                     /* Start character change */
8958               /* extern CHAR stchr; */
8959               /* start = stchr; */
8960               return(1);
8961           }
8962 #endif /* IKS_OPTION */
8963           case 6:                       /* Remote Logout */
8964             ttimoff();
8965             ttclos(0);
8966 #ifdef IKSD
8967             if (inserver && !local)
8968               doexit(GOOD_EXIT,0);
8969             else
8970 #endif /* IKSD */
8971               return(-2);
8972           default:
8973             return(0);
8974         }
8975     } else
8976       return(0);
8977 }
8978 #endif /* TCPSOCKET */
8979
8980 /*  T T F L U I  --  Flush tty input buffer */
8981
8982 void
8983 ttflux() {                              /* But first... */
8984 #ifdef MYREAD
8985 /*
8986   Flush internal MYREAD buffer.
8987 */
8988 #ifdef TCPSOCKET
8989     int dotnopts, x;
8990     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
8991                  (!xlocal && sstelnet)));
8992 #endif /* TCPSOCKET */
8993     debug(F101,"ttflux my_count","",my_count);
8994 #ifdef TCPSOCKET
8995     if (dotnopts) {
8996         CHAR ch = '\0';
8997         while (my_count > 0) {
8998             ch = myread();
8999 #ifdef CK_ENCRYPTION
9000             if (TELOPT_U(TELOPT_ENCRYPTION))
9001               ck_tn_decrypt((char *)&ch,1);
9002 #endif /* CK_ENCRYPTION */
9003             if (ch == IAC)
9004               x = tt_tnopt(ch);
9005         }
9006     } else
9007 #endif /* TCPSOCKET */
9008 #ifdef COMMENT
9009 #ifdef CK_ENCRYPTION
9010     if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
9011       ck_tn_decrypt(&mybuf[my_item+1],my_count);
9012 #endif /* CK_ENCRYPTION */
9013 #endif /* COMMENT */
9014     my_count = 0;                       /* Reset count to zero */
9015     my_item = -1;                       /* And buffer index to -1 */
9016 #endif /* MYREAD */
9017 }
9018
9019 int
9020 ttflui() {
9021     int n, fd;
9022 #ifdef TCPSOCKET
9023     int dotnopts;
9024     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
9025                  (!xlocal && sstelnet)));
9026 #endif /* TCPSOCKET */
9027
9028 #ifdef NETCMD
9029     if (ttpipe)
9030       fd = fdin;
9031     else
9032 #endif /* NETCMD */
9033       fd = ttyfd;
9034
9035 #ifdef TTLEBUF
9036     ttpush = -1;                        /* Clear the peek-ahead char */
9037     while (le_data && (le_inbuf() > 0)) {
9038         CHAR ch = '\0';
9039         if (le_getchar(&ch) > 0) {      /* Clear any more... */
9040             debug(F101,"ttflui le_inbuf ch","",ch);
9041         }
9042     }
9043 #endif /* TTLEBUF */
9044     debug(F101,"ttflui ttpipe","",ttpipe);
9045
9046 #ifdef MYREAD
9047 /*
9048   Flush internal MYREAD buffer *NEXT*, in all cases.
9049 */
9050     ttflux();
9051 #endif /* MYREAD */
9052
9053 #ifdef NETCONN
9054 /* Network flush is done specially, in the network support module. */
9055     if ((netconn || sstelnet) && !ttpipe && !ttpty) {
9056         debug(F100,"ttflui netflui","",0);
9057 #ifdef COMMENT
9058 #ifdef TN_COMPORT
9059         if (istncomport())
9060             tnc_send_purge_data(TNC_PURGE_RECEIVE);
9061 #endif /* TN_COMPORT */
9062 #endif /* COMMENT */
9063         return(netflui());
9064     }
9065 #endif /* NETCONN */
9066
9067     debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
9068     if (ttyfd < 0)
9069       return(-1);
9070
9071 #ifdef aegis
9072     sio_$control((short)yfd, sio_$flush_in, true, st);
9073     if (st.all != status_$ok) {
9074         fprintf(stderr, "flush failed: "); error_$print(st);
9075     } else {      /* sometimes the flush doesn't work */
9076         for (;;) {
9077             char buf[256];
9078             /* eat all the characters that shouldn't be available */
9079             ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
9080             if (st.all == ios_$get_conditional_failed) break;
9081             fprintf(stderr, "flush failed(2): "); error_$print(st);
9082         }
9083     }
9084 #else
9085 #ifdef BSD44                            /* 4.4 BSD */
9086     n = FREAD;                          /* Specify read queue */
9087     debug(F100,"ttflui BSD44","",0);
9088     ioctl(fd,TIOCFLUSH,&n);
9089 #else
9090 #ifdef Plan9
9091 #undef POSIX                            /* Uh oh... */
9092 #endif /* Plan9 */
9093 #ifdef POSIX                            /* POSIX */
9094     debug(F100,"ttflui POSIX","",0);
9095     tcflush(fd,TCIFLUSH);
9096 #else
9097 #ifdef ATTSV                            /* System V */
9098 #ifndef VXVE
9099     debug(F100,"ttflui ATTSV","",0);
9100     ioctl(fd,TCFLSH,0);
9101 #endif /* VXVE */
9102 #else                                   /* Not BSD44, POSIX, or Sys V */
9103 #ifdef TIOCFLUSH                        /* Those with TIOCFLUSH defined */
9104 #ifdef ANYBSD                           /* Berkeley */
9105     n = FREAD;                          /* Specify read queue */
9106     debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
9107     ioctl(fd,TIOCFLUSH,&n);
9108 #else                                   /* Others (V7, etc) */
9109     debug(F100,"ttflui TIOCFLUSH","",0);
9110     ioctl(fd,TIOCFLUSH,0);
9111 #endif /* ANYBSD */
9112 #else                                   /* All others... */
9113 /*
9114   No system call (that we know about) for input buffer flushing.
9115   So see how many there are and read them in a loop, using ttinc().
9116   ttinc() is buffered, so we're not getting charged with a system call
9117   per character, just a function call.
9118 */
9119     if ((n = ttchk()) > 0) {
9120         debug(F101,"ttflui read loop","",n);
9121         while ((n--) && ttinc(0) > 0) ;
9122     }
9123 #endif /* TIOCFLUSH */
9124 #endif /* ATTSV */
9125 #endif /* POSIX */
9126 #ifdef Plan9
9127 #define POSIX
9128 #endif /* Plan9 */
9129 #endif /* BSD44 */
9130 #endif /* aegis */
9131     return(0);
9132 }
9133
9134 int
9135 ttfluo() {                              /* Flush output buffer */
9136     int fd;
9137 #ifdef NETCMD
9138     if (ttpipe)
9139       fd = fdout;
9140     else
9141 #endif /* NETCMD */
9142       fd = ttyfd;
9143
9144 #ifdef Plan9
9145     return 0;
9146 #else
9147 #ifdef POSIX
9148     return(tcflush(fd,TCOFLUSH));
9149 #else
9150 #ifdef OXOS
9151     return(ioctl(fd,TCFLSH,1));
9152 #else
9153     return(0);                          /* All others, nothing */
9154 #endif /* OXOS */
9155 #endif /* POSIX */
9156 #endif /* Plan9 */
9157 }
9158
9159 /* Interrupt Functions */
9160
9161 /* Set up terminal interrupts on console terminal */
9162
9163 #ifndef FIONREAD                        /* We don't need esctrp() */
9164 #ifndef SELECT                          /* if we have any of these... */
9165 #ifndef CK_POLL
9166 #ifndef RDCHK
9167
9168 #ifndef OXOS
9169 #ifdef SVORPOSIX
9170 SIGTYP
9171 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9172     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9173     conesc = 1;
9174     debug(F101,"esctrp caught SIGQUIT","",conesc);
9175 }
9176 #endif /* SVORPOSIX */
9177 #endif /* OXOS */
9178
9179 #ifdef V7
9180 #ifndef MINIX2
9181 SIGTYP
9182 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9183     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9184     conesc = 1;
9185     debug(F101,"esctrp caught SIGQUIT","",conesc);
9186 }
9187 #endif /* MINIX2 */
9188 #endif /* V7 */
9189
9190 #ifdef C70
9191 SIGTYP
9192 esctrp(foo) int foo; {                  /* trap console escapes (^\) */
9193     conesc = 1;
9194     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
9195 }
9196 #endif /* C70 */
9197
9198 #endif /* RDCHK */
9199 #endif /* CK_POLL */
9200 #endif /* SELECT */
9201 #endif /* FIONREAD */
9202
9203 /*  C O N B G T  --  Background Test  */
9204
9205 static int jc = 0;                      /* 0 = no job control */
9206
9207 /*
9208   Call with flag == 1 to prevent signal test, which can not be expected
9209   to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
9210
9211   Call with flag == 0 to use the signal test, but only if the process-group
9212   test fails, as it does on some UNIX systems, where getpgrp() is buggy,
9213   requires an argument when the man page says it doesn't, or vice versa.
9214
9215   If flag == 0 and the process-group test fails, then we determine background
9216   status simply (but not necessarily reliably) from isatty().
9217
9218   conbgt() sets the global backgrd = 1 if we appear to be in the background,
9219   and to 0 if we seem to be in the foreground.  conbgt() is highly prone to
9220   misbehavior.
9221 */
9222 VOID
9223 conbgt(flag) int flag; {
9224     int x = -1,                         /* process group or SIGINT test */
9225         y = 0;                          /* isatty() test */
9226 /*
9227   Check for background operation, even if not running on real tty, so that
9228   background flag can be set correctly.  If background status is detected,
9229   then Kermit will not issue its interactive prompt or most messages.
9230   If your prompt goes away, you can blame (and fix?) this function.
9231 */
9232
9233 /* Use process-group test if possible. */
9234
9235 #ifdef POSIX                            /* We can do it in POSIX */
9236 #define PGROUP_T
9237 #else
9238 #ifdef BSD4                             /* and in BSD 4.x. */
9239 #define PGROUP_T
9240 #else
9241 #ifdef HPUXJOBCTL                       /* and in most HP-UX's */
9242 #define PGROUP_T
9243 #else
9244 #ifdef TIOCGPGRP                        /* and anyplace that has this ioctl. */
9245 #define PGROUP_T
9246 #endif /* TIOCGPGRP */
9247 #endif /* HPUXJOBCTL */
9248 #endif /* BSD4 */
9249 #endif /* POSIX */
9250
9251 #ifdef MIPS                             /* Except if it doesn't work... */
9252 #undef PGROUP_T
9253 #endif /* MIPS */
9254
9255 #ifdef MINIX
9256 #undef PGROUP_T
9257 #endif  /* MINIX */
9258
9259 #ifdef PGROUP_T
9260 /*
9261   Semi-reliable process-group test.  Check whether this process's group is
9262   the same as the controlling terminal's process group.  This works if the
9263   getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
9264 */
9265     PID_T mypgrp = (PID_T)0;            /* Kermit's process group */
9266     PID_T ctpgrp = (PID_T)0;            /* The terminal's process group */
9267 #ifndef _POSIX_SOURCE
9268 /*
9269   The getpgrp() prototype is obtained from system header files for POSIX
9270   and Sys V R4 compilations.  Other systems, who knows.  Some complain about
9271   a duplicate declaration here, others don't, so it's safer to leave it in
9272   if we don't know for certain.
9273 */
9274 #ifndef SVR4
9275 #ifndef PS2AIX10
9276 #ifndef HPUX9
9277     extern PID_T getpgrp();
9278 #endif /* HPUX9 */
9279 #endif /* PS2AIX10 */
9280 #endif /* SVR4 */
9281 #endif /* _POSIX_SOURCE */
9282
9283 /* Get my process group. */
9284
9285 #ifdef SVR3 /* Maybe this should be ATTSV? */
9286 /* This function is not described in SVID R2 */
9287     mypgrp = getpgrp();
9288     /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
9289 #else
9290 #ifdef POSIX
9291     mypgrp = getpgrp();
9292     /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
9293 #else
9294 #ifdef OSFPC
9295     mypgrp = getpgrp();
9296     /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
9297 #else
9298 #ifdef QNX
9299     mypgrp = getpgrp();
9300     /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
9301 #else
9302 #ifdef OSF32                            /* (was OSF40) */
9303     mypgrp = getpgrp();
9304     /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
9305 #else /* BSD, V7, etc */
9306 #ifdef MINIX2
9307     mypgrp = getpgrp();
9308 #else
9309     mypgrp = getpgrp(0);
9310 #endif /* MINIX2 */
9311     /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
9312 #endif /* OSF32 */
9313 #endif /* QNX */
9314 #endif /* OSFPC */
9315 #endif /* POSIX */
9316 #endif /* SVR3 */
9317
9318 #ifdef MINIX
9319     /* MINIX does not support job control so Kermit is always in foreground */
9320     x = 0;
9321
9322 #else  /* Not MINIX */
9323
9324 /* Now get controlling tty's process group */
9325 #ifdef BSD44ORPOSIX
9326     ctpgrp = tcgetpgrp(1);              /* The POSIX way */
9327     /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
9328 #else
9329     ioctl(1, TIOCGPGRP, &ctpgrp);       /* Or the BSD way */
9330    /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
9331 #endif /* BSD44ORPOSIX */
9332
9333     if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
9334       x = (mypgrp == ctpgrp) ? 0 : 1;   /* If they differ, then background. */
9335     else x = -1;                        /* If error, remember. */
9336     debug(F101,"conbgt process group test","",x);
9337 #endif /* PGROUP_T */
9338 #endif  /* MINIX */
9339
9340 /* Try to see if job control is available */
9341
9342 #ifdef NOJC                             /* User override */
9343     jc = 0;                             /* No job control allowed */
9344     debug(F111,"NOJC","jc",jc);
9345 #else
9346 #ifdef BSD44
9347     jc = 1;
9348 #else
9349 #ifdef SVR4ORPOSIX                      /* POSIX actually tells us */
9350     debug(F100,"SVR4ORPOSIX jc test...","",0);
9351 #ifdef _SC_JOB_CONTROL
9352 #ifdef __bsdi__
9353     jc = 1;
9354 #else
9355 #ifdef __386BSD__
9356     jc = 1;
9357 #else
9358     jc = sysconf(_SC_JOB_CONTROL);      /* Whatever system says */
9359     if (jc < 0) {
9360         debug(F101,"sysconf fails, jcshell","",jcshell);
9361         jc = (jchdlr == SIG_DFL) ? 1 : 0;
9362     } else
9363       debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
9364 #endif /* __386BSD__ */
9365 #endif /* __bsdi__ */
9366 #else
9367 #ifdef _POSIX_JOB_CONTROL
9368     jc = 1;                             /* By definition */
9369     debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
9370 #else
9371     jc = 0;                             /* Assume job control not allowed */
9372     debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
9373 #endif /* _POSIX_JOB_CONTROL */
9374 #endif /* _SC_JOB_CONTROL */
9375 #else
9376 #ifdef BSD4
9377     jc = 1;                             /* Job control allowed */
9378     debug(F111,"BSD job control","jc",jc);
9379 #else
9380 #ifdef SVR3JC
9381     jc = 1;                             /* JC allowed */
9382     debug(F111,"SVR3 job control","jc",jc);
9383 #else
9384 #ifdef OXOS
9385     jc = 1;                             /* JC allowed */
9386     debug(F111,"X/OS job control","jc",jc);
9387 #else
9388 #ifdef HPUX9
9389     jc = 1;                             /* JC allowed */
9390     debug(F111,"HP-UX 9.0 job control","jc",jc);
9391 #else
9392 #ifdef HPUX10
9393     jc = 1;                             /* JC allowed */
9394     debug(F111,"HP-UX 10.0 job control","jc",jc);
9395 #else
9396     jc = 0;                             /* JC not allowed */
9397     debug(F111,"job control catch-all","jc",jc);
9398 #endif /* HPUX10 */
9399 #endif /* HPUX9 */
9400 #endif /* OXOS */
9401 #endif /* SVR3JC */
9402 #endif /* BSD4 */
9403 #endif /* SVR4ORPOSIX */
9404 #endif /* BSD44 */
9405 #endif /* NOJC */
9406     debug(F101,"conbgt jc","",jc);
9407 #ifndef NOJC
9408     debug(F101,"conbgt jcshell","",jcshell);
9409 /*
9410   At this point, if jc == 1 but jcshell == 0, it means that the OS supports
9411   job control, but the shell or other process we are running under does not
9412   (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
9413   will come of it.  So...
9414 */
9415     if (jc < 0) jc = 0;
9416     if (jc > 0 && jcshell == 0) jc = 0;
9417 #endif /* NOJC */
9418
9419 /*
9420   Another background test.
9421   Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
9422   which is done by the shell (sh) if the program is started with '&'.
9423   Unfortunately, this is NOT done by csh or ksh so watch out!
9424   Note, it's safe to set SIGINT to SIG_IGN here, because further down
9425   we always set it to something else.
9426   Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
9427   SIG_IGN ourselves.
9428 */
9429     if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
9430
9431         SIGTYP (*osigint)();
9432
9433         osigint = signal(SIGINT,SIG_IGN);       /* What is SIGINT set to? */
9434         sigint_ign = 1;
9435         x = (osigint == SIG_IGN) ? 1 : 0;       /* SIG_IGN? */
9436         /* debug(F101,"conbgt osigint","",osigint); */
9437         /* debug(F101,"conbgt signal test","",x); */
9438     }
9439
9440 /* Also check to see if we're running with redirected stdio. */
9441 /* This is not really background operation, but we want to act as though */
9442 /* it were. */
9443
9444 #ifdef IKSD
9445     if (inserver) {                     /* Internet Kermit Server */
9446         backgrd = 0;                    /* is not in the background */
9447         return;
9448     }
9449 #endif /* IKSD */
9450
9451     y = (isatty(0) && isatty(1)) ? 1 : 0;
9452     debug(F101,"conbgt isatty test","",y);
9453
9454 #ifdef BSD29
9455 /* The process group and/or signal test doesn't work under these... */
9456     backgrd = !y;
9457 #else
9458 #ifdef sxaE50
9459     backgrd = !y;
9460 #else
9461 #ifdef MINIX
9462     backgrd = !y;
9463 #else
9464 #ifdef MINIX2
9465     backgrd = !y;
9466 #else
9467     if (x > -1)
9468       backgrd = (x || !y) ? 1 : 0;
9469     else backgrd = !y;
9470 #endif /* BSD29 */
9471 #endif /* sxaE50 */
9472 #endif /* MINIX */
9473 #endif /* MINIX2 */
9474     debug(F101,"conbgt backgrd","",backgrd);
9475 }
9476
9477 /*  C O N I N T  --  Console Interrupt setter  */
9478
9479 /*
9480   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
9481   Second arg is pointer to function to handle SIGTSTP (suspend).
9482 */
9483
9484 VOID                                    /* Set terminal interrupt traps. */
9485 #ifdef CK_ANSIC
9486 #ifdef apollo
9487 conint(f,s) SIGTYP (*f)(), (*s)();
9488 #else
9489 conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
9490 #endif /* apollo */
9491 #else
9492 conint(f,s) SIGTYP (*f)(), (*s)();
9493 #endif /* CK_ANSIC */
9494 /* conint */ {
9495
9496     debug(F101,"conint conistate","",conistate);
9497
9498     conbgt(0);                          /* Do background test. */
9499
9500 /* Set the desired handlers for hangup and software termination. */
9501
9502 #ifdef SIGTERM
9503     signal(SIGTERM,f);                  /* Software termination */
9504 #endif /* SIGTERM */
9505
9506 /*
9507   Prior to July 1999 we used to call sighup() here but now it's called in
9508   sysinit() so SIGHUP can be caught during execution of the init file or
9509   a kerbang script.
9510 */
9511
9512 /* Now handle keyboard stop, quit, and interrupt signals. */
9513 /* Check if invoked in background -- if so signals set to be ignored. */
9514 /* However, if running under a job control shell, don't ignore them. */
9515 /* We won't be getting any, as we aren't in the terminal's process group. */
9516
9517     debug(F101,"conint backgrd","",backgrd);
9518     debug(F101,"conint jc","",jc);
9519
9520     if (backgrd && !jc) {               /* In background, ignore signals */
9521         debug(F101,"conint background ignoring signals, jc","",jc);
9522 #ifdef SIGTSTP
9523         signal(SIGTSTP,SIG_IGN);        /* Keyboard stop */
9524 #endif /* SIGTSTP */
9525         signal(SIGQUIT,SIG_IGN);        /* Keyboard quit */
9526         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
9527         sigint_ign = 1;
9528         conistate = CONI_NOI;
9529     } else {                            /* Else in foreground or suspended */
9530         debug(F101,"conint foreground catching signals, jc","",jc);
9531         signal(SIGINT,f);               /* Catch terminal interrupt */
9532         sigint_ign = (f == SIG_IGN) ? 1 : 0;
9533
9534 #ifdef SIGTSTP                          /* Keyboard stop (suspend) */
9535         /* debug(F101,"conint SIGSTSTP","",s); */
9536         if (s == NULL) s = SIG_DFL;
9537 #ifdef NOJC                             /* No job control allowed. */
9538         signal(SIGTSTP,SIG_IGN);
9539 #else                                   /* Job control allowed */
9540         if (jc)                         /* if available. */
9541           signal(SIGTSTP,s);
9542         else
9543           signal(SIGTSTP,SIG_IGN);
9544 #endif /* NOJC */
9545 #endif /* SIGTSTP */
9546
9547 #ifndef OXOS
9548 #ifdef SVORPOSIX
9549 #ifndef FIONREAD                        /* Watch out, we don't know this... */
9550 #ifndef SELECT
9551 #ifndef CK_POLL
9552 #ifndef RDCHK
9553         signal(SIGQUIT,esctrp);         /* Quit signal, Sys III/V. */
9554 #endif /* RDCHK */
9555 #endif /* CK_POLL */
9556 #endif /* SELECT */
9557 #endif /* FIONREAD */
9558         if (conesc) conesc = 0;         /* Clear out pending escapes */
9559 #else
9560 #ifdef V7
9561         signal(SIGQUIT,esctrp);         /* V7 like Sys III/V */
9562         if (conesc) conesc = 0;
9563 #else
9564 #ifdef aegis
9565         signal(SIGQUIT,f);              /* Apollo, catch it like others. */
9566 #else
9567         signal(SIGQUIT,SIG_IGN);        /* Others, ignore like 4D & earlier. */
9568 #endif /* aegis */
9569 #endif /* V7 */
9570 #endif /* SVORPOSIX */
9571 #endif /* OXOS */
9572         conistate = CONI_INT;
9573     }
9574 }
9575
9576
9577 /*  C O N N O I  --  Reset console terminal interrupts */
9578
9579 VOID
9580 connoi() {                              /* Console-no-interrupts */
9581
9582     debug(F101,"connoi conistate","",conistate);
9583 #ifdef SIGTSTP
9584     signal(SIGTSTP,SIG_IGN);            /* Suspend */
9585 #endif /* SIGTSTP */
9586     conint(SIG_IGN,SIG_IGN);            /* Interrupt */
9587     sigint_ign = 1;                     /* Remember we did this ourselves */
9588 #ifdef SIGQUIT
9589     signal(SIGQUIT,SIG_IGN);            /* Quit */
9590 #endif /* SIGQUIT */
9591 #ifdef SIGTERM
9592     signal(SIGTERM,SIG_IGN);            /* Term */
9593 #endif /* SIGTERM */
9594     conistate = CONI_NOI;
9595 }
9596
9597 /*  I N I T R A W Q  --  Set up to read /dev/kmem for character count.  */
9598
9599 #ifdef  V7
9600 /*
9601  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
9602  eliminates blocking on a read, because we can read /dev/kmem to get the
9603  number of characters available for raw input.  If your system can't
9604  or you won't let the world read /dev/kmem then you must figure out a
9605  different way to do the counting of characters available, or else replace
9606  this by a dummy function that always returns 0.
9607 */
9608 /*
9609  * Call this routine as: initrawq(tty)
9610  * where tty is the file descriptor of a terminal.  It will return
9611  * (as a char *) the kernel-mode memory address of the rawq character
9612  * count, which may then be read.  It has the side-effect of flushing
9613  * input on the terminal.
9614  */
9615 /*
9616  * John Mackin, Physiology Dept., University of Sydney (Australia)
9617  * ...!decvax!mulga!physiol.su.oz!john
9618  *
9619  * Permission is hereby granted to do anything with this code, as
9620  * long as this comment is retained unmodified and no commercial
9621  * advantage is gained.
9622  */
9623 #ifndef MINIX
9624 #ifndef MINIX2
9625 #ifndef COHERENT
9626 #include <a.out.h>
9627 #include <sys/proc.h>
9628 #endif /* COHERENT */
9629 #endif /* MINIX2 */
9630 #endif /* MINIX */
9631
9632 #ifdef COHERENT
9633 #include <l.out.h>
9634 #include <sys/proc.h>
9635 #endif /* COHERENT */
9636
9637 char *
9638 initrawq(tty) int tty; {
9639 #ifdef MINIX
9640     return(0);
9641 #else
9642 #ifdef MINIX2
9643     return(0);
9644 #else
9645 #ifdef UTS24
9646     return(0);
9647 #else
9648 #ifdef BSD29
9649     return(0);
9650 #else
9651     long lseek();
9652     static struct nlist nl[] = {
9653         {PROCNAME},
9654         {NPROCNAME},
9655         {""}
9656     };
9657     static struct proc *pp;
9658     char *qaddr, *p, c;
9659     int m;
9660     PID_T pid, me;
9661     NPTYPE xproc;                       /* Its type is defined in makefile. */
9662     int catch();
9663
9664     me = getpid();
9665     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
9666     nlist(BOOTNAME, nl);
9667     if (nl[0].n_type == 0) err("proc array");
9668
9669     if (nl[1].n_type == 0) err("nproc");
9670
9671     lseek(m, (long)(nl[1].n_value), 0);
9672     read (m, &xproc, sizeof(xproc));
9673     saval = signal(SIGALRM, catch);
9674     if ((pid = fork()) == 0) {
9675         while(1)
9676             read(tty, &c, 1);
9677     }
9678     alarm(2);
9679
9680     if(setjmp(jjbuf) == 0) {
9681         while(1)
9682           read(tty, &c, 1);
9683     }
9684     signal(SIGALRM, SIG_DFL);
9685
9686 #ifdef DIRECT
9687     pp = (struct proc *) nl[0].n_value;
9688 #else
9689     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
9690     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
9691 #endif
9692     lseek(m, (long)(nl[1].n_value), 0);
9693     read(m, &xproc, sizeof(xproc));
9694
9695     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
9696     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
9697     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
9698         err("read proc table");
9699     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
9700         if (pp -> p_pid == (short) pid) goto iout;
9701     }
9702     err("no such proc");
9703
9704 iout:
9705     close(m);
9706     qaddr = (char *)(pp -> p_wchan);
9707     free (p);
9708     kill(pid, SIGKILL);
9709     wait((WAIT_T *)0);
9710     return (qaddr);
9711 #endif
9712 #endif
9713 #endif
9714 #endif
9715 }
9716
9717 /*  More V7-support functions...  */
9718
9719 static VOID
9720 err(s) char *s; {
9721     char buf[200];
9722
9723     ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
9724     perror(buf);
9725     doexit(1,-1);
9726 }
9727
9728 static VOID
9729 catch(foo) int foo; {
9730     longjmp(jjbuf, -1);
9731 }
9732
9733
9734 /*  G E N B R K  --  Simulate a modem break.  */
9735
9736 #ifdef MINIX
9737 #define BSPEED B110
9738 #else
9739 #ifdef MINIX2
9740 #define BSPEED B110
9741 #else
9742 #define BSPEED B150
9743 #endif /* MINIX2 */
9744 #endif /* MINIX */
9745
9746 #ifndef MINIX2
9747 VOID
9748 genbrk(fn,msec) int fn, msec; {
9749     struct sgttyb ttbuf;
9750     int ret, sospeed, x, y;
9751
9752     ret = ioctl(fn, TIOCGETP, &ttbuf);
9753     sospeed = ttbuf.sg_ospeed;
9754     ttbuf.sg_ospeed = BSPEED;
9755     ret = ioctl(fn, TIOCSETP, &ttbuf);
9756     y = (int)strlen(brnuls);
9757     x = ( BSPEED * 100 ) / msec;
9758     if (x > y) x = y;
9759     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9760     ttbuf.sg_ospeed = sospeed;
9761     ret = ioctl(fn, TIOCSETP, &ttbuf);
9762     ret = write(fn, "@", 1);
9763     return;
9764 }
9765 #endif /* MINIX2 */
9766
9767 #ifdef MINIX2
9768 int
9769 genbrk(fn,msec) int fn, msec; {
9770     struct termios ttbuf;
9771     int ret, x, y;
9772     speed_t sospeed;
9773
9774     ret = tcgetattr(fn, &ttbuf);
9775     sospeed = ttbuf.c_ospeed;
9776     ttbuf.c_ospeed = BSPEED;
9777     ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
9778     y = (int)strlen(brnuls);
9779     x = ( BSPEED * 100 ) / msec;
9780     if (x > y) x = y;
9781     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
9782     ttbuf.c_ospeed = sospeed;
9783     ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
9784     ret = write(fn, "@", 1);
9785     return ret;
9786 }
9787 #endif /* MINIX2 */
9788 #endif /* V7 */
9789
9790 /*
9791   I N C H K  --  Check if chars waiting to be read on given file descriptor.
9792
9793   This routine is a merger of ttchk() and conchk().
9794   Call with:
9795     channel == 0 to check console.
9796     channel == 1 to check communications connection.
9797   and:
9798     fd = file descriptor.
9799   Returns:
9800    >= 0: number of characters waiting, 0 or greater,
9801      -1: on any kind of error,
9802      -2: if there is (definitely) no connection.
9803   Note: In UNIX we don't have to call nettchk() because a socket
9804   file descriptor works just like in serial i/o, ioctls and all.
9805   (But this will change if we add non-file-descriptor channels,
9806   such as IBM X.25 for AIX...)
9807 */
9808 static int
9809 in_chk(channel, fd) int channel, fd; {
9810     int x, n = 0;                       /* Workers, n = return value */
9811     extern int clsondisc;               /* Close on disconnect */
9812 /*
9813   The first section checks to make sure we have a connection,
9814   but only if we're in local mode.
9815 */
9816 #ifdef DEBUG
9817     if (deblog) {
9818         debug(F111,"in_chk entry",ckitoa(fd),channel);
9819         debug(F101,"in_chk ttyfd","",ttyfd);
9820         debug(F101,"in_chk ttpty","",ttpty);
9821     }
9822 #endif /* DEBUG */
9823 /*
9824   But don't say connection is gone if we have any buffered-stuff.
9825 */
9826 #ifdef TTLEBUF
9827     debug(F101,"in_chk ttpush","",ttpush);
9828     if (channel == 1) {
9829         if (ttpush >= 0)
9830           n++;
9831         n += le_inbuf();
9832         if (n > 0)
9833           return(n);
9834     }
9835 #endif /* TTLEBUF */
9836
9837 #ifdef NETPTY
9838 #ifdef HAVE_PTYTRAP
9839     /* Special handling for HP-UX pty i/o */
9840     if (ttpty && pty_trap_pending(ttyfd) > 0) {
9841         if (pty_trap_handler(ttyfd) > 0) {
9842             ttclos(0);
9843             return(-2);
9844         }
9845     }
9846 #endif /* HAVE_PTYTRAP */
9847 #endif /* NETPTY */
9848
9849     if (channel) {                      /* Checking communications channel */
9850         if (ttyfd < 0) {                /* No connection */
9851           return(-2);                   /* That's what this means */
9852         } else if (xlocal &&            /* In local mode */
9853                    (!netconn            /* Serial connection or */
9854 #ifdef TN_COMPORT
9855                     || istncomport()    /* Telnet Com Port */
9856 #endif /* TN_COMPORT */
9857                    ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
9858 #ifdef COMMENT
9859 #ifdef MYREAD
9860 /*
9861   Seems like this would be a good idea but it prevents C-Kermit from
9862   popping back to the prompt automatically when carrier drops.  However,
9863   commenting this out prevents us from seeing the NO CARRIER message.
9864   Needs more work...
9865 */
9866                    && my_count < 1      /* Nothing in our internal buffer */
9867 #endif /* MYREAD */
9868 #endif /* COMMENT */
9869                    ) {
9870             int x;
9871             x = ttgmdm();               /* So get modem signals */
9872             debug(F101,"in_chk close-on-disconnect","",clsondisc);
9873             if (x > -1) {               /* Check for carrier */
9874                 if (!(x & BM_DCD)) {    /* No carrier */
9875                     debug(F101,"in_chk carrier lost","",x);
9876                     if (clsondisc)      /* If "close-on-disconnect" */
9877                       ttclos(0);        /* close device & release lock. */
9878                     return(-2);         /* This means "disconnected" */
9879                 }
9880             /* In case I/O to device after CD dropped always fails */
9881             /* as in Debian Linux 2.1 and Unixware 2.1... */
9882             } else {
9883                 debug(F101,"in_chk ttgmdm I/O error","",errno);
9884                 debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
9885                 if (gotsigs) {          /* If we got signals before... */
9886                     if (errno == 5 || errno == 6) { /* I/O error etc */
9887                         if (clsondisc)  /* like when modem hangs up */
9888                           ttclos(0);
9889                         return(-2);
9890                     }
9891                 }
9892                 /* If we never got modem signals successfully on this */
9893                 /* connection before, we can't conclude that THIS failure */
9894                 /* means the connection was lost. */
9895                 return(0);
9896             }
9897         }
9898     }
9899
9900 /* We seem to have a connection so now see if any bytes are waiting on it */
9901
9902 #ifdef CK_SSL
9903     if (ssl_active_flag || tls_active_flag) {
9904         n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
9905         debug(F101,"in_chk SSL_pending","",n);
9906         if (n < 0) {
9907             ttclos(0);
9908             return(-1);
9909         } else if (n > 0) {
9910             return(n);
9911         }
9912     }
9913 #endif /* CK_SSL */
9914 #ifdef RLOGCODE
9915 #ifdef CK_KERBEROS
9916     /* It is not safe to read any data when using encrypted Klogin */
9917     if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
9918 #ifdef KRB4
9919         if (ttnproto == NP_EK4LOGIN) {
9920             n += krb4_des_avail(ttyfd);
9921             debug(F101,"in_chk krb4_des_avail","",n);
9922         }
9923 #endif /* KRB4 */
9924 #ifdef KRB5
9925         if (ttnproto == NP_EK5LOGIN) {
9926             n += krb5_des_avail(ttyfd);
9927             debug(F101,"in_chk krb5_des_avail","",n);
9928         }
9929 #ifdef KRB5_U2U
9930         if (ttnproto == NP_K5U2U) {
9931             n += krb5_u2u_avail(ttyfd);
9932             debug(F101,"in_chk krb5_des_avail","",n);
9933         }
9934 #endif /* KRB5_U2U */
9935 #endif /* KRB5 */
9936         if (n < 0)                      /* Is this right? */
9937           return(-1);
9938         else
9939           return(n);
9940     }
9941 #endif /* CK_KERBEROS */
9942 #endif /* RLOGCODE */
9943
9944     errno = 0;                          /* Reset this so we log good info */
9945 #ifdef FIONREAD
9946     x = ioctl(fd, FIONREAD, &n);        /* BSD and lots of others */
9947 #ifdef DEBUG                            /* (the more the better) */
9948     if (deblog) {
9949         debug(F101,"in_chk FIONREAD return code","",x);
9950         debug(F101,"in_chk FIONREAD count","",n);
9951         debug(F101,"in_chk FIONREAD errno","",errno);
9952     }
9953 #endif /* DEBUG */
9954 #else /* FIONREAD not defined */
9955 /*
9956   Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
9957   with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
9958   portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
9959   that I looked at, but it is needed to prevent the call from blocking), and
9960   the msghdr struct differs from place to place, so we would need another
9961   avalanche of ifdefs.  Still, when FIONREAD is not available, this is the
9962   only other known method of asking the OS for the *number* of characters
9963   available for reading.
9964 */
9965 #ifdef V7                               /* UNIX V7: look in kernel memory */
9966 #ifdef MINIX
9967     n = 0;                              /* But not in MINIX */
9968 #else
9969 #ifdef MINIX2
9970     n = 0;
9971 #else
9972     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
9973     x = read(kmem[TTY], &n, sizeof(int));
9974     if (x != sizeof(int))
9975       n = 0;
9976 #endif /* MINIX2 */
9977 #endif /* MINIX */
9978 #else /* Not V7 */
9979 #ifdef PROVX1
9980     x = ioctl(fd, TIOCQCNT, &ttbuf);    /* DEC Pro/3xx Venix V.1 */
9981     n = ttbuf.sg_ispeed & 0377;         /* Circa 1984 */
9982     if (x < 0) n = 0;
9983 #else
9984 #ifdef MYREAD
9985 /*
9986   Here we skip all the undependable and expensive calls below if we
9987   already have something in our internal buffer.  This tends to work quite
9988   nicely, so the only really bad case remaining is the one in which neither
9989   FIONREAD or MYREAD are defined, which is increasingly rare these days.
9990 */
9991     if (channel != 0 && my_count > 0) {
9992         debug(F101,"in_chk buf my_count","",my_count);
9993         n = my_count;                   /* n was 0 before we got here */
9994         return(n);
9995     }
9996 #endif /* MYREAD */
9997 /*
9998   rdchk(), select(), and poll() tell us *if* data is available to be read, but
9999   not how much, so these should be used only as a final resort.  Especially
10000   since these calls tend to add a lot overhead.
10001 */
10002 #ifdef RDCHK                            /* This mostly SCO-specific */
10003     n = rdchk(fd);
10004     debug(F101,"in_chk rdchk","",n);
10005 #else /* No RDCHK */
10006 #ifdef SELECT
10007 #ifdef Plan9
10008     /* Only allows select on the console ... don't ask */
10009     if (channel == 0)
10010 #endif /* Plan9 */
10011       {
10012         fd_set rfds;                    /* Read file descriptors */
10013 #ifdef BELLV10
10014         FD_ZERO(rfds);                  /* Initialize them */
10015         FD_SET(fd,rfds);                /* We want to look at this fd */
10016 #else
10017         FD_ZERO(&rfds);                 /* Initialize them */
10018         FD_SET(fd,&rfds);               /* We want to look at this fd */
10019         tv.tv_sec = tv.tv_usec = 0L;    /* A 0-valued timeval structure */
10020 #endif /* BELLV10 */
10021 #ifdef Plan9
10022         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10023         debug(F101,"in_chk Plan 9 select","",n);
10024 #else
10025 #ifdef BELLV10
10026         n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
10027         debug(F101,"in_chk BELLV10 select","",n);
10028 #else
10029 #ifdef BSD44
10030         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10031         debug(F101,"in_chk BSD44 select","",n);
10032 #else
10033 #ifdef BSD43
10034         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10035         debug(F101,"in_chk BSD43 select","",n);
10036 #else
10037 #ifdef SOLARIS
10038         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10039         debug(F101,"in_chk SOLARIS select","",n);
10040 #else
10041 #ifdef QNX6
10042         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10043         debug(F101,"in_chk QNX6 select","",n);
10044 #else
10045 #ifdef QNX
10046         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10047         debug(F101,"in_chk QNX select","",n);
10048 #else
10049 #ifdef COHERENT
10050         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10051         debug(F101,"in_chk COHERENT select","",n);
10052 #else
10053 #ifdef SVR4
10054         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10055         debug(F101,"in_chk SVR4 select","",n);
10056 #else
10057 #ifdef __linux__
10058         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10059         debug(F101,"in_chk LINUX select","",n);
10060 #ifdef OSF
10061         n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
10062         debug(F101,"in_chk OSF select","",n);
10063 #else
10064         n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
10065         debug(F101,"in_chk catchall select","",n);
10066 #endif /* OSF */
10067 #endif /* __linux__ */
10068 #endif /* SVR4 */
10069 #endif /* COHERENT */
10070 #endif /* QNX */
10071 #endif /* QNX6 */
10072 #endif /* SOLARIS */
10073 #endif /* BSD43 */
10074 #endif /* BSD44 */
10075 #endif /* BELLV10 */
10076 #endif /* Plan9 */
10077     }
10078 #else  /* Not SELECT */
10079 #ifdef CK_POLL
10080     {
10081       struct pollfd pfd;
10082
10083       pfd.fd = fd;
10084       pfd.events = POLLIN;
10085       pfd.revents = 0;
10086       n = poll(&pfd, 1, 0);
10087       debug(F101,"in_chk poll","",n);
10088       if ((n > 0) && (pfd.revents & POLLIN))
10089         n = 1;
10090     }
10091 #endif /* CK_POLL */
10092 #endif /* SELECT */
10093 #endif /* RDCHK */
10094 #endif /* PROVX1 */
10095 #endif /* V7 */
10096 #endif /* FIONREAD */
10097
10098 /* From here down, treat console and communication device differently... */
10099
10100     if (channel == 0) {                 /* Console */
10101
10102 #ifdef SVORPOSIX
10103 #ifndef FIONREAD
10104 #ifndef SELECT
10105 #ifndef CK_POLL
10106 #ifndef RDCHK
10107 /*
10108   This is the hideous hack used in System V and POSIX systems that don't
10109   support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
10110   CONNECT-mode escape character is attached to SIGQUIT.  Used, obviously,
10111   only on the console.
10112 */
10113         if (conesc) {                   /* Escape character typed == SIGQUIT */
10114             debug(F100,"in_chk conesc","",conesc);
10115             conesc = 0;
10116             signal(SIGQUIT,esctrp);     /* Restore signal */
10117             n += 1;
10118         }
10119 #endif /* RDCHK */
10120 #endif /* CK_POLL */
10121 #endif /* SELECT */
10122 #endif /* FIONREAD */
10123 #endif /* SVORPOSIX */
10124
10125         return(n);                      /* Done with console */
10126     }
10127
10128     if (channel != 0) {                 /* Communications connection */
10129
10130 #ifdef MYREAD
10131 #ifndef FIONREAD
10132 /*
10133   select() or rdchk(), etc, has told us that something is waiting, but we
10134   don't know how much.  So we do a read to get it and then we know.  Note:
10135   This read is NOT nonblocking if nothing is there (because of VMIN=1), but
10136   it should be safe in this case since the OS tells us at least one byte is
10137   waiting to be read, and MYREAD reads return as much as is there without
10138   waiting for any more.  Controlled tests on Solaris and Unixware (with
10139   FIONREAD deliberately undefined) show this to be true.
10140 */
10141         debug(F101,"in_chk read my_count","",my_count);
10142         debug(F101,"in_chk read n","",n);
10143         if (n > 0 && my_count == 0) {
10144             /* This also catches disconnects etc */
10145             /* Do what mygetbuf does except don't grab a character */
10146             my_count = myfillbuf();
10147             my_item = -1;               /* ^^^ */
10148             debug(F101,"in_chk myfillbuf my_count","",my_count);
10149             if (my_count < 0)
10150               return(-1);
10151             else
10152               n = 0;                    /* NB: n is replaced by my_count */
10153         }
10154 #endif /* FIONREAD */
10155 /*
10156   Here we add whatever we think is unread to what is still in our
10157   our internal buffer.  Thus the importance of setting n to 0 just above.
10158 */
10159         debug(F101,"in_chk my_count","",my_count);
10160         debug(F101,"in_chk n","",n);
10161         if (my_count > 0)
10162           n += my_count;
10163 #endif /* MYREAD */
10164     }
10165     debug(F101,"in_chk result","",n);
10166
10167     /* Errors here don't prove the connection has dropped so just say 0 */
10168
10169     return(n < 0 ? 0 : n);
10170 }
10171
10172
10173 /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
10174
10175 int
10176 ttchk() {
10177     int fd;
10178 #ifdef NETCMD
10179     if (ttpipe)
10180       fd = fdin;
10181     else
10182 #endif /* NETCMD */
10183       fd = ttyfd;
10184     return(in_chk(1,fd));
10185 }
10186
10187 /*  T T X I N  --  Get n characters from tty input buffer  */
10188
10189 /*  Returns number of characters actually gotten, or -1 on failure  */
10190
10191 /*  Intended for use only when it is known that n characters are actually */
10192 /*  Available in the input buffer.  */
10193
10194 int
10195 ttxin(n,buf) int n; CHAR *buf; {
10196     register int x = 0, c = -2;
10197 #ifdef TTLEBUF
10198     register int i = 0;
10199 #endif /* TTLEBUF */
10200     int fd;
10201
10202     if (n < 1)                          /* Nothing to do */
10203       return(0);
10204
10205 #ifdef TTLEBUF
10206     if (ttpush >= 0) {
10207         buf[0] = ttpush;                /* Put pushed char in buffer*/
10208         ttpush = -1;                    /* Clear the push buffer */
10209         if (ttchk() > 0)
10210           return(ttxin(n-1, &buf[1]) + 1);
10211         else
10212           return(1);
10213     }
10214     if (le_data) {
10215         while (le_inbuf() > 0) {
10216             if (le_getchar(&buf[i])) {
10217                 i++;
10218                 n--;
10219             }
10220         }
10221         if (ttchk() > 0)
10222           return(ttxin(n,&buf[i])+i);
10223         else
10224           return(i);
10225     }
10226 #endif /* TTLEBUF */
10227
10228 #ifdef NETCMD
10229     if (ttpipe)
10230       fd = fdin;
10231     else
10232 #endif /* NETCMD */
10233       fd = ttyfd;
10234
10235 #ifdef SUNX25
10236     if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
10237       return(x25xin(n,buf));
10238 #endif /* SUNX25 */
10239
10240 #ifdef IBMX25
10241     /* riehm: possibly not needed. Test worked with normal reads and writes */
10242     if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
10243         x = x25xin(n,buf);
10244         if (x > 0) buf[x] = '\0';
10245         return(x);
10246     }
10247 #endif /* IBMX25 */
10248
10249 #ifdef MYREAD
10250     debug(F101,"ttxin MYREAD","",n);
10251     while (x < n) {
10252         c = myread();
10253         if (c < 0) {
10254             debug(F101,"ttxin myread returns","",c);
10255             if (c == -3) x = -1;
10256             break;
10257         }
10258         buf[x++] = c & ttpmsk;
10259 #ifdef RLOGCODE
10260 #ifdef CK_KERBEROS
10261         /* It is impossible to know how many characters are waiting */
10262         /* to be read when you are using Encrypted Rlogin or SSL    */
10263         /* as the transport since the number of real data bytes     */
10264         /* can be greater or less than the number of bytes on the   */
10265         /* wire which is what ttchk() returns.                      */
10266         if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
10267           if (ttchk() <= 0)
10268             break;
10269 #endif /* CK_KERBEROS */
10270 #endif /* RLOGCODE */
10271 #ifdef CK_SSL
10272         if (ssl_active_flag || tls_active_flag)
10273           if (ttchk() <= 0)
10274             break;
10275 #endif /* CK_SSL */
10276     }
10277 #else
10278     debug(F101,"ttxin READ","",n);
10279     x = read(fd,buf,n);
10280     for (c = 0; c < n; c++)             /* Strip any parity */
10281       buf[c] &= ttpmsk;
10282 #endif /* MYREAD */
10283
10284     debug(F101,"ttxin x","",x);         /* Done */
10285     if (x > 0) buf[x] = '\0';
10286     if (x < 0) x = -1;
10287     return(x);
10288 }
10289
10290 /*  T T O L  --  Write string s, length n, to communication device.  */
10291 /*
10292   Returns:
10293    >= 0 on success, number of characters actually written.
10294    -1 on failure.
10295 */
10296 #ifdef CK_ENCRYPTION
10297 CHAR * xpacket = NULL;
10298 int nxpacket = 0;
10299 #endif /* CK_ENCRYPTION */
10300
10301 #define TTOLMAXT 5
10302 int
10303 ttol(s,n) int n; CHAR *s; {
10304     int x, len, tries, fd;
10305 #ifdef CKXXCHAR
10306     extern int dblflag;                 /* For SET SEND DOUBLE-CHARACTER */
10307     extern short dblt[];
10308     CHAR *p = NULL, *p2, *s2, c;
10309     int n2 = 0;
10310 #endif /* CKXXCHAR */
10311
10312     if (ttyfd < 0)                      /* Not open? */
10313       return(-3);
10314 #ifdef DEBUG
10315     if (deblog) {
10316         /* debug(F101,"ttol ttyfd","",ttyfd); */
10317         ckhexdump("ttol s",s,n);
10318     }
10319 #endif /* DEBUG */
10320
10321 #ifdef NETCMD
10322     if (ttpipe)
10323       fd = fdout;
10324     else
10325 #endif /* NETCMD */
10326       fd = ttyfd;
10327
10328 #ifdef CKXXCHAR
10329 /*  Double any characters that must be doubled.  */
10330     debug(F101,"ttol dblflag","",dblflag);
10331     if (dblflag) {
10332         p = (CHAR *) malloc(n + n + 1);
10333         if (p) {
10334             s2 = s;
10335             p2 = p;
10336             n2 = 0;
10337             while (*s2) {
10338                 c = *s2++;
10339                 *p2++ = c;
10340                 n2++;
10341                 if (dblt[(unsigned) c] & 2) {
10342                     *p2++ = c;
10343                     n2++;
10344                 }
10345             }
10346             s = p;
10347             n = n2;
10348             s[n] = '\0';
10349         }
10350 #ifdef DEBUG
10351         ckhexdump("ttol doubled s",s,n);
10352 #endif /* DEBUG */
10353     }
10354 #endif /* CKXXCHAR */
10355
10356     tries = TTOLMAXT;                   /* Allow up to this many tries */
10357     len = n;                            /* Remember original length */
10358
10359 #ifdef CK_ENCRYPTION
10360 /*
10361   This is to avoid encrypting a packet that is already encrypted, e.g.
10362   when we resend a packet directly out of the packet buffer, and also to
10363   avoid encrypting a constant (literal) string, which can cause a memory
10364   fault.
10365 */
10366     if (TELOPT_ME(TELOPT_ENCRYPTION)) {
10367         int x;
10368         if (nxpacket < n) {
10369             if (xpacket) {
10370                 free(xpacket);
10371                 xpacket = NULL;
10372                 nxpacket = 0;
10373             }
10374             x = n > 10240 ? n : 10240;
10375             xpacket = (CHAR *)malloc(x);
10376             if (!xpacket) {
10377                 fprintf(stderr,"ttol malloc failure\n");
10378                 return(-1);
10379             } else
10380               nxpacket = x;
10381         }
10382         memcpy((char *)xpacket,(char *)s,n);
10383         s = xpacket;
10384         ck_tn_encrypt((char *)s,n);
10385     }
10386 #endif /* CK_ENCRYPTION */
10387
10388     while (n > 0 &&
10389            (tries-- > 0
10390 #ifdef CK_ENCRYPTION
10391             /* keep trying if we are encrypting */
10392             || TELOPT_ME(TELOPT_ENCRYPTION)
10393 #endif /* CK_ENCRYPTION */
10394             )) {                        /* Be persistent */
10395         debug(F101,"ttol try","",TTOLMAXT - tries);
10396 #ifdef BEOSORBEBOX
10397         if (netconn && !ttpipe && !ttpty)
10398           x = nettol((char *)s,n);      /* Write string to device */
10399         else
10400 #endif /* BEOSORBEBOX */
10401 #ifdef IBMX25
10402           if (ttnet == NET_IX25)
10403             /*
10404              * this is a more controlled way of writing to X25
10405              * STREAMS, however write should also work!
10406              */
10407             x = x25write(ttyfd, s, n);
10408           else
10409 #endif /* IBMX25 */
10410 #ifdef CK_SSL
10411             if (ssl_active_flag || tls_active_flag) {
10412                 int error;
10413                 /* Write using SSL */
10414                 ssl_retry:
10415                 if (ssl_active_flag)
10416                   x = SSL_write(ssl_con, s, n);
10417                 else
10418                   x = SSL_write(tls_con, s, n);
10419                 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
10420                 case SSL_ERROR_NONE:
10421                     if (x == n)
10422                       return(len);
10423                     s += x;
10424                     n -= x;
10425                     goto ssl_retry;
10426                   case SSL_ERROR_WANT_WRITE:
10427                   case SSL_ERROR_WANT_READ:
10428                     x = 0;
10429                     break;
10430                   case SSL_ERROR_SYSCALL:
10431                     if (x != 0)
10432                       return(-1);
10433                   case SSL_ERROR_WANT_X509_LOOKUP:
10434                   case SSL_ERROR_SSL:
10435                   case SSL_ERROR_ZERO_RETURN:
10436                   default:
10437                     ttclos(0);
10438                     return(-3);
10439                 }
10440             } else
10441 #endif /* CK_SSL */
10442 #ifdef CK_KERBEROS
10443 #ifdef KRB4
10444 #ifdef RLOGCODE
10445             if (ttnproto == NP_EK4LOGIN) {
10446                 return(krb4_des_write(ttyfd,s,n));
10447             } else
10448 #endif /* RLOGCODE */
10449 #endif /* KRB4 */
10450 #ifdef KRB5
10451 #ifdef RLOGCODE
10452             if (ttnproto == NP_EK5LOGIN) {
10453                 return(krb5_des_write(ttyfd,(char *)s,n,0));
10454             } else
10455 #endif /* RLOGCODE */
10456 #ifdef KRB5_U2U
10457             if (ttnproto == NP_K5U2U) {
10458                 return(krb5_u2u_write(ttyfd,(char *)s,n));
10459             } else
10460 #endif /* KRB5_U2U */
10461 #endif /* KRB5 */
10462 #endif /* CK_KERBEROS */
10463               x = write(fd,s,n);        /* Write string to device */
10464
10465         if (x == n) {                   /* Worked? */
10466             debug(F101,"ttol ok","",x); /* OK */
10467 #ifdef CKXXCHAR
10468             if (p) free(p);
10469 #endif /* CKXXCHAR */
10470             return(len);                /* Done */
10471         } else if (x < 0) {             /* No, got error? */
10472             debug(F101,"ttol write error","",errno);
10473 #ifdef EWOULDBLOCK
10474             if (errno == EWOULDBLOCK) {
10475                 msleep(10);
10476                 continue;
10477             } else
10478 #endif /* EWOULDBLOCK */
10479 #ifdef TCPSOCKET
10480             if (netconn && ttnet == NET_TCPB) {
10481                 debug(F101,"ttol TCP error","",errno);
10482                 ttclos(0);              /* Close the connection. */
10483                 x = -3;
10484             }
10485 #endif /* TCPSOCKET */
10486 #ifdef CKXXCHAR
10487             if (p) free(p);
10488 #endif /* CKXXCHAR */
10489             return(x);
10490         } else {                        /* No error, so partial success */
10491             debug(F101,"ttol partial","",x); /* This never happens */
10492             s += x;                     /* Point to part not written yet */
10493             n -= x;                     /* Adjust length */
10494             if (x > 0) msleep(10);      /* Wait 10 msec */
10495         }                               /* Go back and try again */
10496     }
10497 #ifdef CKXXCHAR
10498     if (p) free(p);
10499 #endif /* CKXXCHAR */
10500     return(n < 1 ? len : -1);           /* Return the results */
10501 }
10502
10503 /*  T T O C  --  Output a character to the communication line  */
10504
10505 /*
10506  This function should only be used for interactive, character-mode operations,
10507  like terminal connection, script execution, dialer i/o, where the overhead
10508  of the signals and alarms does not create a bottleneck.
10509 */
10510 int
10511 #ifdef CK_ANSIC
10512 ttoc(char c)
10513 #else
10514 ttoc(c) char c;
10515 #endif /* CK_ANSIC */
10516 /* ttoc */ {
10517 #define TTOC_TMO 15                     /* Timeout in case we get stuck */
10518     int xx, fd;
10519
10520     if (ttyfd < 0)                      /* Check for not open. */
10521       return(-1);
10522
10523 #ifdef NETCMD
10524     if (ttpipe)
10525       fd = fdout;
10526     else
10527 #endif /* NETCMD */
10528       fd = ttyfd;
10529
10530     c &= 0xff;
10531     /* debug(F101,"ttoc","",(CHAR) c); */
10532     saval = signal(SIGALRM,timerh);     /* Enable timer interrupt */
10533     xx = alarm(TTOC_TMO);               /* for this many seconds. */
10534     if (xx < 0) xx = 0;                 /* Save old alarm value. */
10535     /* debug(F101,"ttoc alarm","",xx); */
10536     if (
10537 #ifdef CK_POSIX_SIG
10538         sigsetjmp(sjbuf,1)
10539 #else
10540         setjmp(sjbuf)
10541 #endif /* CK_POSIX_SIG */
10542         ) {             /* Timer went off? */
10543         ttimoff();                      /* Yes, cancel this alarm. */
10544         if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
10545         /* debug(F100,"ttoc timeout","",0); */
10546 #ifdef NETCONN
10547         if (!netconn) {
10548 #endif /* NETCONN */
10549             debug(F101,"ttoc timeout","",c);
10550             if (ttflow == FLO_XONX) {
10551                 debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
10552 #ifndef Plan9
10553 #ifdef POSIX
10554                 /* POSIX way to unstick. */
10555                 debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
10556 #else
10557 #ifdef BSD4                             /* Berkeley way to do it. */
10558 #ifdef TIOCSTART
10559 /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);".  Who knows? */
10560                 {
10561                   int x = 0;
10562                   debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
10563                 }
10564 #endif /* TIOCSTART */
10565 #endif /* BSD4 */
10566                                         /* Is there a Sys V way to do this? */
10567 #endif /* POSIX */
10568 #endif /* Plan9 */
10569             }
10570 #ifdef NETCONN
10571         }
10572 #endif /* NETCONN */
10573         return(-1);                     /* Return failure code. */
10574     } else {
10575         int rc;
10576 #ifdef BEOSORBEBOX
10577 #ifdef NETCONN
10578         if (netconn && !ttpipe && !ttpty)
10579           rc = nettoc(c);
10580         else
10581 #endif /*  BEOSORBEBOX */
10582 #endif /* NETCONN */
10583 #ifdef CK_ENCRYPTION
10584           if (TELOPT_ME(TELOPT_ENCRYPTION))
10585             ck_tn_encrypt(&c,1);
10586 #endif /* CK_ENCRYPTION */
10587 #ifdef IBMX25
10588         /* riehm: maybe this isn't necessary after all. Test program
10589          * worked fine with data being sent and retrieved with normal
10590          * read's and writes!
10591          */
10592         if (ttnet == NET_IX25)
10593           rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
10594         else
10595 #endif /* IBMX25 */
10596 #ifdef CK_SSL
10597           if (ssl_active_flag || tls_active_flag) {
10598               int error;
10599               /* Write using SSL */
10600               if (ssl_active_flag)
10601                 rc = SSL_write(ssl_con, &c, 1);
10602               else
10603                 rc = SSL_write(tls_con, &c, 1);
10604               switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
10605                 case SSL_ERROR_NONE:
10606                   break;
10607                 case SSL_ERROR_WANT_WRITE:
10608                 case SSL_ERROR_WANT_READ:
10609                   rc = 0;
10610                   break;
10611                 case SSL_ERROR_SYSCALL:
10612                   if (rc != 0)
10613                     return(-1);
10614                 case SSL_ERROR_WANT_X509_LOOKUP:
10615                 case SSL_ERROR_SSL:
10616                 case SSL_ERROR_ZERO_RETURN:
10617                 default:
10618                   ttclos(0);
10619                   return(-1);
10620               }
10621           } else
10622 #endif /* CK_SSL */
10623 #ifdef CK_KERBEROS
10624 #ifdef KRB4
10625 #ifdef RLOGCODE
10626           if (ttnproto == NP_EK4LOGIN) {
10627               rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1);
10628           } else
10629 #endif /* RLOGCODE */
10630 #endif /* KRB4 */
10631 #ifdef KRB5
10632 #ifdef RLOGCODE
10633           if (ttnproto == NP_EK5LOGIN) {
10634               rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
10635           } else
10636 #endif /* RLOGCODE */
10637 #ifdef KRB5_U2U
10638           if (ttnproto == NP_K5U2U) {
10639               rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
10640           } else
10641 #endif /* KRB5_U2U */
10642 #endif /* KRB5 */
10643 #endif /* CK_KERBEROS */
10644             rc = write(fd,&c,1);        /* Try to write the character. */
10645         if (rc < 1) {                   /* Failed */
10646             ttimoff();                  /* Turn off the alarm. */
10647             alarm(xx);                  /* Restore previous alarm. */
10648             debug(F101,"ttoc errno","",errno); /* Log the error, */
10649             return(-1);                 /* and return the error code. */
10650         }
10651     }
10652     ttimoff();                          /* Success, turn off the alarm. */
10653     alarm(xx);                          /* Restore previous alarm. */
10654     return(0);                          /* Return good code. */
10655 }
10656
10657 /*  T T I N L  --  Read a record (up to break character) from comm line.  */
10658 /*
10659   Reads up to "max" characters from the connection, terminating on:
10660     (a) the packet length field if the "turn" argument is zero, or
10661     (b) on the packet-end character (eol) if the "turn" argument is nonzero
10662     (c) a certain number of Ctrl-C's in a row
10663
10664   Returns:
10665     >= 0, the number of characters read upon success;
10666     -1 if "max" exceeded, timeout, or other correctable error;
10667     -2 on user interruption (c);
10668     -3 on fatal error like connection lost.
10669
10670   The name of this routine dates from the early days when Kermit packets
10671   were, indeed, always lines of text.  That was before control-character
10672   unprefixing and length-driven packet framing were introduced, which this
10673   version handle.  NB: this routine is ONLY for reading incoming Kermit
10674   packets, nothing else.  To read other kinds of incoming material, use
10675   ttinc() or ttxin().
10676
10677   The bytes that were input are copied into "dest" with their parity bits
10678   stripped if parity was selected.  Returns the number of bytes read.
10679   Bytes after the eol are available upon the next call to this function.
10680
10681   The idea is to minimize the number of system calls per packet, and also to
10682   minimize timeouts.  This function is the inner loop of the protocol and must
10683   be as efficient as possible.  The current strategy is to use myread(), a
10684   macro to manage buffered (and generally nonblocking) reads.
10685
10686   WARNING: This function calls parchk(), which is defined in another module.
10687   Normally, ckutio.c does not depend on code from any other module, but there
10688   is an exception in this case because all the other ck?tio.c modules also
10689   need to call parchk(), so it's better to have it defined in a common place.
10690 */
10691 #ifdef CTRLC
10692 #undef CTRLC
10693 #endif /* CTRLC */
10694 #define CTRLC '\03'
10695 /*
10696   We have four different declarations here because:
10697   (a) to allow Kermit to be built without the automatic parity sensing feature
10698   (b) one of each type for ANSI C, one for non-ANSI.
10699 */
10700 #ifndef NOXFER
10701
10702 static int pushedback = 0;
10703
10704 int
10705 #ifdef PARSENSE
10706 #ifdef CK_ANSIC
10707 ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
10708 #else
10709 ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
10710 #endif /* CK_ANSIC */
10711 #else /* not PARSENSE */
10712 #ifdef CK_ANSIC
10713 ttinl(CHAR *dest, int max,int timo, CHAR eol)
10714 #else
10715 ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
10716 #endif /* CK_ANSIC */
10717 #endif /* PARSENSE */
10718 /* ttinl */ {
10719
10720 #ifndef MYREAD
10721     CHAR ch, dum;
10722 #endif /* MYREAD */
10723 #ifdef PARSENSE
10724     int pktlen = -1;
10725     int lplen = 0;
10726     int havelen = 0;
10727 #endif /* PARSENSE */
10728     int fd;
10729     int sopmask = 0xff;                 /* Start-Of-Packet mask */
10730 #ifdef CKXXCHAR
10731     extern short dblt[];                /* Ignore-character table */
10732     extern int ignflag;
10733 #endif /* CKXXCHAR */
10734 #ifdef TCPSOCKET
10735     extern CHAR stchr;
10736 #endif /* TCPSOCKET */
10737     int x;
10738 #ifdef STREAMING
10739     extern int streaming;
10740     extern int sndtyp;
10741 #endif /* STREAMING */
10742
10743     if (ttyfd < 0) return(-3);          /* Not open. */
10744 /*
10745   In February 2007 I fixed ttinl() to work better under the truly awful
10746   conditions encountered by the AM-APEX oceanographic floats that gather
10747   hurricane data and phone home using Iridium satellite modems, which under
10748   certain conditions, can send two packets back to back after a long pause.
10749   In this case the second packet would be ignored because the SOH was skipped
10750   due to the ttflui() call.  But the reworked lookahead/pushback logic broke
10751   Kermit transfers on encrypted connections.  This was fixed 12-13 August
10752   2007.  All of this happened after 8.0.212 Dev.27 was released and before
10753   Dev.28, so no harm done other than the delay.
10754 */
10755     debug(F101,"ttinl max","",max);
10756     debug(F101,"ttinl timo","",timo);
10757
10758 #ifdef NETCMD
10759     if (ttpipe)
10760       fd = fdin;
10761     else
10762 #endif /* NETCMD */
10763       fd = ttyfd;
10764
10765 #ifdef COMMENT
10766     if (xlocal && conchk() > 0)         /* Allow for console interruptions */
10767       return(-1);
10768 #endif /* COMMENT */
10769
10770     *dest = '\0';                       /* Clear destination buffer */
10771     if (timo < 0) timo = 0;             /* Safety */
10772     if (timo) {                         /* Don't time out if timo == 0 */
10773         int xx;
10774         saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
10775         xx = alarm(timo);               /* Set it. */
10776         debug(F101,"ttinl alarm","",xx);
10777     }
10778     if (
10779 #ifdef CK_POSIX_SIG
10780         sigsetjmp(sjbuf,1)
10781 #else
10782         setjmp(sjbuf)
10783 #endif /* CK_POSIX_SIG */
10784         ) {                             /* Timer went off? */
10785         debug(F100,"ttinl timout","",0); /* Get here on timeout. */
10786         /* debug(F110," with",(char *) dest,0); */
10787         ttimoff();                      /* Turn off timer */
10788         return(-1);                     /* and return error code. */
10789     } else {
10790         register int i, n = -1;         /* local variables */
10791         int ccn = 0;
10792 #ifdef PARSENSE
10793         register int flag = 0;
10794         debug(F000,"ttinl start","",start);
10795 #endif /* PARSENSE */
10796
10797         ttpmsk = ttprty ? 0177 : 0377;  /* Set parity stripping mask. */
10798         sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
10799
10800 /* Now read into destination, stripping parity and looking for the */
10801 /* the packet terminator, and also for several Ctrl-C's typed in a row. */
10802
10803         i = 0;                          /* Destination index */
10804         debug(F101,"ttinl eol","",eol);
10805
10806         while (i < max-1) {
10807 #ifdef MYREAD
10808             errno = 0;
10809             /* On encrypted connections myread returns encrypted bytes */
10810             n = myread();
10811             debug(F000,"TTINL myread char","",n);
10812             if (n < 0) {        /* Timeout or i/o error? */
10813 #ifdef DEBUG
10814                 if (deblog) {
10815                     debug(F101,"ttinl myread failure, n","",n);
10816                     debug(F101,"ttinl myread errno","",errno);
10817                 }
10818 #endif /* DEBUG */
10819                 /* Don't let EINTR break packets. */
10820                 if (n == -3) {
10821                     if (errno == EINTR && i > 0) {
10822                         debug(F111,"ttinl EINTR myread i","continuing",i);
10823                         continue;
10824                     } else {
10825                         debug(F110,"ttinl non-EINTR -3","closing",0);
10826                         wasclosed = 1;
10827                         ttimoff();      /* Turn off timer */
10828                         ttclos(0);
10829                         return(n);
10830                     }
10831                 } else if (n == -2 && netconn /* && timo == 0 */ ) {
10832                     /* Here we try to catch broken network connections */
10833                     /* even when ioctl() and read() do not catch them */
10834                     debug(F111,"ttinl network myread failure","closing",n);
10835                     wasclosed = 1;
10836                     ttimoff();
10837                     ttclos(0);
10838                     return(-3);
10839                 }
10840 #ifdef STREAMING
10841                 /* Streaming and no data to read */
10842                 else if (n == 0 && streaming && sndtyp == 'D')
10843                   return(0);
10844 #endif /* STREAMING */
10845                 break;                  /* Break out of while loop */
10846             }
10847
10848 #else /* not MYREAD (is this code used anywhere any more?) */
10849 /*
10850   The non-MYREAD code dates from the 1980s and was needed on certain platforms
10851   where there were no nonblocking reads.  -fdc, 2007/02/22.
10852 */
10853             if ((n = read(fd, &n, 1)) < 1)
10854               break;                    /* Error - break out of while loop */
10855
10856 #endif /* MYREAD */
10857
10858             /* Get here with char in n */
10859
10860 #ifdef CK_ENCRYPTION
10861             if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) {
10862                 CHAR ch = n;
10863                 ck_tn_decrypt((char *)&ch,1);
10864                 n = ch;
10865                 debug(F000,"TTINL decryp char","",n);
10866             }
10867             pushedback = 0;
10868 #endif /* CK_ENCRYPTION */
10869
10870 #ifdef TCPSOCKET
10871             if (n == IAC &&             /* Handle Telnet options */
10872                 ((xlocal && netconn && IS_TELNET()) ||
10873                 (!xlocal && sstelnet))) {
10874                 n = tt_tnopt(n);
10875                 if (n < 0)
10876                   return(n);
10877 #ifndef NOPARSEN
10878                 else if (n == 1)
10879                   start = stchr;
10880 #endif /* NOPARSEN */
10881                 if (n != 255)           /* No data - go back for next char */
10882                   continue;
10883             }                           /* Quoted IAC - keep going */
10884 #endif /* TCPSOCKET */
10885
10886 #ifdef CKXXCHAR
10887             if (ignflag)
10888               if (dblt[(unsigned) n] & 1) /* Character to ignore? */
10889                 continue;
10890 #endif /* CKXXCHAR */
10891 /*
10892   Use parity mask, rather than always stripping parity, to check for
10893   cancellation.  Otherwise, runs like \x03\x83\x03 in a packet could cancel
10894   the transfer when parity is NONE.  (Note that \x03\x03\x03 is extremely
10895   unlikely due to run-length encoding.)
10896 */
10897             /* Check cancellation */
10898             if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
10899                 if (++ccn >= xfrnum) {  /* If xfrnum in a row, bail out. */
10900                     if (timo) {         /* Clear timer. */
10901                         ttimoff();
10902                     }
10903                     if (xfrchr < 32)
10904                       printf("^%c...\r\n",(char)(xfrchr+64));
10905                     else
10906                       printf("Canceled...\r\n");
10907                     return(-2);
10908                 }
10909             } else ccn = 0;             /* No cancellation, reset counter, */
10910
10911 #ifdef PARSENSE
10912 /*
10913   Restructured code allows for a new packet to appear somewhere in the
10914   middle of a previous one.  -fdc, 24 Feb 2007.
10915 */
10916             if ((n & sopmask) == start) { /* Start of Packet */
10917                 debug(F101,"ttinl SOP i","",i);
10918                 flag = 1;               /* Flag that we are in a packet */
10919                 havelen = 0;            /* Invalidate previous length */
10920                 pktlen = -1;            /* (if any) in case we were */
10921                 lplen = 0;              /* alread processand a packet */
10922                 i = 0;                  /* and reset the dest buffer pointer */
10923             }
10924             if (flag == 0) {            /* No SOP yet... */
10925                 debug(F000,"ttinl skipping","",n);
10926                 continue;
10927             }
10928             dest[i++] = n & ttpmsk;
10929 /*
10930   If we have not been instructed to wait for a turnaround character, we can go
10931   by the packet length field.  If turn != 0, we must wait for the end of line
10932   (eol) character before returning.  This is an egregious violation of all
10933   principles of layering...  (Less egregious in C-Kermit 9.0, in which we go
10934   by the length field but also look for the eol in case it arrives early,
10935   e.g. if the length field was corrupted upwards.)
10936 */
10937             if (!havelen) {
10938                 if (i == 2) {
10939                     if ((dest[1] & 0x7f) < 32) /* Garbage in length field */
10940                       return(-1);       /* fdc - 13 Apr 2010 */
10941                     pktlen = xunchar(dest[1] & 0x7f);
10942                     if (pktlen > 94)    /* Rubout in length field */
10943                       return(-1);       /* fdc - 13 Apr 2010 */
10944                     if (pktlen > 1) {
10945                         havelen = 1;
10946                         debug(F101,"ttinl pktlen value","",pktlen);
10947                     }
10948                 } else if (i == 5 && pktlen == 0) {
10949                     lplen = xunchar(dest[4] & 0x7f);
10950                 } else if (i == 6 && pktlen == 0) {
10951                     pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
10952                     havelen = 1;
10953                     debug(F101,"ttinl extended length","",pktlen);
10954                 }
10955             }
10956
10957 /*
10958   Suppose we looked at the sequence number here and found it was out of
10959   range?  This would mean either (a) incoming packets had SOP unprefixed
10960   and we are out of sync, or (b) the packet is damaged.  Since (a) is bad
10961   practice, let's ignore it.  So what should we do here if we know the
10962   packet is damaged?
10963
10964    1. Nothing -- keep trying to read the packet till we find what we think
10965       is the end, or we time out, and let the upper layer decide what to
10966       do.  But since either the packet is corrupt or we are out of sync,
10967       our criterion for finding the end does not apply and we are likely
10968       to time out (or swallow a piece of the next packet) if our assumed
10969       length is too long.  (This was the behavior prior to version 7.0.)
10970
10971    2. set flag = 0 and continue?  This would force us to wait for the
10972       next packet to come in, and therefore (in the nonwindowing case),
10973       would force a timeout in the other Kermit.
10974
10975    3. set flag = 0 and continue, but only if the window size is > 1 and
10976       the window is not blocked?  Talk about cheating!
10977
10978    4. Return a failure code and let the upper layer decide what to do.
10979       This should be equivalent to 3, but without the cheating.  So let's
10980       do it that way...  But note that we must ignore the parity bit
10981       in case this is the first packet and we have not yet run parchk().
10982 */
10983             if (i == 3) {               /* Peek at sequence number */
10984                 x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
10985                 if (x < 0 || x > 63) {
10986                     debug(F111,"ttinl bad seq",dest,x);
10987                     if (timo) ttimoff();
10988                     return(-1);         /* return a nonfatal error */
10989                 }
10990             }
10991
10992 #else /* PARSENSE */
10993             dest[i++] = n & ttpmsk;
10994 #endif /* PARSENSE */
10995
10996     /* Check for end of packet */
10997
10998             if (
10999                 ((n & ttpmsk) == eol)   /* Always break on the eol char */
11000 #ifdef PARSENSE
11001                  ||                     /* fdc - see notes of 13 Apr 2010 */
11002 /*
11003   Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
11004   This allows packet terminators and handshake characters to appear
11005   literally inside a packet data field.
11006 */
11007                 (havelen && (i > pktlen+1) &&
11008                  (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
11009
11010 #endif /* PARSENSE */
11011                 ) {
11012 /*
11013   Here we have either read the last byte of the packet based on its length
11014   field, or else we have read the packet terminator (eol) or the half-duplex
11015   line-turnaround char (turn).
11016 */
11017 #ifndef PARSENSE
11018                 debug(F101,"ttinl got eol","",eol); /* (or turn) */
11019                 dest[i] = '\0';         /* Yes, terminate the string, */
11020                 /* debug(F101,"ttinl i","",i); */
11021
11022 #else  /* PARSENSE */
11023
11024 #ifdef DEBUG
11025                 if (deblog) {
11026                     if ((n & ttpmsk) != eol) {
11027                         debug(F101,"ttinl EOP length","",pktlen);
11028                         debug(F000,"ttinl EOP current char","",n);
11029                         debug(F101,"ttinl EOP packet buf index","",i);
11030                     } else debug(F101,"ttinl got eol","",eol);
11031                 }
11032 #endif /* DEBUG */
11033
11034 #ifdef MYREAD
11035 /*
11036   The packet was read based on its length.  This leaves the packet terminator
11037   unread, and so ttchk() will always return at least 1 because of this,
11038   possibly giving a false positive to the "is there another packet waiting?"
11039   test.  But if we know the terminator (or any other interpacket junk) is
11040   there, we can safely get rid of it.
11041
11042   NOTE: This code reworked to (a) execute even if the debug log isn't active;
11043   and (b) actually work.  -fdc, 2007/02/22.  And again 2007/08/12-13 to also
11044   work on encrypted connections.
11045 */      
11046                 debug(F101,"TTINL my_count","",my_count);
11047                 if ((n & ttpmsk) != eol) { /* Not the packet terminator */
11048                     int x;
11049                     while (my_count > 0) {
11050                         x = myread();      /* (was ttinc(0) */
11051                         debug(F000,"TTINL lkread char","",x);
11052 #ifdef CK_ENCRYPTION
11053                         if (TELOPT_U(TELOPT_ENCRYPTION)) {
11054                             CHAR ch = x;
11055                             ck_tn_decrypt((char *)&ch,1);
11056                             x = ch;
11057                             debug(F000,"TTINL lkdecr char","",x); 
11058                         }
11059 #endif  /* CK_ENCRYPTION */
11060                         /*
11061                           Note: while it might seem more elegant to simply
11062                           push back the encrypted byte, that desynchronizes
11063                           the decryption stream; the flag is necessary so we
11064                           don't try to decrypt the same byte twice.
11065                         */
11066                         if ((x & ttpmsk) == start) { /* Start of next packet */
11067                             myunrd(x);  /* Push back the decrypted byte */
11068                             pushedback = 1; /* And set flag */
11069                             debug(F000,"TTINL lkpush char","",x);
11070                             break;
11071                         }
11072                     }
11073                 }
11074 #endif /* MYREAD */
11075
11076                 dest[i] = '\0';         /* Terminate the string, */
11077                 if (needpchk) {         /* Parity checked yet? */
11078                     if (ttprty == 0) {  /* No, check. */
11079                         if ((ttprty = parchk(dest,start,i)) > 0) {
11080                             int j;
11081                             debug(F101,"ttinl senses parity","",ttprty);
11082                             debug(F110,"ttinl packet before",dest,0);
11083                             ttpmsk = 0x7f;
11084                             for (j = 0; j < i; j++)
11085                               dest[j] &= 0x7f;  /* Strip parity from packet */
11086                             debug(F110,"ttinl packet after ",dest,0);
11087                         } else ttprty = 0; /* Restore if parchk error */
11088                     }
11089                     sopmask = ttpmsk;
11090                     needpchk = 0;
11091                 }
11092 #endif /* PARSENSE */
11093
11094                 if (timo)               /* Turn off timer if it was on */
11095                   ttimoff();
11096                 ckhexdump("ttinl got",dest,i);
11097
11098 #ifdef STREAMING
11099                 /* ttinl() was called because there was non-packet */
11100                 /* data sitting in the back channel.  Ignore it.   */
11101                 if (streaming && sndtyp == 'D')
11102                   return(-1);
11103 #endif /* STREAMING */
11104                 return(i);
11105             }
11106         } /* End of while() */
11107         ttimoff();
11108         return(n);
11109     }
11110 }
11111 #endif /* NOXFER */
11112
11113 /*  T T I N C --  Read a character from the communication line  */
11114 /*
11115  On success, returns the character that was read, >= 0.
11116  On failure, returns -1 or other negative myread error code,
11117    or -2 if connection is broken or ttyfd < 0.
11118    or -3 if session limit has expired,
11119    or -4 if something or other...
11120  NOTE: The API does not provide for ttinc() returning a special code
11121  upon timeout, but we need it.  So for this we have a global variable,
11122  ttinctimo.
11123 */
11124 static int ttinctimo = 0;               /* Yuk */
11125
11126 int
11127 ttinc(timo) int timo; {
11128
11129     int n = 0, fd;
11130     int is_tn = 0;
11131     CHAR ch = 0;
11132
11133     ttinctimo = 0;
11134
11135     if (ttyfd < 0) return(-2);          /* Not open. */
11136
11137     is_tn = (xlocal && netconn && IS_TELNET()) ||
11138             (!xlocal && sstelnet);
11139
11140 #ifdef TTLEBUF
11141     if (ttpush >= 0) {
11142         debug(F111,"ttinc","ttpush",ttpush);
11143         ch = ttpush;
11144         ttpush = -1;
11145         return(ch);
11146     }
11147     if (le_data) {
11148         if (le_getchar(&ch) > 0) {
11149             debug(F111,"ttinc le_getchar","ch",ch);
11150             return(ch);
11151         }
11152     }
11153 #endif /* TTLEBUF */
11154
11155 #ifdef NETCMD
11156     if (ttpipe)
11157       fd = fdin;
11158     else
11159 #endif /* NETCMD */
11160       fd = ttyfd;
11161
11162     if ((timo <= 0)                     /* Untimed. */
11163 #ifdef MYREAD
11164         || (my_count > 0)               /* Buffered char already waiting. */
11165 #endif /* MYREAD */
11166         ) {
11167 #ifdef MYREAD
11168         /* Comm line failure returns -1 thru myread, so no &= 0377 */
11169         n = myread();                   /* Wait for a character... */
11170         /* debug(F000,"ttinc MYREAD n","",n); */
11171 #ifdef CK_ENCRYPTION
11172         /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
11173         if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11174             ch = n;
11175             ck_tn_decrypt((char *)&ch,1);
11176             n = ch;
11177         }
11178 #endif /* CK_ENCRYPTION */
11179
11180 #ifdef NETPTY
11181         if (ttpty && n < 0) {
11182             debug(F101,"ttinc error on pty","",n);
11183             ttclos(0);
11184             return(n);
11185         }
11186 #endif /* NETPTY */
11187
11188 #ifdef TNCODE
11189         if ((n > -1) && is_tn)
11190           return((unsigned)(n & 0xff));
11191         else
11192 #endif /* TNCODE */
11193           return(n < 0 ? n : (unsigned)(n & ttpmsk));
11194
11195 #else  /* MYREAD */
11196
11197         while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
11198         /* Shouldn't have to loop in ver 5A. */
11199 #ifdef NETCONN
11200           if (netconn) {                /* Special handling for net */
11201               netclos();                /* If read() returns 0 it means */
11202               netconn = 0;              /* the connection has dropped. */
11203               errno = ENOTCONN;
11204               return(-2);
11205           }
11206 #endif /* NETCONN */
11207           ;
11208         /* debug(F101,"ttinc","",ch); */
11209 #ifdef TNCODE
11210         if ((n > 0) && is_tn) {
11211 #ifdef CK_ENCRYPTION
11212             if (TELOPT_U(TELOPT_ENCRYPTION)) {
11213                 ck_tn_decrypt(&ch,1);
11214                 n = ch;
11215             }
11216 #endif /* CK_ENCRYPTION */
11217             return((unsigned)(ch & 0xff));
11218         } else
11219 #endif /* TNCODE */
11220         return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
11221 #endif /* MYREAD */
11222
11223     } else {                            /* Timed read */
11224
11225         int oldalarm;
11226         saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
11227         oldalarm = alarm(timo);         /* Set alarm, save old one. */
11228         if (
11229 #ifdef CK_POSIX_SIG
11230             sigsetjmp(sjbuf,1)
11231 #else
11232             setjmp(sjbuf)
11233 #endif /* CK_POSIX_SIG */
11234             ) {                         /* Timer expired */
11235             ttinctimo = 1;
11236             n = -1;                     /* set flag */
11237         } else {
11238 #ifdef MYREAD
11239             n = myread();               /* If managing own buffer... */
11240             debug(F101,"ttinc myread","",n);
11241             ch = n;
11242 #else
11243             n = read(fd,&ch,1);         /* Otherwise call the system. */
11244             if (n == 0) n = -1;
11245             debug(F101,"ttinc read","",n);
11246 #endif /* MYREAD */
11247
11248 #ifdef CK_ENCRYPTION
11249             if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
11250                 ck_tn_decrypt((char *)&ch,1);
11251             }
11252 #endif /* CK_ENCRYPTION */
11253             if (n >= 0)
11254               n = (unsigned) (ch & 0xff);
11255             else
11256               n = (n < 0) ? -4 : -2;    /* Special return codes. */
11257         }
11258         ttimoff();                      /* Turn off the timer */
11259         if (oldalarm > 0) {
11260             if (n == -1)                /* and restore any previous alarm */
11261               oldalarm -= timo;
11262             if (oldalarm < 0)           /* adjusted by our timeout interval */
11263               oldalarm = 0;
11264             if (oldalarm) {
11265                 debug(F101,"ttinc restoring oldalarm","",oldalarm);
11266                 alarm(oldalarm);
11267             }
11268         }
11269 #ifdef NETCONN
11270         if (netconn) {
11271             if (n == -2) {              /* read() returns 0 */
11272                 netclos();              /* on network read failure */
11273                 netconn = 0;
11274                 errno = ENOTCONN;
11275             }
11276         }
11277 #endif  /* NETCONN */
11278 #ifdef TNCODE
11279         if ((n > -1) && is_tn)
11280           return((unsigned)(n & 0xff));
11281         else
11282 #endif /* TNCODE */
11283           /* Return masked char or neg. */
11284           return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
11285     }
11286 }
11287
11288 /*  S N D B R K  --  Send a BREAK signal of the given duration  */
11289
11290 static int
11291 #ifdef CK_ANSIC
11292 sndbrk(int msec) {                      /* Argument is milliseconds */
11293 #else
11294 sndbrk(msec) int msec; {
11295 #endif /* CK_ANSIC */
11296 #ifndef POSIX
11297     int x, n;
11298 #endif /* POSIX */
11299
11300 #ifdef OXOS
11301 #define BSDBREAK
11302 #endif /* OXOS */
11303
11304 #ifdef ANYBSD
11305 #define BSDBREAK
11306 #endif /* ANYBSD */
11307
11308 #ifdef BSD44
11309 #define BSDBREAK
11310 #endif /* BSD44 */
11311
11312 #ifdef COHERENT
11313 #ifdef BSDBREAK
11314 #undef BSDBREAK
11315 #endif /* BSDBREAK */
11316 #endif /* COHERENT */
11317
11318 #ifdef BELLV10
11319 #ifdef BSDBREAK
11320 #undef BSDBREAK
11321 #endif /* BSDBREAK */
11322 #endif /* BELLV10 */
11323
11324 #ifdef PROVX1
11325     char spd;
11326 #endif /* PROVX1 */
11327
11328     debug(F101,"ttsndb ttyfd","",ttyfd);
11329     if (ttyfd < 0) return(-1);          /* Not open. */
11330
11331 #ifdef Plan9
11332     return p9sndbrk(msec);
11333 #else
11334 #ifdef NETCONN
11335 #ifdef NETCMD
11336     if (ttpipe)                         /* Pipe */
11337       return(ttoc('\0'));
11338 #endif /* NETCMD */
11339 #ifdef NETPTY
11340     if (ttpty)
11341       return(ttoc('\0'));
11342 #endif /* NETPTY */
11343     if (netconn)                        /* Send network BREAK */
11344       return(netbreak());
11345 #endif /* NETCONN */
11346
11347     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
11348
11349 #ifdef POSIX                            /* Easy in POSIX */
11350     {
11351         int x;
11352         debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
11353         errno = 0;
11354         x = tcsendbreak(ttyfd,msec / 375);
11355         debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
11356         return(x);
11357     }
11358 #else
11359 #ifdef PROVX1
11360     gtty(ttyfd,&ttbuf);                 /* Get current tty flags */
11361     spd = ttbuf.sg_ospeed;              /* Save speed */
11362     ttbuf.sg_ospeed = B50;              /* Change to 50 baud */
11363     stty(ttyfd,&ttbuf);                 /*  ... */
11364     n = (int)strlen(brnuls);            /* Send the right number of nulls */
11365     x = msec / 91;
11366     if (x > n) x = n;
11367     write(ttyfd,brnuls,n);
11368     ttbuf.sg_ospeed = spd;              /* Restore speed */
11369     stty(ttyfd,&ttbuf);                 /*  ... */
11370     return(0);
11371 #else
11372 #ifdef aegis
11373     sio_$control((short)ttyfd, sio_$send_break, msec, st);
11374     return(0);
11375 #else
11376 #ifdef BSDBREAK
11377     n = FWRITE;                         /* Flush output queue. */
11378 /* Watch out for int vs long problems in &n arg! */
11379     debug(F101,"sndbrk BSDBREAK","",msec);
11380     ioctl(ttyfd,TIOCFLUSH,&n);          /* Ignore any errors.. */
11381     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {  /* Turn on BREAK */
11382         perror("Can't send BREAK");
11383         return(-1);
11384     }
11385     x = msleep(msec);                    /* Sleep for so many milliseconds */
11386     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {  /* Turn off BREAK */
11387         perror("BREAK stuck!!!");
11388         doexit(BAD_EXIT,-1);            /* Get out, closing the line. */
11389                                         /*   with bad exit status */
11390     }
11391     return(x);
11392 #else
11393 #ifdef ATTSV
11394 /*
11395   No way to send a long BREAK in Sys V, so send a bunch of regular ones.
11396   (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
11397   but there's no way for this code to know for sure.)
11398 */
11399     debug(F101,"sndbrk ATTSV","",msec);
11400     x = msec / 275;
11401     for (n = 0; n < x; n++) {
11402         /* Reportedly the cast breaks this function on some systems */
11403         /* But then why was it here in the first place? */
11404         if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
11405             perror("Can't send BREAK");
11406             return(-1);
11407         }
11408     }
11409     return(0);
11410 #else
11411 #ifdef  V7
11412     debug(F101,"sndbrk V7","",msec);
11413     return(genbrk(ttyfd,250));          /* Simulate a BREAK */
11414 #else
11415     debug(F101,"sndbrk catchall","",msec);
11416     ttoc(0);ttoc(0);ttoc(0);ttoc(0);
11417     return(0);
11418 #endif /* V7 */
11419 #endif /* BSDBREAK */
11420 #endif /* ATTSV */
11421 #endif /* aegis */
11422 #endif /* PROVX1 */
11423 #endif /* POSIX */
11424 #endif /* Plan9 */
11425 }
11426
11427 /*  T T S N D B  --  Send a BREAK signal  */
11428
11429 int
11430 ttsndb() {
11431 #ifdef TN_COMPORT
11432     if (netconn && istncomport())
11433       return((tnsndb(275L) >= 0) ? 0 : -1);
11434     else
11435 #endif /* TN_COMPORT */
11436       return(sndbrk(275));
11437 }
11438
11439 /*  T T S N D L B  --  Send a Long BREAK signal  */
11440
11441 int
11442 ttsndlb() {
11443 #ifdef TN_COMPORT
11444     if (netconn && istncomport())
11445       return((tnsndb(1800L) >= 0) ? 0 : -1);
11446     else
11447 #endif /* TN_COMPORT */
11448     return(sndbrk(1500));
11449 }
11450
11451 /*  M S L E E P  --  Millisecond version of sleep().  */
11452
11453 /*
11454   Call with number of milliseconds (thousandths of seconds) to sleep.
11455   Intended only for small intervals.  For big ones, just use sleep().
11456   Highly system-dependent.
11457   Returns 0 always, even if it didn't work.
11458 */
11459
11460 /* Define MSLFTIME for systems that must use an ftime() loop. */
11461 #ifdef ANYBSD                           /* For pre-4.2 BSD versions */
11462 #ifndef BSD4
11463 #define MSLFTIME
11464 #endif /* BSD4 */
11465 #endif /* ANYBSD */
11466
11467 #ifdef TOWER1                           /* NCR Tower OS 1.0 */
11468 #define MSLFTIME
11469 #endif /* TOWER1 */
11470
11471 #ifdef COHERENT         /* Coherent... */
11472 #ifndef _I386           /* Maybe Coherent/386 should get this, too */
11473 #define MSLFTIME        /* Opinions are divided */
11474 #endif /* _I386 */
11475 #endif /* COHERENT */
11476
11477 #ifdef COMMENT
11478 #ifdef GETMSEC
11479
11480 /* Millisecond timer */
11481
11482 static long msecbase = 0L;              /* Unsigned long not portable */
11483
11484 long
11485 getmsec() {                             /* Milliseconds since base time */
11486     struct timeval xv;
11487     struct timezone xz;
11488     long secs, msecs;
11489     if (
11490 #ifdef GTODONEARG
11491         gettimeofday(&tv)
11492 #else
11493 #ifdef PTX
11494         gettimeofday(&tv, NULL)
11495 #else
11496         gettimeofday(&tv, &tz)
11497 #endif /* PTX */
11498 #endif /* GTODONEARG */
11499         < 0)
11500       return(-1);
11501     if (msecbase == 0L) {               /* First call, set base time. */
11502         msecbase = tv.tv_sec;
11503         debug(F101,"getmsec base","",msecbase);
11504     }
11505     return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
11506 }
11507 #endif /* GETMSEC */
11508 #endif /* COMMENT */
11509
11510 #ifdef SELECT
11511 int
11512 ttwait(fd, secs) int fd, secs; {
11513     int x;
11514     fd_set rfds;
11515     FD_ZERO(&rfds);
11516     FD_SET(fd,&rfds);
11517     tv.tv_sec = secs;
11518     tv.tv_usec = 0L;
11519     errno = 0;
11520     if ((x = select(FD_SETSIZE,
11521 #ifdef HPUX9
11522                     (int *)
11523 #else
11524 #ifdef HPUX1000
11525                     (int *)
11526 #endif /* HPUX1000 */
11527 #endif /* HPUX9 */
11528                     &rfds,
11529                     0, 0, &tv)) < 0) {
11530         debug(F101,"ttwait select errno","",errno);
11531         return(0);
11532     } else {
11533         debug(F101,"ttwait OK","",errno);
11534         x = FD_ISSET(fd, &rfds);
11535         debug(F101,"ttwait select x","",x);
11536         return(x ? 1 : 0);
11537     }
11538 }
11539 #endif /* SELECT */
11540
11541 int
11542 msleep(m) int m; {
11543 /*
11544   Other possibilities here are:
11545    nanosleep(), reportedly defined in POSIX.4.
11546    sginap(), IRIX only (back to what IRIX version I don't know).
11547 */
11548 #ifdef Plan9
11549     return _SLEEP(m);
11550 #else
11551 #ifdef BEOSORBEBOX
11552     snooze(m*1000);
11553 #else /* BEOSORBEBOX */
11554 #ifdef SELECT
11555     int t1, x;
11556     debug(F101,"msleep SELECT 1","",m);
11557     if (m <= 0) return(0);
11558     if (m >= 1000) {                    /* Catch big arguments. */
11559         sleep(m/1000);
11560         m = m % 1000;
11561         if (m < 10) return(0);
11562     }
11563     debug(F101,"msleep SELECT 2","",m);
11564 #ifdef BELLV10
11565     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
11566     debug(F101,"msleep BELLV10 select","",x);
11567 #else /* BELLV10 */
11568 #ifdef HPUX9
11569     gettimeofday(&tv, &tz);
11570 #else
11571
11572 #ifndef COHERENT
11573 #ifdef GTODONEARG
11574     if (gettimeofday(&tv) < 0)
11575 #else
11576 #ifdef PTX
11577     if (gettimeofday(&tv,NULL) < 0)
11578 #else
11579 #ifdef NOTIMEZONE
11580     if (gettimeofday(&tv, NULL) < 0)    /* wonder what this does... */
11581 #else
11582     if (gettimeofday(&tv, &tz) < 0)
11583 #endif /* NOTIMEZONE */
11584 #endif /* PTX */
11585 #endif /* GTODONEARG */
11586       return(-1);
11587     t1 = tv.tv_sec;                     /* Seconds */
11588 #endif /* COHERENT */
11589 #endif /* HPUX9 */
11590     tv.tv_sec = 0;                      /* Use select() */
11591     tv.tv_usec = m * 1000L;
11592 #ifdef BSD44
11593     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11594     debug(F101,"msleep BSD44 select","",x);
11595 #else /* BSD44 */
11596 #ifdef __linux__
11597     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11598     debug(F101,"msleep __linux__ select","",x);
11599 #else /* __linux__ */
11600 #ifdef BSD43
11601     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11602     debug(F101,"msleep BSD43 select","",x);
11603 #else /* BSD43 */
11604 #ifdef QNX6
11605     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11606     debug(F101,"msleep QNX6 select","",x);
11607 #else /* QNX6 */
11608 #ifdef QNX
11609     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11610     debug(F101,"msleep QNX select","",x);
11611 #else /* QNX */
11612 #ifdef COHERENT
11613     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11614     debug(F101,"msleep COHERENT select","",x);
11615 #else /* COHERENT */
11616 #ifdef HPUX1000                         /* 10.00 only, not 10.10 or later */
11617     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11618     debug(F101,"msleep HP-UX 10.00 select","",x);
11619 #else /* HPUX1000 */
11620 #ifdef SVR4
11621     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11622     debug(F101,"msleep SVR4 select","",x);
11623 #else /* SVR4 */
11624 #ifdef OSF40
11625     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11626     debug(F101,"msleep OSF40 select","",x);
11627 #else /* OSF40 */
11628 #ifdef PTX
11629     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
11630     debug(F101,"msleep OSF40 select","",x);
11631 #else
11632     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
11633     debug(F101,"msleep catch-all select","",x);
11634 #endif /* PTX */
11635 #endif /* OSF40 */
11636 #endif /* HP1000 */
11637 #endif /* SVR4 */
11638 #endif /* COHERENT */
11639 #endif /* QNX */
11640 #endif /* QNX6 */
11641 #endif /* BSD43 */
11642 #endif /* __linux__ */
11643 #endif /* BSD44 */
11644 #endif /* BELLV10 */
11645     return(0);
11646
11647 #else                                   /* Not SELECT */
11648 #ifdef CK_POLL                          /* We have poll() */
11649     struct pollfd pfd;                  /* Supply a valid address for poll() */
11650
11651 #ifdef ODT30                            /* But in SCO ODT 3.0 */
11652 #ifdef NAP                              /* we should use nap() instead */
11653     debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
11654     nap((long)m);                          /* seems to break dialing. */
11655     return(0);
11656 #else
11657     debug(F101,"msleep ODT 3.0 POLL","",m);
11658     poll(&pfd, 0, m);
11659     return(0);
11660 #endif /* NAP */
11661 #else
11662     debug(F101,"msleep POLL","",m);
11663     poll(&pfd, 0, m);
11664     return(0);
11665 #endif /* ODT30 */
11666
11667 /*
11668   We could handle the above more cleanly by just letting nap() always
11669   take precedence over poll() in this routine, but there is no way to know
11670   whether that would break something else.
11671 */
11672
11673 #else                                   /* Not POLL */
11674 #ifdef USLEEP
11675 /*
11676   "This routine is implemented using setitimer(2); it requires eight
11677   system calls...".  In other words, it might take 5 minutes to sleep
11678   10 milliseconds...
11679 */
11680     debug(F101,"msleep USLEEP","",m);
11681     if (m >= 1000) {                    /* Catch big arguments. */
11682         sleep(m/1000);
11683         m = m % 1000;
11684         if (m < 10) return(0);
11685     }
11686     usleep((unsigned int)(m * 1000));
11687     return(0);
11688 #else
11689 #ifdef aegis
11690     time_$clock_t dur;
11691     debug(F101,"msleep aegis","",m);
11692     dur.c2.high16 = 0;
11693     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
11694     time_$wait(time_$relative, dur, st);
11695     return(0);
11696 #else
11697 #ifdef PROVX1
11698     debug(F101,"msleep Venix","",m);
11699     if (m <= 0) return(0);
11700     sleep(-((m * 60 + 500) / 1000));
11701     return(0);
11702 #else
11703 #ifdef NAP
11704     debug(F101,"msleep NAP","",m);
11705     nap((long)m);
11706     return(0);
11707 #else
11708 #ifdef ATTSV
11709 #ifndef BSD44
11710     extern long times();                /* Or #include <times.h> ? */
11711 #endif /* BSD44 */
11712     long t1, t2, tarray[4];
11713     int t3;
11714     char *cp = getenv("HZ");
11715     int CLOCK_TICK;
11716     int hertz;
11717
11718     if (cp && (hertz = atoi(cp))) {
11719         CLOCK_TICK  = 1000 / hertz;
11720     } else {                            /* probably single user mode */
11721 #ifdef HZ
11722         CLOCK_TICK  = 1000 / HZ;
11723 #else
11724         static warned = 0;
11725         /* HZ always exists in, for instance, SCO Xenix, so you don't have to
11726          * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
11727          * have Xenix, you have should have nap(), so the best is to use -DNAP
11728          * in the makefile. Most systems have HZ.
11729          */
11730         CLOCK_TICK = 17;                /* 1/60 sec */
11731         if (!warned) {
11732           printf("warning: environment variable HZ bad... using HZ=%d\r\n",
11733                  1000 / CLOCK_TICK);
11734           warned = 1;
11735         }
11736 #endif /* !HZ */
11737     }
11738     debug(F101,"msleep ATTSV","",m);
11739     if (m <= 0) return(0);
11740     if (m >= 1000) {                    /* Catch big arguments. */
11741         sleep(m/1000);
11742         m = m % 1000;
11743         if (m < 10) return(0);
11744     }
11745     if ((t1 = times(tarray)) < 0) return(-1);
11746     while (1) {
11747         if ((t2 = times(tarray)) < 0) return(-1);
11748         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
11749         if (t3 > m) return(t3);
11750     }
11751 #else /* Not ATTSV */
11752 #ifdef MSLFTIME                         /* Use ftime() loop... */
11753     int t1, t3 = 0;
11754     debug(F101,"msleep MSLFTIME","",m);
11755     if (m <= 0) return(0);
11756     if (m >= 1000) {                    /* Catch big arguments. */
11757         sleep(m/1000);
11758         m = m % 1000;
11759         if (m < 10) return(0);
11760     }
11761 #ifdef QNX
11762     ftime(&ftp);                        /* void ftime() in QNX */
11763 #else
11764     if (ftime(&ftp) < 0) return(-1);    /* Get base time. */
11765 #endif /* QNX */
11766     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
11767     while (1) {
11768         ftime(&ftp);                    /* Get current time and compare. */
11769         t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
11770         if (t3 > m) return(0);
11771     }
11772 #else
11773 /* This includes true POSIX, which has no way to do this. */
11774     debug(F101,"msleep busy loop","",m);
11775     if (m >= 1000) {                    /* Catch big arguments. */
11776         sleep(m/1000);
11777         m = m % 1000;
11778         if (m < 10) return(0);
11779     }
11780     if (m > 0) while (m > 0) m--;       /* Just a dumb busy loop */
11781     return(0);
11782 #endif /* MSLFTIME */
11783 #endif /* ATTSV */
11784 #endif /* NAP */
11785 #endif /* PROVX1 */
11786 #endif /* aegis */
11787 #endif /* CK_POLL */
11788 #endif /* SELECT */
11789 #endif /* BEOSORBEBOX */
11790 #endif /* USLEEP */
11791 #endif /* Plan9 */
11792 }
11793
11794 /*  R T I M E R --  Reset elapsed time counter  */
11795
11796 VOID
11797 rtimer() {
11798     tcount = time( (time_t *) 0 );
11799 }
11800
11801
11802 /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
11803
11804 int
11805 gtimer() {
11806     int x;
11807     x = (int) (time( (time_t *) 0 ) - tcount);
11808     debug(F101,"gtimer","",x);
11809     return( (x < 0) ? 0 : x );
11810 }
11811
11812 #ifdef GFTIMER
11813 /*
11814   Floating-point timers.  Require not only floating point support, but
11815   also gettimeofday().
11816 */
11817 static struct timeval tzero;
11818
11819 VOID
11820 rftimer() {
11821 #ifdef GTODONEARG                       /* Account for Mot's definition */
11822     (VOID) gettimeofday(&tzero);
11823 #else
11824     (VOID) gettimeofday(&tzero, (struct timezone *)0);
11825 #endif /* GTODONEARG */
11826 }
11827
11828 CKFLOAT
11829 gftimer() {
11830     struct timeval tnow, tdelta;
11831     CKFLOAT s;
11832 #ifdef DEBUG
11833     char fpbuf[64];
11834 #endif /* DEBUG */
11835 #ifdef GTODONEARG                       /* Account for Mot's definition */
11836     (VOID) gettimeofday(&tnow);
11837 #else
11838     (VOID) gettimeofday(&tnow, (struct timezone *)0);
11839 #endif /* GTODONEARG */
11840
11841     tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
11842     tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
11843
11844     if (tdelta.tv_usec < 0) {
11845         tdelta.tv_sec--;
11846         tdelta.tv_usec += 1000000;
11847     }
11848     s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
11849     if (s < GFMINTIME)
11850       s = GFMINTIME;
11851 #ifdef DEBUG
11852     if (deblog) {
11853         sprintf(fpbuf,"%f",s);
11854         debug(F110,"gftimer",fpbuf,0);
11855     }
11856 #endif /* DEBUG */
11857     return(s);
11858 }
11859 #endif /* GFTIMER */
11860
11861 /*  Z T I M E  --  Return asctime()-format date/time string  */
11862 /*
11863   NOTE: as a side effect of calling this routine, we can also set the
11864   following two variables, giving the micro- and milliseconds (fractions of
11865   seconds) of the clock time.  Currently this is done only in BSD-based builds
11866   that use gettimeofday().  When these variables are not filled in, they are
11867   left with a value of -1L.
11868 */
11869 static char asctmbuf[64];
11870
11871 VOID
11872 ztime(s) char **s; {
11873
11874 #ifdef GFTIMER
11875 /*
11876   The gettimeofday() method, which also sets ztmsec and ztusec, works for
11877   all GFTIMER builds.  NOTE: ztmsec and ztusec are defined in ckcmai.c,
11878   and extern declarations for them are in ckcdeb.h; thus they are
11879   declared in this file by inclusion of ckcdeb.h.
11880 */
11881     char *asctime();
11882     struct tm *localtime();
11883     struct tm *tp;
11884     ztmsec = -1L;
11885     ztusec = -1L;
11886
11887     if (!s)
11888       debug(F100,"ztime s==NULL","",0);
11889
11890 #ifdef GTODONEARG
11891     /* No 2nd arg in Motorola SV88 and some others */
11892     if (gettimeofday(&tv) > -1)
11893 #else
11894 #ifndef COHERENT
11895 #ifdef PTX
11896     if (gettimeofday(&tv,NULL) > -1)
11897 #else
11898 #ifdef NOTIMEZONE
11899     if (gettimeofday(&tv, NULL) > -1)   /* wonder what this does... */
11900 #else
11901     if (gettimeofday(&tv, &tz) > -1)
11902 #endif /* NOTIMEZONE */
11903 #endif /* PTX */
11904 #endif /* COHERENT */
11905 #endif /* GTODONEARG */
11906       {                                 /* Fill in tm struct */
11907         ztusec = tv.tv_usec;            /* Microseconds */
11908         ztmsec = ztusec / 1000L;        /* Milliseconds */
11909 #ifdef HPUX9
11910         {
11911             time_t zz;
11912             zz = tv.tv_sec;
11913             tp = localtime(&zz);        /* Convert to local time */
11914         }
11915 #else
11916 #ifdef HPUX1000
11917         {
11918             time_t zz;
11919             zz = tv.tv_sec;
11920             tp = localtime(&zz);
11921         }
11922 #else
11923 #ifdef LINUX
11924         {   /* avoid unaligned access trap on 64-bit platforms */
11925             time_t zz;
11926             zz = tv.tv_sec;
11927             tp = localtime(&zz);
11928         }
11929 #else
11930 #ifdef MACOSX
11931         tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
11932 #else
11933         tp = localtime(&tv.tv_sec);
11934 #endif /* MACOSX */
11935 #endif /* LINUX */
11936 #endif /* HPUX1000 */
11937 #endif /* HPUX9 */
11938         if (s) {
11939             char * s2;
11940             s2 = asctime(tp);           /* Convert result to ASCII string */
11941             asctmbuf[0] = '\0';
11942             if (s2) ckstrncpy(asctmbuf,s2,64);
11943             *s = asctmbuf;
11944             debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
11945         }
11946     }
11947 #else  /* Not GFTIMER */
11948
11949 #undef ZTIMEV7                          /* Which systems need to use */
11950 #ifdef COHERENT                         /* old UNIX Version 7 way... */
11951 #define ZTIMEV7
11952 #endif /* COHERENT */
11953 #ifdef TOWER1
11954 #define ZTIMEV7
11955 #endif /* TOWER1 */
11956 #ifdef ANYBSD
11957 #ifndef BSD42
11958 #define ZTIMEV7
11959 #endif /* BSD42 */
11960 #endif /* ANYBSD */
11961 #ifdef V7
11962 #ifndef MINIX
11963 #define ZTIMEV7
11964 #endif /* MINIX */
11965 #endif /* V7 */
11966 #ifdef POSIX
11967 #define ZTIMEV7
11968 #endif /* POSIX */
11969
11970 #ifdef HPUX1020
11971 /*
11972   Prototypes are in <time.h>, included above.
11973 */
11974     time_t clock_storage;
11975     clock_storage = time((void *) 0);
11976     if (s) {
11977         *s = ctime(&clock_storage);
11978         debug(F110,"ztime: HPUX 10.20",*s,0);
11979     }
11980 #else
11981 #ifdef ATTSV                            /* AT&T way */
11982 /*  extern long time(); */              /* Theoretically these should */
11983     char *ctime();                      /* already been dcl'd in <time.h> */
11984     time_t clock_storage;
11985     clock_storage = time(
11986 #ifdef IRIX60
11987                          (time_t *)
11988 #else
11989 #ifdef BSD44
11990                          (time_t *)
11991 #else
11992                          (long *)
11993 #endif /* BSD44 */
11994 #endif /* IRIX60 */
11995                          0 );
11996     if (s) {
11997         *s = ctime( &clock_storage );
11998         debug(F110,"ztime: ATTSV",*s,0);
11999     }
12000 #else
12001 #ifdef PROVX1                           /* Venix 1.0 way */
12002     int utime[2];
12003     time(utime);
12004     if (s) {
12005         *s = ctime(utime);
12006         debug(F110,"ztime: PROVX1",*s,0);
12007     }
12008 #else
12009 #ifdef BSD42                            /* 4.2BSD way */
12010     char *asctime();
12011     struct tm *localtime();
12012     struct tm *tp;
12013     gettimeofday(&tv, &tz);
12014     ztusec = tv.tv_usec;
12015     ztmsec = tv.tv_usec / 1000L;
12016     tp = localtime(&tv.tv_sec);
12017     if (s) {
12018         *s = asctime(tp);
12019         debug(F111,"ztime: BSD42",*s,ztusec);
12020     }
12021 #else
12022 #ifdef MINIX                            /* MINIX way */
12023 #ifdef COMMENT
12024     extern long time();                 /* Already got these from <time.h> */
12025     extern char *ctime();
12026 #endif /* COMMENT */
12027     time_t utime[2];
12028     time(utime);
12029     if (s) {
12030         *s = ctime(utime);
12031         debug(F110,"ztime: MINIX",*s,0);
12032     }
12033 #else
12034 #ifdef ZTIMEV7                          /* The regular way */
12035     char *asctime();
12036     struct tm *localtime();
12037     struct tm *tp;
12038     long xclock;                        /* or unsigned long for BeBox? */
12039     time(&xclock);
12040     tp = localtime(&xclock);
12041     if (s) {
12042         *s = asctime(tp);
12043         debug(F110,"ztime: ZTIMEV7",*s,0);
12044     }
12045 #else                                   /* Catch-all for others... */
12046     if (s) {
12047         *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
12048         debug(F110,"ztime: catch-all",*s,0);
12049     }
12050 #endif /* ZTIMEV7 */
12051 #endif /* MINIX */
12052 #endif /* BSD42 */
12053 #endif /* PROVX1 */
12054 #endif /* ATTSV */
12055 #endif /* HPUX1020 */
12056 #endif /* GFTIMER */
12057 }
12058
12059 /*  C O N G M  --  Get console terminal modes.  */
12060
12061 /*
12062   Saves initial console mode, and establishes variables for switching
12063   between current (presumably normal) mode and other modes.
12064   Should be called when program starts, but only after establishing
12065   whether program is in the foreground or background.
12066   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
12067 */
12068 int
12069 congm() {
12070     int fd;
12071     if (backgrd || !isatty(0)) {        /* If in background. */
12072         cgmf = -1;                      /* Don't bother, modes are garbage. */
12073         return(-1);
12074     }
12075     if (cgmf > 0) return(0);            /* Already did this. */
12076     debug(F100,"congm getting modes","",0); /* Need to do it. */
12077 #ifdef aegis
12078     ios_$inq_type_uid(ios_$stdin, conuid, st);
12079     if (st.all != status_$ok) {
12080         fprintf(stderr, "problem getting stdin objtype: ");
12081         error_$print(st);
12082     }
12083     concrp = (conuid == mbx_$uid);
12084     conbufn = 0;
12085 #endif /* aegis */
12086
12087 #ifndef BEBOX
12088     if ((fd = open(CTTNAM,2)) < 0) {    /* Open controlling terminal */
12089 #ifdef COMMENT
12090         fprintf(stderr,"Error opening %s\n", CTTNAM);
12091         perror("congm");
12092         return(-1);
12093 #else
12094         fd = 0;
12095 #endif /* COMMENT */
12096     }
12097 #else
12098     fd = 0;
12099 #endif /* !BEBOX */
12100 #ifdef BSD44ORPOSIX
12101     if (tcgetattr(fd,&ccold) < 0) return(-1);
12102     if (tcgetattr(fd,&cccbrk) < 0) return(-1);
12103     if (tcgetattr(fd,&ccraw) < 0) return(-1);
12104 #else
12105 #ifdef ATTSV
12106     if (ioctl(fd,TCGETA,&ccold)  < 0) return(-1);
12107     if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
12108     if (ioctl(fd,TCGETA,&ccraw)  < 0) return(-1);
12109 #ifdef VXVE
12110     cccbrk.c_line = 0;                  /* STTY line 0 for CDC VX/VE */
12111     if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
12112     ccraw.c_line = 0;                   /* STTY line 0 for CDC VX/VE */
12113     if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
12114 #endif /* VXVE */
12115 #else
12116 #ifdef BELLV10
12117     if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
12118     if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
12119     if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
12120     debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
12121 #else
12122     if (gtty(fd,&ccold) < 0) return(-1);
12123     if (gtty(fd,&cccbrk) < 0) return(-1);
12124     if (gtty(fd,&ccraw) < 0) return(-1);
12125 #endif /* BELLV10 */
12126 #endif /* ATTSV */
12127 #endif /* BSD44ORPOSIX */
12128 #ifdef sony_news                        /* Sony NEWS */
12129     if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
12130         perror("congm error getting Kanji mode");
12131         debug(F101,"congm error getting Kanji mode","",0);
12132         km_con = -1;                    /* Make sure this stays undefined. */
12133         return(-1);
12134     }
12135 #endif /* sony_news */
12136     if (fd > 0)
12137       close(fd);
12138     cgmf = 1;                           /* Flag that we got them. */
12139     return(1);
12140 }
12141
12142
12143 static VOID
12144 congetbuf(x) int x; {
12145     int n;
12146     n = CONBUFSIZ - (conbufp - conbuf); /* How much room left in buffer? */
12147     if (x > n) {
12148         debug(F101,"congetbuf char loss","",x-n);
12149         x = n;
12150     }
12151     x = read(0,conbufp,x);
12152     conbufn += x;
12153     debug(F111,"congetbuf readahead",conbuf,x);
12154 }
12155
12156
12157 /*  C O N C B --  Put console in cbreak mode.  */
12158
12159 /*  Returns 0 if ok, -1 if not  */
12160
12161 int
12162 #ifdef CK_ANSIC
12163 concb(char esc)
12164 #else
12165 concb(esc) char esc;
12166 #endif /* CK_ANSIC */
12167 /* concb */ {
12168     int x, y = 0;
12169     debug(F101,"concb constate","",constate);
12170     debug(F101,"concb cgmf","",cgmf);
12171     debug(F101,"concb backgrd","",backgrd);
12172
12173     if (constate == CON_CB)
12174       return(0);
12175
12176     if (cgmf < 1)                       /* Did we get console modes yet? */
12177       if (!backgrd)                     /* No, in background? */
12178         congm();                        /* No, try to get them now. */
12179     if (cgmf < 1)                       /* Still don't have them? */
12180       return(0);                        /* Give up. */
12181     debug(F101,"concb ttyfd","",ttyfd);
12182     debug(F101,"concb ttfdflg","",ttfdflg);
12183 #ifdef COMMENT
12184     /* This breaks returning to prompt after protocol with "-l 0" */
12185     /* Commented out July 1998 */
12186     if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
12187       return(0);
12188 #endif /* COMMENT */
12189     x = isatty(0);
12190     debug(F101,"concb isatty","",x);
12191     if (!x) return(0);                  /* Only when running on real ttys */
12192     debug(F101,"concb xsuspend","",xsuspend);
12193     if (backgrd)                        /* Do nothing if in background. */
12194       return(0);
12195     escchr = esc;                       /* Make this available to other fns */
12196     ckxech = 1;                         /* Program can echo characters */
12197 #ifdef aegis
12198     conbufn = 0;
12199     if (concrp) return(write(1, "\035\002", 2));
12200     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
12201 #endif /* aegis */
12202
12203 #ifdef COHERENT
12204 #define SVORPOSIX
12205 #endif /* COHERENT */
12206
12207 #ifdef Plan9
12208     x = p9concb();
12209 #else
12210 #ifndef SVORPOSIX                       /* BSD, V7, etc */
12211     debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
12212     debug(F101,"concb stty CBREAK","",0);
12213     cccbrk.sg_flags |= (CBREAK|CRMOD);  /* Set to character wakeup, */
12214     cccbrk.sg_flags &= ~ECHO;           /* no echo. */
12215     debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
12216     errno = 0;
12217 /*
12218   BSD stty() clears the console buffer.  So if anything is waiting in it,
12219   we have to read it now to avoid losing it.
12220 */
12221     x = conchk();
12222     if (x > 0)
12223       congetbuf(x);
12224
12225 #ifdef BELLV10
12226     x = ioctl(0,TIOCSETP,&cccbrk);
12227 #else
12228     x = stty(0,&cccbrk);
12229     debug(F101,"cccbrk.sg_flags concb x","", x);
12230 #endif /* BELLV10 */
12231 #else                                   /* Sys V and POSIX */
12232 #ifndef OXOS
12233     debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
12234 #ifdef QNX
12235     /* Don't mess with IEXTEN */
12236     cccbrk.c_lflag &= ~(ICANON|ECHO);
12237 #else
12238 #ifdef COHERENT
12239     cccbrk.c_lflag &= ~(ICANON|ECHO);
12240 #else
12241     cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
12242 #endif /* COHERENT */
12243 #endif /* QNX */
12244     cccbrk.c_lflag |= ISIG;             /* Allow signals in command mode. */
12245     cccbrk.c_iflag |= IGNBRK;           /* But ignore BREAK signal */
12246     cccbrk.c_iflag &= ~BRKINT;
12247
12248 #else /* OXOS */
12249     debug(F100,"concb OXOS is defined","",0);
12250     cccbrk.c_lflag &= ~(ICANON|ECHO);
12251     cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
12252 #endif /* OXOS */
12253 #ifdef COMMENT
12254 /*
12255   Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
12256   array reference is out of bounds.  It's only a debug() call so who needs it.
12257 */
12258 #ifdef VSUSP
12259     debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
12260 #endif /* VSUSP */
12261 #endif /* COMMENT */
12262 #ifndef VINTR
12263     debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
12264     cccbrk.c_cc[0] = 003;               /* Interrupt char is Control-C */
12265 #else
12266     debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
12267     cccbrk.c_cc[VINTR] = 003;
12268 #endif /* VINTR */
12269 #ifndef VQUIT
12270     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
12271 #else
12272     cccbrk.c_cc[VQUIT] = escchr;
12273 #endif /* VQUIT */
12274 #ifndef VEOF
12275     cccbrk.c_cc[4] = 1;
12276 #else
12277 #ifndef OXOS
12278 #ifdef VMIN
12279     cccbrk.c_cc[VMIN] = 1;
12280 #endif /* VMIN */
12281 #else /* OXOS */
12282     cccbrk.c_min = 1;
12283 #endif /* OXOS */
12284 #endif /* VEOF */
12285 #ifdef ZILOG
12286     cccbrk.c_cc[5] = 0;
12287 #else
12288 #ifndef VEOL
12289     cccbrk.c_cc[5] = 1;
12290 #else
12291 #ifndef OXOS
12292 #ifdef VTIME
12293     cccbrk.c_cc[VTIME] = 1;
12294 #endif /* VTIME */
12295 #else /* OXOS */
12296     cccbrk.c_time = 1;
12297 #endif /* OXOS */
12298 #endif /* VEOL */
12299 #endif /* ZILOG */
12300     errno = 0;
12301 #ifdef BSD44ORPOSIX                     /* Set new modes */
12302     x = tcsetattr(0,TCSADRAIN,&cccbrk);
12303 #else /* ATTSV */                       /* or the POSIX way */
12304     x = ioctl(0,TCSETAW,&cccbrk);       /* the Sys V way */
12305 #endif /* BSD44ORPOSIX */
12306 #endif /* SVORPOSIX */
12307
12308 #ifdef COHERENT
12309 #undef SVORPOSIX
12310 #endif /* COHERENT */
12311
12312     debug(F101,"concb x","",x);
12313     debug(F101,"concb errno","",errno);
12314
12315 #ifdef  V7
12316 #ifndef MINIX
12317     if (kmem[CON] < 0) {
12318         qaddr[CON] = initrawq(0);
12319         if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
12320             fprintf(stderr, "Can't read /dev/kmem in concb.\n");
12321             perror("/dev/kmem");
12322             exit(1);
12323         }
12324     }
12325 #endif /* MINIX */
12326 #endif /* V7 */
12327 #endif /* Plan9 */
12328
12329     if (x > -1)
12330       constate = CON_CB;
12331
12332     debug(F101,"concb returns","",x);
12333     return(x);
12334 }
12335
12336 /*  C O N B I N  --  Put console in binary mode  */
12337
12338 /*  Returns 0 if ok, -1 if not  */
12339
12340 int
12341 #ifdef CK_ANSIC
12342 conbin(char esc)
12343 #else
12344 conbin(esc) char esc;
12345 #endif /* CK_ANSIC */
12346 /* conbin */  {
12347
12348     int x;
12349
12350     debug(F101,"conbin constate","",constate);
12351
12352     if (constate == CON_BIN)
12353       return(0);
12354
12355     if (!isatty(0)) return(0);          /* only for real ttys */
12356     congm();                            /* Get modes if necessary. */
12357     debug(F100,"conbin","",0);
12358     escchr = esc;                       /* Make this available to other fns */
12359     ckxech = 1;                         /* Program can echo characters */
12360 #ifdef aegis
12361     conbufn = 0;
12362     if (concrp) return(write(1, "\035\002", 2));
12363     if (conuid == input_pad_$uid) {
12364         pad_$raw(ios_$stdin, st);
12365         return(0);
12366       }
12367 #endif /* aegis */
12368
12369 #ifdef COHERENT
12370 #define SVORPOSIX
12371 #endif /* COHERENT */
12372
12373 #ifdef Plan9
12374     return p9conbin();
12375 #else
12376 #ifdef SVORPOSIX
12377 #ifndef OXOS
12378 #ifdef QNX
12379     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12380 #else
12381 #ifdef COHERENT
12382     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12383 #else
12384     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
12385 #endif /* COHERENT */
12386 #endif /* QNX */
12387 #else /* OXOS */
12388     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
12389     ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
12390 #endif /* OXOS */
12391     ccraw.c_iflag |= IGNPAR;
12392 /*
12393   Note that for terminal sessions we disable Xon/Xoff flow control to allow
12394   the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
12395   transfers to work when C-Kermit is in the middle, etc.  Hardware flow
12396   control, if in use, is not affected.
12397 */
12398 #ifdef ATTSV
12399 #ifdef BSD44
12400     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
12401                         |INPCK|ISTRIP);
12402 #else
12403     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
12404                         |INPCK|ISTRIP);
12405 #endif /* BSD44 */
12406 #else /* POSIX */
12407     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
12408 #endif /* ATTSV */
12409     ccraw.c_oflag &= ~OPOST;
12410 #ifdef COMMENT
12411 /*
12412   WHAT THE HECK WAS THIS FOR?
12413   The B9600 setting (obviously) prevents CONNECT from working at any
12414   speed other than 9600 when you are logged in to the 7300 on a serial
12415   line.  Maybe some of the other flags are necessary -- if so, put back
12416   the ones that are needed.  This code is supposed to work the same, no
12417   matter whether you are logged in to the 7300 on the real console device,
12418   or through a serial port.
12419 */
12420 #ifdef ATT7300
12421     ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
12422 #endif /* ATT7300 */
12423 #endif /* COMMENT */
12424
12425 /*** Kermit used to put the console in 8-bit raw mode, but some users have
12426  *** pointed out that this should not be done, since some sites actually
12427  *** use terminals with parity settings on their Unix systems, and if we
12428  *** override the current settings and stop doing parity, then their terminals
12429  *** will display blotches for characters whose parity is wrong.  Therefore,
12430  *** the following two lines are commented out (Larry Afrin, Clemson U):
12431  ***
12432  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
12433  ***   ccraw.c_cflag |= (CS8|CREAD);
12434  ***
12435  *** Sys III/V sites that have trouble with this can restore these lines.
12436  ***/
12437 #ifndef VINTR
12438     ccraw.c_cc[0] = 003;                /* Interrupt char is Ctrl-C */
12439 #else
12440     ccraw.c_cc[VINTR] = 003;
12441 #endif /* VINTR */
12442 #ifndef VQUIT
12443     ccraw.c_cc[1] = escchr;             /* Escape during packet mode */
12444 #else
12445     ccraw.c_cc[VQUIT] = escchr;
12446 #endif /* VQUIT */
12447 #ifndef VEOF
12448     ccraw.c_cc[4] = 1;
12449 #else
12450 #ifndef OXOS
12451 #ifdef VMIN
12452     ccraw.c_cc[VMIN] = 1;
12453 #endif /* VMIN */
12454 #else /* OXOS */
12455     ccraw.c_min = 1;
12456 #endif /* OXOS */
12457 #endif /* VEOF */
12458
12459 #ifdef ZILOG
12460     ccraw.c_cc[5] = 0;
12461 #else
12462 #ifndef VEOL
12463     ccraw.c_cc[5] = 1;
12464 #else
12465 #ifndef OXOS
12466 #ifdef VTIME
12467     ccraw.c_cc[VTIME] = 1;
12468 #endif /* VTIME */
12469 #else /* OXOS */
12470     ccraw.c_time = 1;
12471 #endif /* OXOS */
12472 #endif /* VEOL */
12473 #endif /* ZILOG */
12474
12475 #ifdef BSD44ORPOSIX
12476     x = tcsetattr(0,TCSADRAIN,&ccraw);  /* Set new modes. */
12477 #else
12478     x = ioctl(0,TCSETAW,&ccraw);
12479 #endif /* BSD44ORPOSIX */
12480 #else /* Berkeley, etc. */
12481     x = conchk();                       /* Because stty() is destructive */
12482     if (x > 0)
12483       congetbuf(x);
12484     ccraw.sg_flags |= (RAW|TANDEM);     /* Set rawmode, XON/XOFF (ha) */
12485     ccraw.sg_flags &= ~(ECHO|CRMOD);    /* Set char wakeup, no echo */
12486 #ifdef BELLV10
12487     x = ioctl(0,TIOCSETP,&ccraw);
12488 #else
12489     x = stty(0,&ccraw);
12490 #endif /* BELLV10 */
12491 #endif /* SVORPOSIX */
12492 #endif /* Plan9 */
12493
12494     if (x > -1)
12495       constate = CON_BIN;
12496
12497     debug(F101,"conbin returns","",x);
12498     return(x);
12499
12500 #ifdef COHERENT
12501 #undef SVORPOSIX
12502 #endif /* COHERENT */
12503
12504 }
12505
12506
12507 /*  C O N R E S  --  Restore the console terminal  */
12508
12509 int
12510 conres() {
12511     int x;
12512     debug(F101,"conres cgmf","",cgmf);
12513     debug(F101,"conres constate","",constate);
12514
12515     if (cgmf < 1)                       /* Do nothing if modes unchanged */
12516       return(0);
12517     if (constate == CON_RES)
12518       return(0);
12519
12520     if (!isatty(0)) return(0);          /* only for real ttys */
12521     debug(F100,"conres isatty ok","",0);
12522     ckxech = 0;                         /* System should echo chars */
12523
12524 #ifdef aegis
12525     conbufn = 0;
12526     if (concrp) return(write(1, "\035\001", 2));
12527     if (conuid == input_pad_$uid) {
12528         pad_$cooked(ios_$stdin, st);
12529         constate = CON_RES;
12530         return(0);
12531     }
12532 #endif /* aegis */
12533
12534 #ifdef Plan9
12535     p9conres();
12536 #else
12537 #ifdef BSD44ORPOSIX
12538     debug(F100,"conres restoring tcsetattr","",0);
12539     x = tcsetattr(0,TCSADRAIN,&ccold);
12540 #else
12541 #ifdef ATTSV
12542     debug(F100,"conres restoring ioctl","",0);
12543     x = ioctl(0,TCSETAW,&ccold);
12544 #else /* BSD, V7, and friends */
12545 #ifdef sony_news                        /* Sony NEWS */
12546     if (km_con != -1)
12547       ioctl(0,TIOCKSET,&km_con);        /* Restore console Kanji mode */
12548 #endif /* sony_news */
12549     msleep(100);
12550     debug(F100,"conres restoring stty","",0);
12551     x = conchk();                       /* Because stty() is destructive */
12552     if (x > 0)
12553       congetbuf(x);
12554 #ifdef BELLV10
12555     x = ioctl(0,TIOCSETP,&ccold);
12556 #else
12557     x = stty(0,&ccold);
12558 #endif /* BELLV10 */
12559 #endif /* ATTSV */
12560 #endif /* BSD44ORPOSIX */
12561 #endif /* Plan9 */
12562     if (x > -1)
12563       constate = CON_RES;
12564
12565     debug(F101,"conres returns","",x);
12566     return(x);
12567 }
12568
12569 /*  C O N O C  --  Output a character to the console terminal  */
12570
12571 int
12572 #ifdef CK_ANSIC
12573 conoc(char c)
12574 #else
12575 conoc(c) char c;
12576 #endif /* CK_ANSIC */
12577 /* conoc */ {
12578
12579 #ifdef IKSD
12580     if (inserver && !local)
12581       return(ttoc(c));
12582
12583 #ifdef CK_ENCRYPTION
12584     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12585         ck_tn_encrypt(&c,1);
12586 #endif /* CK_ENCRYPTION */
12587 #endif /* IKSD */
12588
12589 #ifdef Plan9
12590     return conwrite(&c,1);
12591 #else
12592     return(write(1,&c,1));
12593 #endif /* Plan9 */
12594 }
12595
12596 /*  C O N X O  --  Write x characters to the console terminal  */
12597
12598 int
12599 conxo(x,s) int x; char *s; {
12600
12601 #ifdef IKSD
12602     if (inserver && !local)
12603       return(ttol((CHAR *)s,x));
12604
12605 #ifdef CK_ENCRYPTION
12606     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12607         ck_tn_encrypt(s,x);
12608 #endif /* CK_ENCRYPTION */
12609 #endif /* IKSD */
12610
12611 #ifdef Plan9
12612     return(conwrite(s,x));
12613 #else
12614     return(write(1,s,x));
12615 #endif /* Plan9 */
12616 }
12617
12618 /*  C O N O L  --  Write a line to the console terminal  */
12619
12620 int
12621 conol(s) char *s; {
12622     int len;
12623     if (!s) s = "";                     /* Always do this! */
12624     len = strlen(s);
12625     if (len == 0)
12626       return(0);
12627
12628 #ifdef IKSD
12629     if (inserver && !local)
12630       return(ttol((CHAR *)s,len));
12631
12632 #ifdef CK_ENCRYPTION
12633     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
12634         if (nxpacket < len) {
12635             if (xpacket) {
12636                 free(xpacket);
12637                 xpacket = NULL;
12638                 nxpacket = 0;
12639             }
12640             len = len > 10240 ? len : 10240;
12641             xpacket = (CHAR *)malloc(len);
12642             if (!xpacket) {
12643                 fprintf(stderr,"ttol malloc failure\n");
12644                 return(-1);
12645             } else
12646               nxpacket = len;
12647         }
12648         memcpy(xpacket,s,len);
12649         s = (char *)xpacket;
12650         ck_tn_encrypt(s,len);
12651     }
12652 #endif /* CK_ENCRYPTION */
12653 #endif /* IKSD */
12654
12655 #ifdef Plan9
12656     return(conwrite(s,len));
12657 #else
12658     return(write(1,s,len));
12659 #endif /* Plan9 */
12660 }
12661
12662 /*  C O N O L A  --  Write an array of lines to the console terminal */
12663
12664 int
12665 conola(s) char *s[]; {
12666     char * p;
12667     int i, x;
12668
12669
12670     if (!s) return(0);
12671     for (i = 0; ; i++) {
12672         p = s[i];
12673         if (!p) p = "";                 /* Let's not dump core shall we? */
12674         if (!*p)
12675           break;
12676 #ifdef IKSD
12677         if (inserver && !local)
12678           x = ttol((CHAR *)p,(int)strlen(p));
12679         else
12680 #endif /* IKSD */
12681           x = conol(p);
12682         if (x < 0)
12683           return(-1);
12684     }
12685     return(0);
12686 }
12687
12688 /*  C O N O L L  --  Output a string followed by CRLF  */
12689
12690 int
12691 conoll(s) char *s; {
12692     CHAR buf[3];
12693     buf[0] = '\r';
12694     buf[1] = '\n';
12695     buf[2] = '\0';
12696     if (!s) s = "";
12697
12698 #ifdef IKSD
12699     if (inserver && !local) {
12700         if (*s) ttol((CHAR *)s,(int)strlen(s));
12701         return(ttol(buf,2));
12702     }
12703 #endif /* IKSD */
12704
12705     if (*s) conol(s);
12706 #ifdef IKSD
12707 #ifdef CK_ENCRYPTION
12708     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
12709       ck_tn_encrypt((char *)buf,2);
12710 #endif /* CK_ENCRYPTION */
12711 #endif /* IKSD */
12712
12713 #ifdef Plan9
12714     return(conwrite(buf, 2));
12715 #else
12716     return(write(1,buf,2));
12717 #endif /* Plan9 */
12718 }
12719
12720 /*  C O N C H K  --  Return how many characters available at console  */
12721 /*
12722   We could also use select() here to cover a few more systems that are not
12723   covered by any of the following, e.g. HP-UX 9.0x on the model 800.
12724 */
12725 int
12726 conchk() {
12727     static int contyp = 0;              /* +1 for isatty, -1 otherwise */
12728
12729     if (contyp == 0)                    /* This prevents unnecessary */
12730       contyp = (isatty(0) ? 1 : -1);    /* duplicated calls to isatty() */
12731     debug(F101,"conchk contyp","",contyp);
12732     if (backgrd || (contyp < 0))
12733       return(0);
12734
12735 #ifdef aegis
12736     if (conbufn > 0) return(conbufn);   /* use old count if nonzero */
12737
12738     /* read in more characters */
12739     conbufn = ios_$get(ios_$stdin,
12740               ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
12741     if (st.all != status_$ok) conbufn = 0;
12742     conbufp = conbuf;
12743     return(conbufn);
12744 #else
12745 #ifdef IKSD
12746     if (inserver && !local)
12747       return(in_chk(1,ttyfd));
12748     else
12749 #endif /* IKSD */
12750       return(in_chk(0,0));
12751 #endif /* aegis */
12752 }
12753
12754 /*  C O N I N C  --  Get a character from the console  */
12755 /*
12756   Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
12757   read.  Upon success, returns the character.  Upon failure, returns -1.
12758   A timed read that does not complete within the timeout period returns -2.
12759 */
12760 int
12761 coninc(timo) int timo; {
12762     int n = 0; CHAR ch;
12763     int xx;
12764
12765     if (conbufn > 0) {                  /* If something already buffered */
12766         --conbufn;
12767         return((unsigned)(*conbufp++ & 0xff));
12768     }
12769
12770     errno = 0;                          /* Clear this */
12771 #ifdef IKSD
12772     if (inserver && !local) {
12773         xx = ttinc(timo);
12774         if (xx < 0)
12775           return(ttinctimo ? -2 : -1);
12776         else
12777           return(xx);
12778     }
12779 #endif /* IKSD */
12780
12781 #ifdef aegis                            /* Apollo Aegis only... */
12782     debug(F101,"coninc timo","",timo);
12783     fflush(stdout);
12784     if (conchk() > 0) {
12785         --conbufn;
12786         return((unsigned)(*conbufp++ & 0xff));
12787     }
12788 #endif /* aegis */
12789
12790 #ifdef TTLEBUF
12791     if (
12792 #ifdef IKSD
12793         inserver &&
12794 #endif /* IKSD */
12795         !xlocal
12796         ) {
12797         if (ttpush >= 0) {
12798             debug(F111,"ttinc","ttpush",ttpush);
12799             ch = ttpush;
12800             ttpush = -1;
12801             return(ch);
12802         }
12803         if (le_data) {
12804             if (le_getchar(&ch) > 0) {
12805                 debug(F111,"ttinc LocalEchoInBuf","ch",ch);
12806                 return(ch);
12807             }
12808         }
12809     }
12810 #endif /* TTLEBUF */
12811
12812     if (timo <= 0) {                    /* Untimed, blocking read. */
12813         while (1) {                     /* Keep trying till we get one. */
12814             n = read(0, &ch, 1);        /* Read a character. */
12815             if (n == 0) continue;       /* Shouldn't happen. */
12816             if (n > 0) {                /* If read was successful, */
12817 #ifdef IKSD
12818 #ifdef CK_ENCRYPTION
12819                 debug(F100,"coninc decrypt 1","",0);
12820                 if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12821                   ck_tn_decrypt((char *)&ch,1);
12822 #endif /* CK_ENCRYPTION */
12823 #endif /* IKSD */
12824                 return((unsigned)(ch & 0xff)); /* return the character. */
12825             }
12826
12827 /* Come here if read() returned an error. */
12828
12829             debug(F101, "coninc(0) errno","",errno); /* Log the error. */
12830 #ifndef OXOS
12831 #ifdef SVORPOSIX
12832 #ifdef CIE                             /* CIE Regulus has no EINTR symbol? */
12833 #ifndef EINTR
12834 #define EINTR 4
12835 #endif /* EINTR */
12836 #endif /* CIE */
12837 /*
12838   This routine is used for several different purposes.  In CONNECT mode, it is
12839   used to do an untimed, blocking read from the keyboard in the lower CONNECT
12840   fork.  During local-mode file transfer, it reads a character from the
12841   console to interrupt the file transfer (like A for a status report, X to
12842   cancel a file, etc).  Obviously, we don't want the reads in the latter case
12843   to be blocking, or the file transfer would stop until the user typed
12844   something.  Unfortunately, System V does not allow the console device input
12845   buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
12846   used instead.  During local-mode file transfer, the SIGQUIT signal is armed
12847   and trapped by esctrp(), and this routine pretends to have read the quit
12848   character from the keyboard normally.  But, kludge or no kludge, the read()
12849   issued by this command, under System V only, can fail if a signal -- ANY
12850   signal -- is caught while the read is pending.  This can occur not only when
12851   the user types the quit character, but also during telnet negotiations, when
12852   the lower CONNECT fork signals the upper one about an echoing mode change.
12853   When this happens, we have to post the read() again.  This is apparently not
12854   a problem in BSD-based UNIX versions.
12855 */
12856             if (errno == EINTR)         /* Read interrupted. */
12857               if (conesc)  {            /* If by SIGQUIT, */
12858                  conesc = 0;            /* the conesc variable is set, */
12859                  return(escchr);        /* so return the escape character. */
12860              } else continue;           /* By other signal, try again. */
12861 #else
12862 /*
12863   This might be dangerous, but let's do this on non-System V versions too,
12864   since at least one SunOS 4.1.2 user complains of immediate disconnections
12865   upon first making a TELNET connection.
12866 */
12867             if (errno == EINTR)         /* Read interrupted. */
12868               continue;
12869 #endif /* SVORPOSIX */
12870 #else /* OXOS */
12871             if (errno == EINTR)         /* Read interrupted. */
12872               continue;
12873 #endif /* OXOS */
12874             return(-1);                 /* Error */
12875         }
12876     }
12877 #ifdef DEBUG
12878     if (deblog && timo <= 0) {
12879         debug(F100,"coninc timeout logic error","",0);
12880         timo = 1;
12881     }
12882 #endif /* DEBUG */
12883
12884 /* Timed read... */
12885
12886     saval = signal(SIGALRM,timerh);     /* Set up timeout handler. */
12887     xx = alarm(timo);                   /* Set the alarm. */
12888     debug(F101,"coninc alarm set","",timo);
12889     if (
12890 #ifdef CK_POSIX_SIG
12891         sigsetjmp(sjbuf,1)
12892 #else
12893         setjmp(sjbuf)
12894 #endif /* CK_POSIX_SIG */
12895         )                               /* The read() timed out. */
12896       n = -2;                           /* Code for timeout. */
12897     else
12898       n = read(0, &ch, 1);
12899     ttimoff();                          /* Turn off timer */
12900     if (n > 0) {                        /* Got character OK. */
12901 #ifdef IKSD
12902 #ifdef CK_ENCRYPTION
12903         debug(F100,"coninc decrypt 2","",0);
12904         if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
12905           ck_tn_decrypt((char *)&ch,1);
12906 #endif /* CK_ENCRYPTION */
12907 #endif /* IKSD */
12908         return((unsigned)(ch & 0xff));  /* Return it. */
12909     }
12910 /*
12911   read() returned an error.  Same deal as above, but without the loop.
12912 */
12913     debug(F101, "coninc(timo) n","",n);
12914     debug(F101, "coninc(timo) errno","",errno);
12915 #ifndef OXOS
12916 #ifdef SVORPOSIX
12917     if (n == -1 && errno == EINTR && conesc != 0) {
12918         conesc = 0;
12919         return(escchr);                 /* User entered escape character. */
12920     }
12921 #endif /* SVORPOSIX */
12922     if (n == 0 && errno > 0) {          /* It's an error */
12923         return(-1);
12924     }
12925 #endif /* ! OXOS */
12926     return(n);
12927 }
12928
12929 /*  C O N G K S  --  Console Get Keyboard Scancode  */
12930
12931 #ifndef congks
12932 /*
12933   This function needs to be filled in with the various system-dependent
12934   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
12935   keyboard scan code.  Unfortunately there aren't any.
12936 */
12937 int
12938 congks(timo) int timo; {
12939
12940 #ifdef IKSD
12941     if (inserver && !local)
12942       return(ttinc(timo));
12943 #endif /* IKSD */
12944
12945     return(coninc(timo));
12946 }
12947 #endif /* congks */
12948
12949 #ifdef ATT7300
12950
12951 /*  A T T D I A L  --  Dial up the remote system using internal modem
12952  * Purpose: to open and dial a number on the internal modem available on the
12953  * ATT7300 UNIX PC.  Written by Joe Doupnik. Superceeds version written by
12954  * Richard E. Hill, Dickinson, TX. which employed dial(3c).
12955  * Uses information in <sys/phone.h> and our status int attmodem.
12956  */
12957 attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
12958     char *telnum;
12959
12960     attmodem &= ~ISMODEM;                       /* modem not in use yet */
12961                     /* Ensure O_NDELAY is set, else i/o traffic hangs */
12962                     /* We turn this flag off once the dial is complete */
12963     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
12964
12965     /* Condition line, check availability & DATA mode, turn on speaker */
12966     if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
12967         printf("cannot access phone\n");
12968         ttclos(0);
12969         return (-2);
12970     }
12971     ioctl(ttyfd,PIOCGETP,&dialer);      /* get phone dialer parameters */
12972
12973     if (dialer.c_lineparam & VOICE) {   /* phone must be in DATA mode */
12974         printf(" Should not dial with modem in VOICE mode.\n");
12975         printf(" Exit Kermit, switch to DATA and retry call.\n");
12976         ttclos(0);
12977         return (-2);
12978     }
12979 #ifdef ATTTONED                         /* Old way, tone dialing only. */
12980     dialer.c_lineparam = DATA | DTMF;   /* Dial with tones, */
12981     dialer.c_lineparam &= ~PULSE;       /* not with pulses. */
12982 #else
12983     /* Leave current pulse/tone state alone. */
12984     /* But what about DATA?  Add it back if you have trouble. */
12985     /* sys/phone says you get DATA automatically by opening device RDWR */
12986 #endif
12987     dialer.c_waitdialtone = 5;                  /* wait 5 sec for dialtone */
12988 #ifdef COMMENT
12989     dialer.c_feedback = SPEAKERON|NORMSPK|RINGON;  /* control speaker */
12990 #else
12991     /* sys/phone says RINGON used only for incoming voice calls */
12992     dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
12993     dialer.c_feedback |= SPEAKERON|NORMSPK;
12994 #endif
12995     dialer.c_waitflash = 500;                   /* 0.5 sec flash hook */
12996     if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) {   /* set phone parameters */
12997         printf("Cannot set modem characteristics\n");
12998         ttclos(0);
12999         return (-2);
13000     }
13001     ioctl(ttyfd,PIOCRECONN,0);          /* Turns on speaker for pulse */
13002
13003 #ifdef COMMENT
13004     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
13005 line_status:%o feedback:%o\n",
13006     dialer.c_lineparam, dialer.c_waitdialtone,
13007     dialer.c_linestatus, dialer.c_feedback);
13008 #endif
13009
13010     attmodem |= ISMODEM;                        /* modem is now in-use */
13011     sleep(1);
13012     for (telnum = telnbr; *telnum != '\0'; telnum++)    /* dial number */
13013 #ifdef ATTTONED
13014       /* Tone dialing only */
13015       if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13016           perror("Error in dialing");
13017           ttclos(0);
13018           return(-2);
13019       }
13020 #else /* Allow Pulse or Tone dialing */
13021     switch (*telnum) {
13022       case 't': case 'T': case '%':     /* Tone dialing requested */
13023         dialer.c_lineparam |= DTMF;
13024         dialer.c_lineparam &= ~PULSE;
13025         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13026             printf("Cannot set modem to tone dialing\n");
13027             ttclos(0);
13028             return(-2);
13029         }
13030         break;
13031       case 'd': case 'D': case 'p': case 'P': case '^':
13032         dialer.c_lineparam |= PULSE;
13033         dialer.c_lineparam &= ~DTMF;
13034         if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
13035             printf("Cannot set modem to pulse dialing\n");
13036             ttclos(0);
13037             return(-2);
13038         }
13039         break;
13040       default:
13041         if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
13042             perror("Dialing error");
13043             ttclos(0);
13044             return(-2);
13045         }
13046         break;
13047     }
13048 #endif
13049
13050     ioctl(ttyfd,PIOCDIAL,"@");          /* terminator for data call */
13051     do {                                /* wait for modems to Connect */
13052         if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */
13053             perror("Cannot get modems to connect");
13054             ttclos(0);
13055             return(-2);
13056         }
13057     } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
13058     /* Turn off O_NDELAY flag now. */
13059     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
13060     signal(SIGHUP, sighup);             /* hangup on loss of carrier */
13061     return(0);                          /* return success */
13062 }
13063
13064 /*
13065   Offgetty, ongetty functions. These function get the 'getty(1m)' off
13066   and restore it to the indicated line.  Shell's return codes are:
13067     0: Can't do it.  Probably a user logged on.
13068     1: No need.  No getty on that line.
13069     2: Done, you should restore the getty when you're done.
13070   DOGETY System(3), however, returns them as 0, 256, 512, respectively.
13071   Thanks to Kevin O'Gorman, Anarm Software Systems.
13072
13073    getoff.sh looks like:   geton.sh looks like:
13074      setgetty $1 0           setgetty $1 1
13075      err=$?                  exit $?
13076      sleep 2
13077      exit $err
13078 */
13079
13080 /*  O F F G E T T Y  --  Turn off getty(1m) for the communications tty line
13081  * and get status so it can be restarted after the line is hung up.
13082  */
13083 int
13084 offgetty(ttname) char *ttname; {
13085     char temp[30];
13086     while (*ttname != '\0') ttname++;       /* seek terminator of path */
13087     ttname -= 3;                            /* get last 3 chars of name */
13088     sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
13089     return(zsyscmd(temp));
13090 }
13091
13092 /*  O N G E T T Y  --  Turn on getty(1m) for the communications tty line */
13093
13094 int
13095 ongetty(ttname) char *ttname; {
13096     char temp[30];
13097     while (*ttname != '\0') ttname++;       /* comms tty path name */
13098     ttname -= 3;
13099     sprintf(temp,"/usr/bin/geton.sh %s",ttname);
13100     return(zsyscmd(temp));
13101 }
13102 #endif /* ATT7300 */
13103
13104 /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
13105  *
13106  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
13107  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
13108  *  2 = Auto: For "modem direct": The same as "Off".
13109  *            For real modem types: Heed carrier during connect, but ignore
13110  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
13111  *
13112  * As you can see, this setting does not affect dialing, which always ignores
13113  * carrier (unless there is some special exception for some modem type).  It
13114  * does affect ttopen() if it is set before ttopen() is used.  This setting
13115  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
13116  * (or should be) always called before any communications is tried, which
13117  * means that, practically speaking, the effect is immediate.
13118  *
13119  * Of course, nothing of this applies to remote mode (xlocal = 0).
13120  *
13121  * Someone has yet to uncover how to manipulate the carrier in the BSD
13122  * environment (or any non-termio using environment).  Until that time, this
13123  * will simply be a no-op for BSD.
13124  *
13125  * Note that in previous versions, the carrier was most often left unchanged
13126  * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX.  This
13127  * has changed.  Now it is controlled by ttcarr in conjunction with these
13128  * modes.
13129  */
13130 int
13131 ttscarr(carrier) int carrier; {
13132     ttcarr = carrier;
13133     debug(F101, "ttscarr","",ttcarr);
13134     return(ttcarr);
13135 }
13136
13137 /* C A R R C T L  --  Set tty modes for carrier treatment.
13138  *
13139  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
13140  * (actually, there are no bits in sgttyb for that), or performs any other
13141  * operations needed to control this on the current system.  The function does
13142  * not do the actual TCSETA or stty, since often we want to set other bits too
13143  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
13144  *
13145  * We don't know how to do anything like carrier control on non-ATTSV systems,
13146  * except, apparently, ultrix.  See above.  It is also known that this doesn't
13147  * have much effect on a Xenix system.  For Xenix, one should switch back and
13148  * forth between the upper and lower case device files.  Maybe later.
13149  * Presently, Xenix will stick to the mode it was opened with.
13150  *
13151  * carrier: 0 = ignore carrier, 1 = require carrier.
13152  * The current state is saved in curcarr, and checked to save labour.
13153  */
13154 #ifdef SVORPOSIX
13155 int
13156 #ifdef BSD44ORPOSIX
13157 carrctl(ttpar, carrier) struct termios *ttpar; int carrier;
13158 #else /* ATTSV */
13159 carrctl(ttpar, carrier) struct termio *ttpar; int carrier;
13160 #endif /* BSD44ORPOSIX */
13161 /* carrctl */ {
13162     debug(F101, "carrctl","",carrier);
13163     if (carrier)
13164       ttpar->c_cflag &= ~CLOCAL;
13165     else
13166       ttpar->c_cflag |= CLOCAL;
13167     return(0);
13168 }
13169 #else /* Berkeley, V7, et al... */
13170 int
13171 carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
13172     debug(F101, "carrctl","",carrier);
13173     if (carrier == curcarr)
13174       return(0);
13175     curcarr = carrier;
13176 #ifdef ultrix
13177 #ifdef COMMENT
13178 /*
13179   Old code from somebody at DEC that tends to get stuck, time out, etc.
13180 */
13181     if (carrier) {
13182         ioctl(ttyfd, TIOCMODEM, &temp);
13183         ioctl(ttyfd, TIOCHPCL, 0);
13184     } else {
13185         /* (According to the manuals, TIOCNCAR should be preferred */
13186         /* over TIOCNMODEM...) */
13187         ioctl(ttyfd, TIOCNMODEM, &temp);
13188     }
13189 #else
13190 /*
13191   New code from Jamie Watson that, he says, eliminates the problems.
13192 */
13193     if (carrier) {
13194         ioctl(ttyfd, TIOCCAR);
13195         ioctl(ttyfd, TIOCHPCL);
13196     } else {
13197         ioctl(ttyfd, TIOCNCAR);
13198     }
13199 #endif /* COMMENT */
13200 #endif /* ultrix */
13201     return(0);
13202 }
13203 #endif /* SVORPOSIX */
13204
13205
13206 /*  T T G M D M  --  Get modem signals  */
13207 /*
13208  Looks for RS-232 modem signals, and returns those that are on in as its
13209  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
13210  Returns:
13211  -3 Not implemented
13212  -2 if the communication device does not have modem control (e.g. telnet)
13213  -1 on error.
13214  >= 0 on success, with a bit mask containing the modem signals that are on.
13215 */
13216
13217 /*
13218   Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
13219   modem control, namely the TIOCMGET ioctl.
13220 */
13221
13222 #ifdef BSD43
13223 #define K_MDMCTL
13224 #endif /* BSD43 */
13225
13226 #ifdef SUNOS4
13227 #define K_MDMCTL
13228 #endif /* SUNOS4 */
13229
13230 /*
13231   SCO OpenServer R5.0.4.  The TIOCMGET definition is hardwired in because it
13232   is skipped in termio.h when _POSIX_SOURCE is defined.  But _POSIX_SOURCE
13233   must be defined in order to get the high serial speeds that are new to
13234   5.0.4.  However, the regular SCO drivers do not implement TIOCMGET, so the
13235   ioctl() returns -1 with errno 22 (invalid function).  But third-party
13236   drivers, e.g. for Digiboard, do implement it, and so it should work on ports
13237   driven by those drivers.
13238 */
13239 #ifdef SCO_OSR504
13240 #ifndef TIOCMGET
13241 #define TIOCMGET (('t'<<8)|29)
13242 #endif /* TIOCMGET */
13243 #endif /* SCO_OSR504 */
13244
13245 #ifdef CK_SCOV5
13246 /* Because POSIX strictness in <sys/termio.h> won't let us see these. */
13247 #ifndef TIOCM_DTR
13248 #define TIOCM_DTR       0x0002          /* data terminal ready */
13249 #define TIOCM_RTS       0x0004          /* request to send */
13250 #define TIOCM_CTS       0x0020          /* clear to send */
13251 #define TIOCM_CAR       0x0040          /* carrier detect */
13252 #define TIOCM_RNG       0x0080          /* ring */
13253 #define TIOCM_DSR       0x0100          /* data set ready */
13254 #define TIOCM_CD        TIOCM_CAR
13255 #define TIOCM_RI        TIOCM_RNG
13256 #endif /* TIOCM_DTR */
13257 #endif /* CK_SCOV5 */
13258
13259 #ifdef QNX
13260 #define K_MDMCTL
13261 #else
13262 #ifdef TIOCMGET
13263 #define K_MDMCTL
13264 #endif /* TIOCMGET */
13265 #endif /* QNX */
13266 /*
13267   "A serial communication program that can't read modem signals
13268    is like a car without windows."
13269 */
13270 int
13271 ttgmdm() {
13272
13273 #ifdef QNX
13274 #include <sys/qioctl.h>
13275
13276     unsigned long y, mdmbits[2];
13277     int x, z = 0;
13278
13279     if (xlocal && ttyfd < 0)
13280       return(-1);
13281
13282 #ifdef NETCONN
13283     if (netconn) {                      /* Network connection */
13284 #ifdef TN_COMPORT
13285         if (istncomport()) {
13286             gotsigs = 1;
13287             return(tngmdm());
13288         } else
13289 #endif /* TN_COMPORT */
13290           return(-2);                   /* No modem signals */
13291     }
13292 #endif /* NETCONN */
13293
13294 #ifdef NETCMD
13295     if (ttpipe) return(-2);
13296 #endif /* NETCMD */
13297 #ifdef NETPTY
13298     if (ttpty) return(-2);
13299 #endif /* NETPTY */
13300
13301     mdmbits[0] = 0L;
13302     mdmbits[1] = 0L;
13303 /*
13304  * From <sys/qioctl.h>:
13305  *
13306  * SERIAL devices   (all Dev.ser versions)
13307  * 0 : DTR           8 = Data Bits 0  16 - reserved     24 - reserved
13308  * 1 : RTS           9 = Data Bits 1  17 - reserved     25 - reserved
13309  * 2 = Out 1        10 = Stop Bits    18 - reserved     26 - reserved
13310  * 3 = Int Enable   11 = Par Enable   19 - reserved     27 - reserved
13311  * 4 = Loop         12 = Par Even     20 = CTS          28 - reserved
13312  * 5 - reserved     13 = Par Stick    21 = DSR          29 - reserved
13313  * 6 - reserved     14 : Break        22 = RI           30 - reserved
13314  * 7 - reserved     15 = 0            23 = CD           31 - reserved
13315  */
13316     errno = 0;
13317     x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
13318     debug(F101,"ttgmdm qnx_ioctl","",x);
13319     debug(F101,"ttgmdm qnx_ioctl errno","",errno);
13320     if (!x) {
13321         debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
13322         debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
13323         y = mdmbits[0];
13324         if (y & 0x000001L) z |= BM_DTR; /* Bit  0 */
13325         if (y & 0x000002L) z |= BM_RTS; /* Bit  1 */
13326         if (y & 0x100000L) z |= BM_CTS; /* Bit 20 */
13327         if (y & 0x200000L) z |= BM_DSR; /* Bit 21 */
13328         if (y & 0x400000L) z |= BM_RNG; /* Bit 22 */
13329         if (y & 0x800000L) z |= BM_DCD; /* Bit 23 */
13330         debug(F101,"ttgmdm qnx result","",z);
13331         debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
13332         gotsigs = 1;
13333         return(z);
13334     } else return(-1);
13335 #else /* QNX */
13336 #ifdef HPUX                             /* HPUX has its own way */
13337     int x, z;
13338
13339 #ifdef HPUX10                           /* Modem flag word */
13340     mflag y;                            /* mflag typedef'd in <sys/modem.h> */
13341 #else
13342 #ifdef HPUX9
13343     mflag y;
13344 #else
13345 #ifdef HPUX8
13346     mflag y;
13347 #else
13348     unsigned long y;                    /* Not sure about pre-8.0... */
13349 #endif /* HPUX8 */
13350 #endif /* HPUX9 */
13351 #endif /* HPUX10 */
13352
13353     if (xlocal && ttyfd < 0)
13354       return(-1);
13355
13356 #ifdef NETCONN
13357     if (netconn) {                      /* Network connection */
13358 #ifdef TN_COMPORT
13359         if (istncomport()) {
13360             gotsigs = 1;
13361             return(tngmdm());
13362         } else
13363 #endif /* TN_COMPORT */
13364           return(-2);                   /* No modem signals */
13365     }
13366 #endif /* NETCONN */
13367
13368 #ifdef NETCMD
13369     if (ttpipe) return(-2);
13370 #endif /* NETCMD */
13371 #ifdef NETPTY
13372     if (ttpty) return(-2);
13373 #endif /* NETPTY */
13374
13375     if (xlocal)                         /* Get modem signals */
13376       x = ioctl(ttyfd,MCGETA,&y);
13377     else
13378       x = ioctl(0,MCGETA,&y);
13379     if (x < 0) return(-1);
13380     debug(F101,"ttgmdm","",y);
13381
13382     z = 0;                              /* Initialize return value */
13383
13384 /* Now set bits for each modem signal that is reported to be on. */
13385
13386 #ifdef MCTS
13387     /* Clear To Send */
13388     debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
13389     if (y & MCTS) z |= BM_CTS;
13390 #endif
13391 #ifdef MDSR
13392     /* Data Set Ready */
13393     debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
13394     if (y & MDSR) z |= BM_DSR;
13395 #endif
13396 #ifdef MDCD
13397     /* Carrier */
13398     debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
13399     if (y & MDCD) z |= BM_DCD;
13400 #endif
13401 #ifdef MRI
13402     /* Ring Indicate */
13403     debug(F101,"ttgmdm HPUX RI","",y & MRI);
13404     if (y & MRI) z |= BM_RNG;
13405 #endif
13406 #ifdef MDTR
13407     /* Data Terminal Ready */
13408     debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
13409     if (y & MDTR) z |= BM_DTR;
13410 #endif
13411 #ifdef MRTS
13412     /* Request To Send */
13413     debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
13414     if (y & MRTS) z |= BM_RTS;
13415 #endif
13416     gotsigs = 1;
13417     return(z);
13418
13419 #else /* ! HPUX */
13420
13421 #ifdef K_MDMCTL
13422 /*
13423   Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
13424   If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
13425   are needed.
13426 */
13427 #ifndef TIOCMGET
13428 #include <sys/ttycom.h>
13429 #endif /* TIOCMGET */
13430
13431     int x, y, z;
13432
13433     debug(F100,"ttgmdm K_MDMCTL defined","",0);
13434
13435 #ifdef NETCONN
13436     if (netconn) {                      /* Network connection */
13437 #ifdef TN_COMPORT
13438         if (istncomport()) {
13439             gotsigs = 1;
13440             return(tngmdm());
13441         } else
13442 #endif /* TN_COMPORT */
13443           return(-2);                   /* No modem signals */
13444     }
13445 #endif /* NETCONN */
13446
13447 #ifdef NETCMD
13448     if (ttpipe) return(-2);
13449 #endif /* NETCMD */
13450 #ifdef NETPTY
13451     if (ttpty) return(-2);
13452 #endif /* NETPTY */
13453
13454     if (xlocal && ttyfd < 0)
13455       return(-1);
13456
13457     if (xlocal)
13458       x = ioctl(ttyfd,TIOCMGET,&y);     /* Get modem signals. */
13459     else
13460       x = ioctl(0,TIOCMGET,&y);
13461     debug(F101,"ttgmdm TIOCMGET ioctl","",x);
13462     if (x < 0) {
13463         debug(F101,"ttgmdm errno","",errno);
13464         return(-1);
13465     }
13466     debug(F101,"ttgmdm bits","",y);
13467
13468     z = 0;                              /* Initialize return value. */
13469 #ifdef TIOCM_CTS
13470     /* Clear To Send */
13471     if (y & TIOCM_CTS) z |= BM_CTS;
13472     debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS); 
13473 #else
13474     debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
13475 #endif
13476 #ifdef TIOCM_DSR
13477     /* Data Set Ready */
13478     if (y & TIOCM_DSR) z |= BM_DSR;
13479     debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR); 
13480 #else
13481     debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
13482 #endif
13483 #ifdef TIOCM_CAR
13484     /* Carrier */
13485     if (y & TIOCM_CAR) z |= BM_DCD;
13486     debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR); 
13487 #else
13488     debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
13489 #endif
13490 #ifdef TIOCM_RNG
13491     /* Ring Indicate */
13492     if (y & TIOCM_RNG) z |= BM_RNG;
13493     debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG); 
13494 #else
13495     debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
13496 #endif
13497 #ifdef TIOCM_DTR
13498     /* Data Terminal Ready */
13499     if (y & TIOCM_DTR) z |= BM_DTR;
13500     debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR); 
13501 #else
13502     debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
13503 #endif
13504 #ifdef TIOCM_RTS
13505     /* Request To Send */
13506     if (y & TIOCM_RTS) z |= BM_RTS;
13507     debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS); 
13508 #else
13509     debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
13510 #endif
13511     gotsigs = 1;
13512     return(z);
13513
13514 #else /* !K_MDMCTL catch-All */
13515
13516     debug(F100,"ttgmdm K_MDMCTL not defined","",0);
13517 #ifdef TIOCMGET
13518     debug(F100,"ttgmdm TIOCMGET defined","",0);
13519 #else
13520     debug(F100,"ttgmdm TIOCMGET not defined","",0);
13521 #endif /* TIOCMGET */
13522 #ifdef _SVID3
13523     debug(F100,"ttgmdm _SVID3 defined","",0);
13524 #else
13525     debug(F100,"ttgmdm _SVID3 not defined","",0);
13526 #endif /* _SVID3 */
13527
13528 #ifdef NETCONN
13529     if (netconn) {                      /* Network connection */
13530 #ifdef TN_COMPORT
13531         if (istncomport()) {
13532             gotsigs = 1;
13533             return(tngmdm());
13534         } else
13535 #endif /* TN_COMPORT */
13536           return(-2);                   /* No modem signals */
13537     }
13538 #endif /* NETCONN */
13539
13540 #ifdef NETCMD
13541     if (ttpipe) return(-2);
13542 #endif /* NETCMD */
13543 #ifdef NETPTY
13544     if (ttpty) return(-2);
13545 #endif /* NETPTY */
13546
13547     return(-3);                         /* Sorry, I don't know how... */
13548
13549 #endif /* K_MDMCTL */
13550 #endif /* HPUX */
13551 #endif /* QNX */
13552 }
13553
13554 /*  P S U S P E N D  --  Put this process in the background.  */
13555
13556 /*
13557   Call with flag nonzero if suspending is allowed, zero if not allowed.
13558   Returns 0 on apparent success, -1 on failure (flag was zero, or
13559   kill() returned an error code.
13560 */
13561 int
13562 psuspend(flag) int flag; {
13563
13564 #ifdef RTU
13565     extern int rtu_bug;
13566 #endif /* RTU */
13567
13568     if (flag == 0) return(-1);
13569
13570 #ifdef NOJC
13571     return(-1);
13572 #else
13573 #ifdef SIGTSTP
13574 /*
13575   The big question here is whether job control is *really* supported.
13576   There's no way Kermit can know for sure.  The fact that SIGTSTP is
13577   defined does not guarantee the Unix kernel supports it, and the fact
13578   that the Unix kernel supports it doesn't guarantee that the user's
13579   shell (or other process that invoked Kermit) supports it.
13580 */
13581 #ifdef RTU
13582     rtu_bug = 1;
13583 #endif /* RTU */
13584     if (kill(0,SIGSTOP) < 0
13585 #ifdef MIPS
13586 /* Let's try this for MIPS too. */
13587         && kill(getpid(),SIGSTOP) < 0
13588 #endif /* MIPS */
13589         ) {                             /* If job control, suspend the job */
13590         perror("suspend");
13591         debug(F101,"psuspend error","",errno);
13592         return(-1);
13593     }
13594     debug(F100,"psuspend ok","",0);
13595     return(0);
13596 #else
13597     return(-1);
13598 #endif /* SIGTSTP */
13599 #endif /* NOJC */
13600 }
13601
13602 /*
13603   setuid package, by Kristoffer Eriksson, with contributions from Dean
13604   Long and fdc.
13605 */
13606
13607 /* The following is for SCO when CK_ANSILIBS is defined... */
13608 #ifdef M_UNIX
13609 #ifdef CK_ANSILIBS
13610 #ifndef NOGETID_PROTOS
13611 #define NOGETID_PROTOS
13612 #endif /* NOGETID_PROTOS */
13613 #endif /* CK_ANSILIBS */
13614 #endif /* M_UNIX */
13615
13616 #ifndef _POSIX_SOURCE
13617 #ifndef SUNOS4
13618 #ifndef NEXT
13619 #ifndef PS2AIX10
13620 #ifndef sequent
13621 #ifndef HPUX9
13622 #ifndef HPUX10
13623 #ifndef COHERENT
13624 #ifndef NOGETID_PROTOS
13625 _PROTOTYP( UID_T getuid, (void) );
13626 _PROTOTYP( UID_T geteuid, (void) );
13627 _PROTOTYP( UID_T getreuid, (void) );
13628 _PROTOTYP( UID_T getgid, (void) );
13629 _PROTOTYP( UID_T getegid, (void) );
13630 _PROTOTYP( UID_T getregid, (void) );
13631 #endif /* NOGETID_PROTOS */
13632 #else
13633 _PROTOTYP( UID_T getreuid, (void) );
13634 _PROTOTYP( UID_T getregid, (void) );
13635 #endif /* COHERENT */
13636 #endif /* HPUX10 */
13637 #endif /* HPUX9 */
13638 #endif /* sequent */
13639 #endif /* PS2AIX10 */
13640 #endif /* NEXT */
13641 #endif /* SUNOS4 */
13642 #endif /* _POSIX_SOURCE */
13643
13644 /*
13645 Subject: Set-user-id
13646 To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
13647 Date: Sat, 21 Apr 90 4:48:25 MES
13648 From: Kristoffer Eriksson <ske@pkmab.se>
13649
13650 This is a set of functions to be used in programs that may be run set-user-id
13651 and/or set-group-id. They handle both the case where the program is not run
13652 with such privileges (nothing special happens then), and the case where one
13653 or both of these set-id modes are used.  The program is made to run with the
13654 user's real user and group ids most of the time, except for when more
13655 privileges are needed.  Don't set-user-id to "root".
13656
13657 This works on System V and POSIX.  In BSD, it depends on the
13658 "saved-set-user-id" feature.
13659 */
13660
13661 #define UID_ROOT 0                      /* Root user and group ids */
13662 #define GID_ROOT 0
13663
13664 /*
13665   The following code defines the symbol SETEUID for UNIX systems based
13666   on BSD4.4 (either -Encumbered or -Lite).  This program will then use
13667   seteuid() and setegid() instead of setuid() and setgid(), which still
13668   don't allow arbitrary switching.  It also avoids setreuid() and
13669   setregid(), which are included in BSD4.4 for compatibility only, are
13670   insecure, and print warnings to stderr under at least one system (NetBSD
13671   1.0).  Note that POSIX systems should still use setuid() and setgid();
13672   the seteuid() and setegid() functions are BSD4.4 extensions to the
13673   POSIX model.  Mike Long <mike.long@analog.com>, 8/94.
13674 */
13675 #ifdef BSD44
13676 #define SETEUID
13677 #endif /* BSD44 */
13678
13679 /*
13680   The following construction automatically defines the symbol SETREUID for
13681   UNIX versions based on Berkeley Unix 4.2 and 4.3.  If this symbol is
13682   defined, then this program will use getreuid() and getregid() calls in
13683   preference to getuid() and getgid(), which in Berkeley-based Unixes do
13684   not allow arbitrary switching back and forth of real & effective uid.
13685   This construction also allows -DSETREUID to be put on the cc command line
13686   for any system that has and wants to use setre[ug]id().  It also prevents
13687   automatic definition of SETREUID if -DNOSETREU is included on the cc
13688   command line (or otherwise defined).
13689 */
13690 #ifdef FT18                             /* None of this for Fortune. */
13691 #define NOSETREU
13692 #endif /* FT18 */
13693
13694 #ifdef ANYBSD
13695 #ifndef BSD29
13696 #ifndef BSD41
13697 #ifndef SETREUID
13698 #ifndef NOSETREU
13699 #ifndef SETEUID
13700 #define SETREUID
13701 #endif /* SETEUID */
13702 #endif /* NOSETREU */
13703 #endif /* SETREUID */
13704 #endif /* !BSD41 */
13705 #endif /* !BSD29 */
13706 #endif /* ANYBSD */
13707
13708 /* Variables for user and group IDs. */
13709
13710 static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
13711 static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
13712
13713
13714 /* P R I V _ I N I  --  Initialize privileges package  */
13715
13716 /* Called as early as possible in a set-uid or set-gid program to store the
13717  * set-to uid and/or gid and step down to the users real uid and gid. The
13718  * stored id's can be temporarily restored (allowed in System V) during
13719  * operations that require the privilege.  Most of the time, the program
13720  * should execute in unpriviliged state, to not impose any security threat.
13721  *
13722  * Note: Don't forget that access() always uses the real id:s to determine
13723  * file access, even with privileges restored.
13724  *
13725  * Returns an error mask, with error values or:ed together:
13726  *   1 if setuid() fails,
13727  *   2 if setgid() fails, and
13728  *   4 if the program is set-user-id to "root", which can't be handled.
13729  *
13730  * Only the return value 0 indicates real success. In case of failure,
13731  * those privileges that could be reduced have been, at least, but the
13732  * program should be aborted none-the-less.
13733  *
13734  * Also note that these functions do not expect the uid or gid to change
13735  * without their knowing. It may work if it is only done temporarily, but
13736  * you're on your own.
13737  */
13738 int
13739 priv_ini() {
13740     int err = 0;
13741
13742 #ifndef HAVE_LOCKDEV
13743
13744     /* Save real ID:s. */
13745     realuid = getuid();
13746     realgid = getgid();
13747
13748     /* Save current effective ID:s, those set to at program exec. */
13749     privuid = geteuid();
13750     privgid = getegid();
13751
13752     /* If running set-uid, go down to real uid, otherwise remember that
13753      * no privileged uid is available.
13754      *
13755      * Exceptions:
13756      *
13757      * 1) If the real uid is already "root" and the set-uid uid (the
13758      * initial effective uid) is not "root", then we would have trouble
13759      * if we went "down" to "root" here, and then temporarily back to the
13760      * set-uid uid (not "root") and then again tried to become "root". I
13761      * think the "saved set-uid" is lost when changing uid from effective
13762      * uid "root", which changes all uid, not only the effective uid. But
13763      * in this situation, we can simply go to "root" and stay there all
13764      * the time. That should give sufficient privilege (understatement!),
13765      * and give the right uids for subprocesses.
13766      *
13767      * 2) If the set-uid (the initial effective uid) is "root", and we
13768      * change uid to the real uid, we can't change it back to "root" when
13769      * we need the privilege, for the same reason as in 1). Thus, we can't
13770      * handle programs that are set-user-id to "root" at all. The program
13771      * should be stopped.  Use some other uid.  "root" is probably too
13772      * privileged for such things, anyway. (The uid is reverted to the
13773      * real uid until termination.)
13774      *
13775      * These two exceptions have the effect that the "root" uid will never
13776      * be one of the two uids that are being switched between, which also
13777      * means we don't have to check for such cases in the switching
13778      * functions.
13779      *
13780      * Note that exception 1) is handled by these routines (by constantly
13781      * running with uid "root", while exception 2) is a serious error, and
13782      * is not provided for at all in the switching functions.
13783      */
13784     if (realuid == privuid)
13785         privuid = (UID_T) -1;           /* Not running set-user-id. */
13786
13787     /* If running set-gid, go down to real gid, otherwise remember that
13788      * no privileged gid is available.
13789      *
13790      * There are no exception like there is for the user id, since there
13791      * is no group id that is privileged in the manner of uid "root".
13792      * There could be equivalent problems for group changing if the
13793      * program sometimes ran with uid "root" and sometimes not, but
13794      * that is already avoided as explained above.
13795      *
13796      * Thus we can expect always to be able to switch to the "saved set-
13797      * gid" when we want, and back to the real gid again. You may also
13798      * draw the conclusion that set-gid provides for fewer hassles than
13799      * set-uid.
13800      */
13801
13802 #ifdef SUIDDEBUG
13803     fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
13804     fprintf(stderr,"realuid=%d\n",realuid);
13805     fprintf(stderr,"privuid=%d\n",privuid);
13806 #endif /* SUIDDEBUG */
13807
13808     if (realgid == privgid)             /* If not running set-user-id, */
13809       privgid = (GID_T) -1;             /*  remember it this way. */
13810
13811     err = priv_off();                   /* Turn off setuid privilege. */
13812
13813     if (privuid == UID_ROOT)            /* If setuid to root, */
13814       err |= 4;                         /* return this error. */
13815
13816     if (realuid == UID_ROOT) {          /* If real id is root, */
13817         privuid = (UID_T) -1;           /* stay root at all times. */
13818 #ifdef ATT7300
13819         /* If Kermit installed SUID uucp and user is running as root */
13820         err &= ~1;                      /* System V R0 does not save UID */
13821 #endif /* ATT7300 */
13822     }
13823 #endif /* HAVE_LOCKDEV */
13824     return(err);
13825 }
13826
13827
13828 /* Macros for hiding the differences in UID/GID setting between various Unix
13829  * systems. These macros should always be called with both the privileged ID
13830  * and the non-privileged ID. The one in the second argument, will become the
13831  * effective ID. The one in the first argument will be retained for later
13832  * retrieval.
13833  */
13834 #ifdef SETREUID
13835 #ifdef SAVEDUID
13836 /* On BSD systems with the saved-UID feature, we just juggle the effective
13837  * UID back and forth, and leave the real UID at its true value.  The kernel
13838  * allows switching to both the current real UID, the effective UID, and the
13839  * UID which the program is set-UID to.  The saved set-UID always holds the
13840  * privileged UID for us, and the real UID will always be the non-privileged,
13841  * and we can freely choose one of them for the effective UID at any time.
13842  */
13843 #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
13844 #define switchgid(hidden,active) setregid( (GID_T) -1, active)
13845
13846 #else   /* SETREUID,!SAVEDUID */
13847
13848 /* On systems with setreXid() but without the saved-UID feature, notably
13849  * BSD 4.2, we swap the real and effective UIDs each time.  It's
13850  * the effective UID that we are interested in, but we have to retain the
13851  * unused UID somewhere to enable us to restore it later, and we do this
13852  * in the real UID.  The kernel only allows switching to either the current
13853  * real or the effective UID, unless you're "root".
13854  */
13855 #define switchuid(hidden,active)        setreuid(hidden,active)
13856 #define switchgid(hidden,active)        setregid(hidden,active)
13857 #endif
13858
13859 #else /* !SETREUID, !SAVEDUID */
13860
13861 #ifdef SETEUID
13862 /*
13863   BSD 4.4 works similarly to System V and POSIX (see below), but uses
13864   seteXid() instead of setXid() to change effective IDs.  In addition, the
13865   seteXid() functions work the same for "root" as for other users.
13866 */
13867 #define switchuid(hidden,active)        seteuid(active)
13868 #define switchgid(hidden,active)        setegid(active)
13869
13870 #else /* !SETEUID */
13871
13872 /* On System V and POSIX, the only thing we can change is the effective UID
13873  * (unless the current effective UID is "root", but initsuid() avoids that for
13874  * us).  The kernel allows switching to the current real UID or to the saved
13875  * set-UID.  These are always set to the non-privileged UID and the privileged
13876  * UID, respectively, and we only change the effective UID.  This breaks if
13877  * the current effective UID is "root", though, because for "root" setuid/gid
13878  * becomes more powerful, which is why initsuid() treats "root" specially.
13879  * Note: That special treatment maybe could be ignored for BSD?  Note: For
13880  * systems that don't fit any of these four cases, we simply can't support
13881  * set-UID.
13882  */
13883 #define switchuid(hidden,active)        setuid(active)
13884 #define switchgid(hidden,active)        setgid(active)
13885
13886 #endif /* SETEUID */
13887 #endif /* SETREUID */
13888
13889
13890 /* P R I V _ O N  --  Turn on the setuid and/or setgid */
13891
13892 /* Go to the privileged uid (gid) that the program is set-user-id
13893  * (set-group-id) to, unless the program is running unprivileged.
13894  * If setuid() fails, return value will be 1. If getuid() fails it
13895  * will be 2.  Return immediately after first failure, and the function
13896  * tries to restore any partial work done.  Returns 0 on success.
13897  * Group id is changed first, since it is less serious than user id.
13898  */
13899 int
13900 priv_on() {
13901 #ifndef HAVE_LOCKDEV
13902     if (privgid != (GID_T) -1)
13903       if (switchgid(realgid,privgid))
13904         return(2);
13905
13906     if (privuid != (UID_T) -1)
13907       if (switchuid(realuid,privuid)) {
13908           if (privgid != (GID_T) -1)
13909             switchgid(privgid,realgid);
13910           return(1);
13911       }
13912 #endif /* HAVE_LOCKDEV */
13913     return(0);
13914 }
13915
13916 /* P R I V _ O F F  --  Turn on the real uid and gid */
13917
13918 /* Return to the unprivileged uid (gid) after an temporary visit to
13919  * privileged status, unless the program is running without set-user-id
13920  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
13921  * in setgid() or:ed together. The functions tries to return both uid
13922  * and gid to unprivileged state, regardless of errors. Returns 0 on
13923  * success.
13924  */
13925 int
13926 priv_off() {
13927     int err = 0;
13928 #ifndef HAVE_LOCKDEV
13929     if (privuid != (UID_T) -1)
13930        if (switchuid(privuid,realuid))
13931           err |= 1;
13932
13933     if (privgid != (GID_T) -1)
13934        if (switchgid(privgid,realgid))
13935         err |= 2;
13936 #endif /* HAVE_LOCKDEV */
13937     return(err);
13938 }
13939
13940 /* Turn off privilege permanently.  No going back.  This is necessary before
13941  * a fork() on BSD43 machines that don't save the setUID or setGID, because
13942  * we swap the real and effective ids, and we don't want to let the forked
13943  * process swap them again and get the privilege back. It will work on other
13944  * machines too, such that you can rely on its effect always being the same,
13945  * for instance, even when you're in priv_on() state when this is called.
13946  * (Well, that part about "permanent" is on System V only true if you follow
13947  * this with a call to exec(), but that's what we want it for anyway.)
13948  * Added by Dean Long -- dlong@midgard.ucsc.edu
13949  */
13950 int
13951 priv_can() {
13952 #ifndef HAVE_LOCKDEV
13953 #ifdef SETREUID
13954     int err = 0;
13955     if (privuid != (UID_T) -1)
13956        if (setreuid(realuid,realuid))
13957           err |= 1;
13958
13959     if (privgid != (GID_T) -1)
13960         if (setregid(realgid,realgid))
13961           err |= 2;
13962
13963     return(err);
13964
13965 #else
13966 #ifdef SETEUID
13967     int err = 0;
13968     if (privuid != (UID_T) -1)
13969         if (setuid(realuid)) {
13970             debug(F101,"setuid failed","",errno);
13971             err |= 1;
13972             debug(F101,"ruid","",getuid());
13973             debug(F101,"euid","",geteuid());
13974         }
13975     debug(F101,"setuid","",realuid);
13976     if (privgid != (GID_T) -1)
13977         if (setgid(realgid)) {
13978             debug(F101,"setgid failed","",errno);
13979             err |= 2;
13980             debug(F101,"rgid","",getgid());
13981             debug(F101,"egid","",getegid());
13982         }
13983     debug(F101,"setgid","",realgid);
13984     return(err);
13985 #else
13986     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
13987     return(priv_off());
13988 #endif /* SETEUID */
13989 #endif /* SETREUID */
13990 #else
13991     return(0);
13992 #endif /* HAVE_LOCKDEV */
13993 }
13994
13995 /* P R I V _ O P N  --  For opening protected files or devices. */
13996
13997 int
13998 priv_opn(name, modes) char *name; int modes; {
13999     int x;
14000     priv_on();                          /* Turn privileges on */
14001     debug(F111,"priv_opn",name,modes);
14002     errno = 0;
14003     x = open(name, modes);              /* Try to open the device */
14004     debug(F101,"priv_opn result","",x);
14005     debug(F101,"priv_opn errno","",errno);
14006     priv_off();                         /* Turn privileges off */
14007     return(x);                          /* Return open's return code */
14008 }
14009
14010 /*  P R I V _ C H K  --  Check privileges.  */
14011
14012 /*  Try to turn them off.  If turning them off did not succeed, cancel them */
14013
14014 int
14015 priv_chk() {
14016     int x, y = 0;
14017     x = priv_off();                     /* Turn off privs. */
14018     if (x != 0 || getuid() == privuid || geteuid() == privuid)
14019       y = priv_can();
14020     if (x != 0 || getgid() == privgid || getegid() == privgid)
14021       y = y | priv_can();
14022     return(y);
14023 }
14024
14025 UID_T
14026 real_uid() {
14027     return(realuid);
14028 }
14029
14030 VOID
14031 ttimoff() {                             /* Turn off any timer interrupts */
14032     /* int xx; */
14033 /*
14034   As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
14035   SIG_DFL (to catch alarms, or if there is no handler, to exit).  This is to
14036   cure (mask, really) a deeper problem with stray alarms that occurs on some
14037   systems, possibly having to do with sleep(), that caused core dumps.  It
14038   should be OK to do this, because no code in this module uses nested alarms.
14039   (But we still have to watch out for SCRIPT and DIAL...)
14040 */
14041     /* xx = */ alarm(0);
14042     /* debug(F101,"ttimoff alarm","",xx); */
14043     if (saval) {                        /* Restore any previous */
14044         signal(SIGALRM,saval);          /* alarm handler. */
14045         /* debug(F101,"ttimoff alarm restoring saval","",saval); */
14046         saval = NULL;
14047     } else {
14048         signal(SIGALRM,SIG_IGN);        /* Used to be SIG_DFL */
14049         /* debug(F100,"ttimoff alarm SIG_IGN","",0); */
14050     }
14051 }
14052
14053
14054 int
14055 tt_is_secure() {          /* Tells whether the current connection is secure */
14056
14057     if (ttyfd == -1)
14058       return(0);
14059
14060     if (0
14061 #ifdef SSHBUILTIN
14062         || IS_SSH()
14063 #endif /* SSHBUILTIN */
14064 #ifdef CK_ENCRYPTION
14065         || ck_tn_encrypting() && ck_tn_decrypting()
14066 #endif /* CK_ENCRYPTION */
14067 #ifdef CK_SSL
14068         || tls_active_flag || ssl_active_flag
14069 #endif /* CK_SSL */
14070 #ifdef RLOGCODE
14071 #ifdef CK_KERBEROS
14072 #ifdef CK_ENCRYPTION
14073         || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
14074 #endif /* CK_ENCRYPTION */
14075 #endif /* CK_KERBEROS */
14076 #endif /* RLOGCODE */
14077         )
14078       return(1);
14079     return(0);
14080 }
14081
14082 #ifdef CK_REDIR
14083   
14084 /* External protocol handler parameters from ckuus3.c */
14085 extern int exp_handler, exp_stderr, exp_timo;
14086
14087 #ifdef SELECT
14088 #ifdef NETPTY
14089
14090 /* The right size is 24576 */
14091
14092 #ifndef PTY_PBUF_SIZE                   /* Size of buffer to read from pty */
14093 #define PTY_PBUF_SIZE 24576             /* and write to net. */
14094 #endif  /* PTY_PBUF_SIZE */
14095
14096 #ifndef PTY_TBUF_SIZE                   /* Size of buffer to read from net */
14097 #define PTY_TBUF_SIZE 24576             /* and write to pty. */
14098 #endif  /* PTY_TBUF_SIZE */
14099
14100 #ifdef O_NDELAY                         /* Whether to use nonblocking */
14101 #ifndef PTY_NO_NDELAY                   /* reads on the pseudoterminal */
14102 #ifndef PTY_USE_NDELAY
14103 #define PTY_USE_NDELAY
14104 #endif  /* PTY_USE_NDELAY */
14105 #endif  /* PTY_NO_NDELAY */
14106 #endif  /* O_NDELAY */
14107
14108 #ifndef HAVE_OPENPTY
14109 #ifndef USE_CKUPTY_C
14110 #define USE_CKUPTY_C
14111 #endif /* USE_CKUPTY_C */
14112 #endif /* HAVE_OPENPTY */
14113
14114 VOID
14115 pty_make_raw(fd) int fd; {
14116     int x = -23, i;
14117
14118 #ifdef BSD44ORPOSIX                     /* POSIX */
14119     struct termios tp;
14120 #else
14121 #ifdef ATTSV                            /* AT&T UNIX */
14122 #ifdef CK_ANSIC
14123     struct termio tp = {0};
14124 #else
14125     struct termio tp;
14126 #endif  /* CK_ANSIC */
14127 #else
14128     struct sgttyb tp;                   /* Traditional */
14129 #endif /* ATTSV */
14130 #endif /* BSD44ORPOSIX */
14131
14132     debug(F101,"pty_make_raw fd","",fd);
14133     errno = 0;
14134
14135 #ifdef BSD44ORPOSIX                     /* POSIX */
14136     x = tcgetattr(fd,&tp);
14137     debug(F101,"pty_make_raw tcgetattr","",x);
14138 #else
14139 #ifdef ATTSV                            /* AT&T UNIX */
14140     x = ioctl(fd,TCGETA,&tp);
14141     debug(F101,"pty_make_raw TCGETA ioctl","",x);
14142 #else
14143     x = gtty(fd,&tp);
14144     debug(F101,"pty_make_raw ttty","",x);
14145 #endif /* ATTSV */
14146 #endif /* BSD44ORPOSIX */
14147     debug(F101,"pty_make_raw GET errno","",errno);
14148
14149 #ifdef USE_CFMAKERAW
14150     errno = 0;
14151     cfmakeraw(&tp);
14152     debug(F101,"pty_make_raw cfmakeraw errno","",errno);
14153 #else  /* USE_CFMAKERAW */
14154
14155 #ifdef COMMENT
14156
14157 /* This very simple version recommended by Serg Iakolev doesn't work */
14158
14159     tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
14160     tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
14161     tp.c_cflag &= ~(CSIZE|PARENB);
14162     tp.c_cflag |= CS8;
14163     tp.c_oflag &= ~(OPOST);
14164     tp.c_cc[VMIN] = 1;
14165     tp.c_cc[VTIME] = 0;
14166
14167     debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS);
14168     debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag);
14169     debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag);
14170     debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag);
14171     debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag);
14172
14173 #else
14174 #ifdef COMMENT
14175 /*
14176   In this version we unset everything and then set only the
14177   bits we know we need.
14178 */
14179     /* iflags */
14180     tp.c_iflag = 0L;
14181     tp.c_iflag |= IGNBRK;
14182 #ifdef IMAXBEL
14183     tp.c_iflag |= IMAXBEL;
14184 #endif /* IMAXBEL */
14185
14186     /* oflags */
14187     tp.c_oflag = 0L;
14188
14189     /* lflags */
14190     tp.c_lflag = 0L;
14191 #ifdef NOKERNINFO
14192     tp.c_lflag |= NOKERNINFO;
14193 #endif  /* NOKERNINFO */
14194
14195     /* cflags */
14196     tp.c_cflag = 0L;
14197     tp.c_cflag |= CS8|CREAD;
14198
14199     for (i = 0; i < NCCS; i++) {        /* No special characters */
14200         tp.c_cc[i] = 0;
14201     }
14202 #ifdef VMIN
14203     tp.c_cc[VMIN] = 1;                  /* But always wait for input */
14204 #endif  /* VMIN */
14205     debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS);
14206     debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag);
14207     debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag);
14208     debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag);
14209     debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag);
14210
14211 #else  /* COMMENT */
14212 /*
14213   In this version we set or unset every single flag explicitly.  It works a
14214   bit better than the simple version just above, but it's still far from
14215   adequate.
14216 */
14217     /* iflags */
14218     tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
14219     tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF);
14220     tp.c_iflag |= IGNBRK;
14221 #ifdef IMAXBEL
14222 #ifdef COMMENT
14223     tp.c_iflag |= IMAXBEL;
14224 #else
14225     tp.c_iflag &= ~IMAXBEL;
14226 #endif /* COMMENT */
14227 #endif /* IMAXBEL */
14228 #ifdef IUCLC
14229     tp.c_iflag &= ~IUCLC;
14230 #endif /* IUCLC */
14231
14232     /* oflags */
14233 #ifdef BSDLY
14234     tp.c_oflag &= ~BSDLY;
14235 #endif /* BSDLY */
14236 #ifdef CRDLY
14237     tp.c_oflag &= ~CRDLY;
14238 #endif /* CRDLY */
14239 #ifdef FFDLY
14240     tp.c_oflag &= ~FFDLY;
14241 #endif /* FFDLY */
14242 #ifdef NLDLY
14243     tp.c_oflag &= ~NLDLY;
14244 #endif /* NLDLY */
14245 #ifdef TABDLY
14246     tp.c_oflag &= ~TABDLY;
14247 #endif /* TABDLY */
14248 #ifdef VTDLY
14249     tp.c_oflag &= ~VTDLY;
14250 #endif /* VTDLY */
14251 #ifdef OFDEL
14252     tp.c_oflag &= ~OFDEL;
14253 #endif /* OFDEL */
14254 #ifdef OFILL
14255     tp.c_oflag &= ~OFILL;
14256 #endif /* OFILL */
14257 #ifdef OLCUC
14258     tp.c_oflag &= ~OLCUC;
14259 #endif /* OLCUC */
14260 #ifdef CMSPAR
14261     tp.c_oflag &= ~CMSPAR;
14262 #endif /* CMSPAR */
14263     tp.c_oflag &= ~OPOST;
14264 #ifdef OXTABS
14265     tp.c_oflag &= ~OXTABS;
14266 #endif /* OXTABS */
14267 #ifdef COMMENT
14268 #ifdef ONOCR
14269     tp.c_oflag &= ~ONOCR;               /* Maybe should be |=? */
14270     tp.c_oflag |= ONOCR;                /* makes no difference either way */
14271 #endif /* ONOCR */
14272 #endif /* COMMENT */
14273 #ifdef ONOEOT
14274     tp.c_oflag &= ~ONOEOT;
14275 #endif /* ONOEOT */
14276 #ifdef ONLRET
14277     tp.c_oflag &= ~ONLRET;
14278 #endif /* ONLRET */
14279 #ifdef ONLCR
14280     tp.c_oflag &= ~ONLCR;
14281 #endif /* ONLCR */
14282 #ifdef OCRNL
14283     tp.c_oflag &= ~OCRNL;
14284 #endif /* OCRNL */
14285
14286     /* lflags */
14287     tp.c_lflag &= ~ECHO;
14288 #ifdef ECHOE
14289     tp.c_lflag &= ~ECHOE;
14290 #endif /* ECHOE */
14291 #ifdef ECHONL
14292     tp.c_lflag &= ~ECHONL;
14293 #endif /* ECHONL */
14294 #ifdef ECHOPRT
14295     tp.c_lflag &= ~ECHOPRT;
14296 #endif /* ECHOPRT */
14297 #ifdef ECHOKE
14298     tp.c_lflag &= ~ECHOKE;
14299 #endif /* ECHOKE */
14300 #ifdef ECHOCTL
14301     tp.c_lflag &= ~ECHOCTL;
14302 #endif /* ECHOCTL */
14303 #ifdef XCASE
14304     tp.c_lflag &= ~XCASE;
14305 #endif /* XCASE */
14306 #ifdef ALTWERASE
14307     tp.c_lflag &= ~ALTWERASE;
14308 #endif /* ALTWERASE */
14309 #ifdef EXTPROC
14310     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC);
14311 #else
14312     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
14313 #endif  /* EXTPROC */
14314 #ifdef NOKERNINFO
14315     tp.c_lflag |= NOKERNINFO;
14316 #endif  /* NOKERNINFO */
14317 #ifndef COMMENT
14318     tp.c_lflag &= ~NOFLSH;              /* TRY IT THE OTHER WAY? */
14319 #else
14320     tp.c_lflag |= NOFLSH;               /* No, this way is worse */
14321 #endif /* COMMENT */
14322
14323     /* cflags */
14324     tp.c_cflag &= ~(CSIZE|PARENB|PARODD);
14325     tp.c_cflag |= CS8|CREAD;
14326
14327 #ifdef MDMBUF
14328     tp.c_cflag &= ~(MDMBUF);
14329 #else
14330 #ifdef CCAR_OFLOW
14331     tp.c_cflag &= ~(CCAR_OFLOW);        /* two names for the same thing */
14332 #endif /* CCAR_OFLOW */
14333 #endif /* MDMBUF */
14334
14335 #ifdef CCTS_OFLOW
14336     tp.c_cflag &= ~(CCTS_OFLOW);
14337 #endif /* CCTS_OFLOW */
14338 #ifdef CDSR_OFLOW
14339     tp.c_cflag &= ~(CDSR_OFLOW);
14340 #endif /* CDSR_OFLOW */
14341 #ifdef CDTR_IFLOW
14342     tp.c_cflag &= ~(CDTR_IFLOW);
14343 #endif /* CDTR_IFLOW */
14344 #ifdef CRTS_IFLOW
14345     tp.c_cflag &= ~(CRTS_IFLOW);
14346 #endif /* CRTS_IFLOW */
14347 #ifdef CRTSXOFF
14348     tp.c_cflag &= ~(CRTSXOFF);
14349 #endif /* CRTSXOFF */
14350 #ifdef CRTSCTS
14351     tp.c_cflag &= ~(CRTSCTS);
14352 #endif /* CRTSCTS */
14353 #ifdef CLOCAL
14354     tp.c_cflag &= ~(CLOCAL);
14355 #endif /* CLOCAL */
14356 #ifdef CSTOPB
14357     tp.c_cflag &= ~(CSTOPB);
14358 #endif /* CSTOPB */
14359 #ifdef HUPCL
14360     tp.c_cflag &= ~(HUPCL);
14361 #endif /* HUPCL */
14362
14363     for (i = 0; i < NCCS; i++) {        /* No special characters */
14364         tp.c_cc[i] = 0;
14365     }
14366 #ifdef VMIN
14367     tp.c_cc[VMIN] = 1;                  /* But always wait for input */
14368 #endif  /* VMIN */
14369     debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS);
14370     debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag);
14371     debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag);
14372     debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag);
14373     debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag);
14374 #endif /* COMMENT */
14375 #endif /* COMMENT */
14376
14377     errno = 0;
14378 #ifdef BSD44ORPOSIX                     /* POSIX */
14379     x = tcsetattr(fd,TCSANOW,&tp);
14380     debug(F101,"pty_make_raw tcsetattr","",x);
14381 #else
14382 #ifdef ATTSV                            /* AT&T UNIX */
14383     x = ioctl(fd,TCSETA,&tp);
14384     debug(F101,"pty_make_raw ioctl","",x);
14385 #else
14386     x = stty(fd,&tp);                   /* Traditional */
14387     debug(F101,"pty_make_raw stty","",x);
14388 #endif /* ATTSV */
14389 #endif /* BSD44ORPOSIX */
14390     debug(F101,"pty_make_raw errno","",errno);
14391
14392 #endif /* __NetBSD__ */
14393 }
14394
14395 static int
14396 pty_chk(fd) int fd; {
14397     int x, n = 0;
14398     errno = 0;
14399 #ifdef FIONREAD
14400     x = ioctl(fd, FIONREAD, &n);        /* BSD and most others */
14401     ckmakmsg(msgbuf,500,
14402              "pty_chk ioctl FIONREAD errno=",
14403              ckitoa(errno),
14404              " count=",
14405              ckitoa(n));
14406     debug(F100,msgbuf,"",0);
14407 #else
14408 #ifdef RDCHK
14409     n = rdchk(fd);
14410     debug(F101,"pty_chk rdchk","",n);
14411 #else
14412     n = 1;
14413 #endif  /* RDCHK */
14414 #endif  /* FIONREAD */
14415     return((n > -1) ? n : 0);
14416 }
14417
14418 static int
14419 pty_get_status(fd,pid) int fd; PID_T pid; {
14420     int x, status = -1;
14421     PID_T w;
14422
14423     debug(F101,"pty_get_status fd","",fd);
14424     debug(F101,"pty_get_status pid","",pid);
14425
14426     if (pexitstat > -1)
14427       return(pexitstat);
14428
14429 #ifdef COMMENT
14430     /* Not only unnecessary but harmful */
14431     errno = 0;
14432     x = kill(pty_fork_pid,0);
14433     debug(F101,"pty_get_status kill value","",x);
14434     debug(F101,"pty_get_status kill errno","",errno);
14435     if (x > -1 && errno != ESRCH)
14436       return(-1);                       /* Fork still there */
14437     /* Fork seems to be gone */
14438 #endif  /* COMMENT */
14439
14440     errno = 0;
14441     x = waitpid(pty_fork_pid,&status,WNOHANG);
14442     debug(F111,"pty_get_status waitpid",ckitoa(errno),x);
14443     if (x <= 0 && errno == 0) {
14444         debug(F101,"pty_get_status waitpid return","",-1);
14445         return(-1);
14446     }
14447     if (x > 0) {
14448         if (x != pty_fork_pid)
14449           debug(F101,
14450                 "pty_get_status waitpid pid doesn't match","",pty_fork_pid); 
14451         debug(F101,"pty_get_status waitpid status","",status);
14452         debug(F101,"pty_get_status waitpid errno","",errno);
14453         if (WIFEXITED(status)) {
14454             debug(F100,"pty_get_status WIFEXITED","",0);
14455             status = WEXITSTATUS(status);
14456             debug(F101,"pty_get_status fork exit status","",status);
14457 #ifdef COMMENT
14458             end_pty();
14459 #endif  /* COMMENT */
14460             close(fd);
14461             pexitstat = status;
14462         } else {
14463             debug(F100,"pty_get_status waitpid unexpected status","",0);
14464         }
14465     }
14466     debug(F101,"pty_get_status return status","",status);
14467     return(status);
14468 }
14469
14470 /* t t p t y c m d  --  Run command on pty and forward to net */
14471
14472 /*
14473   Needed for running external protocols on secure connections.
14474   For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet
14475   connection, and then needs to transfer a file with Zmodem, which is
14476   an external program, this routine reads Zmodem's output, encrypts it,
14477   and then forwards it out the connection, and reads the encrypted data
14478   stream coming in from the connection, decrypts it, and forwards it to
14479   Zmodem.
14480
14481   Works like a TCP/IP port forwarder except one end is a pty rather
14482   than a socket, which introduces some complications:
14483
14484    . On most platforms, select() always indicates the output side of
14485      the pty has characters waiting to be read, even when it doesn't,
14486      even when the pty process has already exited.
14487
14488    . Nonblocking reads must be used on the pty, because there is no
14489      way on certain platforms (e.g. NetBSD) to find out how many characters
14490      are available to be read (the FIONREAD ioctl always says 0).  The code
14491      also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not
14492      defined, or if PTY_NO_NDELAY is defined), but on some platforms this can
14493      result in single-byte reads and writes (NetBSD again).
14494
14495    . Testing for "EOF" on the pty is problematic.  select() never gives
14496      any indication.  After the pty process has exited and the fork has
14497      disappeared, read() can still return with 0 bytes read but without an
14498      error (NetBSD); no known test on the pty file descriptor will indicate
14499      that it is no longer valid.  The process ID of the pty fork can be
14500      tested on some platforms (NetBSD, luckily) but not others (Solaris,
14501      Linux).
14502
14503   On the network side, we use ttinc() and ttoc(), which, for network 
14504   connections, handle any active security methods.
14505
14506   Call with s = command.
14507   Returns 0 on failure, 1 on success.
14508   fdc - December 2006 - August 2007.
14509
14510   NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are
14511   defined in the header files, which should be true of every recent Unix
14512   platform.  If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when
14513   building C-Kermit:
14514
14515     touch ckutio.c
14516     make platformname KFLAGS=-DPTY_NO_NODELAY
14517 */
14518 static int have_pty = 0;                /* Do we have a pty? */
14519
14520 static SIGTYP (*save_sigchld)() = NULL; /* For catching SIGCHLD */
14521
14522 static VOID
14523 sigchld_handler(sig) int sig; {
14524     have_pty = 0;                       /* We don't have a pty */
14525 #ifdef DEBUG
14526     if (save_sigchld) {
14527         (VOID) signal(SIGCHLD,save_sigchld);
14528         save_sigchld = NULL;
14529     }
14530     if (deblog) {
14531         debug(F100,"**************","",0);
14532         debug(F100,"SIGCHLD caught","",0);
14533         debug(F100,"**************","",0);
14534     }
14535 #endif  /* DEBUG */
14536 }
14537 #define HAVE_IAC 1
14538 #define HAVE_CR  2
14539
14540 int
14541 ttptycmd(s) char *s; {
14542     CHAR tbuf[PTY_TBUF_SIZE];           /* Read from net, write to pty */
14543     int tbuf_avail = 0;                 /* Pointers for tbuf */
14544     int tbuf_written = 0;
14545     static int in_state = 0;            /* For TELNET IAC and NVT in */
14546     static int out_prev = 0;            /* Simpler scheme for out */
14547
14548     CHAR pbuf[PTY_PBUF_SIZE];           /* Read from pty, write to net */
14549     CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */
14550     int pbuf_avail = 0;                 /* Pointers for pbuf */
14551     int pbuf_written = 0;
14552
14553     int ptyfd = -1;                     /* Pty file descriptor */
14554     int have_net = 0;                   /* We have a network connection */
14555     int pty_err = 0;                    /* Got error on pty */
14556     int net_err = 0;                    /* Got error on net */
14557     int status = -1;                    /* Pty process exit status */
14558     int rc = 0;                         /* Our return code */
14559
14560     int x1 = 0, x2 = 0;                 /* Workers... */
14561     int c, n, m, t, x;                  /* Workers */
14562
14563     long seconds_to_wait = 0L;          /* select() timeout */
14564     struct timeval tv, *tv2;            /* For select() */
14565 #ifdef INTSELECT
14566     int in, out, err;                   /* For select() */
14567 #else
14568     fd_set in, out, err;
14569 #endif /* INTSELECT */
14570     int nfds = 0;                       /* For select() */
14571
14572     int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */
14573     int read_net_bytes = 0;             /* Stats */
14574     int write_net_bytes = 0;            /* Stats */
14575     int read_pty_bytes = 0;             /* Stats */
14576     int write_pty_bytes = 0;            /* Stats */
14577     int is_tn = 0;                      /* TELNET protocol is active */
14578
14579     int masterfd = -1;
14580     int slavefd = -1;
14581 #ifndef USE_CKUPTY_C
14582     struct termios term;
14583     struct winsize twin;
14584     struct stringarray * q;
14585     char ** args = NULL;
14586 #endif /* USE_CKUPTY_C */
14587
14588     in_state = 0;                       /* No previous character yet */
14589
14590     if (ttyfd == -1) {
14591         printf("?Sorry, communication channel is not open\n");
14592         return(0);
14593     } else {
14594         have_net = 1;
14595     }
14596     if (nopush) {
14597         debug(F100,"ttptycmd fail: nopush","",0);
14598         return(0);
14599     }
14600     if (!s) s = "";                     /* Defense de bogus arguments */
14601     if (!*s) return(0);
14602     pexitstat = -1;                     /* Fork process exit status */
14603
14604 #ifdef TNCODE
14605     is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */
14606             (!xlocal && sstelnet);
14607 #endif /* TNCODE */
14608
14609     debug(F110,"ttptycmd command",s,0);
14610     debug(F101,"ttptycmd ttyfd","",ttyfd);
14611     debug(F101,"ttptycmd is_tn","",is_tn);
14612     debug(F101,"ttptycmd ckermit pid","",getpid());
14613
14614 #ifdef USE_CKUPTY_C
14615     /* Call ckupty.c module to get and set up the pty fork */
14616     /* fc 1 == "run an external protocol" */
14617     debug(F100,"ttptycmd using ckupty.c","",0);
14618     if (do_pty(&ptyfd,s,1) < 0) {       /* Start the command on a pty */
14619         debug(F100,"ttptycmd do_pty fails","",0);
14620         return(0);
14621     }
14622     masterfd = ptyfd;
14623     pty_master_fd = ptyfd;
14624 #ifdef COMMENT
14625     slavefd = pty_slave_fd;             /* This is not visible to us */
14626 #endif /* COMMENT */
14627     debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd);
14628     debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd);
14629     debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid);
14630 #ifndef SOLARIS
14631     /* "ioctl inappropriate on device" for pty master */
14632     pty_make_raw(masterfd);
14633 #endif /* SOLARIS */
14634
14635 #else /* USE_CKUPTY_C */
14636
14637     debug(F100,"ttptycmd OPENPTY","",0);
14638     if (tcgetattr(0, &term) == -1) {    /* Get controlling terminal's modes */
14639         perror("tcgetattr");
14640         return(0);
14641     }
14642     if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */
14643         perror("ioctl TIOCGWINSZ");
14644         return(0);
14645     }
14646     if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) {
14647         debug(F101,"ttptycmd openpty failed errno","",errno);
14648         perror("opentpy");
14649         return(0);
14650     }
14651     debug(F101,"ttptycmd openpty masterfd","",masterfd);
14652     debug(F101,"ttptycmd openpty slavefd","",slavefd);
14653     pty_master_fd = masterfd;
14654     pty_slave_fd = slavefd;
14655     debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd);
14656
14657     /* Put pty master in raw mode but let forked app control the slave */
14658     pty_make_raw(masterfd);
14659
14660 #ifdef COMMENT
14661 #ifdef TIOCREMOTE
14662     /* TIOCREMOTE,0 = disable all termio processing */
14663     x = ioctl(masterfd, TIOCREMOTE, 1);
14664     debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno);
14665 #endif  /* TIOCREMOTE */
14666 #ifdef TIOCTTY
14667     /* TIOCTTY,0 = disable all termio processing */
14668     x = ioctl(masterfd, TIOCTTY, 0);
14669     debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno);
14670 #endif  /* TIOCTTY */
14671 #endif /* COMMENT */
14672
14673     have_pty = 1;                       /* We have an open pty */
14674     save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */
14675
14676     pty_fork_pid = fork();              /* Make fork for external protocol */
14677     debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid);
14678     if (pty_fork_pid == -1) {
14679         perror("fork");
14680         return(0);
14681     } else if (pty_fork_pid == 0) {     /* In new fork */
14682         int x;
14683         debug(F101,"ttptycmd new fork pid","",getpid());
14684         close(masterfd);                /* Slave quarters no masters allowed */
14685         x = setsid();
14686         debug(F101,"ttptycmd new fork setsid","",x);
14687         if (x == -1) {
14688             perror("ttptycmd setsid");
14689             exit(1);
14690         }
14691         signal(SIGINT,SIG_IGN);         /* Let upper fork catch this */
14692         
14693 #ifdef COMMENT
14694 #ifdef TIOCSCTTY
14695         /* Make pty the controlling terminal for the process */
14696         /* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */
14697         x = ioctl(slavefd, TIOCSCTTY, NULL);
14698         debug(F101,"ttptycmd TIOCSCTTY","",x);
14699 #endif  /* TIOCSCTTY */
14700 #endif  /* COMMENT */
14701
14702         /* Initialize slave pty modes and size to those of our terminal */
14703         if (tcsetattr(slavefd, TCSANOW, &term) == -1) {
14704             perror("ttptycmd tcsetattr");
14705             exit(1);
14706         }
14707         if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) {
14708             perror("ttptycmd ioctl");
14709             exit(1);
14710         }
14711 #ifdef COMMENT
14712 #ifdef TIOCNOTTY
14713         /* Disassociate this process from its terminal */
14714         /* THIS HAS NO EFFECT */
14715         x = ioctl(slavefd, TIOCNOTTY, NULL);
14716         debug(F101,"ttptycmd TIOCNOTTY","",x);
14717 #endif  /* TIOCNOTTY */
14718 #endif  /* COMMENT */
14719
14720 #ifdef COMMENT
14721 #ifdef SIGTTOU  
14722         /* Ignore terminal output interrupts */
14723         /* THIS HAS NO EFFECT */
14724         debug(F100,"ttptycmd ignoring SIGTTOU","",0);
14725         signal(SIGTTOU, SIG_IGN);
14726 #endif  /* SIGTTOU */
14727 #ifdef SIGTSTP  
14728         /* Ignore terminal output interrupts */
14729         /* THIS HAS NO EFFECT */
14730         debug(F100,"ttptycmd ignoring SIGTSTP","",0);
14731         signal(SIGTSTP, SIG_IGN);
14732 #endif  /* SIGTSTP */
14733 #endif  /* COMMENT */
14734
14735         pty_make_raw(slavefd);          /* Put it in rawmode */
14736
14737         errno = 0;
14738         if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO ||
14739             dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) {
14740             debug(F101,"ttptycmd new fork dup2 error","",errno);
14741             perror("ttptycmd dup2");
14742             exit(1);
14743         }
14744         debug(F100,"ttptycmd new fork dup2 ok","",0);
14745
14746         /* Parse external protocol command line */
14747         q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
14748         if (!q) {
14749             debug(F100,"ttptycmd cksplit failed","",0);
14750             exit(1);
14751         } else {
14752             int i, n;
14753             debug(F100,"ttptycmd cksplit ok","",0);
14754             n = q->a_size;
14755             args = q->a_head + 1;
14756             for (i = 0; i <= n; i++) {
14757                 if (!args[i]) {
14758                     break;
14759                 } else {
14760                     /* sometimes cksplit() doesn't terminate the list */
14761                     if ((i == n) && args[i]) {
14762                         if ((int)strlen(args[i]) == 0)
14763                           makestr(&(args[i]),NULL);
14764                     }
14765                 }
14766             }       
14767         }
14768 #ifdef COMMENT
14769 /*
14770   Putting the slave pty in rawmode should not be necessary because the
14771   external protocol program is supposed to do that itself.  Yet doing this
14772   here cuts down on Zmodem binary-file transmission errors by 30-50% but
14773   still doesn't eliminate them.
14774 */
14775         pty_make_raw(STDIN_FILENO);
14776         pty_make_raw(STDOUT_FILENO);
14777 #endif /* COMMENT */
14778
14779         debug(F100,"ttptycmd execvp'ing external protocol","",0);
14780         execvp(args[0],args);
14781         perror("execvp failed");
14782         debug(F101,"ttptycmd execvp failed","",errno);
14783         close(slavefd);
14784         exit(1);
14785     } 
14786     /* (there are better ways to do this...) */
14787     msleep(1000);                 /* Make parent wait for child to be ready */
14788     ptyfd = masterfd;                   /* We talk to the master */
14789
14790 #endif /* USE_CKUPTY_C */
14791
14792     debug(F101,"ttptycmd ptyfd","",ptyfd);
14793     if (ptyfd < 0) {
14794         printf("?Failure to get pty\n");
14795         return(-9);
14796     }
14797     have_pty = 1;             /* We have an open pty or we wouldn't he here */
14798
14799     debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE);
14800     debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE);
14801
14802 #ifdef PTY_USE_NDELAY
14803     /* 
14804        NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications
14805        on the pty, we don't need nonblocking reads.  Performance of either
14806        method seems to be about the same, so use whatever works.
14807     */
14808     errno = 0;
14809     x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY);
14810     ckmakmsg(msgbuf,500,
14811              "ttptycmd set O_NDELAY errno=",
14812              ckitoa(errno),
14813              " fcntl=",
14814              ckitoa(x));
14815     debug(F100,msgbuf,"",0);
14816 #endif /* PTY_USE_NDELAY */
14817
14818 #ifdef COMMENT
14819 /* Not necessary, the protocol module already did this */
14820
14821 #ifdef USE_CFMAKERAW
14822     if (tcgetattr(ttyfd, &term) > -1) {
14823         cfmakeraw(&term);
14824         debug(F101,"ttptycmd net cfmakeraw errno","",errno);
14825         x tcsetattr(ttyfd, TCSANOW, &term);
14826         debug(F101,"ttptycmd net tcsetattr","",x);
14827         debug(F101,"ttptycmd net tcsetattr","",errno);
14828     }
14829 #else
14830     if (local)                          /* Put network connection in */
14831       ttpkt(ttspeed,ttflow,ttprty);     /* "packet mode". */
14832     else
14833       conbin((char)escchr);             /* OR... pty_make_raw(0) */
14834 #endif /* USE_CFMAKERAW */
14835 #endif /* COMMENT */
14836
14837 #ifdef TNCODE
14838     if (is_tn) {
14839       debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY));
14840       debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY));
14841     }
14842 #endif /* TNCODE */
14843
14844     debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait);
14845
14846     while (have_pty || have_net) {
14847         FD_ZERO(&in);                   /* Initialize select() structs */
14848         FD_ZERO(&out);
14849         FD_ZERO(&err);                  /* (not used because useless) */
14850         nfds = -1;
14851
14852         debug(F101,"ttptycmd loop top have_pty","",have_pty);
14853         debug(F101,"ttptycmd loop top have_net","",have_net);
14854
14855         /* Pty is open and we have room to read from it? */
14856         if (have_pty && pbuf_avail < PTY_PBUF_SIZE) {
14857             debug(F100,"ttptycmd FD_SET ptyfd in","",0);
14858             FD_SET(ptyfd, &in);
14859             nfds = ptyfd;
14860         }
14861         /* Network is open and we have room to read from it? */
14862         if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) {
14863             debug(F100,"ttptycmd FD_SET ttyfd in","",0);
14864             FD_SET(ttyfd, &in);
14865             if (ttyfd > nfds) nfds = ttyfd;
14866         }
14867         /* Pty is open and we have stuff to write to it? */
14868         if (have_pty && tbuf_avail - tbuf_written > 0) {
14869             debug(F100,"ttptycmd FD_SET ptyfd out","",0);
14870             FD_SET (ptyfd, &out);
14871             if (ptyfd > nfds) nfds = ptyfd;
14872         }
14873         /* Net is open and we have stuff to write to it? */
14874         debug(F101,"ttptycmd pbuf_avail-pbuf_written","",
14875               pbuf_avail - pbuf_written);
14876         if (have_net && pbuf_avail - pbuf_written > 0) {
14877             debug(F100,"ttptycmd FD_SET ttyfd out","",0);
14878             FD_SET (ttyfd, &out);
14879             if (ttyfd > nfds) nfds = ttyfd;
14880         }
14881         /* We don't use err because it's not really for errors, */
14882         /* but for out of band data on the TCP socket, which, if it is */
14883         /* to be handled at all, is handled in the tt*() routines */
14884
14885         nfds++;                         /* 0-based to 1-based */
14886         debug(F101,"ttptycmd nfds","",nfds);
14887         if (!nfds) {
14888             debug(F100,"ttptycmd NO FDs set for select","",0);
14889             if (have_pty) {
14890                 /* This is not right -- sleeping won't accomplish anything */
14891                 debug(F101,"ttptycmd msleep","",100);
14892                 msleep(100);        
14893             } else {
14894                 debug(F100,"ttptycmd no pty - quitting loop","",0);
14895                 break;
14896             }
14897         }
14898         errno = 0;
14899
14900         if (seconds_to_wait > 0L) {     /* Timeout in case nothing happens */
14901             tv.tv_sec = seconds_to_wait; /* for a long time */
14902             tv.tv_usec = 0L;            
14903             tv2 = &tv;
14904         } else {
14905             tv2 = NULL;
14906         }
14907         x = select(nfds, &in, &out, NULL, tv2);
14908         debug(F101,"ttptycmd select","",x);
14909         if (x < 0) {
14910             if (errno == EINTR)
14911               continue;
14912             debug(F101,"ttptycmd select error","",errno);
14913             break;
14914         }
14915         if (x == 0) {
14916             debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait); 
14917             if (have_pty) {
14918                 status = pty_get_status(ptyfd,pty_fork_pid);
14919                 debug(F101,"ttptycmd pty_get_status A","",status);
14920                 if (status > -1) pexitstat = status;
14921                 have_pty = 0;
14922             }
14923             break;
14924         }
14925         /* We want to handle any pending writes first to make room */
14926         /* for new incoming. */
14927
14928         if (FD_ISSET(ttyfd, &out)) {    /* Can write to net? */
14929             CHAR * s;
14930             s = pbuf + pbuf_written;    /* Current spot for sending */
14931 #ifdef TNCODE
14932             if (is_tn) {                /* ttol() doesn't double IACs */
14933                 CHAR c;                 /* Rewrite string with IACs doubled */
14934                 int i;
14935                 s = pbuf + pbuf_written; /* Source */
14936                 x = 0;                   /* Count */
14937                 for (i = 0; i < pbuf_avail - pbuf_written; i++) {
14938                     c = s[i];           /* Next character */
14939                     if (c == IAC) {     /* If it's IAC */
14940                         dbuf[x++] = c;  /* put another one */
14941                         debug(F000,">>> QUOTED IAC","",c);
14942                     } else if (c != 0x0a && out_prev == 0x0d) { /* Bare CR */
14943                         if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */
14944                             c = 0x00;
14945                             dbuf[x++] = c;
14946                             debug(F000,">>> CR-NUL","",c);
14947                         }                       
14948                     }
14949                     dbuf[x++] = c;      /* Copy and count it */
14950                     debug(F000,">>> char",ckitoa(in_state),c);
14951                     out_prev = c;
14952                 }
14953                 s = dbuf;               /* New source */
14954             } else
14955 #endif /* TNCODE */
14956               x = pbuf_avail - pbuf_written; /* How much to send */
14957
14958             debug(F101,"ttptycmd bytes to send","",x);
14959             x = ttol(s, x);
14960             debug(F101,">>> ttol","",x);
14961             if (x < 0) {
14962                 net_err++;
14963                 debug(F111,"ttptycmd ttol error",ckitoa(x),errno);
14964                 x = 0;
14965             }
14966             write_net_bytes += x;
14967             pbuf_written += x;
14968         }
14969         if (FD_ISSET(ptyfd, &out)) {    /* Can write to pty? */
14970             debug(F100,"ttptycmd FD_ISSET ptyfd out","",0);
14971             errno = 0;
14972 #ifndef COMMENT
14973             x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written);
14974 #else
14975             /* Byte loop to rule out data overruns in the pty */
14976             /* (it makes no difference) */
14977             {
14978                 char *p = tbuf+tbuf_written;
14979                 int n = tbuf_avail - tbuf_written;
14980                 for (x = 0; x < n; x++) {
14981                     msleep(10);
14982                     if (write(ptyfd,&(p[x]),1) < 0)
14983                       break;
14984                 }
14985             }
14986 #endif /* COMMENT */
14987             debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x);
14988             if (x > 0) {
14989                 tbuf_written += x;
14990                 write_pty_bytes += x;
14991             } else {
14992                 x = 0;
14993                 pty_err++;
14994                 if (pexitstat < 0) {
14995                     status = pty_get_status(ptyfd,pty_fork_pid);
14996                     debug(F101,"ttptycmd pty_get_status B","",status);
14997                     if (status > -1) pexitstat = status;
14998                     have_pty = 0;
14999                 }
15000                 debug(F100,"ttptycmd +++ ptyfd write error","",0);
15001             }
15002         }
15003         if (FD_ISSET(ttyfd, &in)) {     /* Can read from net? */
15004             tset++;
15005             debug(F100,"ttptycmd FD_ISSET ttyfd in","",0);
15006             n = in_chk(1,ttyfd);
15007             debug(F101,"ttptycmd in_chk(ttyfd)","",n); 
15008             if (n < 0 || ttyfd == -1) {
15009                 debug(F101,"ttptycmd +++ ttyfd errno","",errno);
15010                 net_err++;
15011             } else if (n > 0) {
15012                 if (n > PTY_TBUF_SIZE - tbuf_avail)
15013                   n = PTY_TBUF_SIZE - tbuf_avail;
15014                 debug(F101,"ttptycmd net read size adjusted","",n); 
15015                 if (xlocal && netconn) {
15016                     /*
15017                       We have to use a byte loop here because ttxin()
15018                       does not decrypt or, for that matter, handle Telnet.
15019                     */
15020                     int c;
15021                     CHAR * p;
15022                     p = tbuf + tbuf_avail;
15023                     for (x = 0; x < n; x++) {
15024                         if ((c = ttinc(0)) < 0)
15025                           break;
15026                         if (!is_tn) {   /* Not Telnet - keep all bytes */
15027                             *p++ = (CHAR)c;
15028                             debug(F000,"<<< char","",c);
15029 #ifdef TNCODE
15030                         } else {        /* Telnet - must handle IAC and NVT */
15031                             debug(F000,"<<< char",ckitoa(in_state),c);
15032                             switch (c) {
15033                               case 0x00: /* NUL */
15034                                 if (in_state == HAVE_CR) {
15035                                     debug(F000,"<<< SKIP","",c);
15036                                 } else {
15037                                     *p++ = c;
15038                                     debug(F000,"<<< Keep","",c);
15039                                 }
15040                                 in_state = 0;
15041                                 break;
15042                               case 0x0d: /* CR */
15043                                 if (!TELOPT_U(TELOPT_BINARY))
15044                                   in_state = HAVE_CR;
15045                                 *p++ = c;
15046                                 debug(F000,"<<< Keep","",c);
15047                                 break;
15048 #ifdef COMMENT
15049                               case 0x0f: /* Ctrl-O */
15050                               case 0x16: /* Ctrl-V */
15051                                 *p++ = 0x16;
15052                                 *p++ = c;
15053                                 debug(F000,"<<< QUOT","",c);
15054                                 break;
15055 #endif /* COMMENT */
15056                               case 0xff: /* IAC */
15057                                 if (in_state == HAVE_IAC) {
15058                                     debug(F000,"<<< KEEP","",c);
15059                                     *p++ = c;
15060                                     in_state = 0;
15061                                 } else {
15062                                     debug(F000,"<<< SKIP","",c);
15063                                     in_state = HAVE_IAC;
15064                                 }
15065                                 break;
15066                               default:  /* All others */
15067                                 if (in_state == HAVE_IAC) {
15068 #ifdef COMMENT
15069 /*
15070   tn_doop() will consume an unknown number of bytes and we'll overshoot
15071   the for-loop.  The only Telnet command I've ever seen arrive here is
15072   a Data Mark, which comes when the remote protocol exits and the remote
15073   job returns to its shell prompt.  On the assumption it's a 1-byte command,
15074   we don't write out the IAC or the command, and we clear the state.  If
15075   we called tn_doop() we'd have no way of knowing how many bytes it took
15076   from the input stream.
15077 */
15078                                     int xx;
15079                                     xx = tn_doop((CHAR)c,duplex,ttinc);
15080                                     debug(F111,"<<< DOOP",ckctoa(c),xx);
15081 #else
15082                                     debug(F101,"<<< DOOP","",c);
15083 #endif  /* COMMENT */
15084                                     in_state = 0;
15085                                 } else {
15086                                     *p++ = c;
15087                                     debug(F000,"<<< keep","",c);
15088                                     in_state = 0;
15089                                 }
15090                             }
15091 #endif  /* TNCODE */
15092                         }
15093                     }
15094                     ckmakmsg(msgbuf,500,
15095                              "ttptycmd read net [ttinc loop] errno=",
15096                              ckitoa(errno),
15097                              " count=",
15098                              ckitoa(x));
15099                     debug(F100,msgbuf,"",0);
15100                 } else {
15101                     x = ttxin(n,tbuf+tbuf_avail);
15102                     debug(F101,"ttptycmd ttxin x","",x); 
15103                 }
15104
15105                 if (x < 0) {
15106                     debug(F101,"ttptycmd read net error","",x);
15107                     net_err++;
15108                 }
15109                 tbuf_avail += x;
15110                 read_net_bytes += x;
15111             }
15112
15113         } else
15114           tnotset++;
15115
15116         if (FD_ISSET(ptyfd, &in)) {     /* Read from pty? */
15117             pset++;
15118             debug(F100,"ttptycmd FD_ISSET ptyfd in","",0);
15119 #ifdef PTY_USE_NDELAY
15120             n = PTY_PBUF_SIZE;
15121 #else
15122             /*
15123               This does not work on nonblocking channels
15124               on certain platforms such as NetBSD.
15125             */
15126             n = pty_chk(ptyfd);
15127 #endif /* PTY_USE_NDELAY */
15128             debug(F101,"ttptycmd pty_chk() n","",n); 
15129
15130             if (n < 0)
15131               n = 0;
15132             if (n > 0) {
15133                 if (n > PTY_PBUF_SIZE - pbuf_avail)
15134                   n = PTY_PBUF_SIZE - pbuf_avail;
15135                 debug(F101,"ttptycmd pty read size adjusted","",n); 
15136                 errno = 0;
15137                 x = read(ptyfd,pbuf+pbuf_avail,n);
15138 #ifdef DEBUG
15139                 if (deblog) {
15140                     ckmakmsg(msgbuf,500,
15141                              "ttptycmd read pty errno=",
15142                              ckitoa(errno),
15143                              " count=",
15144                              ckitoa(x));
15145                     debug(F100,msgbuf,"",0);
15146                 }
15147 #endif  /* DEBUG */
15148
15149                 if (x < 0 && errno == EAGAIN)
15150                   x = 0;
15151
15152                 if (x < 0) {            /* This works on Solaris and Linux */
15153                     pty_err++;          /* but not NetBSD */
15154                     debug(F100,"TERMINATION TEST A","",0);
15155 #ifdef COMMENT
15156                     if (errno == EIO)
15157                       rc = 1;
15158 #endif  /* COMMENT */
15159                     if (pexitstat < 0) {
15160                         status = pty_get_status(ptyfd,pty_fork_pid);
15161                         debug(F101,"ttptycmd pty_get_status C","",status);
15162                         if (status > -1) pexitstat = status;
15163                     }
15164                     have_pty = 0;
15165                     x = 0;
15166                 }
15167                 if (x == 0 && !pty_err) { /* This works on NetBSD but */
15168                     debug(F100,"TERMINATION TEST B","",0);
15169                     status = pexitstat > -1 ? pexitstat :
15170                         pty_get_status(ptyfd,pty_fork_pid);
15171                     debug(F101,"ttptycmd pty_get_status D","",status);
15172                     if (status > -1) {
15173                         pexitstat = status;
15174                         pty_err++;
15175                         have_pty = 0;
15176                     } else {            /* Select() lied */
15177                         pty_err = 0;    /* pty still there but has nothing */
15178                         msleep(100);    /* sleep a bit */
15179                     }
15180                     x = 0;
15181                 } 
15182                 /* Hopefully the next two are no longer needed... */
15183                 if (!pty_err && (
15184 #ifndef PTY_USE_NDELAY
15185                     x < 1 || errno
15186 #else
15187                     errno != 0 && errno != EAGAIN
15188 #endif /* PTY_USE_NDELAY */
15189                     )) {
15190                     debug(F100,"TERMINATION TEST C","",0);
15191                     pty_err++;
15192                     debug(F101,"ttptycmd SET pty_err","",pty_err);
15193                     if (errno == EIO)   /* errno == EIO is like EOF */
15194                       rc = 1;
15195                     if (x < 0)
15196                       x = 0;
15197                 }
15198 #ifdef COMMENT
15199 #ifdef DEBUG
15200                 if (deblog) {
15201                     pbuf[pbuf_avail + x] = '\0';
15202                     debug(F111,"ttptycmd added to pty buffer",
15203                           pbuf+pbuf_avail,x);
15204                 }
15205 #endif  /* DEBUG */
15206 #endif  /* COMMENT */
15207                 pbuf_avail += x;
15208                 read_pty_bytes += x;
15209             } else {                    /* n == 0 with blocking reads */
15210                 debug(F100,
15211                       "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN",
15212                       "",0);
15213             }
15214         } else
15215           pnotset++;
15216
15217         /* If writes have caught up to reads, reset the buffers */
15218
15219         if (pbuf_written == pbuf_avail)
15220           pbuf_written = pbuf_avail = 0;
15221         if (tbuf_written == tbuf_avail)
15222           tbuf_written = tbuf_avail = 0;
15223
15224         /* See if we can exit */
15225
15226         x1 = pbuf_avail - pbuf_written; 
15227         x2 = tbuf_avail - tbuf_written;
15228
15229         debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err);
15230         debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1);
15231         debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2);
15232         debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc);
15233         debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status);
15234         debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat);
15235
15236         if (net_err) {                  /* Net error? */
15237             debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err);
15238             if (have_net) {
15239                 if (local) {
15240                     ttclos(0);
15241                     printf("?Connection closed\n");
15242                 }
15243                 have_net = 0;
15244             }
15245             debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1);
15246             if (x1 == 0)
15247               break;
15248         }
15249         if (pty_err) {                  /* Pty error? */
15250             if (have_pty) {
15251                 if (pexitstat < 0) {            
15252                     status = pty_get_status(ptyfd,pty_fork_pid);
15253                     debug(F101,"ttptycmd pty_get_status E","",status);
15254                     if (status > -1) pexitstat = status;
15255                 }
15256                 have_pty = 0;
15257             }
15258             if (x1 == 0 && x2 == 0) {   /* If buffers are caught up */
15259                 rc = 1;                 /* set preliminary return to success */
15260                 debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc);
15261                 break;                  /* and exit the loop */
15262             }
15263         }
15264     }
15265     debug(F101,"ttptycmd +++ have_pty","",have_pty);
15266     if (have_pty) {                     /* In case select() failed */
15267 #ifdef USE_CKUPTY_C
15268         end_pty();
15269         close(ptyfd);
15270 #else
15271         close(slavefd);
15272         close(masterfd);
15273 #endif /* USE_CKUPTY_C */
15274     }
15275     pty_master_fd = -1;
15276     debug(F101,"ttptycmd +++ pexitstat","",pexitstat);
15277     if (pexitstat < 0) {                /* Try one last time to get status */
15278         status = pty_get_status(ptyfd,pty_fork_pid);
15279         debug(F101,"ttptycmd pty_get_status F","",status);
15280         if (status > -1) pexitstat = status;
15281     }
15282     debug(F101,"ttptycmd +++ final pexitstat","",pexitstat);
15283     if (deblog) {                       /* Stats for debug log */
15284         debug(F101,"ttptycmd +++ pset   ","",pset);
15285         debug(F101,"ttptycmd +++ pnotset","",pnotset);
15286         debug(F101,"ttptycmd +++ tset   ","",tset);
15287         debug(F101,"ttptycmd +++ tnotset","",tnotset);
15288
15289         debug(F101,"ttptycmd +++  read_pty_bytes","",read_pty_bytes);
15290         debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes);
15291         debug(F101,"ttptycmd +++  read_net_bytes","",read_net_bytes);
15292         debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes);
15293     }
15294 /*
15295   If we got the external protocol's exit status from waitpid(), we use that
15296   to set our return code.  If not, we fall back on whatever rc was previously
15297   set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise.
15298 */
15299     if (save_sigchld) {                 /* Restore this if we changed it */
15300         (VOID) signal(SIGCHLD,save_sigchld);
15301         save_sigchld = NULL;
15302     }
15303     msleep(500);
15304     x = kill(pty_fork_pid,SIGHUP);      /* In case it's still there */
15305     pty_fork_pid = -1;
15306     debug(F101,"ttptycmd fork kill SIGHUP","",x);
15307     if (pexitstat > -1)
15308       rc = (pexitstat == 0 ? 1 : 0);
15309     debug(F101,"ttptycmd +++ rc","",rc);
15310     if (!local) {                       /* If in remote mode */
15311         conres();                       /* restore console to CBREAK mode */
15312         concb((char)escchr);
15313     }
15314     return(rc);
15315 }
15316 #endif  /* NETPTY */
15317 #endif  /* SELECT */
15318
15319 /* T T R U N C M D  --  Redirect an external command over the connection. */
15320
15321 /*
15322   TTRUNCMD is the routine that was originally used for running external
15323   protocols.  It is very simple and works fine provided (a) the connection
15324   is not encrypted, and (b) the external protocol uses standard i/o
15325   (file descriptors 0 and 1) for file transfer.
15326 */
15327
15328 int
15329 ttruncmd(s) char *s; {
15330     PID_T pid;                          /* pid of lower fork */
15331     int wstat;                          /* for wait() */
15332     int x;
15333     int statusp;
15334
15335     if (ttyfd == -1) {
15336         printf("?Sorry, device is not open\n");
15337         return(0);
15338     }
15339     if (nopush) {
15340         debug(F100,"ttruncmd fail: nopush","",0);
15341         return(0);
15342     }
15343
15344 #ifdef NETPTY
15345 /***************
15346   It might also be necessary to use the pty routine for other reasons,
15347   e.g. because the external program does not use stdio.
15348 */
15349 #ifdef NETCONN
15350 /*
15351   If we have a network connection we use a different routine because
15352   (a) if the connection is encrypted, the mechanism used here can't deal
15353   with it; and (b) it won't handle any network protocols either, e.g.
15354   Telnet, Rlogin, K5 U-to-U, etc.  However, this routine works much
15355   better (faster, more transparent) on serial connections and when
15356   C-Kermit is in remote mode (i.e. is on the far end).
15357 */
15358     /* For testing always use this */
15359     if (netconn)
15360       return(ttptycmd(s));
15361 #endif /* NETCONN */
15362
15363 /***************/
15364 #else  /* NETPTY */
15365     if (tt_is_secure()) {
15366         printf("?Sorry, \
15367 external protocols over secure connections not supported in this OS.\n"
15368               );
15369         return(0);
15370     }
15371 #endif  /* NETPTY */
15372
15373     conres();                           /* Make console normal  */
15374     pexitstat = -4;
15375     if ((pid = fork()) == 0) {          /* Make a child fork */
15376         if (priv_can())                 /* Child: turn off privs. */
15377           exit(1);
15378         dup2(ttyfd, 0);                 /* Give stdin/out to the line */
15379         dup2(ttyfd, 1);
15380         x = system(s);
15381         debug(F101,"ttruncmd system",s,x);
15382         _exit(x ? BAD_EXIT : 0);
15383     } else {
15384         SIGTYP (*istat)(), (*qstat)();
15385         if (pid == (PID_T) -1)          /* fork() failed? */
15386           return(0);
15387         istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
15388         qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
15389
15390 #ifdef COMMENT
15391         while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
15392 #else  /* Not COMMENT */
15393         while (1) {
15394             wstat = wait(&statusp);
15395             debug(F101,"ttruncmd wait","",wstat);
15396             if (wstat == pid || wstat == -1)
15397               break;
15398         }
15399 #endif /* COMMENT */
15400
15401         pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
15402         debug(F101,"ttruncmd wait statusp","",statusp);
15403         debug(F101,"ttruncmd wait pexitstat","",pexitstat);
15404         signal(SIGINT,istat);           /* Restore interrupts */
15405         signal(SIGQUIT,qstat);
15406     }
15407     concb((char)escchr);                /* Restore console to CBREAK mode */
15408     return(statusp == 0 ? 1 : 0);
15409 }
15410 #endif  /* CK_REDIR */
15411
15412 struct tm *
15413 #ifdef CK_ANSIC
15414 cmdate2tm(char * date, int gmt)         /* date as "yyyymmdd hh:mm:ss" */
15415 #else
15416 cmdate2tm(date,gmt) char * date; int gmt;
15417 #endif
15418 {
15419     /* date as "yyyymmdd hh:mm:ss" */
15420     static struct tm _tm;
15421     time_t now;
15422
15423     if (strlen(date) != 17 ||
15424         date[8] != ' ' ||
15425         date[11] != ':' ||
15426         date[14] != ':')
15427       return(NULL);
15428
15429     time(&now);
15430     if (gmt)
15431       _tm = *gmtime(&now);
15432     else
15433       _tm = *localtime(&now);
15434     _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
15435                   (date[2]-'0')*10   + (date[3]-'0')-1900;
15436     _tm.tm_mon  = (date[4]-'0')*10   + (date[5]-'0')-1;
15437     _tm.tm_mday = (date[6]-'0')*10   + (date[7]-'0');
15438     _tm.tm_hour = (date[9]-'0')*10   + (date[10]-'0');
15439     _tm.tm_min  = (date[12]-'0')*10  + (date[13]-'0');
15440     _tm.tm_sec  = (date[15]-'0')*10  + (date[16]-'0');
15441
15442     /* Should we set _tm.tm_isdst to -1 here? */
15443
15444     _tm.tm_wday = 0;
15445     _tm.tm_yday = 0;
15446
15447     return(&_tm);
15448 }
15449
15450 #ifdef OXOS
15451 #undef kill
15452 #endif /* OXOS */
15453
15454 #ifdef OXOS
15455 int
15456 priv_kill(pid, sig) int pid, sig; {
15457     int i;
15458
15459     if (priv_on())
15460         debug(F100,"priv_kill priv_on failed","",0);
15461     i = kill(pid, sig);
15462     if (priv_off())
15463         debug(F100,"priv_kill priv_off failed","",0);
15464     return(i);
15465 }
15466 #endif /* OXOS */
15467
15468 #ifdef BEOSORBEBOX
15469 /* #ifdef BE_DR_7 */
15470 /*
15471   alarm() function not supplied with Be OS DR7 - this one contributed by
15472   Neal P. Murphy.
15473 */
15474
15475 /*
15476   This should mimic the UNIX/POSIX alarm() function well enough, with the
15477   caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
15478   and wait for the alarm thread to finish.
15479 */
15480 unsigned int
15481 alarm(unsigned int seconds) {
15482     long time_left = 0;
15483
15484 /* If an alarm is active, turn it off, saving the unused time */
15485     if (alarm_thread != -1) {
15486         /* We'll be generous and count partial seconds as whole seconds. */
15487         time_left = alarm_struct.time -
15488           ((system_time() - time_started) / 1000000.0);
15489
15490         /* Kill the alarm thread */
15491         kill_thread (alarm_thread);
15492
15493         /* We need to clean up as though the alarm occured. */
15494         time_started = 0;
15495         alarm_struct.thread = -1;
15496         alarm_struct.time = 0;
15497         alarm_expired();
15498     }
15499
15500 /* Set a new alarm clock, if requested. */
15501     if (seconds > 0) {
15502         alarm_struct.thread = find_thread(NULL);
15503         alarm_struct.time = seconds;
15504         time_started = system_time();
15505         alarm_thread = spawn_thread (do_alarm,
15506                                      "alarm_thread",
15507                                      B_NORMAL_PRIORITY,
15508                                      (void *) &alarm_struct
15509                                      );
15510         resume_thread (alarm_thread);
15511     }
15512
15513 /* Now return [unused time | 0] */
15514     return ((unsigned int) time_left);
15515 }
15516
15517 /*
15518   This function is the departure from UNIX/POSIX alarm handling. In the case
15519   of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
15520   handler. When Be implements alarm(), this function call can be eliminated
15521   from user's SIGALRM signal handlers.
15522 */
15523
15524 void
15525 alarm_expired(void) {
15526     long ret_val;
15527
15528     if (alarm_thread != -1) {
15529         wait_for_thread (alarm_thread, &ret_val);
15530         alarm_thread = -1;
15531     }
15532 }
15533
15534 /*
15535   This is the function that snoozes the requisite number of seconds and then
15536   SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
15537   uses thread_id; currently they are both typdef'ed as long, but I'll do the
15538   cast anyway. This function is run in a separate thread.
15539 */
15540
15541 long
15542 do_alarm (void *alarm_struct) {
15543     snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
15544     kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
15545     time_started = 0;
15546     ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
15547     ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
15548 }
15549 /* #endif */ /* BE_DR_7 */
15550 #endif /* BEOSORBEBOX */
15551
15552 #ifdef Plan9
15553
15554 int
15555 p9ttyctl(char letter, int num, int param) {
15556     char cmd[20];
15557     int len;
15558
15559     if (ttyctlfd < 0)
15560       return -1;
15561
15562     cmd[0] = letter;
15563     if (num)
15564       len = sprintf(cmd + 1, "%d", param) + 1;
15565     else {
15566         cmd[1] = param;
15567         len = 2;
15568     }
15569     if (write(ttyctlfd, cmd, len) == len) {
15570         cmd[len] = 0;
15571         /* fprintf(stdout, "wrote '%s'\n", cmd); */
15572         return 0;
15573     }
15574     return -1;
15575 }
15576
15577 int
15578 p9ttyparity(char l) {
15579     return p9ttyctl('p', 0, l);
15580 }
15581
15582 int
15583 p9tthflow(int flow, int status) {
15584     return p9ttyctl('m', 1, status);
15585 }
15586
15587 int
15588 p9ttsspd(int cps) {
15589     if (p9ttyctl('b', 1, cps * 10) < 0)
15590       return -1;
15591     ttylastspeed = cps * 10;
15592     return 0;
15593 }
15594
15595 int
15596 p9openttyctl(char *ttname) {
15597     char name[100];
15598
15599     if (ttyctlfd >= 0) {
15600         close(ttyctlfd);
15601         ttyctlfd = -1;
15602         ttylastspeed = -1;
15603     }
15604     sprintf(name, "%sctl", ttname);
15605     ttyctlfd = open(name, 1);
15606     return ttyctlfd;
15607 }
15608
15609 int
15610 p9concb() {
15611     if (consctlfd >= 0) {
15612         if (write(consctlfd, "rawon", 5) == 5)
15613           return 0;
15614     }
15615     return -1;
15616 }
15617
15618 int
15619 p9conbin() {
15620     return p9concb();
15621 }
15622
15623 int
15624 p9conres() {
15625     if (consctlfd >= 0) {
15626         if (write(consctlfd, "rawoff", 6) == 6)
15627           return 0;
15628     }
15629     return -1;
15630 }
15631
15632 int
15633 p9sndbrk(int msec) {
15634     if (ttyctlfd >= 0) {
15635         char cmd[20];
15636         int i = sprintf(cmd, "k%d", msec);
15637         if (write(ttyctlfd, cmd, i) == i)
15638           return 0;
15639     }
15640     return -1;
15641 }
15642
15643 int
15644 conwrite(char *buf, int n) {
15645     int x;
15646     static int length = 0;
15647     static int holdingcr = 0;
15648     int normal = 0;
15649     for (x = 0; x < n; x++) {
15650         char c = buf[x];
15651         if (c == 007) {
15652             if (normal) {
15653                 write(1, buf + (x - normal), normal);
15654                 length += normal;
15655                 normal = 0;
15656             }
15657             /* write(noisefd, "1000 300", 8); */
15658             holdingcr = 0;
15659         } else if (c == '\r') {
15660             if (normal) {
15661                 write(1, buf + (x - normal), normal);
15662                 length += normal;
15663                 normal = 0;
15664             }
15665             holdingcr = 1;
15666         } else if (c == '\n') {
15667             write(1, buf + (x - normal), normal + 1);
15668             normal = 0;
15669             length = 0;
15670             holdingcr = 0;
15671         } else if (c == '\b') {
15672             if (normal) {
15673                 write(1, buf + (x - normal), normal);
15674                 length += normal;
15675                 normal = 0;
15676             }
15677             if (length) {
15678                 write(1, &c, 1);
15679                 length--;
15680             }
15681             holdingcr = 0;
15682         } else {
15683             if (holdingcr) {
15684                 char b = '\b';
15685                 while (length-- > 0)
15686                   write(1, &b, 1);
15687                 length = 0;     /* compiler bug */
15688             }
15689             holdingcr = 0;
15690             normal++;
15691         }
15692     }
15693     if (normal) {
15694         write(1, buf + (x - normal), normal);
15695         length += normal;
15696     }
15697     return n;
15698 }
15699
15700 void
15701 conprint(char *fmt, ...) {
15702     static char buf[1000];              /* not safe if on the stack */
15703
15704     va_list ap;
15705     int i;
15706
15707     va_start(ap, fmt);
15708     i = vsprintf(buf, fmt, ap);
15709     conwrite(buf, i);
15710 }
15711 #endif /* Plan9 */
15712
15713 /* fprintf, printf, perror replacements... */
15714
15715 /* f p r i n t f */
15716
15717 #ifdef UNIX
15718 #ifdef CK_ANSIC
15719 #include <stdarg.h>
15720 #else /* CK_ANSIC */
15721 #ifdef __GNUC__
15722 #include <stdarg.h>
15723 #else
15724 #include <varargs.h>
15725 #endif  /* __GNUC__ */
15726 #endif /* CK_ANSIC */
15727 #ifdef fprintf
15728 #undef fprintf
15729 static char str1[4096];
15730 static char str2[4096];
15731 int
15732 #ifdef CK_ANSIC
15733 ckxfprintf(FILE * file, const char * format, ...)
15734 #else /* CK_ANSIC */
15735 ckxfprintf(va_alist) va_dcl
15736 #endif /* CK_ANSIC */
15737 /* ckxfprintf */ {
15738     int i, j, len, got_cr;
15739     va_list args;
15740     int rc = 0;
15741
15742 #ifdef CK_ANSIC
15743     va_start(args, format);
15744 #else /* CK_ANSIC */
15745     char * format;
15746     FILE * file;
15747     va_start(args);
15748     file = va_arg(args,FILE *);
15749     format = va_arg(args,char *);
15750 #endif /* CK_ANSIC */
15751
15752     if (!inserver || (file != stdout && file != stderr && file != stdin)) {
15753         rc = vfprintf(file,format,args);
15754     } else {
15755         unsigned int c;
15756         rc = vsprintf(str1, format, args);
15757         len = strlen(str1);
15758         if (len >= sizeof(str1)) {
15759             debug(F101,"ckxfprintf() buffer overflow","",len);
15760             doexit(BAD_EXIT,1);
15761         }
15762         for (i = 0, j = 0, got_cr = 0;
15763              i < len && j < sizeof(str1)-2;
15764              i++, j++ ) {
15765             /* We can't use 255 as a case label because of signed chars */
15766             c = (unsigned)(str1[i] & 0xff);
15767 #ifdef TNCODE
15768             if (c == 255) {
15769                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15770                   str2[j++] = '\0';
15771                 str2[j++] = IAC;
15772                 str2[j] = IAC;
15773                 got_cr = 0;
15774             } else
15775 #endif /* TNCODE */
15776             switch (c) {
15777               case '\r':
15778                 if (got_cr
15779 #ifdef TNCODE
15780                     && !TELOPT_ME(TELOPT_BINARY)
15781 #endif /* TNCODE */
15782                     )
15783                   str2[j++] = '\0';
15784                 str2[j] = str1[i];
15785                 got_cr = 1;
15786                 break;
15787               case '\n':
15788                 if (!got_cr)
15789                   str2[j++] = '\r';
15790                 str2[j] = str1[i];
15791                 got_cr = 0;
15792                 break;
15793               default:
15794                 if (got_cr
15795 #ifdef TNCODE
15796                     && !TELOPT_ME(TELOPT_BINARY)
15797 #endif /* TNCODE */
15798                     )
15799                   str2[j++] = '\0';
15800                 str2[j] = str1[i];
15801                 got_cr = 0;
15802             }
15803         }
15804         if (got_cr
15805 #ifdef TNCODE
15806              && !TELOPT_ME(TELOPT_BINARY)
15807 #endif /* TNCODE */
15808              )
15809             str2[j++] = '\0';
15810 #ifdef CK_ENCRYPTION
15811 #ifdef TNCODE
15812         if (TELOPT_ME(TELOPT_ENCRYPTION))
15813           ck_tn_encrypt(str2,j);
15814 #endif /* TNCODE */
15815 #endif /* CK_ENCRYPTION */
15816 #ifdef CK_SSL
15817         if (inserver && (ssl_active_flag || tls_active_flag)) {
15818             /* Write using SSL */
15819             char * p = str2;
15820           ssl_retry:
15821             if (ssl_active_flag)
15822               rc = SSL_write(ssl_con, p, j);
15823             else
15824               rc = SSL_write(tls_con, p, j);
15825             debug(F111,"ckxfprintf","SSL_write",rc);
15826             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
15827               case SSL_ERROR_NONE:
15828                 if (rc == j)
15829                   break;
15830                 p += rc;
15831                 j -= rc;
15832                 goto ssl_retry;
15833               case SSL_ERROR_WANT_WRITE:
15834               case SSL_ERROR_WANT_READ:
15835               case SSL_ERROR_SYSCALL:
15836                 if (rc != 0)
15837                   return(-1);
15838               case SSL_ERROR_WANT_X509_LOOKUP:
15839               case SSL_ERROR_SSL:
15840               case SSL_ERROR_ZERO_RETURN:
15841               default:
15842                 rc = 0;
15843             }
15844         } else
15845 #endif /* CK_SSL */
15846         fwrite(str2,sizeof(char),j,stdout);
15847     }
15848     va_end(args);
15849     return(rc);
15850 }
15851 #endif /* fprintf */
15852
15853 /* p r i n t f */
15854
15855 #ifdef printf
15856 #undef printf
15857 int
15858 #ifdef CK_ANSIC
15859 ckxprintf(const char * format, ...)
15860 #else /* CK_ANSIC */
15861 ckxprintf(va_alist) va_dcl
15862 #endif /* CK_ANSIC */
15863 /* ckxprintf */ {
15864     int i, j, len, got_cr;
15865     va_list args;
15866     int rc = 0;
15867
15868 #ifdef CK_ANSIC
15869     va_start(args, format);
15870 #else /* CK_ANSIC */
15871     char * format;
15872     va_start(args);
15873     format = va_arg(args,char *);
15874 #endif /* CK_ANSIC */
15875
15876     if (!inserver) {
15877         rc = vprintf(format, args);
15878     } else {
15879         unsigned int c;
15880         rc = vsprintf(str1, format, args);
15881         len = strlen(str1);
15882         if (len >= sizeof(str1)) {
15883             debug(F101,"ckxprintf() buffer overflow","",len);
15884             doexit(BAD_EXIT,1);
15885         }
15886         for (i = 0, j = 0, got_cr=0;
15887              i < len && j < sizeof(str1)-2;
15888              i++, j++ ) {
15889             c = (unsigned)(str1[i] & 0xff);
15890 #ifdef TNCODE
15891             if (c == 255) {
15892                 if (got_cr && !TELOPT_ME(TELOPT_BINARY))
15893                   str2[j++] = '\0';
15894                 str2[j++] = IAC;
15895                 str2[j] = IAC;
15896                 got_cr = 0;
15897             } else
15898 #endif /* TNCODE */
15899             switch (c) {
15900               case '\r':
15901                 if (got_cr
15902 #ifdef TNCODE
15903                     && !TELOPT_ME(TELOPT_BINARY)
15904 #endif /* TNCODE */
15905                     )
15906                   str2[j++] = '\0';
15907                 str2[j] = str1[i];
15908                 got_cr = 1;
15909                 break;
15910               case '\n':
15911                 if (!got_cr)
15912                   str2[j++] = '\r';
15913                 str2[j] = str1[i];
15914                 got_cr = 0;
15915                 break;
15916               default:
15917                 if (got_cr
15918 #ifdef TNCODE
15919                     && !TELOPT_ME(TELOPT_BINARY)
15920 #endif /* TNCODE */
15921                     )
15922                   str2[j++] = '\0';
15923                 str2[j] = str1[i];
15924                 got_cr = 0;
15925                 break;
15926             }
15927         }
15928         if (got_cr
15929 #ifdef TNCODE
15930              && !TELOPT_ME(TELOPT_BINARY)
15931 #endif /* TNCODE */
15932              )
15933             str2[j++] = '\0';
15934 #ifdef CK_ENCRYPTION
15935 #ifdef TNCODE
15936         if (TELOPT_ME(TELOPT_ENCRYPTION))
15937           ck_tn_encrypt(str2,j);
15938 #endif /* TNCODE */
15939 #endif /* CK_ENCRYPTION */
15940 #ifdef CK_SSL
15941         if (inserver && (ssl_active_flag || tls_active_flag)) {
15942             char * p = str2;
15943             /* Write using SSL */
15944           ssl_retry:
15945             if (ssl_active_flag)
15946               rc = SSL_write(ssl_con, p, j);
15947             else
15948               rc = SSL_write(tls_con, p, j);
15949             debug(F111,"ckxprintf","SSL_write",rc);
15950             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
15951               case SSL_ERROR_NONE:
15952                 if (rc == j)
15953                   break;
15954                 p += rc;
15955                 j -= rc;
15956                 goto ssl_retry;
15957               case SSL_ERROR_WANT_WRITE:
15958               case SSL_ERROR_WANT_READ:
15959               case SSL_ERROR_SYSCALL:
15960                 if (rc != 0)
15961                   return(-1);
15962               case SSL_ERROR_WANT_X509_LOOKUP:
15963               case SSL_ERROR_SSL:
15964               case SSL_ERROR_ZERO_RETURN:
15965               default:
15966                 rc = 0;
15967             }
15968         } else
15969 #endif /* CK_SSL */
15970           rc = fwrite(str2,sizeof(char),j,stdout);
15971     }
15972     va_end(args);
15973     return(rc);
15974 }
15975 #endif /* printf */
15976
15977 /*  p e r r o r  */
15978
15979 #ifdef perror
15980 #undef perror
15981 _PROTOTYP(char * ck_errstr,(VOID));
15982 #ifdef NEXT
15983 void
15984 #else
15985 #ifdef CK_SCOV5
15986 void
15987 #else
15988 int
15989 #endif /* CK_SCOV5 */
15990 #endif /* NEXT */
15991 #ifdef CK_ANSIC
15992 ckxperror(const char * str)
15993 #else /* CK_ANSIC */
15994 ckxperror(str) char * str;
15995 #endif /* CK_ANSIC */
15996 /* ckxperror */ {
15997     char * errstr = ck_errstr();
15998 #ifndef NEXT
15999 #ifndef CK_SCOV5
16000     return
16001 #endif /* CK_SCOV5 */
16002 #endif /* NEXT */
16003       ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
16004 }
16005 #endif /* perror */
16006 #endif /* UNIX */
16007
16008 #ifdef MINIX2
16009
16010 /* Minix doesn't have a gettimeofday call (but MINIX3 does).
16011  * We fake one here using time(2)
16012  */
16013
16014 #ifndef MINIX3
16015 int
16016 gettimeofday(struct timeval *tp, struct timezone *tzp) {
16017     tp->tv_usec = 0L;                   /* Close enough for horseshoes */
16018     if(time(&(tp->tv_sec))==-1)
16019       return(-1);
16020     return(0);
16021 }
16022 #endif  /* MINIX3 */
16023
16024 #ifndef MINIX3
16025 int
16026 readlink(const char *path, void *buf, size_t bufsiz) {
16027     errno = ENOSYS;
16028     return(-1);
16029 }
16030 #endif  /* MINIX3 */
16031
16032 #endif /* MINIX2 */