home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckutio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  456KB  |  16,051 lines

  1. #define CKUTIO_C
  2.  
  3. #ifdef aegis
  4. char *ckxv = "Aegis Communications support, 9.0.326, 20 August 2011";
  5. #else
  6. #ifdef Plan9
  7. char *ckxv = "Plan 9 Communications support, 9.0.326, 20 August 2011";
  8. #else
  9. char *ckxv = "UNIX Communications support, 9.0.326, 20 August 2011";
  10. #endif /* Plan9 */
  11. #endif /* aegis */
  12.  
  13. /*  C K U T I O  */
  14.  
  15. /* C-Kermit interrupt, communications control and I/O functions for UNIX */
  16.  
  17. /*
  18.   Author: Frank da Cruz (fdc@columbia.edu),
  19.   Columbia University Academic Information Systems, New York City.
  20.  
  21.   Copyright (C) 1985, 2011,
  22.     Trustees of Columbia University in the City of New York.
  23.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  24.     copyright text in the ckcmai.c module for disclaimer and permissions.
  25. */
  26.  
  27. /*
  28.   NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
  29.   compatible with C preprocessors that support only #ifdef, #else, #endif,
  30.   #define, and #undef.  Please do not use #if, logical operators, or other
  31.   preprocessor features in any of the portable C-Kermit modules.  You can,
  32.   of course, use these constructions in platform-specific modules when they
  33.   are supported by all compilers/preprocessors that could be used on that
  34.   platform.
  35. */
  36.  
  37. extern int nettype;            /* Defined in ckcmai.c */
  38. extern int duplex;
  39.  
  40. /* Includes */
  41.  
  42. #include "ckcsym.h"            /* This must go first   */
  43. #include "ckcdeb.h"            /* This must go second  */
  44.  
  45. #ifdef OSF13
  46. #ifdef CK_ANSIC
  47. #ifdef _NO_PROTO
  48. #undef _NO_PROTO
  49. #endif /* _NO_PROTO */
  50. #endif /* CK_ANSIC */
  51. #endif /* OSF13 */
  52.  
  53. #ifndef HPUXPRE65
  54. #include <errno.h>            /* Error number symbols */
  55. #else
  56. #ifndef ERRNO_INCLUDED
  57. #include <errno.h>            /* Error number symbols */
  58. #endif    /* ERRNO_INCLUDED */
  59. #endif    /* HPUXPRE65 */
  60.  
  61. #ifdef __386BSD__
  62. #define ENOTCONN 57
  63. #else
  64. #ifdef __bsdi__
  65. #define ENOTCONN 57
  66. #else
  67. #ifdef __FreeBSD__
  68. #define ENOTCONN 57
  69. #endif /* __FreeBSD__ */
  70. #endif /* __bsdi__ */
  71. #endif /* __386BSD__ */
  72.  
  73. #ifdef SCO_OSR504
  74. #define NBBY 8
  75. #endif /* SCO_OSR504 */
  76.  
  77. #ifdef Plan9
  78. #define SELECT
  79. #include <sys/time.h>
  80. #include <select.h>
  81. #define FD_SETSIZE (3 * sizeof(long) * 8)
  82. static struct timeval tv;
  83. #endif /* Plan9 */
  84.  
  85. #ifdef CLIX
  86. #include <sys/time.h>
  87. #endif /* CLIX */
  88.  
  89. #include "ckcnet.h"            /* Symbols for network types. */
  90. #ifdef CK_SSL
  91. #include "ck_ssl.h"
  92. #endif /* CK_SSL */
  93.  
  94. /*
  95.   The directory-related includes are here because we need to test some
  96.   file-system-related symbols to find out which system we're being compiled
  97.   under.  For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
  98. */
  99. #ifdef SDIRENT                /* Directory bits... */
  100. #define DIRENT
  101. #endif /* SDIRENT */
  102.  
  103. #ifdef XNDIR
  104. #include <sys/ndir.h>
  105. #else /* !XNDIR */
  106. #ifdef NDIR
  107. #include <ndir.h>
  108. #else /* !NDIR, !XNDIR */
  109. #ifdef RTU
  110. #include "/usr/lib/ndir.h"
  111. #else /* !RTU, !NDIR, !XNDIR */
  112. #ifdef DIRENT
  113. #ifdef SDIRENT
  114. #include <sys/dirent.h>
  115. #else
  116. #include <dirent.h>
  117. #endif /* SDIRENT */
  118. #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
  119. #include <sys/dir.h>
  120. #endif /* DIRENT */
  121. #endif /* RTU */
  122. #endif /* NDIR */
  123. #endif /* XNDIR */
  124.  
  125. #ifdef QNX
  126. #include <sys/dev.h>
  127. #endif /* QNX */
  128.  
  129. #ifdef HPUX5
  130. #ifndef TCPSOCKET
  131. /* I don't know why this is needed here since we never reference bzero(). */
  132. /* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
  133. void
  134. bzero(s,n) char *s; int n; {
  135.     extern char * memset();
  136.     memset(s,0,n);
  137. }
  138. #endif /* TCPSOCKET */
  139. #endif /* HPUX5 */
  140.  
  141. /* Definition of HZ, used in msleep() */
  142.  
  143. #ifdef MIPS
  144. #define HZ ( 1000 / CLOCK_TICK )
  145. #else  /* MIPS */
  146. #ifdef ATTSV
  147. #ifndef NAP
  148. #ifdef TRS16
  149. #define HZ ( 1000 / CLOCK_TICK )
  150. #endif /* TRS16 */
  151. #ifdef NAPHACK
  152. #define nap(x) (void)syscall(3112, (x))
  153. #define NAP
  154. #endif /* NAPHACK */
  155. #endif /* NAP */
  156. #endif /* ATTSV */
  157. #endif /* MIPS */
  158.  
  159. #ifdef M_UNIX
  160. #undef NGROUPS_MAX        /* Prevent multiple definition warnings */
  161. #endif /* M_UNIX */
  162.  
  163. /*
  164.   NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
  165.   library routine, so _poll comes up undefined at link time.
  166. */
  167. #ifdef CK_POLL
  168. #ifndef AIXRS            /* IBM AIX needs special handling */
  169. #include <poll.h>        /* "standard" (SVID) i/o multiplexing, etc */
  170. #else /* AIXRS */
  171. #ifdef SVR4            /* AIX 3.2 is like SVID... */
  172. #include <poll.h>
  173. #else                /* But AIX 3.1 is not ... */
  174. #include <sys/poll.h>        /* The include file is in include/sys */
  175. #define events reqevents    /* And it does not map IBM-specific member */
  176. #define revents rtnevents    /* names to the System V equivalents */
  177. #endif /* SVR4 */
  178. #endif /* AIXRS */
  179. #endif /* CK_POLL */
  180.  
  181. #include <signal.h>                     /* Signals */
  182.  
  183. /* For setjmp and longjmp */
  184.  
  185. #ifndef ZILOG
  186. #include <setjmp.h>
  187. #else
  188. #include <setret.h>
  189. #endif /* ZILOG */
  190.  
  191. /*
  192.   The following test differentiates between 4.1 BSD and 4.2 & later.
  193.   If you have a 4.1BSD system with the DIRENT library, this test could
  194.   mistakenly diagnose 4.2BSD and then later enable the use of system calls
  195.   that aren't defined.  If indeed there are such systems, we can use some
  196.   other way of testing for 4.1BSD, or add yet another compile-time switch.
  197. */
  198. #ifdef BSD4
  199. #ifdef MAXNAMLEN
  200. #ifndef FT21                /* Except for Fortune. */
  201. #ifndef FT18
  202. #ifndef BELLV10                /* And Bell Labs Research UNIX V10 */
  203. #define BSD42
  204. #endif /* BELLV10 */
  205. #endif /* FT18 */
  206. #endif /* FT21 */
  207. #endif /* MAXNAMLEN */
  208. #endif /* BSD4 */
  209.  
  210. #ifdef SUNOS41                /* From Christian Corti */
  211. #define BSD44ORPOSIX            /* Uni Stuttgart */
  212. #define SVORPOSIX            /* February 2010 */
  213. #include <termios.h>
  214. #include <sys/ioctl.h>
  215. #include <unistd.h>
  216. #include <limits.h>
  217. #endif    /* SUNOS41 */
  218.  
  219. #ifdef SNI542
  220. #include <sys/filio.h>            /* 299 for FIONREAD */
  221. #endif    /* SNI542 */
  222.  
  223. /*
  224.   Minix 2.0 support added by Terry McConnell,
  225.   Syracuse University <tmc@barnyard.syr.edu>
  226.   No more sgtty interface, posix compliant.
  227. */
  228. #ifdef MINIX2
  229. #define _MINIX   /* Needed for some Minix header files */
  230. #define BSD44ORPOSIX
  231. #define SVORPOSIX
  232. #ifndef MINIX3
  233. #define DCLTIMEVAL
  234. #endif    /* MINIX3 */
  235. #define NOFILEH
  236. #include <sys/types.h>
  237. #include <sys/ioctl.h>
  238. #include <termios.h>
  239. #include <limits.h>
  240. #undef TIOCGETC    /* defined in sys/ioctl.h, but not really supported */
  241. #define TANDEM 0
  242. #endif /* MINIX2 */
  243.  
  244. /*
  245.  MINIX 1.0 support added by Charles Hedrick,
  246.  Rutgers University <hedrick@aramis.rutgers.edu>.
  247.  MINIX also has V7 enabled.
  248. */
  249. #ifdef MINIX
  250. #define TANDEM 0
  251. #define MYREAD
  252. #define NOSYSIOCTLH
  253. #include <limits.h>
  254. #endif /* MINIX */
  255.  
  256. #ifdef CK_REDIR        /* <sys/wait.h> needed only for REDIRECT command. */
  257. /*
  258.   If anybody can figure out how to make this work with NeXTSTEP, be
  259.   my guest!  (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
  260. */
  261. #ifndef CK_WAIT_H            /* If wait.h not already included... */
  262. #ifdef OSF                /* force OSF to select POSIX wait */
  263. #ifdef _BSD                /* instead of BSD (see ckcdeb.h) */
  264. #define CK_OSF_BSD
  265. #undef _BSD
  266. #endif /* _BSD */
  267. #endif /* OSF */
  268. #include <sys/wait.h>            /* Include it */
  269. #ifdef OSF
  270. #ifdef CK_OSF_BSD
  271. #define _BSD                /* Restore it */
  272. #undef CK_OSF_BSD
  273. #endif /* CK_OSF_BSD */
  274. #endif /* OSF */
  275. #endif /* CK_WAIT_H */
  276. #endif /* CK_REDIR */
  277.  
  278. #include "ckuver.h"            /* Version herald */
  279. char *ckxsys = HERALD;
  280.  
  281. #ifdef CK_UTSNAME
  282. #include <sys/utsname.h>
  283.  
  284. #ifdef TRU64                /* Tru64 UNIX 4.0 and later */
  285. /* Verified on Tru64 4.0F - might break on 4.0E or earlier */
  286. #include <sys/sysinfo.h>        /* (don't know about OSF/1 or DU) */
  287. #include <machine/hal_sysinfo.h>
  288. #endif /* TRU64 */
  289.  
  290. #ifdef SOLARIS25            /* Solaris 2.5 and later */
  291. #include <sys/systeminfo.h>        /* (don't know about earlier ones) */
  292. #endif /* SOLARIS25 */
  293.  
  294. #ifdef UW7
  295. #ifndef SYS_NMLN
  296. #define SYS_NMLN 257
  297. #endif /* NMLN */
  298. #endif /* UW7 */
  299. #ifdef HPUX9PLUS
  300. static int hpis800 = 0;
  301. #endif /* HPUX9PLUS */
  302. #ifdef SYS_NMLN
  303. #define CK_SYSNMLN SYS_NMLN
  304. #else
  305. #ifdef _SYS_NMLN
  306. #define CK_SYSNMLN _SYS_NMLN
  307. #else
  308. #ifdef UTSLEN
  309. #define CK_SYSNMLN UTSLEN
  310. #else
  311. #define CK_SYSNMLN 31
  312. #endif /* UTSLEN */
  313. #endif /* _SYS_NMLN */
  314. #endif /* SYS_NMLN */
  315. char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
  316. char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
  317. char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
  318. char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
  319. char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
  320. #endif /* CK_UTSNAME */
  321.  
  322. #ifdef CIE
  323. #include <stat.h>            /* For chasing symlinks, etc. */
  324. #else
  325. #include <sys/stat.h>
  326. #endif /* CIE */
  327.  
  328. #ifdef QNX                /* 299 */
  329. #ifndef IXANY
  330. #define IXANY 0
  331. #endif    /* IXANY */
  332. #endif    /* QNX */
  333.  
  334. /* UUCP lockfile material... */
  335.  
  336. #ifndef NOUUCP
  337. #ifdef USETTYLOCK
  338. #ifdef HAVE_LOCKDEV            /* Red Hat baudboy/lockdev */
  339. /*
  340.   Watch out: baudboy.h references open() without making sure it has been
  341.   declared, resulting in warnings on at least Red Hat 7.3.  It's declared in
  342.   fcntl.h, but we don't include that until later.  In this case only, we
  343.   include it here, and then the second include is harmless because in Red Hat
  344.   Linux (the only place where you find baudboy.h) fcntl.h is protected from
  345.   multiple inclusion by _FCNTL_H.   - fdc, 10 May 2004.
  346.  
  347.   NOTE: Although Linux /usr/sbin/lockdev obviates the need for setuid or
  348.   setgid bits to access the lockfile, C-Kermit will still need them to access
  349.   the serial port itself unless the port is open for world read/write.
  350.   Normally setgid uucp does the trick.
  351.  
  352.   Extra: HAVE_LOCKDEV has been added als openSuSE >= 11.3 doesn't use baudboy
  353.   but ttylock.  - jb, 26 Jul 2010
  354. */
  355. #include <fcntl.h>            /* This has to come before baudboy */
  356. #ifdef HAVE_BAUDBOY            /* Red Hat baudboy/lockdev */
  357. #include <baudboy.h>
  358. #else  /* !HAVE_BAUDBOY */        /* openSuSE lock via ttylock */
  359. #include <ttylock.h>
  360. #endif  /* HAVE_BAUDBOY */
  361. #define LOCK_DIR "/var/lock"        /* (even though we don't care) */
  362.  
  363. #else  /* !HAVE_LOCKDEV */
  364.  
  365. #ifdef USE_UU_LOCK
  366. #ifdef __FreeBSD__
  367. #include <libutil.h>            /* FreeBSD */
  368. #else
  369. #include <util.h>            /* OpenBSD */
  370. #endif /* HAVE_LOCKDEV */
  371. #endif /* __FreeBSD */
  372. #endif /* USE_UU_LOCK */
  373. #else  /* USETTYLOCK */
  374.  
  375. /* Name of UUCP tty device lockfile */
  376.  
  377. #ifdef LINUXFSSTND
  378. #ifndef HDBUUCP
  379. #define HDBUUCP
  380. #endif /* HDBUUCP */
  381. #endif /* LINUXFSSTND */
  382.  
  383. #ifdef ACUCNTRL
  384. #define LCKDIR
  385. #endif /* ACUCNTRL */
  386.  
  387. /*
  388.   PIDSTRING means use ASCII string to represent pid in lockfile.
  389. */
  390. #ifndef PIDSTRING
  391. #ifdef HDBUUCP
  392. #define PIDSTRING
  393. #else
  394. #ifdef BSD44
  395. #define PIDSTRING
  396. #else
  397. #ifdef RTAIX
  398. #define PIDSTRING
  399. #else
  400. #ifdef AIXRS
  401. #define PIDSTRING
  402. #else
  403. #ifdef COHERENT
  404. #define PIDSTRING
  405. #endif /* COHERENT */
  406. #endif /* AIXRS */
  407. #endif /* RTAIX */
  408. #endif /* BSD44 */
  409. #endif /* HDBUUCP */
  410. #endif /* PIDSTRING */
  411.  
  412. /* Now the PIDSTRING exceptions... */
  413.  
  414. #ifdef PIDSTRING
  415. #ifdef HPUX
  416. #undef PIDSTRING
  417. #endif /* HPUX */
  418. #endif /* PIDSTRING */
  419.  
  420. #ifdef __bsdi__                /* BSDI (at least thru 1.1) */
  421. #ifdef PIDSTRING
  422. #undef PIDSTRING
  423. #endif /* PIDSTRING */
  424. #endif /* __bsdi__ */
  425.  
  426. #ifdef OSF32                /* Digital UNIX (OSF/1) 3.2 */
  427. #ifdef PIDSTRING
  428. #undef PIDSTRING
  429. #endif /* PIDSTRING */
  430. #endif /* OSF32 */
  431.  
  432. /*
  433.   LOCK_DIR is the name of the lockfile directory.
  434.   If LOCK_DIR is already defined (e.g. on command line), we don't change it.
  435. */
  436.  
  437. #ifndef LOCK_DIR
  438. #ifdef MACOSX
  439. #define LOCK_DIR "/var/spool/lock"
  440. #endif /* MACOSX */
  441. #endif/* LOCK_DIR */
  442.  
  443. #ifndef LOCK_DIR
  444. #ifdef BSD44
  445. #ifdef __386BSD__
  446. #define LOCK_DIR "/var/spool/lock"
  447. #else
  448. #ifdef __FreeBSD__
  449. #define LOCK_DIR "/var/spool/lock"
  450. #else
  451. #ifdef __NetBSD__
  452. #define LOCK_DIR "/var/spool/lock"
  453. #else
  454. #ifdef __OpenBSD__
  455. #define LOCK_DIR "/var/spool/lock"
  456. #else
  457. /* So which ones is this for? */
  458. /* Probably original 4.4BSD on Vangogh */
  459. /* Plus who knows about Mac OS X... It doesn't even have a cu program */
  460. #define LOCK_DIR "/var/spool/uucp"
  461. #endif /* __OpenBSD__ */
  462. #endif /* __NetBSD__ */
  463. #endif /* __FreeBSD__ */
  464. #endif /* __386BSD__ */
  465. #else
  466. #ifdef DGUX430
  467. #define LOCK_DIR "/var/spool/locks"
  468. #else
  469. #ifdef HPUX10
  470. #define LOCK_DIR "/var/spool/locks"
  471. #else
  472. #ifdef RTAIX                /* IBM RT PC AIX 2.2.1 */
  473. #define LOCK_DIR "/etc/locks"
  474. #else
  475. #ifdef AIXRS
  476. #define LOCK_DIR "/etc/locks"
  477. #else
  478. #ifdef ISIII
  479. #define LOCK_DIR "/etc/locks"
  480. #else
  481. #ifdef HDBUUCP
  482. #ifdef M_SYS5
  483. #define LOCK_DIR "/usr/spool/uucp"
  484. #else
  485. #ifdef M_UNIX
  486. #define LOCK_DIR "/usr/spool/uucp"
  487. #else
  488. #ifdef SVR4
  489. #define LOCK_DIR "/var/spool/locks"
  490. #else
  491. #ifdef SUNOS4
  492. #define LOCK_DIR "/var/spool/locks"
  493. #else
  494. #ifdef LINUXFSSTND
  495. #define LOCK_DIR "/var/lock";
  496. #else
  497. #define LOCK_DIR "/usr/spool/locks"
  498. #endif /* LINUXFSSTND */
  499. #endif /* SUNOS4 */
  500. #endif /* SVR4 */
  501. #endif /* M_UNIX */
  502. #endif /* M_SYS5 */
  503. #else
  504. #ifdef LCKDIR
  505. #define LOCK_DIR "/usr/spool/uucp/LCK"
  506. #else
  507. #ifdef COHERENT
  508. #define LOCK_DIR "/usr/spool/uucp"
  509. #else
  510. #define LOCK_DIR "/usr/spool/uucp"
  511. #endif /* COHERENT */
  512. #endif /* LCKDIR */
  513. #endif /* HDBUUCP */
  514. #endif /* ISIII */
  515. #endif /* AIXRS */
  516. #endif /* RTAIX */
  517. #endif /* HPUX10 */
  518. #endif /* DGUX430 */
  519. #endif /* BSD44 */
  520. #endif /* !LOCK_DIR (outside ifndef) */
  521.  
  522. #ifdef OSF2                /* OSF/1 2.0 or later */
  523. #ifdef LOCK_DIR                /* (maybe 1.x too, who knows...) */
  524. #undef LOCK_DIR
  525. #define LOCK_DIR "/var/spool/locks"
  526. #endif /* LOCK_DIR */
  527. #endif /* OSF2 */
  528.  
  529. #ifdef COMMENT
  530. /* Sorry no more lockf() -- we lock first and THEN open the device. */
  531. #ifdef SVR4
  532. #ifndef BSD44
  533. #ifndef LOCKF
  534. #define LOCKF                /* Use lockf() on tty device in SVR4 */
  535. #endif /* LOCKF */
  536. #endif /* BSD44 */
  537. #endif /* SVR4 */
  538. #endif /* COMMENT */
  539.  
  540. #ifdef NOLOCKF                /* But NOLOCKF cancels LOCKF */
  541. #ifdef LOCKF
  542. #undef LOCKF
  543. #endif /* LOCKF */
  544. #endif /* NOLOCKF */
  545.  
  546. /* More about this below... */
  547.  
  548. #endif /* USETTYLOCK */
  549. #endif /* NOUUCP */
  550.  
  551. /*
  552.   MYREAD means use our internally defined nonblocking buffered read routine.
  553. */
  554. #ifdef ATTSV
  555. #define MYREAD
  556. #endif /* ATTSV */
  557.  
  558. #ifdef ATT7300
  559. #ifndef MYREAD
  560. #define MYREAD
  561. #endif /* MYREAD */
  562. /* bits for attmodem: internal modem in use, restart getty */
  563. #define ISMODEM 1
  564. #define DOGETY 512
  565. #endif  /* ATT7300 */
  566.  
  567. #ifdef BSD42
  568. #define MYREAD
  569. #endif /* BSD42 */
  570.  
  571. #ifdef POSIX
  572. #define MYREAD
  573. #endif /* POSIX */
  574. #ifdef __bsdi__
  575. #ifndef O_NDELAY
  576. #define O_NDELAY O_NONBLOCK
  577. #endif /* O_NDELAY */
  578. #endif /* __bsdi__ */
  579.  
  580. /*
  581.  Variables available to outside world:
  582.  
  583.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  584.    dfloc  -- 0 if dftty is console, 1 if external line.
  585.    dfprty -- Default parity
  586.    dfflow -- Default flow control
  587.    ckxech -- Flag for who echoes console typein:
  588.      1 - The program (system echo is turned off)
  589.      0 - The system (or front end, or terminal).
  590.    functions that want to do their own echoing should check this flag
  591.    before doing so.
  592.  
  593.    flfnam  -- Name of lock file, including its path, e.g.,
  594.                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
  595.    lkflfn  -- Name of link to lock file, including its paths
  596.    haslock -- Flag set if this kermit established a uucp lock.
  597.    lockpid -- PID of other process that has desired line open, as string.
  598.    backgrd -- Flag indicating program executing in background ( & on
  599.                 end of shell command). Used to ignore INT and QUIT signals.
  600.    rtu_bug -- Set by stptrap().  RTU treats ^Z as EOF (but only when we handle
  601.                 SIGTSTP)
  602.  
  603.  Functions for assigned communication line (either external or console tty):
  604.  
  605.    sysinit()               -- System dependent program initialization
  606.    syscleanup()            -- System dependent program shutdown
  607.    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
  608.    ttclos()                -- Close & reset the tty, releasing any access lock.
  609.    ttsspd(cps)             -- Set the transmission speed of the tty.
  610.    ttgspd()                -- Get (read) the the transmission speed of the tty.
  611.    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
  612.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  613.                                 or in DIALING or CONNECTED modem control state.
  614.    ttres()                 -- Restore original tty modes.
  615.    ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
  616.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  617.    ttinc(timo)             -- Timed read character from tty.
  618.    myread()                -- Raw mode bulk buffer read, gives subsequent
  619.                                 chars one at a time and simulates FIONREAD.
  620.    myunrd(c)               -- Places c back in buffer to be read (one only)
  621.    ttchk()                 -- See how many characters in tty input buffer.
  622.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  623.    ttol(string,length)     -- Write a string to the tty.
  624.    ttoc(c)                 -- Write a character to the tty.
  625.    ttflui()                -- Flush tty input buffer.
  626.    ttsndb()                -- Send BREAK signal.
  627.    ttsndlb()               -- Send Long BREAK signal.
  628.  
  629.    ttlock(ttname)          -- "Lock" tty device against uucp collisions.
  630.    ttunlck()               -- Unlock tty device.
  631.  
  632.                               For ATT7300/Unix PC, System V:
  633.    attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
  634.    offgetty(ttname)        -- Turns off getty(1m) for comms line
  635.    ongetty(ttname)         -- Restores getty() to comms line
  636. */
  637.  
  638. /*
  639. Functions for console terminal:
  640.  
  641.    congm()   -- Get console terminal modes.
  642.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  643.    conbin(esc) -- Put the console in binary (raw) mode.
  644.    conres()  -- Restore the console to mode obtained by congm().
  645.    conoc(c)  -- Unbuffered output, one character to console.
  646.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  647.    conola(s) -- Unbuffered output, array of strings to the console.
  648.    conxo(n,s) -- Unbuffered output, n characters to the console.
  649.    conchk()  -- Check if characters available at console (bsd 4.2).
  650.                 Check if escape char (^\) typed at console (System III/V).
  651.    coninc(timo)  -- Timed get a character from the console.
  652.    congks(timo)  -- Timed get keyboard scan code.
  653.    conint()  -- Enable terminal interrupts on the console if not background.
  654.    connoi()  -- Disable terminal interrupts on the console if not background.
  655.  
  656. Time functions
  657.  
  658.    msleep(m) -- Millisecond sleep
  659.    ztime(&s) -- Return pointer to date/time string
  660.    rtimer() --  Reset timer
  661.    gtimer()  -- Get elapsed time since last call to rtimer()
  662. */
  663.  
  664. /* Conditional Includes */
  665.  
  666. /* Whether to include <sys/file.h> */
  667.  
  668. #ifdef RTU                /* RTU doesn't */
  669. #define NOFILEH
  670. #endif /* RTU */
  671.  
  672. #ifdef CIE                /* CIE does. */
  673. #undef NOFILEH
  674. #endif /* CIE */
  675.  
  676. #ifdef BSD41                /* 4.1 BSD doesn't */
  677. #define NOFILEH
  678. #endif /* BSD41 */
  679.  
  680. #ifdef is68k                /* Integrated Solutions 68000 UNIX  */
  681. #define NOFILEH                /* e.g. on Plexux P60 and Sun-1 */
  682. #endif /* is68k */
  683.  
  684. #ifdef MINIX                /* MINIX */
  685. #define NOFILEH
  686. #endif /* MINIX */
  687.  
  688. #ifdef COHERENT                /* Coherent */
  689. #define NOFILEH
  690. #endif /* COHERENT */
  691.  
  692. #ifndef NOFILEH                /* Now include if selected. */
  693. #include <sys/file.h>
  694. #endif /* NOFILEH */
  695.  
  696. /* POSIX */
  697.  
  698. #ifdef BSD44ORPOSIX            /* POSIX uses termios.h */
  699. #define TERMIOS
  700. #ifdef __bsdi__
  701. #ifdef POSIX
  702. #undef _POSIX_SOURCE            /* Get extra stuff from termios.h */
  703. #endif /* POSIX */
  704. #endif /* __bsdi__ */
  705. #include <termios.h>
  706. #ifdef LINUX
  707. #include <sys/ioctl.h>
  708. #endif /* LINUX */
  709. #ifdef QNX16
  710. #include <ioctl.h>
  711. #else
  712. #ifdef QNX6
  713. #include <ioctl.h>
  714. #endif /* QNX6 */
  715. #endif /* QNX16 */
  716. #ifdef __bsdi__
  717. #ifdef POSIX
  718. #define _POSIX_SOURCE
  719. #endif /* POSIX */
  720. #endif /* __bsdi__ */
  721. #ifndef BSD44                /* Really POSIX */
  722. #ifndef CK_QNX32            /* was CK_QNX32 */
  723. #define NOSYSIOCTLH            /* No ioctl's allowed. */
  724. #undef ultrix                /* Turn off any ultrix features. */
  725. #endif /* CK_QNX32 */
  726. #endif /* BSD44 */
  727. #endif /* POSIX */
  728.  
  729. /* System III, System V */
  730.  
  731. #ifdef ATTSV
  732. #ifndef BSD44
  733. #ifndef POSIX
  734. #include <termio.h>
  735. #endif /* POSIX */
  736. #endif /* BSD44 */
  737. #ifdef TERMIOX
  738. /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
  739. #include <termiox.h>
  740.   struct termiox rctsx;
  741. #else
  742. #ifdef STERMIOX
  743. #ifdef SCO_OSR504
  744. /* Sorry, this is truly disgusting but it's SCO's fault. */
  745. #ifndef _SVID3
  746. #define _CK_SVID3_X
  747. #define _SVID3
  748. #endif /* _SVID3 */
  749. #endif /* SCO_OSR504 */
  750. #include <sys/termiox.h>
  751.   struct termiox rctsx;
  752. #ifdef CK_SVID3_X
  753. #undef _SVID3
  754. #undef CK_SVID3_X
  755. #endif /* CK_SVID3_X */
  756. #endif /* STERMIOX */
  757. #endif /* TERMIOX */
  758. #endif /* ATTSV */
  759.  
  760. #ifdef COHERENT            /* Use termio.h, not sgtty.h for Coherent */
  761. #include <termio.h>
  762. #endif /* COHERENT */
  763.  
  764. #ifdef MINIX                /* MINIX uses ioctl's */
  765. #define NOSYSIOCTLH            /* but has no <sys/ioctl.h> */
  766. #endif /* MINIX */
  767.  
  768. /* Others */
  769.  
  770. #ifndef NOSYSIOCTLH            /* Others use ioctl() */
  771. #ifdef SUN4S5
  772. /*
  773.   This is to get rid of cpp warning messages that occur because all of
  774.   these symbols are defined by both termios.h and ioctl.h on the SUN.
  775. */
  776. #undef ECHO
  777. #undef NL0
  778. #undef NL1
  779. #undef TAB0
  780. #undef TAB1
  781. #undef TAB2
  782. #undef XTABS
  783. #undef CR0
  784. #undef CR1
  785. #undef CR2
  786. #undef CR3
  787. #undef FF0
  788. #undef FF1
  789. #undef BS0
  790. #undef BS1
  791. #undef TOSTOP
  792. #undef FLUSHO
  793. #undef PENDIN
  794. #undef NOFLSH
  795. #endif /* SUN4S5 */
  796. #include <sys/ioctl.h>
  797. #endif /* NOSYSIOCTLH */
  798. /*
  799.   We really, really, REALLY want FIONREAD, because it is the only way to find
  800.   out not just *if* stuff is waiting to be read, but how much, which is
  801.   critical to our sliding-window and streaming procedures, not to mention
  802.   efficiency of CONNECT, etc.
  803. */
  804. #ifdef BELLV10
  805. #include <sys/filio.h>            /* For FIONREAD */
  806. #ifdef FIONREAD
  807. #define MYREAD
  808. #endif /* MYREAD */
  809. #endif /* BELLV10 */
  810.  
  811. #ifndef FIONREAD
  812. /* It wasn't found in ioctl.h or term*.h - try these places: */
  813. #ifdef UNIXWARE
  814. #include <sys/filio.h>
  815. #else
  816. #ifdef SOLARIS
  817. #include <sys/filio.h>
  818. #endif /* SOLARIS */
  819. #endif /* UNIXWARE */
  820. #endif /* FIONREAD */
  821.  
  822. #ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
  823. /*
  824.   <sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
  825.   something.  Due to this, in_chk() uses the FIONREAD instead of RDCHK
  826.   and the hot keys during file transfer (X to cancel file etc) do not
  827.   work because FIONREAD doesn't work even though it is defined.
  828.  
  829.   NOTE: This might also be true elsewhere.
  830. */
  831. #ifdef FIONREAD
  832. #undef FIONREAD
  833. #endif /* FIONREAD */
  834. #endif /* XENIX */
  835.  
  836. #ifdef CK_SCOV5                /* Ditto for SCO OpenServer 5.0 */
  837. #ifndef SCO_OSR507            /* 299 */
  838. #ifdef FIONREAD
  839. #undef FIONREAD
  840. #endif /* FIONREAD */
  841. #endif    /* SCO_OSR507 */
  842. #endif /* CK_SCOV5 */
  843.  
  844. #ifdef SCO_OSR507            /* 299 */
  845. #ifdef RDCHK
  846. #undef RDCHK
  847. #endif    /* RDCHK */
  848. #endif    /* SCO_OSR507 */
  849.  
  850. /* Whether to include <fcntl.h> */
  851.  
  852. #ifndef is68k                /* Only a few don't have this one. */
  853. #ifndef BSD41
  854. #ifndef FT21
  855. #ifndef FT18
  856. #ifndef COHERENT
  857. #include <fcntl.h>
  858. #endif /* COHERENT */
  859. #endif /* FT18 */
  860. #endif /* FT21 */
  861. #endif /* BSD41 */
  862. #endif /* not is68k */
  863.  
  864. #ifdef COHERENT
  865. #ifdef _I386
  866. #include <fcntl.h>
  867. #else
  868. #include <sys/fcntl.h>
  869. #endif /* _I386 */
  870. #endif /* COHERENT */
  871.  
  872. #ifdef ATT7300                /* Unix PC, internal modem dialer */
  873. #include <sys/phone.h>
  874. #endif /* ATT7300 */
  875.  
  876. #ifdef HPUX                /* HP-UX variations. */
  877. #define HPUXJOBCTL
  878. #include <sys/modem.h>            /* HP-UX modem signals */
  879. #ifdef hp9000s500            /* Model 500 */
  880. #undef HPUXJOBCTL
  881. #endif /* hp9000s500 */
  882. #ifdef HPUXPRE65
  883. #undef HPUXJOBCTL
  884. typedef long mflag;
  885. #endif /* HPUXPRE65 */
  886. #ifdef HPUXJOBCTL
  887. #include <sys/bsdtty.h>            /* HP-UX Berkeley tty support */
  888. #endif /* HPUXJOBCTL */
  889. #endif /* HPUX */
  890.  
  891. /*
  892.   Which time.h files to include... See ckcdeb.h for defaults.
  893.   Note that 0, 1, 2, or all 3 of these can be included according to
  894.   the symbol definitions.
  895. */
  896. #ifndef NOTIMEH
  897. #ifdef TIMEH
  898. #include <time.h>
  899. #endif /* TIMEH */
  900. #endif /* NOTIMEH */
  901.  
  902. #ifndef NOSYSTIMEH
  903. #ifdef SYSTIMEH
  904. #include <sys/time.h>
  905. #endif /* SYSTIMEH */
  906. #endif /* NOSYSTIMEH */
  907.  
  908. #ifndef NOSYSTIMEBH
  909. #ifdef SYSTIMEBH
  910. #include <sys/timeb.h>
  911. #endif /* SYSTIMEBH */
  912. #endif /* NOSYSTIMEBH */
  913.  
  914. #ifndef NODCLTIMEVAL
  915. #ifdef DCLTIMEVAL
  916. /*
  917.   In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
  918.   define the structs we need to access the higher speeds, so we have to
  919.   do it ourselves.
  920. */
  921. struct timeval {
  922.     long tv_sec;
  923.     long tv_usec;
  924. };
  925. struct timezone {
  926.     int tz_minuteswest;
  927.     int tz_dsttime;
  928. };
  929. #endif /* DCLTIMEVAL */
  930. #endif /* NODCLTIMEVAL */
  931.  
  932. #ifdef __linux__
  933. /* THIS IS OBSOLETE since about Linux 0.92 */
  934. #ifdef OLINUXHISPEED
  935. #include <linux/serial.h>
  936. #endif /* OLINUXHISPEED */
  937. #ifdef __alpha__            /* Linux on DEC Alpha */
  938. #ifndef __GLIBC__            /* But not with glibc */
  939. #include <asm/termios.h>
  940. #endif /* __GLIBC__ */
  941. #endif /* __alpha__ */
  942. #endif /* __linux__ */
  943.  
  944. #ifdef NOIEXTEN                /* This is broken on some systems */
  945. #undef IEXTEN                /* like Convex/OS 9.1 */
  946. #endif /* NOIEXTEN */
  947. #ifndef IEXTEN                /* Turn off ^O/^V processing. */
  948. #define IEXTEN 0            /* Needed, at least, on BSDI. */
  949. #endif /* IEXTEN */
  950. /*
  951.   Pick up definitions needed for select() if we don't have them already.
  952.   Normally they come from <sys/types.h> but some systems get them from
  953.   <sys/select.h>...  Rather than hardwire all of them into the source, we
  954.   include it if SELECT_H is defined in compile-time CFLAGS.
  955. */
  956. #ifndef SCO_OSR504
  957. #ifdef SELECT_H
  958. #include <sys/select.h>
  959. #endif /* SELECT_H */
  960. #endif /* SCO_OSR504 */
  961.  
  962. #ifdef aegis
  963. #include "/sys/ins/base.ins.c"
  964. #include "/sys/ins/error.ins.c"
  965. #include "/sys/ins/ios.ins.c"
  966. #include "/sys/ins/sio.ins.c"
  967. #include "/sys/ins/pad.ins.c"
  968. #include "/sys/ins/time.ins.c"
  969. #include "/sys/ins/pfm.ins.c"
  970. #include "/sys/ins/pgm.ins.c"
  971. #include "/sys/ins/ec2.ins.c"
  972. #include "/sys/ins/type_uids.ins.c"
  973. #include <default_acl.h>
  974. #undef TIOCEXCL
  975. #undef FIONREAD
  976. #endif /* aegis */
  977.  
  978. #ifdef sxaE50                /* PFU Compact A SX/A TISP V10/L50 */
  979. #undef FIONREAD
  980. #endif /* sxaE50 */
  981.  
  982. /* The following #defines are catch-alls for those systems */
  983. /* that didn't have or couldn't find <file.h>... */
  984.  
  985. #ifndef FREAD
  986. #define FREAD 0x01
  987. #endif /* FREAD */
  988.  
  989. #ifndef FWRITE
  990. #define FWRITE 0x10
  991. #endif /* FWRITE */
  992.  
  993. #ifndef O_RDONLY
  994. #define O_RDONLY 000
  995. #endif /* O_RDONLY */
  996.  
  997. /* This is for ancient Unixes that don't have these tty symbols defined. */
  998.  
  999. #ifndef PENDIN
  1000. #define PENDIN ICANON
  1001. #endif /* PENDIN */
  1002. #ifndef FLUSHO
  1003. #define FLUSHO ICANON
  1004. #endif /* FLUSHO */
  1005. #ifndef EXTPROC
  1006. #define EXTPROC ICANON
  1007. #endif /* EXTPROC */
  1008.  
  1009. #ifdef SVORPOSIX
  1010. /*
  1011.   Modem signals are also forbidden in the POSIX world.  But some POSIX-based
  1012.   platforms let us at them anyway if we know where to look.
  1013. */
  1014. #ifndef NEEDMDMDEFS
  1015. /* Doesn't work for Linux */
  1016. #ifdef UNIXWARE7
  1017. #define NEEDMDMDEFS
  1018. #endif /* UNIXWARE7 */
  1019. #endif /* NEEDMDMDEFS */
  1020.  
  1021. #ifdef NEEDMDMDEFS
  1022. #ifndef TIOCMGET
  1023. #define TIOCMGET (('t'<<8)|29)
  1024. #endif /* TIOCMGET */
  1025.  
  1026. #ifndef TIOCM_DTR
  1027. #define TIOCM_DTR 0x0002
  1028. #endif /* TIOCM_DTR */
  1029. #ifndef TIOCM_RTS
  1030. #define TIOCM_RTS 0x0004
  1031. #endif /* TIOCM_RTS */
  1032. #ifndef TIOCM_CTS
  1033. #define TIOCM_CTS 0x0020
  1034. #endif /* TIOCM_CTS */
  1035. #ifndef TIOCM_CAR
  1036. #define TIOCM_CAR 0x0040
  1037. #endif /* TIOCM_CAR */
  1038. #ifndef TIOCM_RNG
  1039. #define TIOCM_RNG 0x0080
  1040. #endif /* TIOCM_RNG */
  1041. #ifndef TIOCM_DSR
  1042. #define TIOCM_DSR 0x0100
  1043. #endif /* TIOCM_DSR */
  1044. #endif /* NEEDMDMDEFS */
  1045. #endif /* SVORPOSIX */
  1046.  
  1047. /* Declarations */
  1048.  
  1049. #ifdef OXOS
  1050. #undef TCGETA
  1051. #undef TCSETA
  1052. #undef TCSETAW
  1053. #undef TCSETAF
  1054. #define TCGETA TCGETS
  1055. #define TCSETA TCSETS
  1056. #define TCSETAW TCSETSW
  1057. #define TCSETAF TCSETSF
  1058. #define termio termios
  1059. #endif /* OXOS */
  1060.  
  1061. #ifdef SVORPOSIX            /* AT&T Sys V or POSIX */
  1062. #ifdef UNIXWAREPOSIX            /* UnixWare 7 POSIX build */
  1063. /*
  1064.   In Unixware POSIX builds, <[sys/]time.h> refuses to define the
  1065.   structs we need to access the higher speeds, so we have to do it
  1066.   ourselves.
  1067. */
  1068. struct timeval {
  1069.     long tv_sec;
  1070.     long tv_usec;
  1071. };
  1072. struct timezone {
  1073.     int tz_minuteswest;
  1074.     int tz_dsttime;
  1075. };
  1076. #endif /* UNIXWAREPOSIX */
  1077. #endif /* SVORPOSIX */
  1078.  
  1079. #ifdef __GNUC__
  1080. #ifdef XENIX
  1081. /*
  1082.   Because Xenix <time.h> doesn't declare time() if we're using gcc.
  1083. */
  1084. time_t time();
  1085. #endif /* XENIX */
  1086. #endif /* __GNUC__ */
  1087.  
  1088. /* Special stuff for V7 input buffer peeking */
  1089.  
  1090. #ifdef  V7
  1091. int kmem[2] = { -1, -1};
  1092. char *initrawq(), *qaddr[2]={0,0};
  1093. #define CON 0
  1094. #define TTY 1
  1095. #endif /* V7 */
  1096.  
  1097. /* dftty is the device name of the default device for file transfer */
  1098. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  1099.  
  1100. #ifdef BEOS
  1101.     char * dftty = NULL;
  1102.     char * dfmdm = "none";
  1103.     int dfloc = 0;                  /* that goes in local mode by default */
  1104. #else
  1105. #ifndef DFTTY
  1106. #ifdef PROVX1
  1107.     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
  1108.     char *dfmdm = "none";
  1109.     int dfloc = 1;                  /* that goes in local mode by default */
  1110. #else
  1111.     char *dftty = CTTNAM;               /* Remote by default, use normal */
  1112.     char *dfmdm = "none";
  1113.     int dfloc = 0;                      /* controlling terminal name. */
  1114. #endif /* PROVX1 */
  1115. #else
  1116.     char *dftty = DFTTY;        /* Default location specified on */
  1117.     char *dfmdm = "none";        /* command line. */
  1118.     int dfloc = 1;                      /* controlling terminal name. */
  1119. #endif /* DFTTY */
  1120. #endif /* BEOS */
  1121.  
  1122. #define CON_RES 0            /* Console state is "reset" */
  1123. #define CON_CB  1            /* Console state is CBREAK */
  1124. #define CON_BIN 2            /* Console state is binary */
  1125.     static int constate = CON_RES;
  1126.  
  1127. #define CONI_RES 0            /* Console interrupts are "reset" */
  1128. #define CONI_INT 1            /* Console intterupts are set */
  1129. #define CONI_NOI 2            /* Console intterupts are disabled */
  1130.     static int conistate = CONI_RES;
  1131.  
  1132. #ifdef CK_SMALL
  1133. #define CONBUFSIZ 15
  1134. #else
  1135. #define CONBUFSIZ 255
  1136. #endif /* CK_SMALL */
  1137.     static char conbuf[CONBUFSIZ];    /* Console readahead buffer */
  1138.     static int  conbufn = 0;        /* Chars in readahead buffer */
  1139.     static char *conbufp = conbuf;    /* Next char in readahead buffer */
  1140.  
  1141.     char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
  1142.  
  1143. #ifdef RTU
  1144.     int rtu_bug = 0;            /* set to 1 when returning from SIGTSTP */
  1145. #endif /* RTU */
  1146.  
  1147.     int dfprty = DEFPAR;                /* Default parity (0 = none) */
  1148.     int ttprty = 0;                     /* The parity that is in use. */
  1149.     static int ttpmsk = 0xff;        /* Parity stripping mask. */
  1150.     int ttmdm = 0;                      /* Modem in use. */
  1151.     int ttcarr = CAR_AUT;        /* Carrier handling mode. */
  1152.     int dfflow = FLO_NONE;        /* Default flow control is NONE */
  1153.     int backgrd = 0;                    /* Assume in foreground (no '&' ) */
  1154. #ifdef F_SETFL
  1155.     int iniflags = -1;            /* fcntl flags for ttyfd */
  1156. #endif /* F_SETFL */
  1157.     int fdflag = 0;            /* Flag for redirected stdio */
  1158.     int ttfdflg = 0;            /* Open File descriptor was given */
  1159.     int tvtflg = 0;            /* Flag that ttvt has been called */
  1160.     long ttspeed = -1L;            /* For saving speed */
  1161.     int ttflow = -9;            /* For saving flow */
  1162.     int ttld = -1;            /* Line discipline */
  1163.  
  1164. #ifdef sony_news
  1165.     static int km_con = -1;        /* Kanji mode for console tty */
  1166.     static int km_ext = -1;        /* Kanji mode for external device */
  1167. #endif /* sony_news */
  1168.  
  1169. #ifdef PARSENSE
  1170.     static int needpchk = 1;        /* Need parity check */
  1171. #else
  1172.     static int needpchk = 0;
  1173. #endif /* PARSENSE */
  1174.  
  1175.     extern int stopbits;        /* Stop bits */
  1176. #ifdef HWPARITY
  1177. /*
  1178.   Unfortunately we must do this with global variables rather than through the
  1179.   tt...() APIs to avoid changing the APIs and the many modules that use them.
  1180.   If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
  1181.   bits + parity or 8 data bits and no parity, and overrides the regular parity
  1182.   variable, which is communicated to this module thru ttpkt(), and represented
  1183.   locally by the ttprty variable.
  1184. */
  1185.     extern int hwparity;        /* Hardware parity */
  1186. #endif /* HWPARITY */
  1187.  
  1188. #ifdef TCPSOCKET
  1189. #ifdef TCP_NODELAY
  1190. static int nodelay_sav = -1;
  1191. #endif /* TCP_NODELAY */
  1192. #endif /* TCPSOCKET */
  1193.  
  1194. static int sigint_ign = 0;        /* SIGINT is ignored */
  1195.  
  1196. /*
  1197.   Having this module rely on external globals is bad, but fixing this
  1198.   requires overhaul of the ck*tio.c modules for all the different operating
  1199.   systems supported by C-Kermit.  Left for a future release.
  1200. */
  1201. extern int ttnproto;            /* Defined in ckcnet.c */
  1202. extern int ttnet;            /* Defined in ckcnet.c */
  1203. extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
  1204. extern int xsuspend, wasclosed;
  1205. extern int inserver, local;
  1206.  
  1207. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  1208.  
  1209. int ckmaxfiles = 0;            /* Max number of open files */
  1210.  
  1211. #ifdef CK_ENCRYPTION            /* Kerberos */
  1212. #include "ckuath.h"
  1213. extern int me_encrypt, u_encrypt;
  1214. #endif /* CK_ENCRYPTION */
  1215.  
  1216. /* Declarations of variables global within this module */
  1217.  
  1218. #ifdef TTLEBUF                /* See ckcnet.h */
  1219. int ttpush = -1;
  1220. #define LEBUFSIZ 4096
  1221. static CHAR le_buf[LEBUFSIZ];
  1222. static int le_start = 0, le_end = 0, le_data = 0;
  1223. #endif /* TTLEBUF */
  1224.  
  1225. #define MSGBUF_SIZE 1024        /* For debugging */
  1226. static char msgbuf[MSGBUF_SIZE];
  1227.  
  1228. static int gotsigs = 0;
  1229.  
  1230. static time_t tcount = (time_t)0;    /* Elapsed time counter */
  1231.  
  1232. static SIGTYP (*saval)()     = NULL;    /* For saving alarm() handler */
  1233. static SIGTYP (*savquit)()   = NULL;    /* and other signal handlers */
  1234. #ifdef SIGUSR1
  1235. static SIGTYP (*savusr1)()   = NULL;
  1236. #endif /* SIGUSR1 */
  1237. #ifdef SIGUSR2
  1238. static SIGTYP (*savusr2)()   = NULL;
  1239. #endif /* SIGUSR2 */
  1240. #ifdef SIGPIPE
  1241. static SIGTYP (*savpipe)()   = NULL;
  1242. #endif /* SIGPIPE */
  1243. #ifdef SIGDANGER
  1244. static SIGTYP (*savdanger)() = NULL;
  1245. #endif /* SIGDANGER */
  1246.  
  1247. #ifndef NOJC
  1248. static SIGTYP (*jchdlr)()    = NULL;    /* For checking suspend handler */
  1249. #endif /* NOJC */
  1250. static int jcshell = -1;        /* And flag for result */
  1251.  
  1252. /*
  1253.   BREAKNULS is defined for systems that simulate sending a BREAK signal
  1254.   by sending a bunch of NUL characters at low speed.
  1255. */
  1256. #ifdef PROVX1
  1257. #ifndef BREAKNULS
  1258. #define BREAKNULS
  1259. #endif /* BREAKNULS */
  1260. #endif /* PROVX1 */
  1261.  
  1262. #ifdef V7
  1263. #ifndef BREAKNULS
  1264. #define BREAKNULS
  1265. #endif /* BREAKNULS */
  1266. #endif /* V7 */
  1267.  
  1268. #ifdef BREAKNULS
  1269. static char                /* A string of nulls */
  1270. *brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  1271. #endif /* BREAKNULS */
  1272.  
  1273. #ifdef CK_POSIX_SIG            /* Longjump buffers */
  1274. static sigjmp_buf sjbuf;        /* POSIX signal handling */
  1275. #else
  1276. static jmp_buf sjbuf;
  1277. #endif /* CK_POSIX_SIG */
  1278.  
  1279. #ifdef V7
  1280. static jmp_buf jjbuf;
  1281. #endif /* V7 */
  1282.  
  1283. /* static */                /* (Not static any more) */
  1284. int ttyfd = -1;                /* TTY file descriptor */
  1285.  
  1286. int ttpipe = 0;                /* NETCMD: Use pipe instead of ttyfd */
  1287. int ttpty  = 0;                         /* NETPTY: Use pty instead of ttfyd */
  1288.  
  1289. #ifdef NETPTY                /* These are in ckupty.c */
  1290. extern PID_T pty_fork_pid;
  1291. extern int pty_master_fd, pty_slave_fd;
  1292. #endif    /* NETPTY */
  1293.  
  1294. #ifdef NETCMD
  1295. #ifdef NETCONN
  1296. static int pipe0[2], pipe1[2];        /* Pipes for net i/o */
  1297. #endif /* NETCONN */
  1298. static PID_T ttpid = 0;            /* Process ID for fork */
  1299. static int fdin, fdout;            /* File descriptors for pipe */
  1300. static FILE * ttout = NULL;        /* File pointer for output pipe */
  1301. #ifdef DCLFDOPEN
  1302. /* fdopen() needs declaring because it's not declared in <stdio.h> */
  1303. _PROTOTYP( FILE * fdopen, (int, char *) );
  1304. #endif /* DCLFDOPEN */
  1305. #endif /* NETCMD */
  1306.  
  1307. extern int pexitstat, quiet;
  1308.  
  1309. #ifdef Plan9
  1310. int ttyctlfd  = -1;   /* TTY control channel - What? UNIX doesn't have one? */
  1311. int consctlfd = -1;            /* Console control channel */
  1312. int noisefd = -1;            /* tone channel */
  1313. static int ttylastspeed = -1;        /* So we can lie about the speed */
  1314. #endif /* Plan9 */
  1315.  
  1316. int telnetfd = 0;            /* File descriptor is for telnet */
  1317. #ifdef NETCONN
  1318. int x25fd = 0;                /* File descriptor is for X.25 */
  1319. #endif /* NETCONN */
  1320.  
  1321. char lockpid[16] = { '\0', '\0' };    /* PID stored in lockfile, as string */
  1322.  
  1323. static int lkf = 0,                     /* Line lock flag */
  1324.     cgmf = 0,                           /* Flag that console modes saved */
  1325.     xlocal = 0,                         /* Flag for tty local or remote */
  1326.     curcarr = 0;            /* Carrier mode: require/ignore. */
  1327.  
  1328. static int netconn = 0;            /* 1 if network connection active */
  1329.  
  1330. static char escchr;                     /* Escape or attn character */
  1331.  
  1332. #ifdef CK_SCO32V4
  1333. #include <sys/time.h>
  1334. #endif /* CK_SCO32V4 */
  1335.  
  1336. #ifdef HAVE_TV
  1337.     static struct timeval tv;        /* For getting time, from sys/time.h */
  1338. #endif /* HAVE_TV */
  1339. #ifdef HAVE_TZ
  1340.     static struct timezone tz;
  1341. #endif /* HAVE_TZ */
  1342.  
  1343. #ifdef OSF
  1344.     static struct timeb ftp;            /* And from sys/timeb.h */
  1345. #endif /* OSF */
  1346.  
  1347. #ifdef BSD29
  1348.     static long xclock;            /* For getting time from sys/time.h */
  1349.     static struct timeb ftp;            /* And from sys/timeb.h */
  1350. #endif /* BSD29 */
  1351.  
  1352. #ifdef BSD41
  1353.     static long xclock;            /* For getting time from sys/time.h */
  1354.     static struct timeb ftp;            /* And from sys/timeb.h */
  1355. #endif /* BSD41 */
  1356.  
  1357. #ifdef BELLV10
  1358.     static long xclock;            /* For getting time from sys/time.h */
  1359.     static struct timeb ftp;            /* And from sys/timeb.h */
  1360. #endif /* BELLV10 */
  1361.  
  1362. #ifdef FT21
  1363.     static long xclock;            /* For getting time from sys/time.h */
  1364.     static struct timeb ftp;            /* And from sys/timeb.h */
  1365. #endif /* FT21 */
  1366.  
  1367. #ifdef TOWER1
  1368.     static long xclock;            /* For getting time from sys/time.h */
  1369.     static struct timeb ftp;        /* And from sys/timeb.h */
  1370. #endif /* TOWER1 */
  1371.  
  1372. #ifdef COHERENT
  1373.     static long xclock;            /* For getting time from sys/time.h */
  1374.     static struct timeb ftp;        /* And from sys/timeb.h */
  1375. #endif /* COHERENT */
  1376.  
  1377. #ifdef V7
  1378.     static long xclock;
  1379. #endif /* V7 */
  1380.  
  1381. /* sgtty/termio information... */
  1382.  
  1383. #ifdef BSD44ORPOSIX            /* POSIX or BSD44 */
  1384.   static struct termios
  1385.     ttold, ttraw, tttvt, ttcur,
  1386.     ccold, ccraw, cccbrk;
  1387. #else                    /* BSD, V7, etc */
  1388.  
  1389. #ifdef COHERENT                /* Hack alert... */
  1390. #define ATTSV
  1391. #endif /* COHERENT */
  1392.  
  1393. #ifdef ATTSV
  1394.   static struct termio ttold = {0};    /* Init'd for word alignment, */
  1395.   static struct termio ttraw = {0};    /* which is important for some */
  1396.   static struct termio tttvt = {0};    /* systems, like Zilog... */
  1397.   static struct termio ttcur = {0};
  1398.   static struct termio ccold = {0};
  1399.   static struct termio ccraw = {0};
  1400.   static struct termio cccbrk = {0};
  1401. #else
  1402.   static struct sgttyb                  /* sgtty info... */
  1403.     ttold, ttraw, tttvt, ttcur,     /* for communication line */
  1404.     ccold, ccraw, cccbrk;        /* and for console */
  1405. #ifdef BELLV10
  1406.   static struct ttydevb            /* Device info... */
  1407.     tdold, tdcur;            /* for communication device */
  1408. #endif /* BELLV10 */
  1409. #ifdef TIOCGETC
  1410.   static struct tchars tchold, tchnoi;
  1411.  
  1412.   static int tcharf;
  1413. #endif /* TIOCGETC */
  1414. #ifdef TIOCGLTC
  1415.   static struct ltchars ltchold, ltchnoi;
  1416.   static int ltcharf;
  1417. #endif /* TIOCGLTC */
  1418.   int lmodef = 0;            /* Local modes */
  1419.   int lmode = 0;
  1420. #endif /* ATTSV */
  1421. #endif /* BSD44ORPOSIX */
  1422.  
  1423. #ifdef COMMENT
  1424. /* It picks up the speeds but they don't work */
  1425. #ifdef UNIXWARE                /* For higher serial speeds */
  1426. #ifdef UW7                /* in Unixware 7.0 */
  1427. #include <sys/asyc.h>            /* This picks up 57600 and 115200 */
  1428. #endif /* UW7 */
  1429. #endif /* UNIXWARE */
  1430. #endif /* COMMENT */
  1431.  
  1432. #ifdef PROVX1
  1433.   static struct sgttyb ttbuf;
  1434. #endif /* PROVX1 */
  1435.  
  1436. #ifdef ultrix
  1437. /* do we really need this? */
  1438.   static struct sgttyb vanilla;
  1439. #endif /* ultrix */
  1440.  
  1441. #ifdef ATT7300
  1442. static int attmodem = 0;                /* ATT7300 internal-modem status */
  1443. struct updata dialer = {0};        /* Condition dialer for data call */
  1444. #endif /* ATT7300 */
  1445.  
  1446. #ifndef NOUUCP
  1447. #define FLFNAML 128
  1448. #ifndef USETTYLOCK
  1449. #ifdef RTAIX
  1450. char lkflfn[FLFNAML] = { '\0', '\0' };    /* and possible link to it */
  1451. #endif /* RTAIX */
  1452. char lock2[FLFNAML] =  { '\0', '\0' };    /* Name of second lockfile */
  1453. #endif /* USETTYLOCK */
  1454. #else
  1455. #define FLFNAML 7
  1456. #endif /* NOUUCP */
  1457. char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
  1458.  
  1459. int haslock = 0;            /* =1 if this kermit locked uucp */
  1460.  
  1461. #ifndef OXOS
  1462. #ifdef SVORPOSIX
  1463. static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
  1464. #else
  1465. #ifdef V7
  1466. static int conesc = 0;
  1467. #else
  1468. #ifdef C70
  1469. static int conesc = 0;
  1470. #endif /* C70 */
  1471. #endif /* V7 */
  1472. #endif /* SVORPOSIX */
  1473. #endif /* OXOS */
  1474.  
  1475. /* Local copy of comm device name or network host */
  1476. static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
  1477. #ifdef USETTYLOCK
  1478. static char lockname[DEVNAMLEN+1];    /* Ditto, the part after "/dev/". */
  1479. #endif /* USETTYLOCK */
  1480.  
  1481. #ifdef aegis
  1482. static status_$t st;                    /* error status return value */
  1483. static short concrp = 0;                /* true if console is CRP pad */
  1484. static uid_$t ttyuid;                   /* tty type uid */
  1485. static uid_$t conuid;                   /* stdout type uid */
  1486.  
  1487. /* APOLLO Aegis main()
  1488.  * establish acl usage and cleanup handling
  1489.  *    this makes sure that CRP pads
  1490.  *    get restored to a usable mode
  1491.  */
  1492. main(argc,argv) int argc; char **argv; {
  1493.         status_$t status;
  1494.         pfm_$cleanup_rec dirty;
  1495.  
  1496.         PID_T pid = getpid();
  1497.  
  1498.         /* acl usage according to invoking environment */
  1499.         default_acl(USE_DEFENV);
  1500.  
  1501.         /* establish a cleanup continuation */
  1502.         status = pfm_$cleanup(dirty);
  1503.         if (status.all != pfm_$cleanup_set) {
  1504.                 /* only handle faults for the original process */
  1505.                 if (pid == getpid() && status.all > pgm_$max_severity) {
  1506.             /* blew up in main process */
  1507.             status_$t quo;
  1508.             pfm_$cleanup_rec clean;
  1509.  
  1510.             /* restore the console in any case */
  1511.             conres();
  1512.  
  1513.             /* attempt a clean exit */
  1514.             debug(F101, "cleanup fault status", "", status.all);
  1515.  
  1516.             /* doexit(), then send status to continuation */
  1517.             quo = pfm_$cleanup(clean);
  1518.             if (quo.all == pfm_$cleanup_set)
  1519.               doexit(pgm_$program_faulted,-1);
  1520.             else if (quo.all > pgm_$max_severity)
  1521.               pfm_$signal(quo); /* blew up in doexit() */
  1522.                 }
  1523.                 /* send to the original continuation */
  1524.                 pfm_$signal(status);
  1525.                 /*NOTREACHED*/
  1526.         }
  1527.         return(ckcmai(argc, argv));
  1528. }
  1529. #endif /* aegis */
  1530.  
  1531. /* ANSI-style prototypes for internal functions. */
  1532. /* Functions used outside this module are prototyped in ckcker.h. */
  1533.  
  1534. #ifdef apollo
  1535. _PROTOTYP( SIGTYP timerh, () );
  1536. _PROTOTYP( SIGTYP cctrap, () );
  1537. _PROTOTYP( SIGTYP esctrp, () );
  1538. _PROTOTYP( SIGTYP sig_ign, () );
  1539. #else
  1540. _PROTOTYP( SIGTYP timerh, (int) );
  1541. _PROTOTYP( SIGTYP cctrap, (int) );
  1542. _PROTOTYP( SIGTYP esctrp, (int) );
  1543. #endif /* apollo */
  1544. _PROTOTYP( int do_open, (char *) );
  1545. _PROTOTYP( static int in_chk, (int, int) );
  1546. _PROTOTYP( static int ttrpid, (char *) );
  1547. _PROTOTYP( static int ttchkpid, (char *) );
  1548. _PROTOTYP( static int ttlock, (char *) );
  1549. _PROTOTYP( static int ttunlck, (void) );
  1550. _PROTOTYP( static VOID sigchld_handler, (int) );
  1551. _PROTOTYP( int mygetbuf, (void) );
  1552. _PROTOTYP( int myfillbuf, (void) );
  1553. _PROTOTYP( VOID conbgt, (int) );
  1554. #ifdef ACUCNTRL
  1555. _PROTOTYP( VOID acucntrl, (char *, char *) );
  1556. #endif /* ACUCNTRL */
  1557.  
  1558. #ifdef BSD44ORPOSIX
  1559. _PROTOTYP( int carrctl, (struct termios *, int) );
  1560. #else
  1561. #ifdef ATTSV
  1562. _PROTOTYP( int carrctl, (struct termio *, int) );
  1563. #else
  1564. _PROTOTYP( int carrctl, (struct sgttyb *, int) );
  1565. #endif /* ATTSV */
  1566. #endif /* BSD44ORPOSIX */
  1567.  
  1568. #ifdef ATT7300
  1569. _PROTOTYP( int attdial, (char *, long, char *) );
  1570. _PROTOTYP( int offgetty, (char *) );
  1571. _PROTOTYP( int ongetty, (char *) );
  1572. #endif /* ATT7300 */
  1573.  
  1574. #ifdef BEOSORBEBOX
  1575. #ifdef SELECT
  1576.     /* BeOS is not capable of using SELECT on anything but sockets */
  1577. #undef SELECT
  1578. #endif /* SELECT */
  1579. #include <kernel/OS.h>
  1580. /* #ifdef BE_DR_7 */
  1581. static double time_started = 0.0;
  1582. struct ALARM_STRUCT {
  1583.     thread_id thread;
  1584.     int time;
  1585. };
  1586. static thread_id alarm_thread = -1;
  1587. static struct ALARM_STRUCT alarm_struct;
  1588. _PROTOTYP( long do_alarm, (void *) );
  1589. _PROTOTYP( unsigned int alarm, (unsigned int) );
  1590. _PROTOTYP( void alarm_expired, (void) );
  1591. /* #endif */ /* BE_DR_7 */
  1592. #endif /* BEOSORBEBOX */
  1593.  
  1594. #ifndef xunchar
  1595. #define xunchar(ch) (((ch) - 32 ) & 0xFF )    /* Character to number */
  1596. #endif /* xunchar */
  1597.  
  1598. #ifdef CK_ANSIC
  1599. static char *
  1600. xxlast(char *s, char c)
  1601. #else
  1602. static char *
  1603. xxlast(s,c) char *s; char c;
  1604. #endif /* CK_ANSIC */
  1605. /* xxlast */ {        /*  Last occurrence of character c in string s. */
  1606.     int i;
  1607.     for (i = (int)strlen(s); i > 0; i--)
  1608.       if (s[i-1] == c ) return(s + (i - 1));
  1609.     return(NULL);
  1610. }
  1611.  
  1612. /* Timeout handler for communication line input functions */
  1613.  
  1614. /*ARGSUSED*/
  1615. SIGTYP
  1616. timerh(foo) int foo; {
  1617.     ttimoff();
  1618. #ifdef BEOSORBEBOX
  1619. /* #ifdef BE_DR_7 */
  1620.     alarm_expired();
  1621. /* #endif */ /* BE_DR_7 */
  1622. #endif /* BEOSORBEBOX */
  1623. #ifdef CK_POSIX_SIG
  1624.     siglongjmp(sjbuf,1);
  1625. #else
  1626.     longjmp(sjbuf,1);
  1627. #endif /* CK_POSIX_SIG */
  1628. }
  1629.  
  1630. /*ARGSUSED*/
  1631. SIGTYP
  1632. xtimerh(foo) int foo; {            /* Like timerh() but does */
  1633. #ifdef BEOSORBEBOX            /* not reset the timer itself */
  1634. /* #ifdef BE_DR_7 */
  1635.     alarm_expired();
  1636. /* #endif */ /* BE_DR_7 */
  1637. #endif /* BEOSORBEBOX */
  1638. #ifdef CK_POSIX_SIG
  1639.     siglongjmp(sjbuf,1);
  1640. #else
  1641.     longjmp(sjbuf,1);
  1642. #endif /* CK_POSIX_SIG */
  1643. }
  1644.  
  1645.  
  1646. /* Control-C trap for communication line input functions */
  1647.  
  1648. int cc_int;                /* Flag */
  1649. SIGTYP (* occt)();            /* For saving old SIGINT handler */
  1650.  
  1651. /*ARGSUSED*/
  1652. SIGTYP
  1653. cctrap(foo) int foo; {            /* Needs arg for ANSI C */
  1654.   cc_int = 1;                /* signal() prototype. */
  1655.   return;
  1656. }
  1657.  
  1658. /*  S Y S I N I T  --  System-dependent program initialization.  */
  1659.  
  1660. /*
  1661.  * ttgwsiz() returns:
  1662.  *    1    tt_rows and tt_cols are known, both altered, both > 0
  1663.  *    0    tt_rows and/or tt_cols are known, both altered, one or both <= 0
  1664.  *    -1   tt_rows and tt_cols are unknown and unaltered
  1665.  */
  1666.  
  1667. extern int tt_rows, tt_cols;
  1668.  
  1669. static int
  1670. xttgwsiz() {
  1671.     char *p;
  1672.     int rows = 0, cols = 0;
  1673.     p = getenv("LINES");
  1674.     debug(F110,"xttgwsiz LINES",p,0);
  1675.     if (p) {
  1676.     rows = atol(p);
  1677.     if (rows > 0) {
  1678.         p = getenv("COLUMNS");
  1679.         debug(F110,"xttgwsiz COLUMNS",p,0);
  1680.         if (p) {
  1681.         cols = atol(p);
  1682.         if (cols > 0) {
  1683.             tt_rows = rows;
  1684.             tt_cols = cols;
  1685.             return(1);
  1686.         }
  1687.         return(0);
  1688.         }
  1689.     }
  1690.     }
  1691.     return(-1);
  1692. }
  1693.  
  1694. #ifdef TTLEBUF
  1695. VOID
  1696. le_init() {                /* LocalEchoInit() */
  1697.     int i;
  1698.     for (i = 0; i < LEBUFSIZ; i++)
  1699.       le_buf[i] = '\0';
  1700.     le_start = 0;
  1701.     le_end = 0;
  1702.     le_data = 0;
  1703. }
  1704.  
  1705. VOID
  1706. le_clean() {                /* LocalEchoCleanup() */
  1707.     le_init();
  1708.     return;
  1709. }
  1710.  
  1711. int
  1712. le_inbuf() {
  1713.     int rc = 0;
  1714.     if (le_start != le_end) {
  1715.     rc = (le_end -
  1716.           le_start +
  1717.           LEBUFSIZ) % LEBUFSIZ;
  1718.     }
  1719.     debug(F111,"le_inbuf","chars waiting",rc);
  1720.     return(rc);
  1721. }
  1722.  
  1723. int
  1724. #ifdef CK_ANSIC
  1725. le_putchar(CHAR ch)
  1726. #else
  1727. le_putchar(ch) CHAR ch;
  1728. #endif /* CK_ANSIC */
  1729. /* le_putchar */ {
  1730. #ifdef COMMENT
  1731.     /* In UNIX we do not have another thread taking chars out of the buffer */
  1732.     while ((le_start - le_end == 1) ||
  1733.             (le_start == 0 && le_end == LEBUFSIZ - 1)) {
  1734.     /* Buffer is full */
  1735.         debug(F111,"le_putchar","Buffer is Full",ch);
  1736.         ReleaseLocalEchoMutex() ;
  1737.         msleep(250);
  1738.         RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
  1739.     }
  1740. #else
  1741.     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
  1742.         debug(F110,"le_putchar","buffer is full",0);
  1743.         return(-1);
  1744.     }
  1745. #endif /* COMMENT */
  1746.     le_buf[le_end++] = ch;
  1747.     if (le_end == LEBUFSIZ)
  1748.       le_end = 0;
  1749.     le_data = 1;
  1750.     return(0);
  1751. }
  1752.  
  1753. int
  1754. #ifdef CK_ANSIC
  1755. le_puts(CHAR * s, int n)
  1756. #else
  1757. le_puts(s,n) CHAR * s; int n;
  1758. #endif /* CK_ANSIC */
  1759. /* le_puts */ {
  1760.     int rc = 0;
  1761.     int i = 0;
  1762.     CHAR * p = (CHAR *)"le_puts";
  1763.     ckhexdump(p,s,n);
  1764.     for (i = 0; i < n; i++)
  1765.       rc = le_putchar((char)s[i]);
  1766.     debug(F101,"le_puts","",rc);
  1767.     return(rc);
  1768. }
  1769.  
  1770. int
  1771. #ifdef CK_ANSIC
  1772. le_putstr(CHAR * s)
  1773. #else
  1774. le_putstr(s) CHAR * s;
  1775. #endif /* CK_ANSIC */
  1776. /* le_puts */ {
  1777.     CHAR * p;
  1778.     int rc = 0;
  1779.     p = (CHAR *)"le_putstr";
  1780.     ckhexdump(p,s,(int)strlen((char *)s));
  1781.     for (p = s; *p && !rc; p++)
  1782.       rc = le_putchar(*p);
  1783.     return(rc);
  1784. }
  1785.  
  1786. int
  1787. #ifdef CK_ANSIC
  1788. le_getchar(CHAR * pch)
  1789. #else /* CK_ANSIC */
  1790. le_getchar(pch) CHAR * pch;
  1791. #endif /* CK_ANSIC */
  1792. /* le_gatchar */ {
  1793.     int rc = 0;
  1794.     if (le_start != le_end) {
  1795.         *pch = le_buf[le_start];
  1796.         le_buf[le_start] = 0;
  1797.         le_start++;
  1798.  
  1799.         if (le_start == LEBUFSIZ)
  1800.           le_start = 0;
  1801.  
  1802.         if (le_start == le_end) {
  1803.             le_data = 0;
  1804.         }
  1805.         rc++;
  1806.     } else {
  1807.         *pch = 0;
  1808.     }
  1809.     return(rc);
  1810. }
  1811. #endif /* TTLEBUF */
  1812.  
  1813. #ifdef COMMENT
  1814. /*
  1815.   Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
  1816.   But as far as I know, whenever TIOCGSIZE is defined, it is
  1817.   equated to TIOCGWINSZ.  For cases where this is not done, try this:
  1818. */
  1819. #ifndef TIOCGWINSZ
  1820. #ifdef TIOCGSIZE
  1821. #define TIOCGWINSZ TIOCGSIZE
  1822. #endif /* TIOCGSIZE */
  1823. #endif /* TIOCGWINSZ */
  1824. #endif /* COMMENT */
  1825.  
  1826. static int tt_xpixel = 0, tt_ypixel = 0;
  1827.  
  1828. int
  1829. ttgwsiz() {
  1830.     int x = 0;
  1831. #ifndef NONAWS
  1832. #ifdef QNX
  1833. /*
  1834.   NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
  1835.   This code works for both the 16- and 32-bit versions.
  1836. */
  1837.     extern int dev_size(int, int, int, int *, int *);
  1838.     int r, c;
  1839.  
  1840.     if (dev_size(0, -1, -1, &r, &c) == 0) {
  1841.     debug(F101,"ttgwsiz QNX r","",r);
  1842.     debug(F101,"ttgwsiz QNX c","",c);
  1843.     tt_rows = r;
  1844.     tt_cols = c;
  1845.     return ((r > 0 && c > 0) ? 1 : 0);
  1846.     } else return(xttgwsiz());
  1847. #else /* QNX */
  1848. #ifdef TIOCGWINSZ
  1849.  
  1850. /* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
  1851. #ifdef XENIX                /* SCO UNIX 3.2v4.0 */
  1852. #include <sys/stream.h>            /* typedef mblk_t needed by ptem.h */
  1853. #include <sys/ptem.h>            /* for ttgwsiz() */
  1854. #endif /* XENIX */
  1855.  
  1856. #ifdef I386IX                /* Ditto for Interactive */
  1857. #include <sys/stream.h>
  1858. #include <sys/ptem.h>
  1859. #endif /* I386IX */
  1860.  
  1861. /* Note, the above might be needed for some other older SVR3 Intel makes... */
  1862.  
  1863.     struct winsize w;
  1864.     tt_xpixel = 0;
  1865.     tt_ypixel = 0;
  1866.  
  1867. #ifdef IKSD
  1868.     if (inserver)
  1869.       return(xttgwsiz());
  1870. #endif /* IKSD */
  1871.     x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
  1872.     debug(F101,"ttgwsiz TIOCGWINSZ","",x);
  1873.     if (x < 0) {
  1874.     return(xttgwsiz());
  1875.     } else if (w.ws_row > 0 && w.ws_col > 0) {
  1876.     tt_rows = w.ws_row;
  1877.     tt_cols = w.ws_col;
  1878.     tt_xpixel = w.ws_xpixel;
  1879.     tt_ypixel = w.ws_ypixel;
  1880.     debug(F101,"ttgwsiz tt_rows","",tt_rows);
  1881.     debug(F101,"ttgwsiz tt_cols","",tt_cols);
  1882.     return(1);
  1883.     } else {
  1884.     debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
  1885.     return(xttgwsiz());
  1886.     }
  1887. #else
  1888.     return(xttgwsiz());
  1889. #endif /* TIOCGWINSZ */
  1890. #endif /* QNX */
  1891. #endif /* NONAWS */
  1892. }
  1893.  
  1894.  
  1895. #ifdef RLOGCODE
  1896. _PROTOTYP( int rlog_naws, (void) );
  1897. #endif    /* RLOGCODE */
  1898.  
  1899. #ifndef NOSIGWINCH
  1900. #ifdef SIGWINCH
  1901. SIGTYP
  1902. winchh(foo) int foo; {            /* SIGWINCH handler */
  1903.     int x = 0;
  1904. #ifdef CK_TTYFD
  1905. #ifndef VMS
  1906.     extern int ttyfd;
  1907. #endif /* VMS */
  1908. #endif /* CK_TTYFD */
  1909.     extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
  1910. #ifdef DEBUG
  1911.     if (deblog) {
  1912.     debug(F100,"***************","",0);
  1913.     debug(F100,"SIGWINCH caught","",0);
  1914.     debug(F100,"***************","",0);
  1915. #ifdef NETPTY
  1916.     debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
  1917. #endif /* NETPTY */
  1918.     }
  1919. #endif /* DEUB */
  1920.     signal(SIGWINCH,winchh);            /* Re-arm the signal */
  1921.     x = ttgwsiz();                      /* Get new window size */
  1922.     cmd_rows = tt_rows;            /* Adjust command screen too */
  1923.     cmd_cols = tt_cols;
  1924.  
  1925. #ifdef CK_TTYFD
  1926.     if                    /* If we don't have a connection */
  1927. #ifdef VMS                /* we're done. */
  1928.       (vmsttyfd() == -1)
  1929. #else
  1930.       (ttyfd == -1)
  1931. #endif /* VMS */
  1932. #else
  1933.       (!local)
  1934. #endif /* CK_TTYFD */
  1935.         return;
  1936.  
  1937. #ifdef NETPTY
  1938.     if (pty_fork_pid > -1) {        /* "set host" to a PTY? */
  1939.     int x;
  1940.  
  1941. #ifdef TIOCSWINSZ
  1942.     struct winsize w;        /* Resize the PTY */
  1943.     errno = 0;
  1944.     w.ws_col = tt_cols;
  1945.     w.ws_row = tt_rows;
  1946.     w.ws_xpixel = tt_xpixel;
  1947.     w.ws_ypixel = tt_ypixel;
  1948.     x = ioctl(ttyfd,TIOCSWINSZ,&w);
  1949.     debug(F101,"winchh TIOCSWINSZ","",x);
  1950.     debug(F101,"winchh TIOCSWINSZ errno","",errno);
  1951. #endif /* TIOCSWINSZ */
  1952.  
  1953.     errno = 0;
  1954.     x = kill(pty_fork_pid,SIGWINCH);
  1955.     debug(F101,"winchh kill","",x);
  1956.     debug(F101,"winchh kill errno","",errno);
  1957.     }
  1958. #endif /* NETPTY */
  1959.  
  1960. /*
  1961.   This should be OK.  It might seem that sending this from
  1962.   interrupt level could interfere with another TELNET IAC string
  1963.   that was in the process of being sent.  But we always send
  1964.   TELNET strings with a single write(), which should prevent mixups.
  1965.   blah_snaws() should protect themselves from being called on the
  1966.   wrong kind of connection.
  1967. */
  1968. #ifdef TCPSOCKET
  1969. #ifndef NOTTGWSIZ
  1970.     if (x > 0 && tt_rows > 0 && tt_cols > 0) {
  1971.         tn_snaws();
  1972. #ifdef RLOGCODE
  1973.         rlog_naws();
  1974. #endif /* RLOGCODE */
  1975.     }
  1976. #endif /* NOTTGWSIZ */
  1977. #endif /* TCPSOCKET */
  1978.     SIGRETURN;
  1979. }
  1980. #endif /* SIGWINCH */
  1981. #endif /* NOSIGWINCH */
  1982.  
  1983. SIGTYP
  1984. sighup(foo) int foo; {            /* SIGHUP handler */
  1985.     backgrd = 1;
  1986.     debug(F100,"***************","",0);
  1987.     debug(F100,"SIGHUP received","",0);
  1988.     debug(F100,"***************","",0);
  1989.     doexit(BAD_EXIT,-1);
  1990.     /*NOTREACHED*/
  1991.     SIGRETURN;                /* Shut picky compilers up... */
  1992. }
  1993.  
  1994. #ifdef CK_SCO32V4
  1995. /* Exists but there is no prototype in the header files */
  1996. _PROTOTYP( char * ttyname, (int) );
  1997. #else
  1998. #ifdef SV68R3V6
  1999. _PROTOTYP( char * ttyname, (int) );
  2000. #else
  2001. #ifdef ultrix
  2002. _PROTOTYP( char * ttyname, (int) );
  2003. #else
  2004. #ifdef HPUX6
  2005. _PROTOTYP( char * ttyname, (int) );
  2006. #else
  2007. #ifdef HPUX5
  2008. _PROTOTYP( char * ttyname, (int) );
  2009. #else
  2010. #ifdef PS2AIX10
  2011. _PROTOTYP( char * ttyname, (int) );
  2012. #else
  2013. #ifdef BSD42
  2014. _PROTOTYP( char * ttyname, (int) );
  2015. #endif /* BSD42 */
  2016. #endif /* PS2AIX10 */
  2017. #endif /* HPUX5 */
  2018. #endif /* HPUX6 */
  2019. #endif /* ultrix */
  2020. #endif /* SV68R3V6 */
  2021. #endif /* CK_SCO32V4 */
  2022.  
  2023. #ifndef SIGUSR1                /* User-defined signals */
  2024. #define SIGUSR1 30
  2025. #endif /* SIGUSR1 */
  2026.  
  2027. #ifndef SIGUSR2
  2028. #define SIGUSR2 31
  2029. #endif /* SIGUSR2 */
  2030.  
  2031. /*
  2032.   ignorsigs() sets certain signals to SIG_IGN.  But when a signal is
  2033.   ignored, it remains ignored across exec(), so we have to restore these
  2034.   signals before exec(), which is the purpose of restorsigs().
  2035. */
  2036. static VOID
  2037. ignorsigs() {                /* Ignore these signals */
  2038.     savquit = signal(SIGQUIT,SIG_IGN);    /* Ignore Quit signal */
  2039.  
  2040. #ifdef SIGDANGER            /* Ignore danger signals */
  2041. /*
  2042.   This signal is sent when the system is low on swap space.  Processes
  2043.   that don't handle it are candidates for termination.  If swap space doesn't
  2044.   clear out enough, we still might be terminated via kill() -- nothing we can
  2045.   do about that!  Conceivably, this could be improved by installing a real
  2046.   signal handler that warns the user, but that would be pretty complicated,
  2047.   since we are not always in control of the screen -- e.g. during remote-mode
  2048.   file transfer.
  2049. */
  2050.     savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
  2051. #endif /* SIGDANGER */
  2052. #ifdef SIGPIPE
  2053. /*
  2054.   This one comes when a TCP/IP connection is broken by the remote.
  2055.   We prefer to catch this situation by examining error codes from write().
  2056. */
  2057.     savpipe = signal(SIGPIPE,SIG_IGN);
  2058. #endif /* SIGPIPE */
  2059.     savusr1 = signal(SIGUSR1,SIG_IGN);    /* Ignore user-defined signals */
  2060.     savusr2 = signal(SIGUSR2,SIG_IGN);
  2061. }
  2062.  
  2063. VOID
  2064. restorsigs() {                /* Restore these signals */
  2065.     (VOID) signal(SIGQUIT,savquit);    /* (used in ckufio.c) */
  2066. #ifdef SIGDANGER
  2067.     (VOID) signal(SIGDANGER,savdanger);
  2068. #endif /* SIGDANGER */
  2069. #ifdef SIGPIPE
  2070.     (VOID) signal(SIGPIPE,savpipe);
  2071. #endif /* SIGPIPE */
  2072.     (VOID) signal(SIGUSR1,savusr1);
  2073.     (VOID) signal(SIGUSR2,savusr2);
  2074. }
  2075.  
  2076. int
  2077. sysinit() {
  2078.     int x;
  2079.     char * s;
  2080. #ifdef CK_UTSNAME
  2081.     struct utsname name;
  2082. #endif /* CK_UTSNAME */
  2083.  
  2084.     extern char startupdir[];
  2085. /*
  2086.   BEFORE ANYTHING ELSE: Initialize the setuid package.
  2087.   Change to the user's real user and group ID.
  2088.   If this can't be done, don't run at all.
  2089. */
  2090.     x = priv_ini();
  2091. #ifdef SUIDDEBUG
  2092.     fprintf(stderr,"PRIV_INI=%d\n",x);
  2093. #endif /* SUIDDEBUG */
  2094.     if (x) {
  2095.     if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
  2096.     if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
  2097.     if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
  2098.     exit(1);
  2099.     }
  2100.     signal(SIGINT,SIG_IGN);        /* Ignore interrupts at first */
  2101.     signal(SIGFPE,SIG_IGN);        /* Ignore floating-point exceptions */
  2102.     signal(SIGHUP,sighup);        /* Catch SIGHUP */
  2103. #ifndef NOSIGWINCH
  2104. #ifdef SIGWINCH
  2105.     signal(SIGWINCH,winchh);        /* Catch window-size change */
  2106. #endif /* SIGWINCH */
  2107. #endif /* NOSIGWINCH */
  2108.  
  2109. #ifdef SIGXFSZ
  2110.     signal(SIGXFSZ,SIG_IGN);        /* Ignore writing past file limit */ 
  2111. #endif    /* SIGXFSZ */
  2112.  
  2113. #ifndef NOJC
  2114. /*
  2115.   Get the initial job control state.
  2116.   If it is SIG_IGN, that means the shell does not support job control,
  2117.   and so we'd better not suspend ourselves.
  2118. */
  2119. #ifdef SIGTSTP
  2120.     jchdlr = signal(SIGTSTP,SIG_IGN);
  2121.     if (jchdlr == SIG_IGN) {
  2122.     jcshell = 0;
  2123.     debug(F100,"sysinit jchdlr: SIG_IGN","",0);
  2124.     } else if (jchdlr == SIG_DFL) {
  2125.     debug(F100,"sysinit jchdlr: SIG_DFL","",0);
  2126.     jcshell = 1;
  2127.     } else {
  2128.     debug(F100,"sysinit jchdlr: other","",0);
  2129.     jcshell = 3;
  2130.     }
  2131.     (VOID) signal(SIGTSTP,jchdlr);    /* Put it back... */
  2132. #endif /* SIGTSTP */
  2133. #endif /* NOJC */
  2134.  
  2135.     conbgt(0);                /* See if we're in the background */
  2136.     congm();                /* Get console modes */
  2137.  
  2138.     (VOID) signal(SIGALRM,SIG_IGN);    /* Ignore alarms */
  2139.  
  2140.     ignorsigs();            /* Ignore some other signals */
  2141.  
  2142. #ifdef F_SETFL
  2143.     iniflags = fcntl(0,F_GETFL,0);    /* Get stdin flags */
  2144. #endif /* F_SETFL */
  2145.  
  2146. #ifdef ultrix
  2147.     gtty(0,&vanilla);            /* Get sgtty info */
  2148. #else
  2149. #ifdef AUX
  2150.     set42sig();                /* Don't ask! (hakanson@cs.orst.edu) */
  2151. #endif /* AUX */
  2152. #endif /* ultrix */
  2153. /*
  2154.   Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
  2155.   never closes it.  If it is called often enough, we run out of file
  2156.   descriptors and subsequent open()'s of other devices or files can fail.
  2157. */
  2158.     s = NULL;
  2159. #ifndef MINIX
  2160.     if (isatty(0))            /* Name of controlling terminal */
  2161.       s = ttyname(0);
  2162.     else if (isatty(1))
  2163.       s = ttyname(1);
  2164.     else if (isatty(2))
  2165.       s = ttyname(2);
  2166.     debug(F110,"sysinit ttyname(0)",s,0);
  2167. #endif /* MINIX */
  2168.  
  2169. #ifdef BEOS
  2170.     if (!dftty)
  2171.       makestr(&dftty,s);
  2172. #endif /* BEOS */
  2173.  
  2174.     if (s)
  2175.       ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
  2176. #ifdef SVORPOSIX
  2177.     if (!cttnam[0])
  2178.       ctermid(cttnam);
  2179. #endif /* SVORPOSIX */
  2180.     if (!cttnam[0])
  2181.       ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
  2182.     debug(F110,"sysinit CTTNAM",CTTNAM,0);
  2183.     debug(F110,"sysinit cttnam",cttnam,0);
  2184.  
  2185.     ttgwsiz();                /* Get window (screen) dimensions. */
  2186.  
  2187. #ifndef NOSYSCONF
  2188. #ifdef _SC_OPEN_MAX
  2189.     ckmaxfiles = sysconf(_SC_OPEN_MAX);
  2190. #endif /* _SC_OPEN_MAX */
  2191. #endif /* NOSYSCONF */
  2192.  
  2193. #ifdef Plan9
  2194.     if (!backgrd) {
  2195.         consctlfd = open("/dev/consctl", O_WRONLY);
  2196.         /*noisefd = open("/dev/noise", O_WRONLY)*/
  2197.     }
  2198.     ckxech = 1;
  2199. #endif /* Plan9 */
  2200.  
  2201. #ifdef CK_UTSNAME
  2202.     if (uname(&name) > -1) {
  2203.     ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
  2204.     ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
  2205.     ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
  2206.     ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
  2207. #ifdef DEBUG
  2208.     if (deblog) {
  2209.         debug(F110,"sysinit uname machine",unm_mch,0);
  2210.         debug(F110,"sysinit uname sysname",unm_nam,0);
  2211.         debug(F110,"sysinit uname release",unm_rel,0);
  2212.         debug(F110,"sysinit uname version",unm_ver,0);
  2213.     }
  2214. #endif /* DEBUG */
  2215.  
  2216. #ifdef HPUX9PLUS
  2217.     if (name.machine[5] == '8')
  2218.       hpis800 = 1;
  2219.     else
  2220.       hpis800 = 0;
  2221.     debug(F101,"sysinit hpis800","",hpis800);
  2222. #endif /* HPUX9PLUS */
  2223. #ifdef TRU64
  2224.         getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
  2225.         debug(F110,"sysinit getsysinfo model",unm_mod,0);
  2226. #endif /* TRU64 */
  2227. #ifdef SOLARIS25
  2228.         sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
  2229.         debug(F110,"sysinit sysinfo model",unm_mod,0);
  2230. #endif /* SOLARIS25 */
  2231.     }
  2232. #endif /* CK_UTSNAME */
  2233.  
  2234. #ifdef CK_ENVIRONMENT
  2235.     {
  2236. #ifdef TNCODE
  2237.     extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
  2238.     tn_env_prnt[], tn_env_sys[];
  2239. #endif /* TNCODE */
  2240.     extern char uidbuf[];
  2241.         extern char * whoami();
  2242.     char *p;
  2243. #ifdef CKSENDUID
  2244.         uidbuf[0] = '\0';
  2245. #ifdef IKSD
  2246.         if (!inserver) {
  2247. #endif /* IKSD */
  2248.             p = getenv("USER");
  2249.             debug(F110,"sysinit uidbuf from USER",uidbuf,0);
  2250.         if (!p) p = "";
  2251.             if (!*p) {
  2252.                 p = getenv("LOGNAME");
  2253.                 debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
  2254.             }
  2255.         if (!p) p = "";
  2256.             if (!*p) {
  2257.                 p = whoami();
  2258.                 debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
  2259.             }
  2260.         if (!p) p = "";
  2261.         ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
  2262. #ifdef IKSD
  2263.         }
  2264. #endif /* IKSD */
  2265.     debug(F110,"sysinit final uidbuf",uidbuf,0);
  2266. #endif /* CKSENDUID */
  2267.  
  2268. #ifdef TNCODE
  2269.     if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
  2270.     if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
  2271.     if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
  2272.     if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
  2273. #ifdef aegis
  2274.     ckstrncpy(tn_env_sys,"Aegis",64);
  2275. #else
  2276. #ifdef Plan9
  2277.     ckstrncpy(tn_env_sys,"Plan9",64);
  2278. #else
  2279.     ckstrncpy(tn_env_sys,"UNIX",64);
  2280. #endif /* Plan9 */
  2281. #endif /* aegis */
  2282. #endif /* TNCODE */
  2283.     }
  2284. #endif /* CK_ENVIRONMENT */
  2285. #ifdef CK_SNDLOC
  2286.     {
  2287.     extern char * tn_loc;
  2288.     char *p;
  2289.     if (p = getenv("LOCATION"))
  2290.       if (tn_loc = (char *)malloc((int)strlen(p)+1))
  2291.         strcpy(tn_loc,p);        /* safe */
  2292.     }
  2293. #endif /* CK_SNDLOC */
  2294.  
  2295.     ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
  2296.     startupdir[CKMAXPATH] = '\0';
  2297.     x = strlen(startupdir);
  2298.     if (x <= 0) {
  2299.     startupdir[0] = '/';
  2300.     startupdir[1] = '\0';
  2301.     } else if (startupdir[x-1] != '/') {
  2302.     startupdir[x] = '/';
  2303.     startupdir[x+1] = '\0';
  2304.     }
  2305.     debug(F110,"sysinit startupdir",startupdir,0);
  2306. #ifdef TTLEBUF
  2307.     le_init();
  2308. #endif /* TTLEBUF */
  2309. #ifdef BSD44ORPOSIX
  2310.     /* This should catch the ncurses platforms */
  2311.     /* Some platforms don't have putenv(), like NeXTSTEP */
  2312.     putenv("NCURSES_NO_SETBUF=1");
  2313. #endif /* BSD44ORPOSIX */
  2314.     return(0);
  2315. }
  2316.  
  2317. /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
  2318.  
  2319. int
  2320. syscleanup() {
  2321. #ifdef F_SETFL
  2322.     if (iniflags > -1)
  2323.       fcntl(0,F_SETFL,iniflags);    /* Restore stdin flags */
  2324. #endif /* F_SETFL */
  2325. #ifdef ultrix
  2326.     stty(0,&vanilla);                   /* Get sgtty info */
  2327. #endif /* ultrix */
  2328. #ifdef NETCMD
  2329.     if (ttpid) kill(ttpid,9);
  2330. #endif /* NETCMD */
  2331.     return(0);
  2332. }
  2333.  
  2334. /*  T T O P E N  --  Open a tty for exclusive access.  */
  2335.  
  2336. /*
  2337.   Call with:
  2338.     ttname: character string - device name or network host name.
  2339.     lcl:
  2340.   If called with lcl < 0, sets value of lcl as follows:
  2341.   0: the terminal named by ttname is the job's controlling terminal.
  2342.   1: the terminal named by ttname is not the job's controlling terminal.
  2343.   But watch out: if a line is already open, or if requested line can't
  2344.   be opened, then lcl remains (and is returned as) -1.
  2345.     modem:
  2346.   Less than zero: ttname is a network host name.
  2347.   Zero or greater: ttname is a terminal device name.
  2348.   Zero means a local connection (don't use modem signals).
  2349.   Positive means use modem signals.
  2350.    timo:
  2351.   0 = no timer.
  2352.   nonzero = number of seconds to wait for open() to return before timing out.
  2353.  
  2354.   Returns:
  2355.     0 on success
  2356.    -5 if device is in use
  2357.    -4 if access to device is denied
  2358.    -3 if access to lock directory denied
  2359.    -2 upon timeout waiting for device to open
  2360.    -1 on other error
  2361. */
  2362. static int ttotmo = 0;            /* Timeout flag */
  2363. /* Flag kept here to avoid being clobbered by longjmp.  */
  2364.  
  2365. int
  2366. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
  2367.  
  2368. #ifdef BSD44
  2369. #define ctermid(x) strcpy(x,"")
  2370. #else
  2371. #ifdef SVORPOSIX
  2372. #ifndef CIE
  2373.     extern char *ctermid();        /* Wish they all had this! */
  2374. #else                    /* CIE Regulus */
  2375. #define ctermid(x) strcpy(x,"")
  2376. #endif /* CIE */
  2377. #endif /* SVORPOSIX */
  2378. #endif /* BSD44 */
  2379.  
  2380. #ifdef ultrix
  2381.     int temp = 0;
  2382. #endif /* ultrix */
  2383.  
  2384. #ifndef OPENFIRST
  2385.     char fullname[DEVNAMLEN+1];
  2386. #endif /* OPENFIRST */
  2387.  
  2388.     char * fnam;            /* Full name after expansion */
  2389.  
  2390.     int y;
  2391.  
  2392. #ifndef pdp11
  2393. #define NAMEFD     /* Feature to allow name to be an open file descriptor */
  2394. #endif /* pdp11 */
  2395.  
  2396. #ifdef NAMEFD
  2397.     char *p;
  2398.     debug(F101,"ttopen telnetfd","",telnetfd);
  2399. #endif /* NAMEFD */
  2400.  
  2401.     debug(F110,"ttopen ttname",ttname,0);
  2402.     debug(F110,"ttopen ttnmsv",ttnmsv,0);
  2403.     debug(F101,"ttopen modem","",modem);
  2404.     debug(F101,"ttopen netconn","",netconn);
  2405.     debug(F101,"ttopen ttyfd","",ttyfd);
  2406.     debug(F101,"ttopen *lcl","",*lcl);
  2407.     debug(F101,"ttopen ttmdm","",ttmdm);
  2408.     debug(F101,"ttopen ttnet","",ttnet);
  2409.  
  2410.     ttpmsk = 0xff;
  2411.     lockpid[0] = '\0';
  2412.  
  2413.     if (ttyfd > -1) {            /* If device already opened */
  2414.         if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
  2415.       return(0);            /* Yes, nothing to do - just return */
  2416.     ttnmsv[0] = '\0';        /* No, clear out old name */
  2417.     ttclos(ttyfd);            /* close old connection.  */
  2418.     }
  2419.     wasclosed = 0;            /* New connection, not closed yet. */
  2420.     ttpipe = 0;                /* Assume it's not a pipe */
  2421.     ttpty = 0;                /* or a pty... */
  2422.  
  2423. #ifdef NETCONN
  2424. /*
  2425.   This is a bit tricky...  Suppose that previously Kermit had dialed a telnet
  2426.   modem server ("set host xxx:2001, set modem type usr, dial ...").  Then the
  2427.   connection was closed (ttyfd = -1), and then a REDIAL command was given.  At
  2428.   this point we've obliterated the negative modem type hack, and so would
  2429.   treat the IP hostname as a device name, and would then fail because of "No
  2430.   such device or directory".  But the previous connection has left behind some
  2431.   clues, so let's use them...
  2432. */
  2433.     if (ttyfd < 0) {            /* Connection is not open */
  2434.     if (!strcmp(ttname,ttnmsv)) {    /* Old and new names the same? */
  2435.         if (((netconn > 0) && (ttmdm < 0)) ||
  2436.         ((ttnet > 0) &&
  2437.          (!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
  2438.         ) {
  2439.         int x, rc;
  2440.         x = (ttmdm < 0) ? -ttmdm : ttnet;
  2441.         rc = netopen(ttname, lcl, x);
  2442.         debug(F111,"ttopen REOPEN netopen",ttname,rc);
  2443.         if (rc > -1) {
  2444.             netconn = 1;
  2445.             xlocal = *lcl = 1;
  2446.         } else {
  2447.             netconn = 0;
  2448.         }
  2449.         gotsigs = 0;
  2450.         return(rc);
  2451.         }
  2452.     }
  2453.     }
  2454. #endif /* NETCONN */
  2455.  
  2456. #ifdef MAXNAMLEN
  2457.     debug(F100,"ttopen MAXNAMLEN defined","",0);
  2458. #else
  2459.     debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
  2460. #endif
  2461.  
  2462. #ifdef BSD4
  2463.     debug(F100,"ttopen BSD4 defined","",0);
  2464. #else
  2465.     debug(F100,"ttopen BSD4 *NOT* defined","",0);
  2466. #endif /* BSD4 */
  2467.  
  2468. #ifdef BSD42
  2469.     debug(F100,"ttopen BSD42 defined","",0);
  2470. #else
  2471.     debug(F100,"ttopen BSD42 *NOT* defined","",0);
  2472. #endif /* BSD42 */
  2473.  
  2474. #ifdef MYREAD
  2475.     debug(F100,"ttopen MYREAD defined","",0);
  2476. #else
  2477.     debug(F100,"ttopen MYREAD *NOT* defined","",0);
  2478. #endif /* MYREAD */
  2479.  
  2480. #ifdef    NETCONN
  2481.     if (modem < 0) {            /* modem < 0 = code for network */
  2482.     int x;
  2483.     ttmdm = modem;
  2484.     modem = -modem;            /* Positive network type number */
  2485.     fdflag = 0;            /* Stdio not redirected. */
  2486.     netconn = 1;            /* And it's a network connection */
  2487.     debug(F111,"ttopen net",ttname,modem);
  2488. #ifdef NAMEFD
  2489.     for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
  2490.      if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
  2491.         ttyfd = atoi(ttname);    /* Is there a way to test it's open? */
  2492.         ttfdflg = 1;        /* We got an open file descriptor */
  2493.         debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
  2494.         debug(F101,"ttopen net ttyfd","",ttyfd);
  2495.         ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
  2496.         x = 1;            /* Return code is "good". */
  2497.         if (telnetfd) {
  2498.         ttnet = NET_TCPB;
  2499.         if (ttnproto != NP_TCPRAW)
  2500.           ttnproto = NP_TELNET;
  2501. #ifdef SUNX25
  2502.         } else if (x25fd) {
  2503.         ttnet = NET_SX25;
  2504.         ttnproto = NP_NONE;
  2505. #endif /* SUNX25 */
  2506.         }
  2507.     } else {            /* Host name or address given */
  2508. #ifdef NETPTY
  2509.         if (modem == NET_PTY) {
  2510.         int x;
  2511.         if (nopush) {
  2512.             debug(F100,"ttopen PTY: nopush","",0);
  2513.             return(-1);
  2514.         }
  2515.                 ttnet = NET_PTY;
  2516.         ttnproto = NP_NONE;
  2517.                 netconn = 1;            /* but we don't use network i/o */
  2518.                 ttpty = 1;
  2519.                 debug(F110,"ttopen PTY",ttname,0);
  2520.         x = do_pty(&ttyfd,ttname,0);
  2521.         if (x > -1) {
  2522.             ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
  2523.             xlocal = *lcl = 1;    /* It's local */
  2524.         } else {
  2525.             ttpty = 0;
  2526.             netconn = 0;
  2527.         }
  2528.         gotsigs = 0;
  2529.         return(x);
  2530.         }
  2531. #endif /* NETPTY */
  2532. #ifdef NETCMD
  2533. /*
  2534.   dup2() is not available on older System V platforms like AT&T 3Bx.  For
  2535.   those systems we punt by not defining NETCMD, but we might be able to do
  2536.   better -- see workarounds for this problem in ckufio.c (search for dup2).
  2537. */
  2538.         if (modem == NET_CMD) {
  2539.         if (nopush) {
  2540.             debug(F100,"ttopen pipe: nopush","",0);
  2541.             return(-1);
  2542.         }
  2543.         if (pipe(pipe0) || pipe(pipe1)) {
  2544.             perror("Pipe error");
  2545.             return(-1);
  2546.         }
  2547.         ttpid = fork();        /* Make a fork */
  2548.  
  2549.         switch (ttpid) {
  2550.           case -1:        /* Error making fork */
  2551.             close(pipe0[0]);
  2552.             close(pipe0[1]);
  2553.             close(pipe1[0]);
  2554.             close(pipe1[1]);
  2555.             perror("Fork error");
  2556.             return(-1);
  2557.           case 0:        /* Child. */
  2558.             close(pipe0[0]);
  2559.             close(pipe1[1]);
  2560.             dup2(pipe0[1], 1);
  2561.             close(pipe0[1]);
  2562.             dup2(pipe1[0], 0);
  2563.             close(pipe1[0]);
  2564.             system(ttname);
  2565.             _exit(0);
  2566.           default:        /* Parent */
  2567.             close(pipe0[1]);
  2568.             close(pipe1[0]);
  2569.             fdin = pipe0[0];    /* Read from pipe */
  2570.             fdout = pipe1[1];    /* Write to pipe */
  2571.             ttout = fdopen(fdout,"w"); /* Get stream so we can */
  2572.             if (!ttout) {    /* make it unbuffered. */
  2573.             perror("fdopen failure");
  2574.             return(-1);
  2575.             }
  2576.             setbuf(ttout,NULL);
  2577.             ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
  2578.             xlocal = *lcl = 1;    /* It's local */
  2579.             netconn = 1;    /* Call it a network connection */
  2580.             ttmdm = modem;    /* Remember network type */
  2581.             ttyfd = fdin;
  2582.             ttpipe = 1;
  2583.             gotsigs = 0;
  2584.             return(0);
  2585.         }
  2586.         }
  2587. #endif /* NETCMD */
  2588. #endif /* NAMEFD */
  2589.         x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
  2590.         if (x > -1) {
  2591.         ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
  2592.         } else netconn = 0;
  2593. #ifdef NAMEFD
  2594.     }
  2595. #endif /* NAMEFD */
  2596.  
  2597. #ifdef sony_news            /* Sony NEWS */
  2598.     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
  2599.         perror("ttopen error getting Kanji mode (network)");
  2600.         debug(F111,"ttopen error getting Kanji mode","network",0);
  2601.         km_ext = -1;        /* Make sure this stays undefined. */
  2602.     }
  2603. #endif /* sony_news */
  2604.  
  2605.     xlocal = *lcl = 1;        /* Network connections are local. */
  2606.     debug(F101,"ttopen net x","",x);
  2607. #ifdef COMMENT
  2608. /* Let netopen() do this */
  2609.     if (x > -1 && !x25fd)
  2610.       x = tn_ini();            /* Initialize TELNET protocol */
  2611. #endif /* COMMENT */
  2612.     gotsigs = 0;
  2613.     return(x);
  2614.     } else {                /* Terminal device */
  2615. #endif    /* NETCONN */
  2616.  
  2617. #ifdef NAMEFD
  2618. /*
  2619.   This code lets you give Kermit an open file descriptor for a serial
  2620.   communication device, rather than a device name.  Kermit assumes that the
  2621.   line is already open, locked, conditioned with the right parameters, etc.
  2622. */
  2623.     for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
  2624.     if (*p == '\0') {
  2625.         ttyfd = atoi(ttname);    /* Is there a way to test it's open? */
  2626.         debug(F111,"ttopen got open fd",ttname,ttyfd);
  2627.         ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
  2628.         if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
  2629.           xlocal = *lcl = 0;    /* we're in remote mode */
  2630.         else            /* otherwise */
  2631.           xlocal = *lcl = 1;    /* local mode. */
  2632.         netconn = 0;        /* Assume it's not a network. */
  2633.         tvtflg = 0;            /* Might need to initialize modes. */
  2634.         ttmdm = modem;        /* Remember modem type. */
  2635.         fdflag = 0;            /* Stdio not redirected. */
  2636.         ttfdflg = 1;        /* Flag we were opened this way. */
  2637.         debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
  2638.         debug(F101,"ttopen non-net ttyfd","",ttyfd);
  2639.  
  2640. #ifdef sony_news            /* Sony NEWS */
  2641.         /* Get device Kanji mode */
  2642.         if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
  2643.         perror("ttopen error getting Kanji mode");
  2644.         debug(F101,"ttopen error getting Kanji mode","",0);
  2645.         km_ext = -1;        /* Make sure this stays undefined. */
  2646.         }
  2647. #endif /* sony_news */
  2648.         gotsigs = 0;
  2649.         return(0);            /* Return success */
  2650.     }
  2651. #endif /* NAMEFD */
  2652. #ifdef NETCONN
  2653.     }
  2654. #endif /* NETCONN */
  2655.  
  2656. /* Here we have to open a serial device of the given name. */
  2657.  
  2658.     netconn = 0;            /* So it's not a network connection */
  2659.     occt = signal(SIGINT, cctrap);    /* Set Control-C trap, save old one */
  2660.     sigint_ign = 0;
  2661.  
  2662.     tvtflg = 0;            /* Flag for use by ttvt(). */
  2663.                 /* 0 = ttvt not called yet for this device */
  2664.  
  2665.     fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
  2666.     debug(F101,"ttopen fdflag","",fdflag);
  2667.  
  2668.     ttmdm = modem;                      /* Make this available to other fns */
  2669.     xlocal = *lcl;                      /* Make this available to other fns */
  2670.  
  2671. /* Code for handling bidirectional tty lines goes here. */
  2672. /* Use specified method for turning off logins and suppressing getty. */
  2673.  
  2674. #ifdef ACUCNTRL
  2675.     /* Should put call to priv_on() here, but that would be very risky! */
  2676.     acucntrl("disable",ttname);         /* acucntrl() program. */
  2677.     /* and priv_off() here... */
  2678. #else
  2679. #ifdef ATT7300
  2680.     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
  2681.       attmodem |= offgetty(ttname);    /* Remember response.  */
  2682. #endif /* ATT7300 */
  2683. #endif /* ACUCNTRL */
  2684.  
  2685. #ifdef OPENFIRST
  2686. /*
  2687.  1985-2001: opens device first then gets lock; reason:
  2688.  Kermit usually has to run setuid or setgid in order to create a lockfile.
  2689.  If you give a SET LINE command for a device that happens to be your job's
  2690.  controlling terminal, Kermit doesn't have to create a lockfile, and in fact
  2691.  should not create one, and would fail if it tried to if it did not have the
  2692.  required privileges.  But you can't find out if two tty device names are
  2693.  equivalent until you have a file descriptor that you can give to ttyname().
  2694.  But this can cause a race condition between Kermit and [m]getty.  So see
  2695.  the [#]else part...
  2696. */ 
  2697.  
  2698. /*
  2699.  In the following section, we open the tty device for read/write.
  2700.  If a modem has been specified via "set modem" prior to "set line"
  2701.  then the O_NDELAY parameter is used in the open, provided this symbol
  2702.  is defined (e.g. in fcntl.h), so that the program does not hang waiting
  2703.  for carrier (which in most cases won't be present because a connection
  2704.  has not been dialed yet).  O_NDELAY is removed later on in ttopen().  It
  2705.  would make more sense to first determine if the line is local before
  2706.  doing this, but because ttyname() requires a file descriptor, we have
  2707.  to open it first.  See do_open().
  2708.  
  2709.  Now open the device using the desired treatment of carrier.
  2710.  If carrier is REQUIRED, then open could hang forever, so an optional
  2711.  timer is provided.  If carrier is not required, the timer should never
  2712.  go off, and should do no harm...
  2713. */
  2714.     ttotmo = 0;                /* Flag no timeout */
  2715.     debug(F101,"ttopen timo","",timo);
  2716.     debug(F101,"ttopen xlocal","",xlocal);
  2717.     if (timo > 0) {
  2718.     int xx;
  2719.     saval = signal(SIGALRM,timerh);    /* Timed, set up timer. */
  2720.     xx = alarm(timo);        /* Timed open() */
  2721.     debug(F101,"ttopen alarm","",xx);
  2722.     if (
  2723. #ifdef CK_POSIX_SIG
  2724.         sigsetjmp(sjbuf,1)
  2725. #else
  2726.         setjmp(sjbuf)
  2727. #endif /* CK_POSIX_SIG */
  2728.         ) {
  2729.         ttotmo = 1;            /* Flag timeout. */
  2730.     } else ttyfd = do_open(ttname);
  2731.     ttimoff();
  2732.     debug(F111,"ttopen","modem",modem);
  2733.     debug(F101,"ttopen ttyfd","",ttyfd);
  2734.     debug(F101,"ttopen alarm return","",ttotmo);
  2735.     } else {
  2736.     errno = 0;
  2737.     ttyfd = do_open(ttname);
  2738.     }
  2739.     debug(F111,"ttopen ttyfd",ttname,ttyfd);
  2740.     if (ttyfd < 0) {            /* If couldn't open, fail. */
  2741.     debug(F101,"ttopen errno","",errno);
  2742.     if (errno > 0 && !quiet)
  2743.       perror(ttname);        /* Print message */
  2744.  
  2745. #ifdef ATT7300
  2746.     if (attmodem & DOGETY)        /* was getty(1m) running before us? */
  2747.       ongetty(ttnmsv);        /* yes, restart on tty line */
  2748.     attmodem &= ~DOGETY;        /* no phone in use, getty restored */
  2749. #else
  2750. #ifdef ACUCNTRL
  2751.         /* Should put call to priv_on() here, but that would be risky! */
  2752.     acucntrl("enable",ttname);    /* acucntrl() program. */
  2753.     /* and priv_off() here... */
  2754. #endif /* ACUNTRL */
  2755. #endif /* ATT7300 */
  2756.  
  2757.     signal(SIGINT,occt);        /* Put old Ctrl-C trap back. */
  2758.     if (errno == EACCES) {        /* Device is protected against user */
  2759.         debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
  2760.         return(-4);
  2761.     } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
  2762.     }
  2763.  
  2764. #ifdef QNX
  2765.     {
  2766.     extern int qnxportlock;
  2767.     x = qnxopencount();
  2768.     debug(F101,"ttopen qnxopencount","",x);
  2769.     debug(F101,"ttopen qnxportlock","",qnxportlock);
  2770.     if (x < 0 && qnxportlock) {
  2771.         ttclos(0);
  2772.         printf("?Can't get port open count\n");
  2773.         printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
  2774.         return(-1);            /* Indicate device is in use */
  2775.     }
  2776.     if (x > 1) {            /* 1 == me */
  2777.         if (qnxportlock)
  2778.           ttclos(0);
  2779.           return(-2);        /* Indicate device is in use */
  2780.         else if (!quiet)
  2781.           printf("WARNING: \"%s\" looks busy...\n",ttdev);
  2782.     }
  2783.     }
  2784. #endif /* QNX */
  2785.  
  2786. #ifdef Plan9
  2787.     /* take this opportunity to open the control channel */
  2788.     if (p9openttyctl(ttname) < 0)
  2789. #else
  2790.     /* Make sure it's a real tty. */
  2791.     if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
  2792. #endif /* Plan9 */
  2793.       {
  2794.     fprintf(stderr,"%s is not a terminal device\n",ttname);
  2795.     debug(F111,"ttopen not a tty",ttname,errno);
  2796.     close(ttyfd);
  2797.     ttyfd = -1;
  2798.     wasclosed = 1;
  2799.     signal(SIGINT,occt);
  2800.     return(-1);
  2801.     }
  2802.  
  2803. #ifdef aegis
  2804.     /* Apollo C runtime claims that console pads are tty devices, which
  2805.      * is reasonable, but they aren't any good for packet transfer. */
  2806.     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
  2807.     if (st.all != status_$ok) {
  2808.         fprintf(stderr, "problem getting tty object type: ");
  2809.         error_$print(st);
  2810.     } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
  2811.         close(ttyfd); ttyfd = -1;
  2812.         wasclosed = 1;
  2813.         errno = ENOTTY; perror(ttname);
  2814.         signal(SIGINT,occt);
  2815.         return(-1);
  2816.     }
  2817. #endif /* aegis */
  2818.  
  2819.     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
  2820.  
  2821.     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);    /* Keep copy of name locally. */
  2822.  
  2823. /* Caller wants us to figure out if line is controlling tty */
  2824.  
  2825.     if (*lcl < 0) {
  2826.         if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
  2827.             xlocal = 0;
  2828.         debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
  2829.         } else if (strcmp(ttname,cttnam) == 0) {
  2830.             xlocal = 0;
  2831.         debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
  2832.     } else if (cttnam[0]) {
  2833. #ifdef BEBOX_DR7
  2834.             x = ttnmsv;            /* ttyname() is broken */
  2835. #else
  2836.             x = ttyname(ttyfd);         /* Get real name of ttname. */
  2837. #endif /* BEBOX_DR7 */
  2838.         if (!x) x = "";
  2839.         if (*x)
  2840.           xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
  2841.         else
  2842.           xlocal = 1;
  2843.             debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
  2844.         }
  2845.     }
  2846.  
  2847. #ifndef NOFDZERO
  2848. /* Note, the following code was added so that Unix "idle-line" snoopers */
  2849. /* would not think Kermit was idle when it was transferring files, and */
  2850. /* maybe log people out. */
  2851.     if (xlocal == 0) {            /* Remote mode */
  2852.     if (fdflag == 0) {        /* Standard i/o is not redirected */
  2853.         debug(F100,"ttopen setting ttyfd = 0","",0);
  2854. #ifdef LYNXOS
  2855.         /* On Lynx OS, fd 0 is open for read only. */
  2856.         dup2(ttyfd,0);
  2857. #endif /* LYNXOS */
  2858.         close(ttyfd);        /* Use file descriptor 0 */
  2859.         ttyfd = 0;
  2860.     } else {            /* Standard i/o is redirected */
  2861.         debug(F101,"ttopen stdio redirected","",ttyfd);
  2862.     }
  2863.     }
  2864. #endif /* NOFDZERO */
  2865.  
  2866. /* Now check if line is locked -- if so fail, else lock for ourselves */
  2867. /* Note: After having done this, don't forget to delete the lock if you */
  2868. /* leave ttopen() with an error condition. */
  2869.  
  2870.     lkf = 0;                            /* Check lock */
  2871.     if (xlocal > 0) {
  2872.     int xx; int xpid;
  2873.         if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
  2874.             debug(F111,"ttopen ttlock fails",ttname,xx);
  2875.         /* WARNING - This close() can hang if tty is an empty socket... */
  2876.             close(ttyfd);        /* Close the device. */
  2877.         ttyfd = -1;            /* Erase its file descriptor. */
  2878.         wasclosed = 1;
  2879.         signal(SIGINT,occt);    /* Put old SIGINT back. */
  2880.         sigint_ign = (occt == SIG_IGN) ? 1 : 0;
  2881.         if (xx == -2) {        /* If lockfile says device in use, */
  2882. #ifndef NOUUCP
  2883.         debug(F111,"ttopen reading lockfile pid",flfnam,xx);
  2884.         xpid = ttrpid(flfnam);    /* Try to read pid from lockfile */
  2885.         if (xpid > -1) {    /* If we got a pid */
  2886.                     if (!quiet)
  2887.               printf("Locked by process %d\n",xpid); /* tell them. */
  2888.             sprintf(lockpid,"%d",xpid);    /* Record it too */
  2889.             debug(F110,"ttopen lockpid",lockpid,0);
  2890.         } else if (*flfnam) {
  2891.             extern char *DIRCMD;
  2892.             char *p = NULL;
  2893.             int x;
  2894.             x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
  2895.             p = malloc(x);    /* Print a directory listing. */
  2896. /*
  2897.   Note: priv_on() won't help here, because we do not pass privs along to
  2898.   to inferior processes, in this case ls.  So if the real user does not have
  2899.   directory-listing access to the lockfile directory, this will result in
  2900.   something like "not found".  That's why we try this only as a last resort.
  2901. */
  2902.             if (p) {        /* If we got the space... */
  2903.             ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
  2904.             zsyscmd(p);    /* Get listing. */
  2905.             if (p) {    /* free the space */
  2906.                 free(p);
  2907.                 p = NULL;
  2908.             }
  2909.             }
  2910.         }
  2911. #endif /* NOUUCP */
  2912.         return(-5);        /* Code for device in use */
  2913.         } else return(-3);        /* Access denied */
  2914.         } else lkf = 1;
  2915.     }
  2916. #else  /* OPENFIRST */
  2917.  
  2918. /*
  2919.   27 Oct 2001: New simpler code that gets the lock first and then opens the
  2920.   device, which eliminates the race condition.  The downside is you can no
  2921.   longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
  2922.   terminal, without trying to create a lockfile, which fails if C-Kermit lacks
  2923.   privs, and if it succeeds, it has created a lockfile where it didn't create
  2924.   one before.
  2925. */
  2926.     xlocal = *lcl;            /* Is the device my login terminal? */
  2927.     debug(F111,"ttopen xlocal","A",xlocal);
  2928.     fnam = ttname;
  2929.     if (strcmp(ttname,CTTNAM) && netconn == 0) {
  2930.     if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
  2931.         if ((int)strlen(fullname) > 0)
  2932.           fnam = fullname;
  2933.     }
  2934.     }
  2935.     debug(F110,"ttopen fnam",fnam,0);
  2936.     if (xlocal < 0) {
  2937.     xlocal = (strcmp(fnam,CTTNAM) != 0);
  2938.     }
  2939.     debug(F111,"ttopen xlocal","B",xlocal);
  2940.  
  2941.     lkf = 0;                            /* No lock yet */
  2942.     if (xlocal > 0) {            /* If not... */
  2943.     int xx; int xpid;
  2944.     xx = ttlock(fnam);        /* Try to lock it. */
  2945.     debug(F101,"ttopen ttlock","",xx);
  2946.         if (xx < 0) {            /* Can't lock it. */
  2947.             debug(F111,"ttopen ttlock fails",fnam,xx);
  2948.         if (xx == -2) {        /* If lockfile says device in use, */
  2949. #ifndef NOUUCP
  2950.         debug(F111,"ttopen reading lockfile pid",flfnam,xx);
  2951.         xpid = ttrpid(flfnam);    /* Try to read pid from lockfile */
  2952.         if (xpid > -1) {    /* If we got a pid */
  2953.                     if (!quiet)
  2954.               printf("Locked by process %d\n",xpid); /* tell them. */
  2955.             ckstrncpy(lockpid,ckitoa(xpid),16);
  2956.             debug(F110,"ttopen lockpid",lockpid,0);
  2957. #ifndef NOPUSH
  2958.         } else if (flfnam[0] && !nopush) {
  2959.             extern char *DIRCMD;
  2960.             char *p = NULL;
  2961.             int x;
  2962.             x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
  2963.             p = malloc(x);    /* Print a directory listing. */
  2964. /*
  2965.   Note: priv_on() won't help here, because we do not pass privs along to
  2966.   to inferior processes, in this case ls.  So if the real user does not have
  2967.   directory-listing access to the lockfile directory, this will result in
  2968.   something like "not found".  That's why we try this only as a last resort.
  2969. */
  2970.             if (p) {        /* If we got the space... */
  2971.             ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
  2972.             zsyscmd(p);    /* Get listing. */
  2973.             if (p) {    /* free the space */
  2974.                 free(p);
  2975.                 p = NULL;
  2976.             }
  2977.             }
  2978. #endif /* NOPUSH */
  2979.         }
  2980. #endif /* NOUUCP */
  2981.         return(-5);        /* Code for device in use */
  2982.         } else return(-3);        /* Access denied */
  2983.         } else lkf = 1;
  2984.     }
  2985.     /* Have lock -- now it's safe to open the device */
  2986.  
  2987.     debug(F101,"ttopen lkf","",lkf);
  2988.     debug(F101,"ttopen timo","",timo);
  2989.  
  2990.     ttotmo = 0;                /* Flag no timeout */
  2991.     if (timo > 0) {
  2992.     int xx;
  2993.     saval = signal(SIGALRM,timerh);    /* Timed, set up timer. */
  2994.     xx = alarm(timo);        /* Timed open() */
  2995.     debug(F101,"ttopen alarm","",xx);
  2996.     if (
  2997. #ifdef CK_POSIX_SIG
  2998.         sigsetjmp(sjbuf,1)
  2999. #else
  3000.         setjmp(sjbuf)
  3001. #endif /* CK_POSIX_SIG */
  3002.         ) {
  3003.         ttotmo = 1;            /* Flag timeout. */
  3004.     } else {
  3005.         ttyfd = do_open(fnam);
  3006.     }
  3007.     ttimoff();
  3008.     debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
  3009.     } else {
  3010.     errno = 0;
  3011.     ttyfd = do_open(fnam);
  3012.     debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
  3013.     }
  3014.     if (ttyfd < 0) {            /* If couldn't open, fail. */
  3015.     debug(F111,"ttopen errno",fnam,errno);
  3016.     debug(F111,"ttopen xlocal","C",xlocal);
  3017.     if (xlocal == 0) {
  3018.         debug(F100,"ttopen substituting 0","",0);
  3019.         ttyfd = 0;
  3020.     } else {
  3021.         if (errno > 0 && !quiet) {
  3022.             debug(F111,"ttopen perror",fnam,errno);
  3023.         perror(fnam);        /* Print message */
  3024.         }
  3025.         if (ttunlck())                  /* Release the lock file */
  3026.           fprintf(stderr,"Warning, problem releasing lock\r\n");
  3027.     }
  3028.     }
  3029.  
  3030.     if (ttyfd < 0) {            /* ttyfd is still < 0? */
  3031. #ifdef ATT7300
  3032.     if (attmodem & DOGETY)        /* was getty(1m) running before us? */
  3033.       ongetty(ttnmsv);        /* yes, restart on tty line */
  3034.     attmodem &= ~DOGETY;        /* no phone in use, getty restored */
  3035. #else
  3036. #ifdef ACUCNTRL
  3037.         /* Should put call to priv_on() here, but that would be risky! */
  3038.     acucntrl("enable",fnam);    /* acucntrl() program. */
  3039.     /* and priv_off() here... */
  3040. #endif /* ACUNTRL */
  3041. #endif /* ATT7300 */
  3042.  
  3043.     signal(SIGINT,occt);        /* Put old Ctrl-C trap back. */
  3044.     if (errno == EACCES) {        /* Device is protected against user */
  3045.         debug(F110,"ttopen EACCESS",fnam,0); /* Return -4 */
  3046.         return(-4);
  3047.     } else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
  3048.     }
  3049.  
  3050. /* Make sure it's a real tty. */
  3051.  
  3052. #ifdef Plan9
  3053.     /* take this opportunity to open the control channel */
  3054.     if (p9openttyctl(fnam) < 0)       
  3055. #else
  3056.       if (!ttfdflg && !isatty(ttyfd) && strcmp(fnam,"/dev/null"))
  3057. #endif /* Plan9 */
  3058.     {
  3059.         fprintf(stderr,"%s is not a terminal device\n",fnam);
  3060.         debug(F111,"ttopen not a tty",fnam,errno);
  3061.         if (ttunlck())        /* Release the lock file */
  3062.           fprintf(stderr,"Warning, problem releasing lock\r\n");
  3063.         close(ttyfd);
  3064.         ttyfd = -1;
  3065.         wasclosed = 1;
  3066.         signal(SIGINT,occt);
  3067.         return(-1);
  3068.     }
  3069.  
  3070. #ifdef aegis
  3071.     /*
  3072.       Apollo C runtime claims that console pads are tty devices, which
  3073.       is reasonable, but they aren't any good for packet transfer.
  3074.     */
  3075.     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
  3076.     if (st.all != status_$ok) {
  3077.     fprintf(stderr, "problem getting tty object type: ");
  3078.     error_$print(st);
  3079.     } else if (ttyuid != sio_$uid) {    /* Reject non-SIO lines */
  3080.     close(ttyfd); ttyfd = -1;
  3081.     wasclosed = 1;
  3082.     errno = ENOTTY; perror(fnam);
  3083.     signal(SIGINT,occt);
  3084.     return(-1);
  3085.     }
  3086. #endif /* aegis */
  3087.  
  3088.     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
  3089.  
  3090.     ckstrncpy(ttnmsv,ttname,DEVNAMLEN);    /* Keep copy of name locally. */
  3091.  
  3092. /* Caller wants us to figure out if line is controlling tty */
  3093.  
  3094.     if (*lcl < 0) {
  3095.     char * s;
  3096.         if (strcmp(fnam,CTTNAM) == 0) { /* "/dev/tty" always remote */
  3097.             xlocal = 0;
  3098.         debug(F111,"ttopen fnam=CTTNAM",fnam,xlocal);
  3099.         } else if (strcmp(fnam,cttnam) == 0) {
  3100.             xlocal = 0;
  3101.         debug(F111,"ttopen fnam=cttnam",fnam,xlocal);
  3102.     } else if (cttnam[0]) {
  3103. #ifdef BEBOX_DR7
  3104.             s = ttnmsv;            /* ttyname() is broken */
  3105. #else
  3106.             s = ttyname(ttyfd);         /* Get real name of ttname. */
  3107. #endif /* BEBOX_DR7 */
  3108.         if (!s) s = "";
  3109.         if (*s)
  3110.           xlocal = ((strncmp(s,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
  3111.         else
  3112.           xlocal = 1;
  3113.             debug(F111,"ttopen ttyname(ttyfd) xlocal",s,xlocal);
  3114.         }
  3115.     }
  3116.  
  3117. #ifndef NOFDZERO
  3118. /* Note, the following code was added so that Unix "idle-line" snoopers */
  3119. /* would not think Kermit was idle when it was transferring files, and */
  3120. /* maybe log people out. */
  3121.     if (xlocal == 0) {            /* Remote mode */
  3122.     if (fdflag == 0) {        /* Standard i/o is not redirected */
  3123.         debug(F100,"ttopen setting ttyfd = 0","",0);
  3124. #ifdef LYNXOS
  3125.         /* On Lynx OS, fd 0 is open for read only. */
  3126.         dup2(ttyfd,0);
  3127. #endif /* LYNXOS */
  3128.         close(ttyfd);        /* Use file descriptor 0 */
  3129.         ttyfd = 0;
  3130.     } else {            /* Standard i/o is redirected */
  3131.         debug(F101,"ttopen stdio redirected","",ttyfd);
  3132.     }
  3133.     }
  3134. #endif /* NOFDZERO */
  3135. #endif /* OPENFIRST */
  3136.  
  3137. /* Got the line, now set the desired value for local. */
  3138.  
  3139.     if (*lcl != 0) *lcl = xlocal;
  3140.  
  3141. /* Some special stuff for v7... */
  3142.  
  3143. #ifdef  V7
  3144. #ifndef MINIX
  3145.     if (kmem[TTY] < 0) {        /*  If open, then skip this.  */
  3146.     qaddr[TTY] = initrawq(ttyfd);   /* Init the queue. */
  3147.     if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
  3148.         fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
  3149.         perror("/dev/kmem");
  3150.         exit(1);
  3151.     }
  3152.     }
  3153. #endif /* !MINIX */
  3154. #endif /* V7 */
  3155.  
  3156. /* No failure returns after this point */
  3157.  
  3158. #ifdef ultrix
  3159.     ioctl(ttyfd, TIOCMODEM, &temp);
  3160. #ifdef TIOCSINUSE
  3161.     if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
  3162.     if (!quiet)
  3163.       perror(fnam);
  3164.     }
  3165. #endif /* TIOCSINUSE */
  3166. #endif /* ultrix */
  3167.  
  3168. /* Get tty device settings  */
  3169.  
  3170. #ifdef BSD44ORPOSIX            /* POSIX */
  3171.     tcgetattr(ttyfd,&ttold);
  3172.     debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
  3173.     tcgetattr(ttyfd,&ttraw);
  3174.     debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
  3175.     tcgetattr(ttyfd,&tttvt);
  3176.     debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
  3177. #else                    /* BSD, V7, and all others */
  3178. #ifdef ATTSV                /* AT&T UNIX */
  3179.     ioctl(ttyfd,TCGETA,&ttold);
  3180.     debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
  3181.     ioctl(ttyfd,TCGETA,&ttraw);
  3182.     ioctl(ttyfd,TCGETA,&tttvt);
  3183. #else
  3184. #ifdef BELLV10
  3185.     ioctl(ttyfd,TIOCGETP,&ttold);
  3186.     debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
  3187.     ioctl(ttyfd,TIOCGDEV,&tdold);
  3188.     debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
  3189. #else
  3190.     gtty(ttyfd,&ttold);
  3191.     debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
  3192. #endif /* BELLV10 */
  3193.  
  3194. #ifdef sony_news            /* Sony NEWS */
  3195.     if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
  3196.     perror("ttopen error getting Kanji mode");
  3197.     debug(F101,"ttopen error getting Kanji mode","",0);
  3198.     km_ext = -1;            /* Make sure this stays undefined. */
  3199.     }
  3200. #endif /* sony_news */
  3201.  
  3202. #ifdef TIOCGETC
  3203.     debug(F100,"ttopen TIOCGETC","",0);
  3204.     tcharf = 0;                /* In remote mode, also get */
  3205.     if (xlocal == 0) {            /* special characters */
  3206.     if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
  3207.         debug(F100,"ttopen TIOCGETC failed","",0);
  3208.     } else {
  3209.         tcharf = 1;            /* It worked. */
  3210.         ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
  3211.         debug(F100,"ttopen TIOCGETC ok","",0);
  3212.     }
  3213.     }
  3214. #else
  3215.     debug(F100,"ttopen TIOCGETC not defined","",0);
  3216. #endif /* TIOCGETC */
  3217.  
  3218. #ifdef TIOCGLTC
  3219.     debug(F100,"ttopen TIOCGLTC","",0);
  3220.     ltcharf = 0;            /* In remote mode, also get */
  3221.     if (xlocal == 0) {            /* local special characters */
  3222.     if (ioctl(ttyfd,TIOCGLTC,<chold) < 0) {
  3223.         debug(F100,"ttopen TIOCGLTC failed","",0);
  3224.     } else {
  3225.         ltcharf = 1;        /* It worked. */
  3226.         ioctl(ttyfd,TIOCGLTC,<chnoi); /* Get another copy */
  3227.         debug(F100,"ttopen TIOCGLTC ok","",0);
  3228.     }
  3229.     }
  3230. #else
  3231.     debug(F100,"ttopen TIOCGLTC not defined","",0);
  3232. #endif /* TIOCGLTC */
  3233.  
  3234. #ifdef TIOCLGET
  3235.     debug(F100,"ttopen TIOCLGET","",0);
  3236.     lmodef = 0;
  3237.     if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
  3238.     debug(F100,"ttopen TIOCLGET failed","",0);
  3239.     } else {
  3240.     lmodef = 1;
  3241.     debug(F100,"ttopen TIOCLGET ok","",0);
  3242.     }
  3243. #endif /* TIOCLGET */
  3244.  
  3245. #ifdef BELLV10
  3246.     ioctl(ttyfd,TIOCGETP,&ttraw);
  3247.     ioctl(ttyfd,TIOCGETP,&tttvt);
  3248. #else
  3249.     gtty(ttyfd,&ttraw);                 /* And a copy of it for packets*/
  3250.     gtty(ttyfd,&tttvt);                 /* And one for virtual tty service */
  3251. #endif /* BELLV10 */
  3252.  
  3253. #endif /* ATTSV */
  3254. #endif /* BSD44ORPOSIX */
  3255.  
  3256. /* Section for changing line discipline.  It's restored in ttres(). */
  3257.  
  3258. #ifdef AIXRS
  3259. #ifndef AIX41
  3260.     { union txname ld_name; int ld_idx = 0;
  3261.       ttld = 0;
  3262.         do {
  3263.         ld_name.tx_which = ld_idx++;
  3264.         ioctl(ttyfd, TXGETCD, &ld_name);
  3265.       if (!strncmp(ld_name.tx_name, "rts", 3))
  3266.           ttld |= 1;
  3267.         } while (*ld_name.tx_name);
  3268.         debug(F101,"AIX line discipline","",ttld);
  3269.       }
  3270. #endif /* AIX41 */
  3271. #endif /* AIXRS */
  3272.  
  3273. #ifdef BSD41
  3274. /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
  3275.     { int k;
  3276.       ioctl(ttyfd, TIOCGETD, &ttld);    /* Get and save line discipline */
  3277.       debug(F101,"4.1bsd line discipline","",ttld);
  3278.       k = OTTYDISC;            /* Switch to "old" discipline */
  3279.       k = ioctl(ttyfd, TIOCSETD, &k);
  3280.       debug(F101,"4.1bsd tiocsetd","",k);
  3281.     }
  3282. #endif /* BSD41 */
  3283.  
  3284. #ifdef aegis
  3285.     /* This was previously done before the last two TCGETA or gtty above,
  3286.      * in both the ATTSV and not-ATTSV case.  If it is not okay to have only
  3287.      * one copy if it here instead, give us a shout!
  3288.      */
  3289.     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
  3290.     if (xlocal) {       /* ignore breaks from local line */
  3291.         sio_$control((short)ttyfd, sio_$int_enable, false, st);
  3292.         sio_$control((short)ttyfd, sio_$quit_enable, false, st);
  3293.     }
  3294. #endif /* aegis */
  3295.  
  3296. #ifdef VXVE
  3297.     ttraw.c_line = 0;                   /* STTY line 0 for VX/VE */
  3298.     tttvt.c_line = 0;                   /* STTY line 0 for VX/VE */
  3299.     ioctl(ttyfd,TCSETA,&ttraw);
  3300. #endif /* vxve */
  3301.  
  3302. /* If O_NDELAY was used during open(), then remove it now. */
  3303.  
  3304. #ifdef O_NDELAY
  3305.     debug(F100,"ttopen O_NDELAY","",0);
  3306.     if (xlocal > 0) {
  3307.       if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
  3308.     debug(F100,"ttopen fcntl O_NDELAY","",0);
  3309. #ifndef aegis
  3310.     if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
  3311.         debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
  3312.         perror("Can't unset O_NDELAY");
  3313.     }
  3314. #endif /* aegis */
  3315.     /* Some systems, notably Xenix (don't know how common this is in
  3316.      * other systems), need special treatment to get rid of the O_NDELAY
  3317.      * behaviour on read() with respect to carrier presence (i.e. read()
  3318.      * returning 0 when carrier absent), even though the above fcntl()
  3319.      * is enough to make read() wait for input when carrier is present.
  3320.      * This magic, in turn, requires CLOCAL for working when the carrier
  3321.      * is absent. But if xlocal == 0, presumably you already have CLOCAL
  3322.      * or you have a carrier, otherwise you wouldn't be running this.
  3323.      */
  3324.     debug(F101,"ttopen xlocal","",xlocal);
  3325. #ifdef ATTSV
  3326. #ifdef BSD44ORPOSIX
  3327. #ifdef COMMENT                /* 12 Aug 1997 */
  3328. #ifdef __bsdi__
  3329.     if (xlocal)
  3330.       ttraw.c_cflag |= CLOCAL;
  3331. #else
  3332. #ifdef __FreeBSD__
  3333.     if (xlocal)
  3334.       ttraw.c_cflag |= CLOCAL;
  3335. #endif /* __FreeBSD__ */
  3336. #endif /* __bsdi__ */
  3337. #else /* Not COMMENT */
  3338. #ifdef CLOCAL
  3339.     if (xlocal)            /* Unset this if it's defined. */
  3340.       ttraw.c_cflag |= CLOCAL;
  3341. #endif /* CLOCAL */
  3342. #endif /* COMMENT */
  3343.     debug(F101,"ttopen BSD44ORPOSIX calling tcsetattr","",TCSADRAIN);
  3344.     if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
  3345.         debug(F100,"ttopen POSIX tcseattr fails","",0);
  3346.         perror("tcsetattr");
  3347.     }
  3348. #else /* !BSD44ORPOSIX */
  3349.     if (xlocal) {
  3350.         ttraw.c_cflag |= CLOCAL;
  3351.         debug(F100,"ttopen calling ioctl(TCSETA)","",0);
  3352.         errno = 0;
  3353.         if (ioctl(ttyfd, TCSETA, &ttraw) < 0) {
  3354.                 debug(F101,"ttopen ioctl(TCSETA) fails","",errno);
  3355.                 perror("ioctl(TCSETA)");
  3356.             }
  3357.     }
  3358. #endif /* BSD44ORPOSIX */
  3359. #endif /* ATTSV */
  3360. #ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
  3361. /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
  3362.     debug(F100,"ttopen executing close/open","",0);
  3363.     close( priv_opn(fnam, O_RDWR) ); /* Magic to force change. */
  3364. #endif /* NOCOTFMC */
  3365.       }
  3366.     }
  3367. #endif /* O_NDELAY */
  3368.  
  3369. /* Instruct the system how to treat the carrier, and set a few other tty
  3370.  * parameters.
  3371.  *
  3372.  * This also undoes the temporary setting of CLOCAL that may have been done
  3373.  * for the close(open()) above (except in Xenix).  Also throw in ~ECHO, to
  3374.  * prevent the other end of the line from sitting there talking to itself,
  3375.  * producing garbage when the user performs a connect.
  3376.  *
  3377.  * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
  3378.  * Now it thinks CLOCAL is always on. It seems the only real solution for
  3379.  * Xenix is to switch between the lower and upper case device names.
  3380.  *
  3381.  * This section may at some future time expand into setting a complete
  3382.  * collection of tty parameters, or call a function shared with ttpkt()/
  3383.  * ttvt() that does so.  On the other hand, the initial parameters are not
  3384.  * that important, since ttpkt() or ttvt() should always fix that before
  3385.  * any communication is done.  Well, we'll see...
  3386.  */
  3387.     if (xlocal) {
  3388.         curcarr = -2;
  3389.     debug(F100,"ttopen calling carrctl","",0);
  3390.     carrctl(&ttraw, ttcarr == CAR_ON);
  3391.     debug(F100,"ttopen carrctl ok","",0);
  3392.  
  3393. #ifdef COHERENT
  3394. #define SVORPOSIX
  3395. #endif /* COHERENT */
  3396.  
  3397. #ifdef SVORPOSIX
  3398.     ttraw.c_lflag &= ~ECHO;
  3399.     ttold.c_lflag &= ~ECHO;
  3400. #ifdef BSD44ORPOSIX
  3401.     y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
  3402.     debug(F101,"ttopen tcsetattr","",y);
  3403. #else
  3404.     y = ioctl(ttyfd, TCSETA, &ttraw);
  3405.     debug(F100,"ttopen ioctl","",y);
  3406. #endif /* BSD44ORPOSIX */
  3407.  
  3408. #else /* BSD, etc */
  3409.     ttraw.sg_flags &= ~ECHO;
  3410.     ttold.sg_flags &= ~ECHO;
  3411. #ifdef BELLV10
  3412.     y = ioctl(ttyfd,TIOCSETP,&ttraw);
  3413.     debug(F100,"ttopen ioctl","",y);
  3414. #else
  3415.     y = stty(ttyfd,&ttraw);
  3416.     debug(F100,"ttopen stty","",y);
  3417. #endif /* BELLV10 */
  3418. #endif /* SVORPOSIX */
  3419.  
  3420. #ifdef COHERENT
  3421. #undef SVORPOSIX
  3422. #endif /* COHERENT */
  3423.  
  3424.     /* ttflui(); */  /*  This fails for some reason.  */
  3425.     }
  3426.  
  3427.     /* Get current speed */
  3428.  
  3429. #ifndef BEBOX
  3430.     ttspeed = ttgspd();
  3431. #else
  3432.     ttspeed = 19200;
  3433. #endif /* !BEBOX */
  3434.     debug(F101,"ttopen ttspeed","",ttspeed);
  3435.  
  3436.     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
  3437.  
  3438.     debug(F101,"ttopen ttyfd","",ttyfd);
  3439.     debug(F101,"ttopen *lcl","",*lcl);
  3440.     debug(F111,"ttopen lock file",flfnam,lkf);
  3441.     signal(SIGINT,occt);
  3442.     sigint_ign = (occt == SIG_IGN) ? 1 : 0;
  3443.     gotsigs = 0;
  3444.     return(0);
  3445. }
  3446.  
  3447.  
  3448. /*  D O _ O P E N  --  Do the right kind of open() call for the tty. */
  3449.  
  3450. int
  3451. do_open(ttname) char *ttname; {
  3452.     int flags;
  3453.  
  3454. #ifdef QNX6
  3455.     /* O_NONBLOCK on /dev/tty makes open() fail */
  3456.     return(priv_opn(ttname, O_RDWR |
  3457.             (
  3458.              ((int)strcmp(ttname,"/dev/tty") == 0) ?
  3459.              0 :
  3460.              (ttcarr != CAR_ON) ? O_NONBLOCK : 0)
  3461.             )
  3462.        ); 
  3463. #else  /* !QNX6 */
  3464.  
  3465. #ifndef    O_NDELAY            /* O_NDELAY not defined */
  3466.     return(priv_opn(ttname,2));
  3467. #else                    /* O_NDELAY defined */
  3468.  
  3469. #ifdef ATT7300
  3470. /*
  3471.  Open comms line without waiting for carrier so initial call does not hang
  3472.  because state of "modem" is likely unknown at the initial call  -jrd.
  3473.  If this is needed for the getty stuff to work, and the open would not work
  3474.  without O_NDELAY when getty is still on, then this special case is ok.
  3475.  Otherwise, get rid of it. -ske
  3476. */
  3477.     return(priv_opn(ttname, O_RDWR | O_NDELAY));
  3478.  
  3479. #else    /* !ATT7300 */
  3480.  
  3481.     /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
  3482.     flags = O_RDWR;
  3483.     debug(F101,"do_open xlocal","",xlocal);
  3484.     debug(F111,"do_open flags A",ttname,flags);
  3485.     if (xlocal && (ttcarr != CAR_ON))
  3486.       flags |= O_NDELAY;
  3487.     debug(F111,"do_open flags B",ttname,flags);
  3488.     return(priv_opn(ttname, flags));
  3489. #endif /* !ATT7300 */
  3490. #endif /* O_NDELAY */
  3491. #endif /* QNX6 */
  3492. }
  3493.  
  3494. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  3495.  
  3496. static int ttc_state = 0;        /* ttclose() state */
  3497. static char * ttc_nam[] = { "setup", "hangup", "reset", "close" };
  3498.  
  3499. int
  3500. ttclos(foo) int foo; {            /* Arg req'd for signal() prototype */
  3501.     int xx, x = 0;
  3502.     extern int exithangup;
  3503.  
  3504.     debug(F101,"ttclos ttyfd","",ttyfd);
  3505.     debug(F101,"ttclos netconn","",netconn);
  3506.     debug(F101,"ttclos xlocal","",xlocal);
  3507. #ifdef NOFDZERO
  3508.     debug(F100,"ttclos NOFDZERO","",0);
  3509. #endif /* NOFDZERO */
  3510.  
  3511. #ifdef COMMENT
  3512. #ifdef TTLEBUF
  3513.     le_init();                /* No need for any of this */
  3514. #endif /* TTLEBUF */
  3515. #endif /* COMMENT */
  3516.  
  3517.     if (ttyfd < 0)            /* Wasn't open. */
  3518.       return(0);
  3519.  
  3520.     if (ttfdflg)            /* If we inherited ttyfd from */
  3521.       return(0);            /* another process, don't close it. */
  3522.  
  3523.     tvtflg = 0;                /* (some day get rid of this...) */
  3524.     gotsigs = 0;
  3525.  
  3526. #ifdef IKSD
  3527.     if (inserver) {
  3528. #ifdef TNCODE
  3529.           tn_push();                    /* Place any waiting data into input*/
  3530.           tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
  3531.           TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
  3532.           tn_reset();                   /* The Reset Telnet Option table.  */
  3533. #endif /* TNCODE */
  3534. #ifdef CK_SSL
  3535.       if (ssl_active_flag) {
  3536.           if (ssl_debug_flag)
  3537.         BIO_printf(bio_err,"calling SSL_shutdown(ssl)\n");
  3538.           SSL_shutdown(ssl_con);
  3539.           SSL_free(ssl_con);
  3540.           ssl_con = NULL;
  3541.           ssl_active_flag = 0;
  3542.       }
  3543.       if (tls_active_flag) {
  3544.           if (ssl_debug_flag)
  3545.         BIO_printf(bio_err,"calling SSL_shutdown(tls)\n");
  3546.           SSL_shutdown(tls_con);
  3547.           SSL_free(tls_con);
  3548.           tls_con = NULL;
  3549.           tls_active_flag = 0;
  3550.       }
  3551. #endif /* CK_SSL */
  3552.     }
  3553. #endif /* IKSD */
  3554. #ifdef NETCMD
  3555.     if (ttpipe) {            /* We've been using a pipe */
  3556.     /* ttpipe = 0; */
  3557.     if (ttpid > 0) {
  3558.         int wstat;
  3559.         int statusp;
  3560.         close(fdin);        /* Close these. */
  3561.         close(fdout);
  3562.         fdin = fdout = -1;
  3563.         kill(ttpid,1);        /* Kill fork with SIGHUP */
  3564.         while (1) {
  3565.         wstat = wait(&statusp);
  3566.         if (wstat == ttpid || wstat == -1)
  3567.           break;
  3568.         pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
  3569.         }
  3570.         ttpid = 0;
  3571.     }
  3572.     netconn = 0;
  3573.     wasclosed = 1;
  3574.     ttyfd = -1;
  3575.     return(0);
  3576.     }
  3577. #endif /* NETCMD */
  3578. #ifdef NETPTY
  3579.     if (ttpty) {
  3580. #ifndef NODOPTY
  3581.         end_pty();
  3582. #endif /* NODOPTY */
  3583.         close(ttyfd);
  3584.     netconn = 0;
  3585.     wasclosed = 1;
  3586.         ttpty = 0;
  3587.         ttyfd = -1;
  3588.         return(0);
  3589.     }
  3590. #endif /* NETPTY */
  3591.  
  3592. #ifdef    NETCONN
  3593.     if (netconn) {            /* If it's a network connection. */
  3594.     debug(F100,"ttclos closing net","",0);
  3595.     netclos();            /* Let the network module close it. */
  3596.     netconn = 0;            /* No more network connection. */
  3597.     debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
  3598.     return(0);
  3599.     }
  3600. #endif    /* NETCONN */
  3601.  
  3602.     if (xlocal) {            /* We're closing a SET LINE device */
  3603. #ifdef FT21                /* Fortune 2.1-specific items ... */
  3604.     ioctl(ttyfd,TIOCHPCL, NULL);
  3605. #endif /* FT21 */
  3606. #ifdef ultrix                /* Ultrix-specific items ... */
  3607. #ifdef TIOCSINUSE
  3608.     /* Unset the INUSE flag that we set in ttopen() */
  3609.     ioctl(ttyfd, TIOCSINUSE, NULL);
  3610. #endif /* TIOCSINUSE */
  3611.     ioctl(ttyfd, TIOCNMODEM, &x);
  3612. #ifdef COMMENT
  3613.     /* What was this? */
  3614.     ioctl(ttyfd, TIOCNCAR, NULL);
  3615. #endif /* COMMENT */
  3616. #endif /* ultrix */
  3617.     }
  3618.  
  3619.     /* This is to prevent us from sticking in tthang() or close(). */
  3620.  
  3621. #ifdef O_NDELAY
  3622. #ifndef aegis
  3623.     if (ttyfd > 0) {            /* But skip it on stdin. */
  3624.     debug(F100,"ttclos setting O_NDELAY","",0);
  3625.     x = fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL, 0)|O_NDELAY);
  3626. #ifdef DEBUG
  3627.     if (deblog && x == -1) {
  3628.         perror("Warning - Can't set O_NDELAY");
  3629.         debug(F101,"ttclos fcntl failure to set O_NDELAY","",x);
  3630.     }
  3631. #endif /* DEBUG */
  3632.     }
  3633. #endif /* aegis */
  3634. #endif /* O_NDELAY */
  3635.  
  3636.     x = 0;
  3637.     ttc_state = 0;
  3638.     if (xlocal
  3639. #ifdef NOFDZERO
  3640.     || ttyfd > 0
  3641. #endif /* NOFDZERO */
  3642.     ) {
  3643.     saval = signal(SIGALRM,xtimerh); /* Enable timer interrupt. */
  3644.     xx = alarm(8);            /* Allow 8 seconds. */
  3645.     debug(F101,"ttclos alarm","",xx);
  3646.     if (
  3647. #ifdef CK_POSIX_SIG
  3648.         sigsetjmp(sjbuf,1)
  3649. #else
  3650.         setjmp(sjbuf)
  3651. #endif /* CK_POSIX_SIG */
  3652.         ) {                /* Timer went off? */
  3653.         x = -1;
  3654. #ifdef DEBUG
  3655.         debug(F111,"ttclos ALARM TRAP errno",ckitoa(ttc_state),errno);
  3656.         printf("ttclos() timeout: %s\n", ttc_nam[ttc_state]);
  3657. #endif /* DEBUG */
  3658.     }
  3659.     /* Hang up the device (drop DTR) */
  3660.  
  3661.     errno = 0;
  3662.     debug(F111,"ttclos A",ckitoa(x),ttc_state);
  3663.     if (ttc_state < 1) {
  3664.         ttc_state = 1;
  3665.         debug(F101,"ttclos exithangup","",exithangup);
  3666.         if (exithangup) {
  3667.         alarm(8);        /* Re-arm the timer */
  3668.         debug(F101,"ttclos calling tthang()","",x);
  3669.         x = tthang();        /* Hang up first, then... */
  3670.         debug(F101,"ttclos tthang()","",x);
  3671.         }
  3672. #ifndef CK_NOHUPCL
  3673. /*
  3674.   Oct 2006 - Leave DTR on if SET EXIT HANGUP OFF.
  3675.   Suggested by Soewono Effendi.
  3676. */
  3677. #ifdef HUPCL
  3678.         else {
  3679.         ttold.c_cflag &= ~HUPCL; /* Let's see how this travels */
  3680. #ifdef BSD44ORPOSIX
  3681.         tcsetattr(ttyfd,TCSANOW,&ttold);
  3682. #else /* !BSD44ORPOSIX */
  3683. #ifdef ATTSV
  3684.         ioctl(ttyfd,TCSETAW,&ttold);        
  3685. #else  /* !ATTSV */
  3686.         stty(ttyfd,&ttold);
  3687. #endif    /* ATTSV */
  3688. #endif    /* BSD44ORPOSIX */
  3689.         }
  3690. #endif    /* HUPCL */
  3691. #endif    /* CK_NOHUPCL */
  3692.     }
  3693.     /* Put back device modes as we found them */
  3694.  
  3695.     errno = 0;
  3696.     debug(F111,"ttclos B",ckitoa(x),ttc_state);
  3697.     if (ttc_state < 2) {
  3698.         ttc_state = 2;
  3699.         /* Don't try to mess with tty modes if tthang failed() */
  3700.         /* since it probably won't work. */
  3701.         if (x > -1) {
  3702.         debug(F101,"ttclos calling ttres()","",x);
  3703.         signal(SIGALRM,xtimerh); /* Re-enable the alarm. */
  3704.         alarm(8);        /* Re-arm the timer */
  3705.         x = ttres();        /* Reset device modes. */
  3706.         debug(F101,"ttclos ttres()","",x);
  3707.         alarm(0);
  3708.         }
  3709.     }
  3710.     /* Close the device */
  3711.  
  3712.     errno = 0;
  3713.     debug(F101,"ttclos C","",ttc_state);
  3714.     if (ttc_state < 3) {
  3715.         ttc_state = 3;
  3716.         errno = 0;
  3717.         debug(F101,"ttclos calling close","",x);
  3718.         signal(SIGALRM,xtimerh);    /* Re-enable alarm. */
  3719.         alarm(8);            /* Re-arm the timer */
  3720.         x = close(ttyfd);        /* Close the device. */
  3721.         debug(F101,"ttclos close()","",x);
  3722.         if (x > -1)
  3723.           ttc_state = 3;
  3724.     }
  3725.     debug(F101,"ttclos D","",ttc_state);
  3726.     ttimoff();            /* Turn off timer. */
  3727.     if (x < 0) {
  3728.         printf("?WARNING - close failed: %s\n",ttnmsv);
  3729. #ifdef DEBUG
  3730.         if (deblog) {
  3731.         printf("errno = %d\n", errno);
  3732.         debug(F101,"ttclos failed","",errno);
  3733.         }
  3734. #endif /* DEBUG */
  3735.     }
  3736.     /* Unlock after closing but before any getty mumbo jumbo */
  3737.  
  3738.     debug(F100,"ttclos about to call ttunlck","",0);
  3739.         if (ttunlck())                  /* Release uucp-style lock */
  3740.       fprintf(stderr,"Warning, problem releasing lock\r\n");
  3741.     }
  3742.  
  3743. /* For bidirectional lines, restore getty if it was there before. */
  3744.  
  3745. #ifdef ACUCNTRL                /* 4.3BSD acucntrl() method. */
  3746.     if (xlocal) {
  3747.     debug(F100,"ttclos ACUCNTRL","",0);
  3748.     acucntrl("enable",ttnmsv);    /* Enable getty on the device. */
  3749.     }
  3750. #else
  3751. #ifdef ATT7300                /* ATT UNIX PC (3B1, 7300) method. */
  3752.     if (xlocal) {
  3753.     debug(F100,"ttclos ATT7300 ongetty","",0);
  3754.     if (attmodem & DOGETY)        /* Was getty(1m) running before us? */
  3755.       ongetty(ttnmsv);        /* Yes, restart getty on tty line */
  3756.     attmodem &= ~DOGETY;        /* No phone in use, getty restored */
  3757.     }
  3758. #endif /* ATT7300 */
  3759. #endif /* System-dependent getty-restoring methods */
  3760.  
  3761. #ifdef sony_news
  3762.     km_ext = -1;            /* Invalidate device's Kanji-mode */
  3763. #endif /* sony_news */
  3764.  
  3765.     ttyfd = -1;                         /* Invalidate the file descriptor. */
  3766.     wasclosed = 1;
  3767.     debug(F100,"ttclos done","",0);
  3768.     return(0);
  3769. }
  3770.  
  3771. /*  T T H A N G  --  Hangup phone line or network connection.  */
  3772. /*
  3773.   Returns:
  3774.   0 if it does nothing.
  3775.   1 if it believes that it hung up successfully.
  3776.  -1 if it believes that the hangup attempt failed.
  3777. */
  3778.  
  3779. #define HUPTIME 500            /* Milliseconds for hangup */
  3780.  
  3781. #ifdef COMMENT
  3782. /* The following didn't work but TIOCSDTR does work */
  3783. #ifdef UNIXWARE
  3784. /* Define HUP_POSIX to force non-POSIX builds to use the POSIX hangup method */
  3785. #ifndef POSIX                /* Such as Unixware 1.x, 2.x */
  3786. #ifndef HUP_POSIX
  3787. #define HUP_POSIX
  3788. #endif /* HUP_POSIX */
  3789. #endif /* POSIX */
  3790. #endif /* UNIXWARE */
  3791. #endif /* COMMENT */
  3792.  
  3793. #ifndef USE_TIOCSDTR
  3794. #ifdef __NetBSD__
  3795. /* Because the POSIX method (set output speed to 0) doesn't work in NetBSD */
  3796. #ifdef TIOCSDTR
  3797. #ifdef TIOCCDTR
  3798. #define USE_TIOCSDTR
  3799. #endif /* TIOCCDTR */
  3800. #endif /* TIOCSDTR */
  3801. #endif /* __NetBSD__ */
  3802. #endif /* USE_TIOCSDTR */
  3803.  
  3804. #ifndef HUP_CLOSE_POSIX
  3805. #ifdef OU8
  3806. #define HUP_CLOSE_POSIX
  3807. #else
  3808. #ifdef CK_SCOV5
  3809. #define HUP_CLOSE_POSIX
  3810. #endif /* CK_SCOV5 */
  3811. #endif /* OU8 */
  3812. #endif /* HUP_CLOSE_POSIX */
  3813.  
  3814. #ifdef NO_HUP_CLOSE_POSIX
  3815. #ifdef HUP_CLOSE_POSIX
  3816. #undef HUP_CLOSE_POSIX
  3817. #endif /* HUP_CLOSE_POSIX */
  3818. #endif /* NO_HUP_CLOSE_POSIX */
  3819.  
  3820. int
  3821. tthang() {
  3822. #ifdef NOLOCAL
  3823.     return(0);
  3824. #else
  3825.     int x = 0;                /* Sometimes used as return code. */
  3826. #ifndef POSIX
  3827.     int z;                /* worker */
  3828. #endif /* POSIX */
  3829.  
  3830. #ifdef COHERENT
  3831. #define SVORPOSIX
  3832. #endif /* COHERENT */
  3833.  
  3834. #ifdef SVORPOSIX            /* AT&T, POSIX, HPUX declarations. */
  3835.     int spdsav;                /* for saving speed */
  3836. #ifdef HUP_POSIX
  3837.     int spdsavi;
  3838. #else
  3839. #ifdef BSD44ORPOSIX
  3840.     int spdsavi;
  3841. #endif /* BSD44ORPOSIX */
  3842. #endif /* HUP_POSIX */
  3843. #ifdef HPUX
  3844. /*
  3845.   Early versions of HP-UX omitted the mflag typedef.  If you get complaints
  3846.   about it, just change it to long (or better still, unsigned long).
  3847. */
  3848.     mflag
  3849.       dtr_down = 00000000000,
  3850.       modem_rtn,
  3851.       modem_sav;
  3852.     char modem_state[64];
  3853. #endif /* HPUX */
  3854.     int flags;                /* fcntl flags */
  3855.     unsigned short ttc_save;
  3856. #endif /* SVORPOSIX */
  3857.  
  3858.     if (ttyfd < 0) return(0);           /* Don't do this if not open  */
  3859.     if (xlocal < 1) return(0);        /* Don't do this if not local */
  3860.  
  3861. #ifdef NETCMD
  3862.     if (ttpipe)
  3863.       return((ttclos(0) < 0) ? -1 : 1);
  3864. #endif /* NETCMD */
  3865. #ifdef NETPTY
  3866.     if (ttpty)
  3867.       return((ttclos(0) < 0) ? -1 : 1);
  3868. #endif /* NETPTY */
  3869. #ifdef NETCONN
  3870.     if (netconn) {            /* Network connection. */
  3871. #ifdef TN_COMPORT
  3872.         if (istncomport()) {
  3873.             int rc = tnc_set_dtr_state(0);
  3874.             if (rc >= 0) {
  3875.                 msleep(HUPTIME);
  3876.                 rc = tnc_set_dtr_state(1);
  3877.             }
  3878.             return(rc >= 0 ? 1 : -1);
  3879.         } else
  3880. #endif /* TN_COMPORT */
  3881.       return((netclos() < 0) ? -1 : 1); /* Just close it. */
  3882.   }
  3883. #endif /* NETCONN */
  3884.  
  3885. /* From here down, we handle real tty devices. */
  3886. #ifdef HUP_POSIX
  3887. /*
  3888.   e.g. for Unixware 2, where we don't have a full POSIX build, we
  3889.   still have to use POSIX-style hangup.  Thus the duplication of this
  3890.   and the next case, the only difference being we use a local termios
  3891.   struct here, since a different model is used elsewhere.
  3892.  
  3893.   NO LONGER USED as of C-Kermit 8.0 -- it turns out that this method,
  3894.   even though it compiles and executes without error, doesn't actually
  3895.   work (i.e. DTR does not drop), whereas the TIOCSDTR method works just fine,
  3896. */
  3897.     {
  3898.     struct termios ttcur;
  3899.     int x;
  3900.     debug(F100,"tthang HUP_POSIX style","",0);
  3901.     x = tcgetattr(ttyfd, &ttcur);    /* Get current attributes */
  3902.     debug(F111,"tthang tcgetattr",ckitoa(errno),x);
  3903.     if (x < 0) return(-1);
  3904.     spdsav = cfgetospeed(&ttcur);    /* Get current speed */
  3905.     debug(F111,"tthang cfgetospeed",ckitoa(errno),spdsav);
  3906.     spdsavi = cfgetispeed(&ttcur);    /* Get current speed */
  3907.     debug(F111,"tthang cfgetispeed",ckitoa(errno),spdsavi);
  3908.     x = cfsetospeed(&ttcur,B0);    /* Replace by 0 */
  3909.     debug(F111,"tthang cfsetospeed",ckitoa(errno),x);
  3910.     if (x < 0) return(-1);
  3911.     x = cfsetispeed(&ttcur,B0);
  3912.     debug(F111,"tthang cfsetispeed",ckitoa(errno),x);
  3913.     if (x < 0) return(-1);
  3914.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
  3915.     debug(F111,"tthang tcsetattr B0",ckitoa(errno),x);
  3916.     if (x < 0) return(-1);
  3917.     msleep(HUPTIME);        /* Sleep 0.5 sec */
  3918.     x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
  3919.     if (x < 0) return(-1);
  3920.     debug(F111,"tthang cfsetospeed prev",ckitoa(errno),x);
  3921.     x = cfsetispeed(&ttcur,spdsavi);
  3922.     debug(F111,"tthang cfsetispeed prev",ckitoa(errno),x);
  3923.     if (x < 0) return(-1);
  3924.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
  3925.     debug(F111,"tthang tcsetattr restore",ckitoa(errno),x);
  3926.     if (x < 0) return(-1);
  3927.     return(1);
  3928.     }
  3929. #else
  3930. #ifdef BSD44ORPOSIX
  3931. #ifdef QNX
  3932.     {
  3933.     int x;
  3934.     x = tcdropline(ttyfd,500);
  3935.     debug(F101,"tthang QNX tcdropline","",x);
  3936.     ttcur.c_cflag |= CLOCAL;
  3937.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
  3938.     debug(F101,"tthang QNX tcsetattr restore","",x);
  3939.     if (x < 0) {
  3940.         debug(F101,"tthang QNX tcsetattr restore errno","",errno);
  3941.         return(-1);
  3942.     }
  3943.     /* Fix flags - ensure O_NONBLOCK is off */
  3944.  
  3945.     errno = 0;
  3946.     debug(F101,"tthang QNX iniflags","",iniflags);
  3947.     if (fcntl(ttyfd, F_SETFL, iniflags) == -1) {
  3948.         debug(F101,"tthang QNX F_SETFL errno","",errno);
  3949.         return(-1);
  3950.     }
  3951.     return(x);
  3952.     }
  3953. #else  /* QNX */
  3954.     {
  3955.     int x;
  3956. #ifdef USE_TIOCSDTR
  3957.     debug(F100,"tthang BSD44ORPOSIX USE_TIOCSDTR","",0);
  3958.     errno = 0;
  3959.     x = ioctl(ttyfd, TIOCCDTR, NULL);
  3960.     debug(F111,"tthang BSD44ORPOSIX ioctl TIOCCDTR",ckitoa(errno),x);
  3961.     if (x < 0) return(-1);
  3962.     msleep(HUPTIME);        /* Sleep 0.5 sec */
  3963.     errno = 0;
  3964.     x = ioctl(ttyfd, TIOCSDTR, NULL);
  3965.     debug(F111,"tthang BSD44ORPOSIX ioctl TIOCSDTR",ckitoa(errno),x);
  3966.     if (x < 0) return(-1);
  3967. #else  /* USE_TIOCSDTR */
  3968.  
  3969. #ifdef HUP_CLOSE_POSIX
  3970. /*
  3971.   In OSR5 versions where TIOCSDTR is not defined (up to and including at
  3972.   least 5.0.6a) the POSIX APIs in the "#else" part below are available but
  3973.   don't work, and no other APIs are available that do work.  In this case
  3974.   we have to drop DTR by brute force: close and reopen the port.  This
  3975.   code actually works, but all the steps are crucial: setting CLOCAL, the
  3976.   O_NDELAY manipulations, etc.
  3977. */
  3978.     debug(F100,"tthang HUP_CLOSE_POSIX close/open","",0);
  3979.     debug(F101,"tthang HUP_CLOSE_POSIX O_NONBLOCK","",O_NONBLOCK);
  3980.     debug(F101,"tthang HUP_CLOSE_POSIX O_NDELAY","",O_NDELAY);
  3981.     errno = 0;
  3982.     x = tcgetattr(ttyfd, &ttcur);    /* Get current attributes */
  3983.     debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr","",x);
  3984.     if (x < 0) {
  3985.         debug(F101,"tthang HUP_CLOSE_POSIX tcgetattr errno","",errno);
  3986.         return(-1);
  3987.     }
  3988.     errno = 0;
  3989.  
  3990.     x = close(ttyfd);        /* Close without releasing lock */
  3991.     if (x < 0) {
  3992.         debug(F101,"tthang HUP_CLOSE_POSIX close errno","",errno);
  3993.         return(-1);
  3994.     }
  3995.     errno = 0;
  3996.     x = msleep(500);        /* Pause half a second */
  3997.     if (x < 0) {            /* Or if that doesn't work, 1 sec */
  3998.         debug(F101,"tthang HUP_CLOSE_POSIX msleep errno","",errno);
  3999.         sleep(1);
  4000.     }
  4001.     errno = 0;
  4002.     ttyfd = priv_opn(ttnmsv, (O_RDWR|O_NDELAY)); /* Reopen the device */
  4003.     debug(F111,"tthang HUP_CLOSE_POSIX reopen",ttnmsv,ttyfd);
  4004.     if (ttyfd < 0) {
  4005.         debug(F101,"tthang HUP_CLOSE_POSIX reopen errno","",errno);
  4006.         return(-1);
  4007.     }
  4008.     debug(F101,"tthang HUP_CLOSE_POSIX re-ttopen ttyfd","",ttyfd);
  4009.  
  4010.     /* Restore previous attributes */
  4011.  
  4012.     errno = 0;
  4013.     tvtflg = 0;
  4014.     ttcur.c_cflag |= CLOCAL;
  4015.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
  4016.     debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore","",x);
  4017.     if (x < 0) {
  4018.         debug(F101,"tthang HUP_CLOSE_POSIX tcsetattr restore errno",
  4019.           "",errno);
  4020.         return(-1);
  4021.     }
  4022.     /* Fix flags - ensure O_NDELAY and O_NONBLOCK are off */
  4023.  
  4024.     errno = 0;
  4025.         if ((x = fcntl(ttyfd, F_GETFL, 0)) == -1) {
  4026.         debug(F101,"tthang HUP_CLOSE_POSIX F_GETFL errno","",errno);
  4027.         return(-1);
  4028.     }
  4029.     debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
  4030.     errno = 0;
  4031.         x &= ~(O_NONBLOCK|O_NDELAY);
  4032.     debug(F101,"tthang HUP_CLOSE_POSIX flags to set","",x);
  4033.     debug(F101,"tthang HUP_CLOSE_POSIX iniflags","",iniflags);
  4034.     if (fcntl(ttyfd, F_SETFL, x) == -1) {
  4035.         debug(F101,"tthang HUP_CLOSE_POSIX F_SETFL errno","",errno);
  4036.         return(-1);
  4037.     }
  4038. #ifdef DEBUG
  4039.     if (deblog) {
  4040.         if ((x = fcntl(ttyfd, F_GETFL, 0)) > -1) {
  4041.         debug(F101,"tthang HUP_CLOSE_POSIX flags","",x);
  4042.         debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NONBLOCK",
  4043.               "",x&O_NONBLOCK);
  4044.         debug(F101,"tthang HUP_CLOSE_POSIX flags & O_NDELAY",
  4045.               "",x&O_NDELAY);
  4046.         }
  4047.     }
  4048. #endif /* DEBUG */
  4049.  
  4050. #else  /* HUP_CLOSE_POSIX */
  4051.     
  4052.     /* General BSD44ORPOSIX case (Linux, BSDI, FreeBSD, etc) */
  4053.  
  4054.     debug(F100,"tthang BSD44ORPOSIX B0","",0);
  4055.     x = tcgetattr(ttyfd, &ttcur);    /* Get current attributes */
  4056.     debug(F111,"tthang BSD44ORPOSIX tcgetattr",ckitoa(errno),x);
  4057.     if (x < 0) return(-1);
  4058.     spdsav = cfgetospeed(&ttcur);    /* Get current speed */
  4059.     debug(F111,"tthang BSD44ORPOSIX cfgetospeed",ckitoa(errno),spdsav);
  4060.     spdsavi = cfgetispeed(&ttcur);    /* Get current speed */
  4061.     debug(F111,"tthang BSD44ORPOSIX cfgetispeed",ckitoa(errno),spdsavi);
  4062.     x = cfsetospeed(&ttcur,B0);    /* Replace by 0 */
  4063.     debug(F111,"tthang BSD44ORPOSIX cfsetospeed",ckitoa(errno),x);
  4064.     if (x < 0) return(-1);
  4065.     x = cfsetispeed(&ttcur,B0);
  4066.     debug(F111,"tthang BSD44ORPOSIX cfsetispeed",ckitoa(errno),x);
  4067.     if (x < 0) return(-1);
  4068.     /* This gets EINVAL on NetBSD 1.4.1 because of B0... */
  4069.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
  4070.     debug(F111,"tthang BSD44ORPOSIX tcsetattr B0",ckitoa(errno),x);
  4071.     if (x < 0) return(-1);
  4072.     msleep(HUPTIME);        /* Sleep 0.5 sec */
  4073.     debug(F101,"tthang BSD44ORPOSIX restore output speed","",spdsav);
  4074.     x = cfsetospeed(&ttcur,spdsav); /* Restore prev speed */
  4075.     debug(F111,"tthang BSD44ORPOSIX cfsetospeed prev",ckitoa(errno),x);
  4076.     if (x < 0) return(-1);
  4077.     debug(F101,"tthang BSD44ORPOSIX restore input speed","",spdsavi);
  4078.     x = cfsetispeed(&ttcur,spdsavi);
  4079.     debug(F111,"tthang BSD44ORPOSIX cfsetispeed prev",ckitoa(errno),x);
  4080.     if (x < 0) return(-1);
  4081.     ttcur.c_cflag |= CLOCAL;    /* Don't expect CD after hangup */
  4082.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
  4083.     debug(F111,"tthang BSD44ORPOSIX tcsetattr restore",ckitoa(errno),x);
  4084.     if (x < 0) return(-1);
  4085.  
  4086. #endif /* HUP_CLOSE_POSIX */
  4087. #endif /* USE_TIOCSDTR */
  4088.  
  4089.     return(1);
  4090.     }
  4091.  
  4092. #endif /* QNX */
  4093. #else /* BSD44ORPOSIX */
  4094.  
  4095. #ifdef aegis                /* Apollo Aegis */
  4096.     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
  4097.     msleep(HUPTIME);                    /* pause */
  4098.     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
  4099.     return(1);
  4100. #endif /* aegis */
  4101.  
  4102. #ifdef ANYBSD                /* Any BSD version. */
  4103. #ifdef TIOCCDTR                /* Except those that don't have this */
  4104.     debug(F100,"tthang BSD style","",0);
  4105.     if (ioctl(ttyfd,TIOCCDTR,0) < 0) {    /* Clear DTR. */
  4106.     debug(F101,"tthang TIOCCDTR fails","",errno);
  4107.     return(-1);
  4108.     }
  4109.     msleep(HUPTIME);            /* For about 1/2 sec */
  4110.     errno = 0;
  4111.     x = ioctl(ttyfd,TIOCSDTR,0);    /* Restore DTR */
  4112.     if (x < 0) {
  4113.     /*
  4114.       For some reason, this tends to fail with "no such device or address"
  4115.       but the operation still works, probably because of the close/open
  4116.       later on.  So let's not scare the user unnecessarily here.
  4117.     */
  4118.     debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
  4119.     x = 1;                /* Pretend we succeeded */
  4120.     } else if (x == 0) x = 1;        /* Success */
  4121. #ifdef COMMENT
  4122. #ifdef FT21
  4123.     ioctl(ttyfd, TIOCSAVEMODES, 0);
  4124.     ioctl(ttyfd, TIOCHPCL, 0);
  4125.     close(ttyfd);            /* Yes, must do this twice */
  4126.     if ((ttyfd = open(ttnmsv,2)) < 0)    /* on Fortune computers... */
  4127.       return(-1);            /* (but why?) */
  4128.     else x = 1;
  4129. #endif /* FT21 */
  4130. #endif /* COMMENT */
  4131. #endif /* TIOCCDTR */
  4132.     close(do_open(ttnmsv));        /* Clear i/o error condition */
  4133.     errno = 0;
  4134. #ifdef COMMENT
  4135. /* This is definitely dangerous.  Why was it here? */
  4136.     z = ttvt(ttspeed,ttflow);        /* Restore modes. */
  4137.     debug(F101,"tthang ttvt returns","",z);
  4138.     return(z < 0 ? -1 : 1);
  4139. #else
  4140.     return(x);
  4141. #endif /* COMMENT */
  4142. #endif /* ANYBSD */
  4143.  
  4144. #ifdef ATTSV
  4145. /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
  4146.  
  4147. #ifdef HPUX
  4148. /* Hewlett Packard allows explicit manipulation of modem signals. */
  4149.  
  4150. #ifdef COMMENT
  4151. /* Old way... */
  4152.     debug(F100,"tthang HP-UX style","",0);
  4153.     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0)        /* lower DTR */
  4154.       return(-1);                           /* oops, can't. */
  4155.     msleep(HUPTIME);                       /* Pause half a second. */
  4156.     x = 1;                           /* Set return code */
  4157.     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) {     /* Get line status. */
  4158.     if ((modem_rtn & MDCD) != 0)             /* Check if CD is low. */
  4159.       x = -1;                                  /* CD didn't drop, fail. */
  4160.     } else x = -1;
  4161.  
  4162.     /* Even if above calls fail, RTS & DTR should be turned back on. */
  4163.     modem_rtn = MRTS | MDTR;
  4164.     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
  4165.     return(x);
  4166. #else
  4167. /* New way, from Hellmuth Michaelis */
  4168.     debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
  4169.     if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
  4170.     debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
  4171.     return(-1);
  4172.     }
  4173.     sprintf(modem_state,"%#lx",modem_rtn);
  4174.     debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
  4175.     modem_sav = modem_rtn;        /* Save current modem signals */
  4176.     modem_rtn &= ~MDTR;            /* Turn DTR bit off */
  4177.     sprintf(modem_state,"%#lx",modem_rtn);
  4178.     debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
  4179.     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
  4180.     debug(F100,"tthang HP-UX: can't lower DTR!","",0);
  4181.     return(-1);            /* oops, can't. */
  4182.     }
  4183.     msleep(HUPTIME);            /* Pause half a second. */
  4184.     x = 1;                /* Set return code */
  4185.     if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
  4186.     sprintf(modem_state,"%#lx",modem_rtn);
  4187.     debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
  4188.     if ((modem_rtn & MDCD) != 0) {    /* Check if CD is low. */
  4189.         debug(F100,"tthang HP-UX: DCD not down","",0);
  4190.         x = -1;            /* CD didn't drop, fail. */
  4191.     } else {
  4192.         debug(F100,"tthang HP-UX: DCD down","",0);
  4193.     }
  4194.     } else {
  4195.     x = -1;
  4196.     debug(F100,"tthang HP-UX: can't get DCD status !","",0);
  4197.     }
  4198.  
  4199.     /* Even if above calls fail, DTR should be turned back on. */
  4200.  
  4201.     modem_sav |= MDTR;
  4202.     if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
  4203.     x = -1;
  4204.     debug(F100,"tthang HP-UX: can't set saved state","",0);
  4205.     } else {
  4206.     sprintf(modem_state,"%#lx",modem_sav);
  4207.     debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
  4208.     }
  4209.     return(x);
  4210. #endif /* COMMENT */
  4211.  
  4212. #else /* AT&T but not HP-UX */
  4213.  
  4214. /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
  4215. /* It is not known how many, if any, systems actually implement them, */
  4216. /* so we include them here in ifdef's. */
  4217.  
  4218. /*
  4219.   Unixware has the TIOCMxxx symbols defined, but calling ioctl() with them
  4220.   gives error 22 (invalid argument).
  4221. */
  4222. #ifndef _IBMR2
  4223. /*
  4224.   No modem-signal twiddling for IBM RT PC or RS/6000.
  4225.   In AIX 3.1 and earlier, the ioctl() call is broken.
  4226.   This code could be activated for AIX 3.1 with PTF 2006 or later
  4227.   (e.g. AIX 3.2), but close/open does the job too, so why bother.
  4228. */
  4229. #ifdef TIOCMBIS                /* Bit Set */
  4230. #ifdef TIOCMBIC                /* Bit Clear */
  4231. #ifdef TIOCM_DTR            /* DTR */
  4232.  
  4233. /* Clear DTR, sleep 300 msec, turn it back on. */
  4234. /* If any of the ioctl's return failure, go on to the next section. */
  4235.  
  4236.     z = TIOCM_DTR;            /* Code for DTR. */
  4237. #ifdef COMMENT
  4238. /*
  4239.   This was the cause of the troubles with the Solaris Port Monitor.
  4240.   The problem is: RTS never comes back on.  Moral: Don't do it!
  4241.   (But why doesn't it come back on?  See the TIOCMBIS call...)
  4242. */
  4243. #ifdef TIOCM_RTS            /* Lower RTS too if symbol is known. */
  4244.     z |= TIOCM_RTS;
  4245. #endif /* TIOCM_RTS */
  4246. #endif /* COMMENT */
  4247.  
  4248.     debug(F101,"tthang TIOCM signal mask","",z);
  4249.     if (ioctl(ttyfd,TIOCMBIC,&z) > -1) {   /* Try to lower DTR. */
  4250.     debug(F100,"tthang TIOCMBIC ok","",0);
  4251.     msleep(HUPTIME);           /* Pause half a second. */
  4252.     if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
  4253.         debug(F100,"tthang TIOCMBIS ok","",0);
  4254. #ifndef CLSOPN
  4255.         return(1);            /* Success, done. */
  4256. #endif /* CLSOPN */
  4257.     } else {            /* Couldn't raise, continue. */
  4258.         debug(F101,"tthang TIOCMBIS errno","",errno);
  4259.     }
  4260.     } else {                /* Couldn't lower, continue. */
  4261.      debug(F101,"tthang TIOCMBIC errno","",errno);
  4262.     }
  4263. #endif /* TIOCM_DTR */
  4264. #endif /* TIOCMBIC */
  4265. #endif /* TIOCMBIS */
  4266. #endif /* _IBMR2 */
  4267.  
  4268. /*
  4269.   General AT&T UNIX case, not HPUX.  The following code is highly suspect.  No
  4270.   two AT&T-based systems seem to do this the same way.  The object is simply
  4271.   to turn off DTR and then turn it back on.  SVID says the universal method
  4272.   for turning off DTR is to set the speed to zero, and this does seem to do
  4273.   the trick in all cases.  But neither SVID nor any known man pages say how to
  4274.   turn DTR back on again.  Some variants, like most Xenix implementations,
  4275.   raise DTR again when the speed is restored to a nonzero value.  Others
  4276.   require the device to be closed and opened again, but this is risky because
  4277.   getty could seize the device during the instant it is closed.
  4278. */
  4279.  
  4280. /* Return code for ioctl failures... */
  4281. #ifdef ATT6300
  4282.     x = 1;                /* ATT6300 doesn't want to fail... */
  4283. #else
  4284.     x = -1;
  4285. #endif /* ATT6300 */
  4286.  
  4287.     debug(F100,"tthang get settings","",0);
  4288.     if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
  4289.       return(x);            /* Fail if this doesn't work. */
  4290.     if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
  4291.       return(x);
  4292.     ttc_save = ttcur.c_cflag;        /* Remember current speed. */
  4293.     spdsav = ttc_save & CBAUD;
  4294.     debug(F101,"tthang speed","",spdsav);
  4295.  
  4296. #ifdef O_NDELAY
  4297.     debug(F100,"tthang turning O_NDELAY on","",0);
  4298.     fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
  4299. #endif /* O_NDELAY */
  4300.  
  4301. #ifdef ATT7300 /* This is the way it is SUPPOSED to work */
  4302.     ttcur.c_cflag &= ~CBAUD;        /* Change the speed to zero.  */
  4303. #else
  4304. #ifdef RTAIX
  4305.     ttcur.c_cflag &= ~CBAUD;        /* Change the speed to zero.  */
  4306. #else          /* This way really works but may be dangerous */
  4307. #ifdef u3b2
  4308.     ttcur.c_cflag = ~(CBAUD|CLOCAL);    /* Special for AT&T 3B2s */
  4309.                     /* (CLOCAL must be OFF) */
  4310. #else
  4311. #ifdef SCO3R2                /* SCO UNIX 3.2 */
  4312. /*
  4313.   This is complete nonsense, but an SCO user claimed this change made
  4314.   hanging up work.  Comments from other SCO UNIX 3.2 users would be
  4315.   appreciated.
  4316. */
  4317.     ttcur.c_cflag = CBAUD|B0;
  4318. #else
  4319. #ifdef AIXRS                /* AIX on RS/6000 */
  4320. /*
  4321.   Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
  4322.   even though you can do it on the built-in port and the 8- and 16-port
  4323.   adapters.  (Untested on 128-port adapter.)
  4324. */
  4325.     ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
  4326. #else                    /* None of the above */
  4327. /*
  4328.   Set everything, including the speed, to zero, except for the CLOCAL
  4329.   and HUPCL bits.
  4330. */
  4331.     ttcur.c_cflag = CLOCAL|HUPCL;
  4332. #endif /* AIXRS */
  4333. #endif /* SCO3R2 */
  4334. #endif /* u3b2 */
  4335. #endif /* RTAIX */
  4336. #endif /* ATT7300 */
  4337.  
  4338. #ifdef COMMENT
  4339.     /* and if none of those work, try one of these... */
  4340.     ttcur.c_cflag = 0;
  4341.     ttcur.c_cflag = CLOCAL;
  4342.     ttcur.c_cflag &= ~(CBAUD|HUPCL);
  4343.     ttcur.c_cflag &= ~(CBAUD|CREAD);
  4344.     ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
  4345.     /* or other combinations */
  4346. #endif /* COMMENT */
  4347.  
  4348. #ifdef TCXONC
  4349.     debug(F100,"tthang TCXONC","",0);
  4350.     if (ioctl(ttyfd, TCXONC, 1) < 0) {
  4351.     debug(F101,"tthang TCXONC failed","",errno);
  4352.     }
  4353. #endif /* TCXONC */
  4354.  
  4355. #ifdef TIOCSTART
  4356.     debug(F100,"tthang TIOCSTART","",0);
  4357.     if (ioctl(ttyfd, TIOCSTART, 0) < 0) {
  4358.     debug(F101,"tthang TIOCSTART failed","",errno);
  4359.     }
  4360. #endif /* TIOCSTART */
  4361.  
  4362.     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
  4363.     debug(F101,"tthang TCSETAF failed","",errno);
  4364.     fcntl(ttyfd, F_SETFL, flags);    /* Restore flags */
  4365.     return(-1);            /* before returning. */
  4366.     }
  4367.     msleep(300);            /* Give modem time to notice. */
  4368.  
  4369. #ifndef NOCOTFMC
  4370.  
  4371. /* Now, even though it doesn't say this in SVID or any man page, we have */
  4372. /* to close and reopen the device.  This is not necessary for all systems, */
  4373. /* but it's impossible to predict which ones need it and which ones don't. */
  4374.  
  4375. #ifdef ATT7300
  4376. /*
  4377.   Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
  4378.   related ioctl's for their internal modems.  attmodem has getty status and
  4379.   modem-in-use bit.  Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
  4380.   but also ruins the file descriptor, and no other phone(7) ioctl call can fix
  4381.   it.  Whatever it does, it seems to escape detection with PIOCGETA and TCGETA.
  4382.   The only way to undo the damage is to close the fd and then reopen it.
  4383. */
  4384.     if (attmodem & ISMODEM) {
  4385.     debug(F100,"tthang attmodem close/open","",0);
  4386.     ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
  4387.     ioctl(ttyfd,PIOCDISC,&dialer);    /* Disconnect phone. */
  4388.     close(ttyfd);            /* Close and reopen the fd. */
  4389.     ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
  4390.     attmodem &= ~ISMODEM;        /* Phone no longer in use. */
  4391.     }
  4392. #else /* !ATT7300 */
  4393. /* It seems we have to close and open the device for other AT&T systems */
  4394. /* too, and this is the place to do it.  The following code does the */
  4395. /* famous close(open(...)) magic by default.  If that doesn't work for you, */
  4396. /* then try uncommenting the following statement or putting -DCLSOPN in */
  4397. /* the makefile CFLAGS. */
  4398.  
  4399. /* #define CLSOPN */
  4400.  
  4401. #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
  4402.  
  4403. #ifdef O_NDELAY
  4404. #define OPENFLGS O_RDWR | O_NDELAY
  4405. #else
  4406. #define OPENFLGS O_RDWR
  4407. #endif
  4408.  
  4409. #ifndef CLSOPN
  4410. /* This method is used by default, i.e. unless CLSOPN is defined. */
  4411. /* It is thought to be safer because there is no window where getty */
  4412. /* can seize control of the device.  The drawback is that it might not work. */
  4413.  
  4414.     debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
  4415.     close(priv_opn(ttnmsv, OPENFLGS));
  4416.  
  4417. #else
  4418. /* This method is used if you #define CLSOPN.  It is more likely to work */
  4419. /* than the previous method, but it's also more dangerous. */
  4420.  
  4421.     debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
  4422.     close(ttyfd);
  4423.     msleep(10);
  4424.     ttyfd = priv_opn(ttnmsv, OPENFLGS);    /* Open it again */
  4425. #endif /* CLSOPN */
  4426. #undef OPENFLGS
  4427.  
  4428. #endif /* SCO32 */
  4429. #endif /* ATT7300 */
  4430.  
  4431. #endif /* NOCOTFMC */
  4432.  
  4433. /* Now put all flags & modes back the way we found them. */
  4434. /* (Does the order of ioctl & fcntl matter ? ) */
  4435.  
  4436.     debug(F100,"tthang restore settings","",0);
  4437.     ttcur.c_cflag = ttc_save;        /* Get old speed back. */
  4438.     if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
  4439.       return(-1);
  4440. #ifdef O_NDELAY
  4441. /*
  4442.   This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
  4443.   After closing a modem line, the modem will probably not be asserting
  4444.   carrier any more, so we should not require carrier any more.  If this
  4445.   causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
  4446.   than O_NDELAY.
  4447. */
  4448.     flags &= ~O_NDELAY;            /* Don't require carrier on reopen */
  4449. #endif /* O_NDELAY */
  4450.     if (fcntl(ttyfd,F_SETFL,flags) < 0)    /* fcntl parameters */
  4451.       return(-1);
  4452.  
  4453.     return(1);
  4454. #endif /* not HPUX */
  4455. #endif /* ATTSV */
  4456. #endif /* BSD44ORPOSIX */
  4457. #endif /* HUP_POSIX */
  4458. #endif /* NOLOCAL */
  4459. }
  4460.  
  4461. /*
  4462.   Major change in 5A(174).  We used to use LPASS8, if it was defined, to
  4463.   allow 8-bit data and Xon/Xoff flow control at the same time.  But this
  4464.   LPASS8 business seems to have been causing trouble for everybody but me!
  4465.   For example, Annex terminal servers, commonly used with Encore computers,
  4466.   do not support LPASS8 even though the Encore itself does.  Ditto for many
  4467.   other terminal servers, TELNET connections, rlogin connections, etc etc.
  4468.   Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
  4469.   serial lines, even though LPASS8 is a feature of 4.3BSD.  So let's turn it
  4470.   off for everybody.  That means we goes back to using raw mode, with no
  4471.   flow control.  Phooey.
  4472.  
  4473.   NOTE: This must be done before the first reference to LPASS8 in this file,
  4474.   and after the last #include statment.
  4475. */
  4476. #ifdef LPASS8
  4477. #undef LPASS8
  4478. #endif /* LPASS8 */
  4479.  
  4480. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  4481.  
  4482. /* ske@pkmab.se: There are two choices for what this function should do.
  4483.  * (1) Restore the tty to current "normal" mode, with carrier treatment
  4484.  * according to ttcarr, to be used after every kermit command. (2) Restore
  4485.  * the tty to the state it was in before kermit opened it. These choices
  4486.  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
  4487.  * is currently being called as in choice (1), but ttold basically holds
  4488.  * the initial parameters, as in (2), and the description at the beginning
  4489.  * of this file says (2).
  4490.  *
  4491.  * I don't think restoring tty parameters after all kermit commands makes
  4492.  * much of a difference.  Restoring them upon exit from kermit may be of
  4493.  * some use in some cases (when the line is not restored automatically on
  4494.  * close, by the operating system).
  4495.  *
  4496.  * I can't choose which one it should be, so I haven't changed it. It
  4497.  * probably works as it is, too. It would probably even work even with
  4498.  * ttres() entirely deleted...
  4499.  *
  4500.  * (from fdc: Actually, this function operates in remote mode too, so
  4501.  * it restores the console (command) terminal to whatever mode it was
  4502.  * in before packet operations began, so that commands work right again.)
  4503.  */
  4504. int
  4505. ttres() {                               /* Restore the tty to normal. */
  4506.     int x;
  4507.  
  4508.     if (ttyfd < 0) return(-1);          /* Not open. */
  4509.  
  4510.     if (ttfdflg) return(0);        /* Don't mess with terminal modes if */
  4511.                     /* we got ttyfd from another process */
  4512. #ifdef    NETCONN
  4513.     if (netconn) {            /* Network connection */
  4514.         tvtflg = 0;
  4515. #ifdef TCPSOCKET
  4516. #ifdef TCP_NODELAY
  4517.         {
  4518.         extern int tcp_nodelay;    /* Just put this back if necessary */
  4519.         if (ttnet == NET_TCPB) {
  4520.         if (nodelay_sav > -1) {
  4521.             no_delay(ttyfd,nodelay_sav);
  4522.             nodelay_sav = -1;
  4523.         }
  4524.         }
  4525.         }
  4526. #endif /* TCP_NODELAY */
  4527. #ifdef TN_COMPORT
  4528.         if (istncomport()) {
  4529.             int rc = -1;
  4530.             if ((rc = tnsetflow(ttflow)) < 0)
  4531.           return(rc);
  4532.             if (ttspeed <= 0) 
  4533.           ttspeed = tnc_get_baud();
  4534.             else if ((rc = tnc_set_baud(ttspeed)) < 0)
  4535.           return(rc);
  4536.             tnc_set_datasize(8);
  4537.         tnc_set_stopsize(stopbits);
  4538.  
  4539. #ifdef HWPARITY
  4540.             if (hwparity) {
  4541.                 switch (hwparity) {
  4542.           case 'e':            /* Even */
  4543.                     debug(F100,"ttres 8 bits + even parity","",0);
  4544.                     tnc_set_parity(3);
  4545.                     break;
  4546.           case 'o':            /* Odd */
  4547.                     debug(F100,"ttres 8 bits + odd parity","",0);
  4548.                     tnc_set_parity(2);
  4549.                     break;
  4550.           case 'm':            /* Mark */
  4551.                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
  4552.                     tnc_set_parity(4);
  4553.                     break;
  4554.           case 's':            /* Space */
  4555.                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
  4556.                     tnc_set_parity(5);
  4557.                     break;
  4558.                 }
  4559.             } else
  4560. #endif /* HWPARITY */
  4561.         {
  4562.                 tnc_set_parity(1);              /* None */
  4563.             }
  4564.             tvtflg = 0;
  4565.             return(0);
  4566.         }
  4567. #endif /* TN_COMPORT */
  4568. #endif /* TCPSOCKET */
  4569.     return(0);
  4570.     }
  4571. #endif    /* NETCONN */
  4572. #ifdef NETCMD
  4573.     if (ttpipe) return(0);
  4574. #endif /* NETCMD */
  4575. #ifdef NETPTY
  4576.     if (ttpty) return(0);
  4577. #endif /* NETPTY */
  4578.  
  4579. /* Real terminal device, so restore its original modes */
  4580.  
  4581. #ifdef BSD44ORPOSIX            /* For POSIX like this */
  4582.     debug(F100,"ttres BSD44ORPOSIX","",0);
  4583.     x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
  4584. #else                    /* For all others... */
  4585. #ifdef ATTSV                            /* For AT&T versions... */
  4586.     debug(F100,"ttres ATTSV","",0);
  4587.     x = ioctl(ttyfd,TCSETAW,&ttold);    /* Restore tty modes this way. */
  4588. #else
  4589. /* Here we restore the modes for BSD */
  4590.  
  4591. #ifdef LPASS8                /* Undo "pass8" if it were done */
  4592.     if (lmodef) {
  4593.     if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
  4594.       debug(F100,"ttres TIOCLSET failed","",0);
  4595.     else
  4596.       debug(F100,"ttres TIOCLSET ok","",0);
  4597.     }
  4598. #endif /* LPASS8 */
  4599.  
  4600. #ifdef CK_DTRCTS           /* Undo hardware flow if it were done */
  4601.     if (lmodef) {
  4602.      if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
  4603.        debug(F100,"ttres TIOCLSET failed","",0);
  4604.      else
  4605.        debug(F100,"ttres TIOCLSET ok","",0);
  4606.     }
  4607. #endif /* CK_DTRCTS */
  4608.  
  4609. #ifdef TIOCGETC                /* Put back special characters */
  4610.     if (tcharf && (xlocal == 0)) {
  4611.     if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
  4612.       debug(F100,"ttres TIOCSETC failed","",0);
  4613.     else
  4614.       debug(F100,"ttres TIOCSETC ok","",0);
  4615.     }
  4616. #endif /* TIOCGETC */
  4617.  
  4618. #ifdef TIOCGLTC                /* Put back local special characters */
  4619.     if (ltcharf && (xlocal == 0)) {
  4620.     if (ioctl(ttyfd,TIOCSLTC,<chold) < 0)
  4621.       debug(F100,"ttres TIOCSLTC failed","",0);
  4622.     else
  4623.       debug(F100,"ttres TIOCSLTC ok","",0);
  4624.     }
  4625. #endif /* TIOCGLTC */
  4626.  
  4627. #ifdef BELLV10
  4628.     debug(F100,"ttres BELLV10","",0);
  4629.     x = ioctl(ttyfd,TIOCSETP,&ttold);    /* Restore both structs */
  4630.     x = ioctl(ttyfd,TIOCSDEV,&tdold);
  4631. #else
  4632.     debug(F100,"ttres stty","",0);
  4633.     x = stty(ttyfd,&ttold);             /* Restore tty modes the old way. */
  4634. #endif /* BELLV10 */
  4635.  
  4636.     if (!xlocal)
  4637.       msleep(100);            /* This replaces sleep(1)... */
  4638.                     /* Put back sleep(1) if tty is */
  4639.                     /* messed up after close. */
  4640. #endif /* ATTSV */
  4641. #endif /* BSD44ORPOSIX */
  4642.  
  4643.     debug(F101,"ttres result","",x);
  4644. #ifndef QNX
  4645.     if (x < 0) debug(F101,"ttres errno","",errno);
  4646. #endif /* QNX */
  4647.  
  4648. #ifdef AIXRS
  4649. #ifndef AIX41
  4650.     x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
  4651.     debug(F101,"ttres AIX line discipline rts restore","",x);
  4652. #endif /* AIX41 */
  4653. #endif /* AIXRS */
  4654.  
  4655. #ifdef BSD41
  4656.     if (ttld > -1) {            /* Put back line discipline */
  4657.     x = ioctl(ttyfd, TIOCSETD, &ttld);
  4658.     debug(F101,"ttres BSD41 line discipline restore","",x);
  4659.     if (x < 0) debug(F101,"...ioctl errno","",errno);
  4660.     ttld = -1;
  4661.     }
  4662. #endif /* BSD41 */
  4663.  
  4664. #ifdef sony_news
  4665.     x = xlocal ? km_ext : km_con;    /* Restore Kanji mode. */
  4666.     if (x != -1) {            /* Make sure we know original modes. */
  4667.     if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
  4668.         perror("ttres can't set Kanji mode");
  4669.         debug(F101,"ttres error setting Kanji mode","",x);
  4670.         return(-1);
  4671.     }
  4672.     }
  4673.     debug(F100,"ttres set Kanji mode ok","",0);
  4674. #endif /* sony_news */
  4675.  
  4676.     tvtflg = 0;                /* Invalidate terminal mode settings */
  4677.     debug(F101,"ttres return code","",x);
  4678.     return(x);
  4679. }
  4680.  
  4681. #ifndef NOUUCP
  4682.  
  4683. /*  T T C H K P I D  --  Check lockfile pid  */
  4684. /*
  4685.   Read pid from lockfile named f, check that it's still valid.
  4686.   If so, return 1.
  4687.   On failure to read pid, return 1.
  4688.   Otherwise, try to delete lockfile f and return 0 if successful, else 1.
  4689. */
  4690. static int
  4691. ttchkpid(f) char *f; {
  4692.     int pid, mypid, x;
  4693.     pid = ttrpid(f);            /* Read pid from file. */
  4694.     if (pid > -1) {            /* If we were able to read the pid.. */
  4695.     debug(F101,"ttchkpid lock pid","",pid);
  4696.     errno = 0;            /* See if process still exists. */
  4697.     mypid = (int)getpid();        /* Get my own pid. */
  4698.     debug(F101,"ttchkpid my pid","",mypid);
  4699.     if (pid == mypid) {        /* It's me! */
  4700.         x = -1;            /* So I can delete it */
  4701.         errno = ESRCH;        /* pretend it's invalid */
  4702.     } else {            /* It's not me */
  4703.         x = kill((PID_T)pid, 0);    /* See if it's a live process */
  4704.         debug(F101,"ttchkpid kill errno","",errno);
  4705.     }
  4706.     debug(F101,"ttchkpid pid test","",x);
  4707.     if (x < 0 && errno == ESRCH) { /* pid is invalid */
  4708.         debug(F111,"removing stale lock",f,pid);
  4709.         if (!backgrd)
  4710.           printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
  4711.         priv_on();
  4712.         x = unlink(f);        /* Remove the lockfile. */
  4713.         priv_off();
  4714.         debug(F111,"ttchkpid unlink",f,x);
  4715.         if (x > -1)
  4716.           return(0);        /* Device is not locked after all */
  4717.         else if (!backgrd)
  4718.           perror(f);
  4719.     }
  4720.     return(1);
  4721.     }
  4722.     return(1);                /* Failure to read pid */
  4723. }
  4724.  
  4725. #ifdef HPUX
  4726.  
  4727. /* Aliases (different drivers) for HP-UX dialout devices: */
  4728.  
  4729. static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
  4730. static int ttydexists = 0;
  4731.  
  4732. #endif /* HPUX */
  4733.  
  4734. /*  T T R P I D  --  Read pid from lockfile "name" */
  4735.  
  4736. static int
  4737. ttrpid(name) char *name; {
  4738.     long len;
  4739.     int x, fd, pid;
  4740.     short spid;
  4741.     char buf[32];
  4742.  
  4743.     debug(F110,"ttrpid",name,0);
  4744.     if (!name) return(-1);
  4745.     if (!*name) return(-1);
  4746.     priv_on();
  4747.     len = zchki(name);            /* Get file length */
  4748.     priv_off();
  4749.     debug(F101,"ttrpid zchki","",len);
  4750.     if (len < 0)
  4751.       return(-1);
  4752.     if (len > 31)
  4753.       return(-1);
  4754.     priv_on();
  4755.     fd = open(name,O_RDONLY);        /* Try to open lockfile. */
  4756.     priv_off();
  4757.     debug(F101,"ttrpid fd","",fd);
  4758.     if (fd <= 0)
  4759.       return(-1);
  4760. /*
  4761.   Here we try to be flexible and allow for all different binary and string
  4762.   formats at runtime, rather than a specific format for each configuration
  4763.   hardwired at compile time.
  4764. */
  4765.     pid = -1;
  4766. #ifndef COHERENT
  4767. /*
  4768.   COHERENT uses a string PID but without leading spaces or 0's, so there is
  4769.   no way to tell from the file's length whether it contains a string or binary
  4770.   pid.  So for COHERENT only, we only allow string pids.  For all others, we
  4771.   decide based on the size of the lockfile.
  4772. */
  4773.     if (len > 4) {            /* If file > 4 bytes it's a string */
  4774. #endif /* COHERENT */
  4775.     x = read(fd,buf,(int)len);
  4776.     debug(F111,"ttrpid string read",buf,x);
  4777.     if (x < 0) {
  4778.         pid = -1;
  4779.     } else {
  4780.         buf[31] = '\0';
  4781.         x = sscanf(buf,"%d",&pid);    /* Get the integer pid from it. */
  4782.     }
  4783. #ifndef COHERENT
  4784.     } else if (len == 4) {        /* 4 bytes so binary */
  4785.     x = read(fd, (char *)&pid, 4);    /* Read the bytes into an int */
  4786.     debug(F101,"ttrpid integer read","",x);
  4787.     if (x < 4)
  4788.       pid = -1;
  4789.     } else if (len == 2) {        /* 2 bytes binary */
  4790.     x = read(fd, (char *)&spid, 2);    /* Read the bytes into a short */
  4791.     debug(F101,"ttrpid short read","",x);
  4792.     if (x < 2)
  4793.       pid = -1;
  4794.     else
  4795.       pid = spid;
  4796.     } else
  4797.       pid = -1;
  4798. #endif /* COHERENT */
  4799.     close(fd);                /* Close the lockfile */
  4800.     debug(F101,"ttrpid pid","",pid);
  4801.     return(pid);
  4802. }
  4803. #endif /* NOUUCP */
  4804.  
  4805. /*  T T L O C K  */
  4806.  
  4807. /*
  4808.   This function attempts to coordinate use of the communication device with
  4809.   other copies of Kermit and any other program that follows the UUCP
  4810.   device-locking conventions, which, unfortunately, vary among different UNIX
  4811.   implementations.  The idea is to look for a file of a certain name, the
  4812.   "lockfile", in a certain directory.  If such a file is found, then the line
  4813.   is presumed to be in use, and Kermit should not use it.  If no such file is
  4814.   found, Kermit attempts to create one so that other programs will not use the
  4815.   same line at the same time.  Because the lockfile and/or the directory it's
  4816.   in might lack write permission for the person running Kermit, Kermit could
  4817.   find itself running setuid to uucp or other user that does have the
  4818.   necessary permissions.  At startup, Kermit has changed its effective uid to
  4819.   the user's real uid, and so ttlock() must switch back to the original
  4820.   effective uid in order to create the lockfile, and then back again to the
  4821.   real uid to prevent unauthorized access to other directories or files owned
  4822.   by the user the program is setuid to.
  4823.  
  4824.   Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
  4825.   based on suggestions from Warren Tucker.  Call with pointer to name of
  4826.   tty device.  Returns:
  4827.  
  4828.    0 on success
  4829.   -1 on failure
  4830.  
  4831.   Note: Once privileges are turned on using priv_on(), it is essential that
  4832.   they are turned off again before this function returns.
  4833. */
  4834. #ifdef SVR4                /* Lockfile uses device numbers. */
  4835. /*
  4836.   Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
  4837.   it is the behavior of the "reference version" of SVR4, i.e. the Intel
  4838.   port from UNIX Systems Laboratories, then called Univel UnixWare,
  4839.   then called Novell UnixWare, then called SCO Unixware, then called Caldera
  4840.   Open UNIX...  It also makes much more sense than device-name-based lockfiles
  4841.   since there can be multiple names for the same device, symlinks, etc.
  4842. */
  4843. #ifndef NOLFDEVNO
  4844. #ifndef LFDEVNO                /* Define this for SVR4 */
  4845. #ifndef AIXRS                /* But not for RS/6000 AIX 3.2, etc. */
  4846. #ifndef BSD44                /* If anybody else needs it... */
  4847. #ifndef __386BSD__
  4848. #ifndef __FreeBSD__
  4849. #ifndef HPUX10
  4850. #ifndef IRIX51                /* SGI IRIX 5.1 or later */
  4851. #ifndef CK_SCOV5            /* SCO Open Server 5.0 */
  4852. #define LFDEVNO
  4853. #endif /* CK_SCOV5 */
  4854. #endif /* IRIX51 */
  4855. #endif /* HPUX10 */
  4856. #endif /* __FreeBSD__ */
  4857. #endif /* __386BSD__ */
  4858. #endif /* BSD44 */
  4859. #endif /* AIXRS */
  4860. #endif /* LFDEVNO */            /* ... define it here or on CC */
  4861. #endif /* NOLFDEVNO */
  4862. #endif /* SVR4 */            /* command line. */
  4863.  
  4864. #ifdef COHERENT
  4865. #define LFDEVNO
  4866. #endif /* COHERENT */
  4867.  
  4868. /*
  4869.   For platforms where the lockfile name is made from device/major/minor
  4870.   device number, as in SVR4.  Which, if we must have lockfiles at all, is
  4871.   by far the best format, since it eliminates all the confusion that stems
  4872.   from multiple names (or drivers) for the same port, not to mention
  4873.   symlinks.  It might even be a good idea to start using this form even
  4874.   on platforms where it's not supported, alongside the normal forms for those
  4875.   platforms, in order to get people used to it...
  4876. */
  4877. #ifdef LFDEVNO
  4878. #ifndef major                /* If we didn't find it */
  4879. #ifdef SVR4                /* then for Sys V R4 */
  4880. #include <sys/mkdev.h>            /* look here */
  4881. #else                    /* or for SunOS versions */
  4882. #ifdef SUNOS4                /* ... */
  4883. #include <sys/sysmacros.h>        /* look here */
  4884. #else                    /* Otherwise take a chance: */
  4885. #define    major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
  4886. #define    minor(dev) ( (int) ( (dev) & 0xff))
  4887. #endif /* SUNOS4 */
  4888. #endif /* SVR4 */
  4889. #endif /* major */
  4890. #endif /* LFDEVNO */
  4891.  
  4892. /* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
  4893.  
  4894. #ifdef LOCKF
  4895. #ifndef F_TLOCK
  4896. #undef LOCKF
  4897. #ifndef NOLOCKF
  4898. #define NOLOCKF
  4899. #endif /* NOLOCKF */
  4900. #endif /* F_TLOCK */
  4901. #endif /* LOCKF */
  4902.  
  4903. #ifdef LOCKF
  4904. #ifndef F_ULOCK
  4905. #undef LOCKF
  4906. #ifndef NOLOCKF
  4907. #define NOLOCKF
  4908. #endif /* NOLOCKF */
  4909. #endif /* F_ULOCK */
  4910. #endif /* LOCKF */
  4911.  
  4912. static char linkto[DEVNAMLEN+1];
  4913. static char * linkdev = NULL;
  4914.  
  4915. #ifndef NOUUCP
  4916. #ifdef USETTYLOCK
  4917. #ifdef LOCK_DIR
  4918. char * uucplockdir = LOCK_DIR;
  4919. #else
  4920. char * uucplockdir = "";
  4921. #endif /* LOCK_DIR */
  4922. #else
  4923. #ifdef LOCK_DIR
  4924. char * uucplockdir = LOCK_DIR;
  4925. #else
  4926. char * uucplockdir = "";
  4927. #endif /* LOCK_DIR */
  4928. #endif /* USETTYLOCK */
  4929. #else
  4930. char * uucplockdir = "";
  4931. #endif /* NOUUCP */
  4932.  
  4933. #ifdef QNX                /* Only for QNX4 */
  4934. int                    /* Visible to outside world */
  4935. qnxopencount() {            /* Get QNX device open count */
  4936.     struct _dev_info_entry info;
  4937.     int x;
  4938.  
  4939.     x = -1;                /* Unknown */
  4940.     if (ttyfd > -1) {
  4941.     if (!dev_info(ttyfd, &info)) {
  4942.         debug(F101,"ttlock QNX open_count","",info.open_count);
  4943.         x = info.open_count;
  4944.     }
  4945.     }
  4946.     return(x);
  4947. }
  4948. #endif /* QNX */
  4949.  
  4950. char *
  4951. ttglckdir() {                /* Get Lockfile directory name */
  4952. #ifdef __OpenBSD__
  4953.     return("/var/spool/lock");
  4954. #else /* __OpenBSD__ */
  4955. #ifdef __FreeBSD__
  4956.     return("/var/spool/lock");
  4957. #else  /* __FreeBSD__ */
  4958. #ifdef LOCK_DIR
  4959.     char * s = LOCK_DIR;
  4960. #endif /* LOCK_DIR */
  4961. #ifdef NOUUCP
  4962.     return("");
  4963. #else  /* NOUUCP */
  4964. #ifdef LOCK_DIR
  4965.     return(s);
  4966. #else  /* LOCK_DIR */
  4967.     return("");
  4968. #endif /* LOCK_DIR */
  4969. #endif /* NOUUCP */
  4970. #endif /* __FreeBSD__ */
  4971. #endif /* __OpenBSD__ */
  4972. }
  4973.  
  4974. static int
  4975. ttlock(ttdev) char *ttdev; {
  4976.  
  4977.     int x, n;
  4978.     int islink = 0;
  4979. #ifdef __FreeBSD__
  4980.     char *devname;
  4981. #endif    /* __FreeBSD__ */
  4982.  
  4983. #ifdef NOUUCP
  4984.     debug(F100,"ttlock NOUUCP","",0);
  4985.     ckstrncpy(flfnam,"NOLOCK",FLFNAML);
  4986.     haslock = 1;
  4987.     return(0);
  4988. #else /* !NOUUCP */
  4989.  
  4990. #ifdef USETTYLOCK
  4991.     haslock = 0;                        /* Not locked yet. */
  4992.     *flfnam = '\0';            /* Lockfile name is empty. */
  4993. #ifdef __FreeBSD__
  4994.     if ((devname = xxlast(ttdev,'/')) != NULL)
  4995. #ifdef FREEBSD8
  4996.       ckstrncat(lockname,devname+1,DEVNAMLEN-ckstrncpy(lockname,"pts",4));
  4997. #else
  4998.       ckstrncpy(lockname,devname+1,DEVNAMLEN);
  4999. #endif    /* FREEBSD8 */
  5000. #else
  5001.     if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
  5002.       ckstrncpy(lockname,ttdev+5,DEVNAMLEN);
  5003. #endif    /* __FreeBSD__ */
  5004.     else
  5005.       ckstrncpy(lockname,ttdev,DEVNAMLEN);
  5006. /*
  5007.   This might be overkill, but it's not clear from the man pages whether
  5008.   ttylock() can be called without calling ttylocked() first, since the doc
  5009.   says that ttylocked() removes any stale lockfiles, but it does not say this
  5010.   about ttylock().  Also the docs don't say what ttylocked() returns in the
  5011.   case when it finds and removes a stale lockfile.  So one or both calls to
  5012.   to ttylocked() might be superfluous, but they should do no harm.  Also I'm
  5013.   assuming that we have to do all the same ID swapping, etc, with these
  5014.   routines as we do without them.  Thus the priv_on/off() sandwich.
  5015. */
  5016. #ifdef USE_UU_LOCK
  5017.     priv_on();                /* Turn on privs */
  5018.     x = uu_lock(lockname);        /* Try to set the lock */
  5019.     priv_off();                /* Turn privs off */
  5020.     debug(F111,"ttlock uu_lock",lockname,x);
  5021.     switch (x) {
  5022.       case UU_LOCK_INUSE:
  5023.     return(-2);
  5024.       case UU_LOCK_OK:
  5025. #ifdef BSD44
  5026.     ckmakmsg(flfnam,FLFNAML,"/var/spool/lock/LCK..",lockname,NULL,NULL);
  5027. #endif /* BSD44 */
  5028.     haslock = 1;
  5029.     return(0);
  5030.       default:
  5031.     return(-1);
  5032.     }
  5033. #else  /* USE_UU_LOCK */
  5034.     priv_on();                /* Turn on privs */
  5035.     if (ttylocked(lockname)) {        /* This should remove any stale lock */
  5036.     if (ttylocked(lockname)) {    /* so check again. */
  5037.         priv_off();
  5038.         return(-5);            /* Still locked, fail. */
  5039.     }
  5040.     }
  5041.     x = ttylock(lockname);        /* Lock it. */
  5042.     priv_off();                /* Turn off privs */
  5043.  
  5044.     debug(F111,"ttlock lockname",lockname,x);
  5045.     if (x > -1) {
  5046.     /*
  5047.       We don't really know the name of the lockfile, but
  5048.       this is what the man page says it is.  In USETTYLOCK
  5049.           builds, it is used only for display by SHOW COMM.
  5050.     */
  5051.     ckmakmsg(flfnam,FLFNAML,"/etc/locks/LCK..",lockname,NULL,NULL);
  5052.     haslock = 1;
  5053.     }
  5054.     return(x);
  5055. #endif /* USE_UU_LOCK */
  5056. #else  /* Systems that don't have ttylock()... */
  5057.  
  5058. #ifndef HPUX
  5059.  
  5060.     int lockfd;                /* File descriptor for lock file. */
  5061.     PID_T pid;                /* Process id of this process. */
  5062.     int tries;                /* How many times we've tried... */
  5063.     struct stat devbuf;            /* For device numbers (SVR4). */
  5064.  
  5065. #ifdef PIDSTRING
  5066.     char pid_str[32];            /* My pid in string format. */
  5067. #endif /* PIDSTRING */
  5068.  
  5069.     char *device, *devname;
  5070.  
  5071. #define LFNAML 256            /* Max length for lock file name. */
  5072.     char lockfil[LFNAML];        /* Lock file name */
  5073. #ifdef RTAIX
  5074.     char lklockf[LFNAML];        /* Name for link to lock file  */
  5075. #endif /* RTAIX */
  5076. #ifdef CKSYMLINK
  5077.     char symlock[LFNAML];        /* Name for symlink lockfile name */
  5078. #endif /* CKSYMLINK */
  5079.     char tmpnam[LFNAML+30];        /* Temporary lockfile name. */
  5080.     char *lockdir = LOCK_DIR;        /* Defined near top of this file, */
  5081.                     /* or on cc command line. */
  5082.     haslock = 0;                        /* Not locked yet. */
  5083.     *flfnam = '\0';            /* Lockfile name is empty. */
  5084.     lock2[0] = '\0';            /* Clear secondary lockfile name. */
  5085.     pid = getpid();            /* Get id of this process. */
  5086.  
  5087. /*  Construct name of lockfile and temporary file */
  5088.  
  5089. /*  device  = name of tty device without the path, e.g. "ttyh8" */
  5090. /*  lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
  5091.  
  5092.     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
  5093.  
  5094.     if (stat(ttdev,&devbuf) < 0)
  5095.       return(-1);
  5096.  
  5097. #ifdef CKSYMLINK
  5098.     islink = 1;                /* Assume it's a symlink */
  5099.     linkto[0] = '\0';            /* But we don't know to what */
  5100. #ifdef COMMENT
  5101. /*
  5102.   This is undependable.  If it worked it would save the readlink call if
  5103.   we knew the device name was not a link.
  5104. */
  5105. #ifdef S_ISLNK
  5106.     islink = S_ISLNK(devbuf.st_mode);
  5107.     debug(F101,"ttlock stat S_ISLNK","",islink);
  5108. #endif /* S_ISLNK */
  5109. #endif /* COMMENT */
  5110.     if (islink) {
  5111.     n = readlink(ttdev,linkto,DEVNAMLEN); /* See if it's a link */
  5112.     debug(F111,"ttlock readlink",ttdev,n);
  5113.     if (n > -1)            /* It is */
  5114.       linkto[n] = '\0';
  5115.     else                /* It's not */
  5116.       islink = 0;
  5117.     debug(F111,"ttlock link",linkto,islink);
  5118.     }
  5119.     if (islink) {
  5120.     linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
  5121.     debug(F110,"ttlock linkdev",linkdev,0);
  5122.     }
  5123. #endif /* CKSYMLINK */
  5124.  
  5125. /*
  5126.   On SCO platforms, if we don't have a symlink, then let's pretend the
  5127.   name given for the device is a symlink, because later we will change
  5128.   the name if it contains any uppercase characters.
  5129. */
  5130. #ifdef CK_SCOV5                /* SCO Open Server 5.0 */
  5131.     if (!islink) {
  5132.     islink = 1;
  5133.     ckstrncpy(linkto,ttdev,DEVNAMLEN);
  5134.     linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
  5135.     debug(F110,"ttlock linkdev",linkdev,0);
  5136.     }
  5137. #else
  5138. #ifdef M_XENIX                /* SCO Xenix or UNIX */
  5139.     if (!islink) {
  5140.     islink = 1;
  5141.     ckstrncpy(linkto,ttdev,DEVNAMLEN);
  5142.     linkdev = (devname = xxlast(linkto,'/')) ? devname + 1 : linkto;
  5143.     debug(F110,"ttlock linkdev",linkdev,0);
  5144.     }
  5145. #endif /* M_XENIX */
  5146. #endif /* CK_SCOV5 */
  5147.  
  5148. #ifdef ISIII                /* Interactive System III, PC/IX */
  5149.     ckstrncpy(lockfil, device, DEVNAMLEN);
  5150. #else  /* not ISIII */
  5151. #ifdef LFDEVNO                /* Lockfilename has device numbers. */
  5152. #ifdef COHERENT
  5153.     sprintf(lockfil,"LCK..%d.%d",    /* SAFE */
  5154.         major(devbuf.st_rdev),       /* major device number */
  5155.         0x1f & minor(devbuf.st_rdev)); /* minor device number */
  5156. #else
  5157.     /* Note: %d changed to %u in 8.0 -- %u is part of SVID for SVR4 */
  5158.     /* Lockfile name format verified to agree with Solaris cu, Dec 2001 */
  5159.     sprintf(lockfil,"LK.%03u.%03u.%03u", /* SAFE */
  5160.         major(devbuf.st_dev),    /* device */
  5161.         major(devbuf.st_rdev),    /* major device number */
  5162.         minor(devbuf.st_rdev));    /* minor device number */
  5163. #endif /* COHERENT */
  5164. #else  /* Not LFDEVNO */
  5165. #ifdef PTX                /* Dynix PTX */
  5166.     if ((device != &ttdev[5]) && (strncmp(ttdev,"/dev/",5) == 0)) {
  5167.     if ((int)strlen(device) + 8 < LFNAML)
  5168.       sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
  5169.     else
  5170.       ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
  5171.     } else
  5172. #endif /* PTX */
  5173.       if ((int)strlen(device) + 5 < LFNAML)
  5174.     sprintf(lockfil,"LCK..%s", device);
  5175.       else
  5176.     ckstrncpy(lockfil,"LOCKFILE_NAME_TOO_LONG",LFNAML);
  5177. #ifdef RTAIX
  5178.     ckstrncpy(lklockf,device,DEVNAMLEN);
  5179. #endif /* RTAIX */
  5180. #ifdef CKSYMLINK
  5181.     symlock[0] = '\0';
  5182.     if (islink)
  5183.       ckmakmsg(symlock,LFNAML, "LCK..", linkdev, NULL, NULL);
  5184. #endif /* CKSYMLINK */
  5185. #endif /* LFDEVNO */
  5186. #endif /* ISIII */
  5187.  
  5188. #ifdef CK_SCOV5                /* SCO Open Server 5.0 */
  5189.     {
  5190.     /* Lowercase the entire filename. */
  5191.         /* SCO says we must do this in V5.0 and later. */
  5192.     /* BUT... watch out for devices -- like Digiboard Portserver */
  5193.     /* That can have hundreds of ports... */
  5194.     char *p = (char *)(lockfil + 5);
  5195.     while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
  5196.     }
  5197. #ifdef CKSYMLINK
  5198.     if (islink) {            /* If no change */
  5199.     if (!strcmp(lockfil,symlock)) {    /* then no second lockfile needed */
  5200.         islink = 0;
  5201.         symlock[0] = '\0';
  5202.     }
  5203.     }
  5204. #endif /* CKSYMLINK */
  5205. #else
  5206. #ifdef M_XENIX                /* SCO Xenix or UNIX */
  5207.     {
  5208.     int x; char c;
  5209.     x = (int)strlen(lockfil) - 1;    /* Get last letter of device name. */
  5210.     if (x > 0) {            /* If it's uppercase, lower it. */
  5211.         c = lockfil[x];
  5212.         if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
  5213.     }
  5214.     }
  5215. #ifdef CKSYMLINK
  5216.     if (islink) {
  5217.     if (!strcmp(lockfil,symlock)) {    /* No change */
  5218.         islink = 0;            /* so no second lockfile */
  5219.         symlock[0] = '\0';
  5220.     }
  5221.     }
  5222. #endif /* CKSYMLINK */
  5223. #endif /* M_XENIX */
  5224. #endif /* CK_SCOV5 */
  5225.  
  5226. /*  flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
  5227. /*  tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
  5228.  
  5229.     ckmakmsg(flfnam,LFNAML,lockdir,"/",lockfil,NULL);
  5230.  
  5231. #ifdef RTAIX
  5232.     ckmakmsg(lkflfn,FLFNAML,lockdir,"/",lklockf,NULL);
  5233. #endif /* RTAIX */
  5234.  
  5235. #ifndef LFDEVNO
  5236. #ifdef CKSYMLINK
  5237.     /* If it's a link then also make a lockfile for the real name */
  5238.     debug(F111,"ttlock link symlock",symlock,islink);
  5239.     if (islink && symlock[0]) {
  5240.     /* But only if the lockfile names would be different. */
  5241.     /* WARNING: They won't be, e.g. for /dev/ttyd2 => /hw/ttys/ttyd2 */
  5242.     ckmakmsg(lock2,FLFNAML,lockdir,"/",symlock,NULL);
  5243.     debug(F110,"ttlock lock2",lock2,0);
  5244.     if (!strcmp(lock2,flfnam)) {    /* Are lockfile names the same? */
  5245.         debug(F100,"ttlock lock2 cleared","",0);
  5246.         lock2[0] = '\0';        /* Clear secondary lockfile name. */
  5247.     }
  5248.     }
  5249. #endif /* CKSYMLINK */
  5250. #endif /* LFDEVNO */
  5251.  
  5252.     sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* safe */
  5253.     debug(F110,"ttlock flfnam",flfnam,0);
  5254.     debug(F110,"ttlock tmpnam",tmpnam,0);
  5255.  
  5256.     priv_on();                /* Turn on privileges if possible. */
  5257.     lockfd = creat(tmpnam, 0444);    /* Try to create temp lock file. */
  5258.     if (lockfd < 0) {            /* Create failed. */
  5259.     debug(F111,"ttlock creat failed",tmpnam,errno);
  5260.     if (errno == ENOENT) {
  5261.         perror(lockdir);
  5262.         printf("UUCP not installed or Kermit misconfigured\n");
  5263.     } else {
  5264.         if (!quiet)
  5265.           perror(lockdir);
  5266.         unlink(tmpnam);        /* Get rid of the temporary file. */
  5267.     }
  5268.     priv_off();            /* Turn off privileges!!! */
  5269.     return(-1);            /* Return failure code. */
  5270.     }
  5271. /* Now write the pid into the temp lockfile in the appropriate format */
  5272.  
  5273. #ifdef PIDSTRING            /* For Honey DanBer UUCP, */
  5274.     sprintf(                /* write PID as decimal string */
  5275.         pid_str,
  5276. #ifdef LINUXFSSTND            /* The "Linux File System Standard" */
  5277. #ifdef FSSTND10                /* Version 1.0 calls for */
  5278.         "%010d\n",            /* leading zeros */
  5279. #else                    /* while version 1.2 calls for */
  5280.         "%10d\n",            /* leading spaces */
  5281. #endif /* FSSTND10 */
  5282. #else
  5283. #ifdef COHERENT
  5284.         "%d\n",            /* with leading nothing */
  5285. #else
  5286.         "%10d\n",            /* with leading blanks */
  5287. #endif /* COHERENT */
  5288. #endif /* LINUXFSSTND */
  5289.         (int) pid
  5290.         );                /* safe */
  5291.     write(lockfd, pid_str, 11);
  5292.     debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
  5293.  
  5294. #else /* Not PIDSTRING, use integer PID */
  5295.  
  5296.     write(lockfd, (char *)&pid, sizeof(pid) );
  5297.     debug(F101,"ttlock pid","",(int) pid);
  5298.  
  5299. #endif /* PIDSTRING */
  5300.  
  5301. /* Now try to rename the temp file to the real lock file name. */
  5302. /* This will fail if a lock file of that name already exists.  */
  5303.  
  5304.     close(lockfd);            /* Close the temp lockfile. */
  5305.     chmod(tmpnam,0444);            /* Permission for a valid lock. */
  5306.     tries = 0;
  5307.     while (!haslock && tries++ < 2) {
  5308.     haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
  5309.     if (haslock) {                  /* If we got the lockfile */
  5310. #ifdef RTAIX
  5311.         link(flfnam,lkflfn);
  5312. #endif /* RTAIX */
  5313. #ifdef CKSYMLINK
  5314. #ifndef LFDEVNO
  5315.         if (islink && lock2[0])
  5316.           link(flfnam,lock2);
  5317. #endif /* LFDEVNO */
  5318. #endif /* CKSYMLINK */
  5319.  
  5320. #ifdef COMMENT
  5321. /* Can't do this any more because device is not open yet so no ttyfd. */
  5322. #ifdef LOCKF
  5323. /*
  5324.   Advisory file locking works on SVR4, so we use it.  In fact, it is
  5325.   necessary in some cases, e.g. when SLIP is involved.  But it still doesn't
  5326.   seem to prevent multiple users accessing the same device by different names.
  5327. */
  5328.             while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
  5329.                 debug(F111, "ttlock lockf returns errno", "", errno);
  5330.                 if ((++tries >= 3) || (errno != EAGAIN)) {
  5331.                     x = unlink(flfnam); /* remove the lockfile */
  5332. #ifdef RTAIX
  5333.             unlink(lkflfn);    /* And any links to it... */
  5334. #endif /* RTAIX */
  5335. #ifdef CKSYMLINK
  5336. #ifndef LFDEVNO
  5337.             if (islink && lock2[0])
  5338.               unlink(lock2);    /* ditto... */
  5339. #endif /* LFDEVNO */
  5340. #endif /* CKSYMLINK */
  5341.                     debug(F111,"ttlock unlink",flfnam,x);
  5342.                     haslock = 0;
  5343.             break;
  5344.         }
  5345.                 sleep(2);
  5346.         }
  5347.         if (haslock)        /* If we got an advisory lock */
  5348. #endif /* LOCKF */
  5349. #endif /* COMMENT */
  5350.           break;            /* We're done. */
  5351.  
  5352.     } else {            /* We didn't create a new lockfile. */
  5353.         priv_off();
  5354.         if (ttchkpid(flfnam)) {    /* Check existing lockfile */
  5355.         priv_on();        /* cause ttchkpid turns priv_off... */
  5356.         unlink(tmpnam);        /* Delete the tempfile */
  5357.         debug(F100,"ttlock found tty locked","",0);
  5358.         priv_off();        /* Turn off privs */
  5359.         return(-2);        /* Code for device is in use. */
  5360.         }
  5361.         priv_on();
  5362.     }
  5363.     }
  5364.     unlink(tmpnam);            /* Unlink (remove) the temp file. */
  5365.     priv_off();                /* Turn off privs */
  5366.     return(haslock ? 0 : -1);        /* Return link's return code. */
  5367.  
  5368. #else /* HPUX */
  5369.  
  5370. /*
  5371.   HP-UX gets its own copy of this routine, modeled after the observed behavior
  5372.   of the HP-UX 'cu' program.  HP-UX serial device names consist of a base name
  5373.   such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
  5374.   designator which is a string of digits, possibly containing an imbedded
  5375.   letter "p".  Examples (for base name "tty"):
  5376.  
  5377.      /dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
  5378.  
  5379.   According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
  5380.   used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
  5381.   on other models.  In HP-UX 10.00, "0p0" notation was adopted for all models.
  5382.   However, we make and enforce no such distinctions; either notation is
  5383.   accepted on any model or HP-UX version as a valid unit designator.
  5384.  
  5385.   If a valid unit is specified (as opposed to a designer name or symlink), we
  5386.   check for all aliases of the given unit according to the devprefix[] array.
  5387.   If no lockfiles are found for the given unit, we can have the device; we
  5388.   create a lockfile LCK..name in the lockfile directory appropriate for the
  5389.   HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
  5390.   9.xx and earlier).  If it is a "cua" or "cul" device, a second lockfile is
  5391.   created with the "ttyd" prefix.  This is exactly what cu does.
  5392.  
  5393.   If the "set line" device does not have a valid unit designator, then it is
  5394.   used literally and no synomyms are searched for and only one lockfile is
  5395.   created.
  5396.  
  5397.   -fdc, March 1998.
  5398. */
  5399. #define LFNAML 80            /* Max length for lock file name. */
  5400.  
  5401.     int lockfd;                /* File descriptor for lock file. */
  5402.     PID_T pid;                /* Process ID of this process. */
  5403.     int fpid;                /* pid found in existing lockfile. */
  5404.     int tries;                /* How many times we've tried... */
  5405.     int i, k;                /* Workers */
  5406.  
  5407.     char *device, *devname;        /* "/dev/xxx", "xxx" */
  5408.     char *unit, *p;            /* <instance>p<port> part of xxx */
  5409.  
  5410.     char lockfil[LFNAML];        /* Lockfile name (no path) */
  5411.     char tmpnam[LFNAML];        /* Temporary lockfile name. */
  5412.  
  5413. #ifdef HPUX10                /* Lockfile directory */
  5414.     char *lockdir = "/var/spool/locks";    /* Always this for 10.00 and higher */
  5415. #else  /* HP-UX 9.xx and below */
  5416. #ifdef LOCK_DIR
  5417.     char *lockdir = LOCK_DIR;        /* Defined near top of this file */
  5418. #else
  5419.     char *lockdir = "/usr/spool/uucp";    /* or not... */
  5420. #endif /* LOCK_DIR */
  5421. #endif /* HPUX10 */
  5422.  
  5423.     haslock = 0;                        /* Not locked yet. */
  5424.     *flfnam = '\0';            /* Lockfile name is empty. */
  5425.     lock2[0] = '\0';            /* Second one too. */
  5426.     pid = getpid();            /* Get my process ID */
  5427. /*
  5428.   Construct name of lockfile and temporary file...
  5429.   device  = name of tty device without the path, e.g. "tty0p0"
  5430.   lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
  5431. */
  5432.     device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
  5433.     debug(F110,"TTLOCK device",device,0);
  5434.     ckmakmsg(lockfil,LFNAML,"LCK..",device,NULL,NULL);
  5435.  
  5436.     k = 0;                /* Assume device is not locked */
  5437.     n = 0;                /* Digit counter */
  5438.     unit = device;            /* Unit = <instance>p<port> */
  5439.     while (*unit && !isdigit(*unit))    /* Search for digit... */
  5440.       unit++;
  5441.     p = unit;                /* Verify <num>p<num> format... */
  5442.     debug(F110,"TTLOCK unit 1",unit,0);
  5443. /*
  5444.   The unit number is recognized as:
  5445.   (a) any sequence of digits that runs to the end of the string.
  5446.   (b) any (a) that includes one and only one letter "p", with at least
  5447.       one digit before and after it.
  5448. */
  5449.     while (isdigit(*p)) p++, n++;    /* Get a run of digits */
  5450.     if (*p && n > 0) {            /* Have a "p"? */
  5451.     if (*p == 'p' && isdigit(*(p+1))) {
  5452.         p++;
  5453.         n = 0;
  5454.         while (isdigit(*p)) p++, n++;
  5455.     }
  5456.     }
  5457.     if (n == 0 || *p) unit = "";
  5458.     debug(F110,"TTLOCK unit 2",unit,0);
  5459.  
  5460.     if (*unit) {            /* Device name has unit number. */
  5461.     /* The following loop not only searches for the various lockfile    */
  5462.     /* synonyms, but also removes all -- not just one -- stale lockfile */
  5463.     /* for the device, should there be more than one.  See ttchkpid().  */
  5464.     ttydexists = 0;
  5465.     for (i = 0; *devprefix[i]; i++) { /* For each driver... */
  5466.         /* Make device name */
  5467.         ckmakmsg(lock2,FLFNAML,"/dev/",devprefix[i],unit,NULL);
  5468.         priv_on();            /* Privs on */
  5469.         k = zchki(lock2) != -1;    /* See if device exists */
  5470.         priv_off();            /* Privs off */
  5471.         debug(F111,"TTLOCK exist",lock2,k);
  5472.             if (k) {
  5473.         if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
  5474.           ttydexists = 1;
  5475.         /* Make lockfile name */
  5476.         ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",devprefix[i],unit);
  5477.         debug(F110,"TTLOCK checking",lock2,0);
  5478.         priv_on();        /* Privs on */
  5479.         k = zchki(lock2) != -1;    /* See if lockfile exists */
  5480.         priv_off();        /* Privs off */
  5481.         debug(F111,"TTLOCK check for lock A",lock2,k);
  5482.         if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
  5483.             ckstrncpy(flfnam,lock2,FLFNAML);
  5484.             return(-2);
  5485.         }
  5486.         }
  5487.     }
  5488.     } else {                /* Some other device-name format */
  5489.     /* This takes care of symbolic links, etc... */
  5490.     /* But does not chase them down! */
  5491.     ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..",device,NULL);
  5492.     priv_on();
  5493.     k = zchki(lock2) != -1;        /* Check for existing lockfile */
  5494.     priv_off();
  5495.     debug(F111,"TTLOCK check for lock B",lock2,k);
  5496.     if (k) if (ttchkpid(lock2)) {    /* Check pid from lockfile */
  5497.         ckstrncpy(flfnam,lock2,FLFNAML);
  5498.         debug(F110,"TTLOCK in use",device,0);
  5499.         debug(F101,"TTLOCK returns","",-2);
  5500.         return(-2);
  5501.     }
  5502.     }
  5503. /*
  5504.   Get here only if there is no (more) lockfile, so now we make one (or two)...
  5505.   flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
  5506.   tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
  5507. */
  5508.     ckmakmsg(flfnam,FLFNAML,lockdir,"/",lockfil,NULL); /* SET LINE device */
  5509.  
  5510.     /* If dialout device, also make one for corresponding dialin device */
  5511.     lock2[0] = '\0';
  5512.     if (!strncmp(device,"cu",2) && *unit && ttydexists)
  5513.       ckmakmsg(lock2,FLFNAML,lockdir,"/LCK..ttyd",unit,NULL);
  5514.  
  5515.     if ((int)strlen(lockdir)+12 < LFNAML)
  5516.       sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temp name */
  5517. #ifdef DEBUG
  5518.     if (deblog) {
  5519.     debug(F110,"TTLOCK flfnam",flfnam,0);
  5520.     debug(F110,"TTLOCK lock2",lock2,0);
  5521.     debug(F110,"TTLOCK tmpnam",tmpnam,0);
  5522.     }
  5523. #endif /* DEBUG */
  5524. /*
  5525.    Lockfile permissions...
  5526.    444 is standard, HP-UX 10.00 uses 664.  It doesn't matter.
  5527.    Kermit uses 444; the difference lets us tell whether Kermit created
  5528.    the lock file.
  5529. */
  5530.     priv_on();                /* Turn on privileges. */
  5531.     lockfd = creat(tmpnam, 0444);    /* Try to create temporary file. */
  5532.     if (lockfd < 0) {            /* Create failed. */
  5533.     debug(F111,"TTLOCK creat failed",tmpnam,errno);
  5534.     if (errno == ENOENT) {
  5535.         perror(lockdir);
  5536.         printf("UUCP not installed or Kermit misconfigured\n");
  5537.     } else {
  5538.         if (!quiet)
  5539.           perror(lockdir);
  5540.         unlink(tmpnam);        /* Get rid of the temporary file. */
  5541.     }
  5542.     priv_off();            /* Turn off privileges!!! */
  5543.     debug(F101,"TTLOCK returns","",-1);
  5544.     return(-1);            /* Return failure code. */
  5545.     }
  5546.     debug(F110,"TTLOCK temp ok",tmpnam,0);
  5547.  
  5548. /* Now write our pid into the temp lockfile in integer format. */
  5549.  
  5550.     i = write(lockfd, (char *)&pid, sizeof(pid));
  5551.  
  5552. #ifdef DEBUG
  5553.     if (deblog) {
  5554.     debug(F101,"TTLOCK pid","",pid);
  5555.     debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
  5556.     debug(F101,"TTLOCK write pid returns","",i);
  5557.     }
  5558. #endif /* DEBUG */
  5559.  
  5560. /*
  5561.   Now try to rename the temporary file to the real lockfile name.
  5562.   This will fail if a lock file of that name already exists, which
  5563.   will catch race conditions with other users.
  5564. */
  5565.     close(lockfd);            /* Close the temp lockfile. */
  5566.     chmod(tmpnam,0444);
  5567.  
  5568.     tries = 0;
  5569.     while (!haslock && tries++ < 2) {
  5570.     haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
  5571.     debug(F101,"TTLOCK link","",haslock);
  5572.     if (haslock) {            /* If we made the lockfile... */
  5573.  
  5574. #ifdef COMMENT
  5575. /* We can't do this any more because we don't have a file descriptor yet. */
  5576. #ifdef LOCKF                /* Can be canceled with -DNOLOCKF */
  5577. /*
  5578.   Create an advisory lock on the device through its file descriptor.
  5579.   This code actually seems to work.  If it is executed, and then another
  5580.   process tries to open the same device under a different name to circumvent
  5581.   the lockfile, they get a "device busy" error.
  5582. */
  5583.         debug(F100,"TTLOCK LOCKF code...","",0);
  5584.             while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
  5585.                 debug(F111, "TTLOCK lockf error", "", errno);
  5586.                 if ((++tries >= 3) || (errno != EAGAIN)) {
  5587.                     x = unlink(flfnam); /* Remove the lockfile */
  5588.             if (errno == EACCES && !quiet)
  5589.               printf("Device already locked by another process\n");
  5590.                     haslock = 0;
  5591.             break;
  5592.         }
  5593.                 sleep(2);
  5594.         }
  5595. #endif /* LOCKF */
  5596. #endif /* COMMENT */
  5597.  
  5598.         if (haslock) {        /* If we made the lockfile ... */
  5599.         if (lock2[0]) {        /* if there is to be a 2nd lockfile */
  5600.             lockfd = creat(lock2, 0444); /* Create it */
  5601.             debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
  5602.             if (lockfd > -1) {    /* Created OK, write pid. */
  5603.             write(lockfd, (char *)&pid, sizeof(pid) );
  5604.             close(lockfd);    /* Close and */
  5605.             chmod(lock2, 0444); /* set permissions. */
  5606.             } else {         /* Not OK, but don't fail. */
  5607.             lock2[0] = '\0'; /* Just remember it's not there. */
  5608.             }
  5609.         }
  5610.         break;            /* and we're done. */
  5611.         }
  5612.     }
  5613.     }
  5614.     unlink(tmpnam);            /* Unlink (remove) the temp file. */
  5615.     priv_off();                /* Turn off privs */
  5616.     i = haslock ? 0 : -1;        /* Our return value */
  5617.     debug(F101,"TTLOCK returns","",i);
  5618.     return(i);
  5619. #endif /* HPUX */
  5620. #endif /* USETTYLOCK */
  5621. #endif /* !NOUUCP */
  5622. }
  5623.  
  5624. /*  T T U N L O C K  */
  5625.  
  5626. static int
  5627. ttunlck() {                             /* Remove UUCP lockfile(s). */
  5628. #ifndef NOUUCP
  5629.     int x;
  5630.  
  5631.     debug(F111,"ttunlck",flfnam,haslock);
  5632.  
  5633. #ifdef USETTYLOCK
  5634.  
  5635.     if (haslock && *flfnam) {
  5636.     int x;
  5637.     priv_on();            /* Turn on privs */
  5638. #ifdef USE_UU_LOCK
  5639.     x = uu_unlock(lockname);
  5640. #else  /* USE_UU_LOCK */
  5641.     x = ttyunlock(lockname);    /* Try to unlock */
  5642. #endif /* USE_UU_LOCK */
  5643.     priv_off();            /* Turn off privs */
  5644.     if (x < 0 && !quiet)
  5645.       printf("Warning - Can't remove lockfile: %s\n", flfnam);
  5646.  
  5647.     *flfnam = '\0';            /* Erase the name. */
  5648.     haslock = 0;
  5649.     return(0);
  5650.     }
  5651.  
  5652. #else  /* No ttylock()... */
  5653.  
  5654.     if (haslock && *flfnam) {
  5655.     /* Don't remove lockfile if we didn't make it ourselves */
  5656.     if ((x = ttrpid(flfnam)) != (int)getpid()) {
  5657.         debug(F111,"ttunlck lockfile seized",flfnam,x);
  5658.         printf("Warning - Lockfile %s seized by pid %d\n",
  5659.            flfnam,
  5660.            x
  5661.            );
  5662.         return(0);
  5663.     }
  5664.     priv_on();            /* Turn privileges on.  */
  5665.     errno = 0;
  5666.     x = unlink(flfnam);        /* Remove the lockfile. */
  5667.     debug(F111,"ttunlck unlink",flfnam,x);
  5668.     if (x < 0) {
  5669.         if (errno && !quiet)
  5670.           perror(ttnmsv);
  5671.         printf("Warning - Can't remove lockfile: %s\n", flfnam);
  5672.     }
  5673.     haslock = 0;
  5674.     *flfnam = '\0';            /* Erase the name. */
  5675.  
  5676. #ifdef RTAIX
  5677.     errno = 0;
  5678.     x = unlink(lkflfn);        /* Remove link to lockfile */
  5679.     debug(F111,"ttunlck AIX link unlink",lkflfn,x);
  5680.     if (x < 0) {
  5681.         if (errno && !quiet)
  5682.           perror(ttnmsv);
  5683.         printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
  5684.     }
  5685.     *lkflfn = '\0';
  5686. #else
  5687.     if (lock2[0]) {            /* If there is a second lockfile, */
  5688.         errno = 0;
  5689.         x = unlink(lock2);        /*  remove it too. */
  5690.         debug(F111,"ttunlck lock2 unlink",lock2,x);
  5691.         if (x < 0) {
  5692.         if (errno && !quiet)
  5693.           perror(ttnmsv);
  5694.         printf("Warning - Can't remove secondary lockfile: %s\n",
  5695.                lock2
  5696.                );
  5697.         }
  5698.         lock2[0] = '\0';        /* Forget its name. */
  5699.     }
  5700. #endif /* RTAIX */
  5701.  
  5702. #ifdef COMMENT
  5703. #ifdef LOCKF
  5704.         (VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
  5705. #endif /* LOCKF */
  5706. #endif /* COMMENT */
  5707.  
  5708.     priv_off();            /* Turn privileges off. */
  5709.     }
  5710. #endif /* USETTYLOCK */
  5711. #endif /* !NOUUCP */
  5712.     return(0);
  5713. }
  5714.  
  5715. /*
  5716.   4.3BSD-style UUCP line direction control.
  5717.   (Stan Barber, Rice U, 1980-something...)
  5718. */
  5719. #ifndef NOUUCP
  5720. #ifdef ACUCNTRL
  5721. VOID
  5722. acucntrl(flag,ttname) char *flag, *ttname; {
  5723.     char x[DEVNAMLEN+32], *device, *devname;
  5724.  
  5725.     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
  5726.       return;                /* just return. */
  5727.     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
  5728.     if (strncmp(device,"LCK..",4) == 0) device += 5;
  5729.     ckmakmsg(x,DEVNAMLEN+32,"/usr/lib/uucp/acucntrl ",flag," ",device);
  5730.     debug(F110,"called ",x,0);
  5731.     zsyscmd(x);
  5732. }
  5733. #endif /* ACUCNTRL */
  5734. #endif /* NOUUCP */
  5735.  
  5736. /*
  5737.   T T H F L O W  --  Set or Reset hardware flow control.
  5738.  
  5739.   This is an attempt to collect all hardware-flow-control related code
  5740.   into a single module.  Thanks to Rick Sladkey and John Kohl for lots of
  5741.   help here.  Overview:
  5742.  
  5743.   Hardware flow control is not supported in many UNIX implementions.  Even
  5744.   when it is supported, there is no (ha ha) "standard" for the programming
  5745.   interface.  In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
  5746.   SunOS, AIX, etc, have totally different methods.  (And, not strictly
  5747.   relevant here, the programming interface often brings one only to a no-op
  5748.   in the device driver!)
  5749.  
  5750.   Among all these, we have two major types of APIs: those in which hardware
  5751.   flow control is determined by bits in the same termio/termios/sgtty mode
  5752.   word(s) that are used for controlling such items as CBREAK vs RAW mode, and
  5753.   which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
  5754.   for changing terminal modes.  And those that use entirely different
  5755.   mechanisms.
  5756.  
  5757.   In the first category, it is important that any change in the mode bits be
  5758.   reflected in the relevant termio(s)/sgtty structure, so that subsequent
  5759.   changes to that structure do not wipe out the effects of this routine.  That
  5760.   is why a pointer, attrs, to the appropriate structure is passed as a
  5761.   parameter to this routine.
  5762.  
  5763.   The second category should give us no worries, since any changes to hardware
  5764.   flow control accomplished by this routine should not affect the termio(s)/
  5765.   sgtty structures, and therefore will not be undone by later changes to them.
  5766.  
  5767.   The second argument, status, means to turn on hardware flow control if
  5768.   nonzero, and to turn it off if zero.
  5769.  
  5770.   Returns: 0 on apparent success, -1 on probable failure.
  5771. */
  5772.  
  5773. /*
  5774.   The following business is for BSDI, where it was discovered that two
  5775.   separate bits, CCTS_OFLOW and CRTS_IFLOW, are used in hardware flow control,
  5776.   but CTRSCTS is defined (in <termios.h>) to be just CCTS_OFLOW rather both
  5777.   bits, so hwfc only works in one direction if you use CRTSCTS to control it.
  5778.   Other 4.4BSD-based Unixes such as FreeBSD 4.1, which use these two bits,
  5779.   define CRTSCTS correctly.
  5780. */
  5781. #ifdef FIXCRTSCTS
  5782. #ifdef CRTSCTS
  5783. #ifdef CCTS_OFLOW
  5784. #ifdef CRTS_IFLOW
  5785. #undef CRTSCTS
  5786. #define CRTSCTS (CRTS_IFLOW|CCTS_OFLOW)
  5787. #endif /* CRTS_IFLOW */
  5788. #endif /* CCTS_OFLOW */
  5789. #endif /* CRTSCTS */
  5790. #endif /* FIXCRTSCTS */
  5791.  
  5792. static int
  5793. tthflow(flow, status, attrs)
  5794.     int flow,                /* Type of flow control (ckcdeb.h) */
  5795.     status;                /* Nonzero = turn it on */
  5796.                     /* Zero = turn it off */
  5797. #ifdef BSD44ORPOSIX            /* POSIX or BSD44 */
  5798.     struct termios *attrs;
  5799. #else                    /* System V */
  5800. #ifdef ATTSV
  5801. #ifdef ATT7300
  5802. #ifdef UNIX351M
  5803. /* AT&T UNIX 3.51m can set but not test for hardware flow control */
  5804. #define RTSFLOW CTSCD
  5805. #define CTSFLOW CTSCD
  5806. #endif /* ATT7300 */
  5807. #endif /* UNIX351M */
  5808.     struct termio *attrs;
  5809. #else                    /* BSD, V7, etc */
  5810.     struct sgttyb *attrs;        /* sgtty info... */
  5811. #endif /* ATTSV */
  5812. #endif /* BSD44ORPOSIX */
  5813. /* tthflow */ {
  5814.  
  5815.     int x = 0;                /* tthflow() return code */
  5816.  
  5817. #ifdef Plan9
  5818.     return p9tthflow(flow, status);
  5819. #else
  5820.  
  5821. #ifndef OXOS                /* NOT Olivetti X/OS... */
  5822. /*
  5823.   For SunOS 4.0 and later in the BSD environment ...
  5824.  
  5825.   The declarations are copied and interpreted from the System V header files,
  5826.   so we don't actually have to pull in all the System V junk when building
  5827.   C-Kermit for SunOS in the BSD environment, which would be dangerous because
  5828.   having those symbols defined would cause us to take the wrong paths through
  5829.   the code.  The code in this section is used in both the BSD and Sys V SunOS
  5830.   versions.
  5831. */
  5832. #ifdef SUNOS41
  5833. /*
  5834.   In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
  5835.   because GNU CC uses different formats for the _IOxxx macros than regular CC;
  5836.   the POSIX forms work for both.  But the POSIX calls are not available in
  5837.   SunOS 4.0.
  5838. */
  5839. #define CRTSCTS 0x80000000        /* RTS/CTS flow control */
  5840. #define TCSANOW 0            /* Do it now */
  5841.  
  5842.     struct termios {
  5843.     unsigned long c_iflag;        /* Input modes */
  5844.     unsigned long c_oflag;        /* Output modes */
  5845.     unsigned long c_cflag;        /* Control modes */
  5846.     unsigned long c_lflag;        /* Line discipline modes */
  5847.     char c_line;
  5848.     CHAR c_cc[17];
  5849.     };
  5850.     struct termios temp;
  5851.  
  5852. _PROTOTYP( int tcgetattr, (int, struct termios *) );
  5853. _PROTOTYP( int tcsetattr, (int, int, struct termios *) );
  5854. /*
  5855.   When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
  5856.   asserted.  So we don't set CRTSCTS unless CD is up.  This should be OK,
  5857.   since we don't need RTS/CTS during dialing, and after dialing is complete,
  5858.   we should have CD.  If not, we still communicate, but without RTS/CTS.
  5859. */
  5860.     int mflags;                /* Modem signal flags */
  5861.  
  5862. #ifdef NETCMD
  5863.     if (ttpipe) return(0);
  5864. #endif /* NETCMD */
  5865. #ifdef NETPTY
  5866.     if (ttpty) return(0);
  5867. #endif /* NETPTY */
  5868.  
  5869.     debug(F101,"tthflow SUNOS41 entry status","",status);
  5870.     if (!status) {            /* Turn hard flow off */
  5871.     if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
  5872.         (temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
  5873.         temp.c_cflag &= ~CRTSCTS;    /* It's there, remove it */
  5874.         x = tcsetattr(ttyfd,TCSANOW,&temp);
  5875.     }
  5876.     } else {                /* Turn hard flow on */
  5877.     if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
  5878.         (mflags & TIOCM_CAR)) {        /* Check for CD */
  5879.         debug(F100,"tthflow SunOS has CD","",0);
  5880.         if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
  5881.         !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
  5882.         temp.c_cflag |= CRTSCTS;    /* Not there, add it */
  5883.         x = tcsetattr(ttyfd,TCSANOW,&temp);
  5884.         }
  5885.     } else {
  5886.         x = -1;
  5887.         debug(F100,"tthflow SunOS no CD","",0);
  5888.     }
  5889.     }
  5890. #else
  5891. #ifdef QNX
  5892.     struct termios temp;
  5893. #ifdef NETCMD
  5894.     if (ttpipe) return(0);
  5895. #endif /* NETCMD */
  5896. #ifdef NETPTY
  5897.     if (ttpty) return(0);
  5898. #endif /* NETPTY */
  5899.     debug(F101,"tthflow QNX entry status","",status);
  5900.     if (tcgetattr(ttyfd, &temp) > -1) {    /* Get device attributes */
  5901.     if (!status) {            /* Turn hard flow off */
  5902.         if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
  5903.         temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
  5904.         attrs->c_cflag &= ~(IHFLOW|OHFLOW);
  5905.         x = tcsetattr(ttyfd,TCSANOW,&temp);
  5906.         }
  5907.     } else {            /* Turn hard flow on */
  5908.         if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
  5909.         temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
  5910.         temp.c_iflag &= ~(IXON|IXOFF);   /* Bye to IXON/IXOFF */
  5911.         ttraw.c_lflag |= IEXTEN;         /* Must be on */
  5912.         x = tcsetattr(ttyfd,TCSANOW,&temp);
  5913.         attrs->c_cflag |= (IHFLOW|OHFLOW);
  5914.         attrs->c_iflag &= ~(IXON|IXOFF);
  5915.         }
  5916.     }
  5917.     } else {
  5918.     x = -1;
  5919.     debug(F100, "tthflow QNX getattr fails", "", 0);
  5920.     }
  5921. #else
  5922. #ifdef POSIX_CRTSCTS
  5923. /*
  5924.   POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
  5925.   Note: Do not assume CRTSCTS is a one-bit field!
  5926. */
  5927.     struct termios temp;
  5928. #ifdef NETCMD
  5929.     if (ttpipe) return(0);
  5930. #endif /* NETCMD */
  5931. #ifdef NETPTY
  5932.     if (ttpty) return(0);
  5933. #endif /* NETPTY */
  5934.     debug(F101,"tthflow POSIX_CRTSCTS entry status","",status);
  5935.     errno = 0;
  5936.     x = tcgetattr(ttyfd, &temp);
  5937.     debug(F111,"tthflow POSIX_CRTSCTS tcgetattr",ckitoa(x),errno);
  5938.     errno = 0;
  5939.     if (x < 0) {
  5940.     x = -1;
  5941.     } else {
  5942.     if (!status) {            /* Turn hard flow off */
  5943.         if (
  5944. #ifdef COMMENT
  5945.         /* This can fail because of sign extension */
  5946.         /* e.g. in Linux where it's Bit 31 */
  5947.         (temp.c_cflag & CRTSCTS) == CRTSCTS
  5948. #else
  5949.         (temp.c_cflag & CRTSCTS) != 0
  5950. #endif /* COMMENT */
  5951.         ) {
  5952.         temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
  5953.         attrs->c_cflag &= ~CRTSCTS;
  5954.         x = tcsetattr(ttyfd,TCSANOW,&temp);
  5955.         debug(F111,"tthflow POSIX_CRTSCTS OFF tcsetattr",
  5956.               ckitoa(x),errno);
  5957.         } else {            /* John Dunlap 2010-01-26 */
  5958.         debug(F001,
  5959.               "tthflow before forcing off attrs CRTSCTS",
  5960.               "",
  5961.               attrs->c_cflag&CRTSCTS
  5962.               );
  5963.         attrs->c_cflag &= ~CRTSCTS; /* force it off if !status */
  5964.         debug(F001,
  5965.               "tthflow after forcing off attrs CRTSCTS",
  5966.               "",
  5967.               attrs->c_cflag&CRTSCTS
  5968.               );
  5969.         }
  5970.     } else {            /* Turn hard flow on */
  5971.         if (
  5972. #ifdef COMMENT
  5973.         /* This can fail because of sign extension */
  5974.         (temp.c_cflag & CRTSCTS) != CRTSCTS
  5975. #else
  5976.         (temp.c_cflag & CRTSCTS) == 0
  5977. #endif /* COMMENT */
  5978.         ) {
  5979.         temp.c_cflag |= CRTSCTS; /* Not there, add it */
  5980.         temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
  5981.         x = tcsetattr(ttyfd,TCSANOW,&temp);
  5982.         debug(F111,"tthflow POSIX_CRTSCTS ON tcsetattr",
  5983.               ckitoa(x),errno);
  5984.         attrs->c_cflag |= CRTSCTS;
  5985.         attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
  5986.         }
  5987.     }
  5988.     }
  5989. #else
  5990. #ifdef SUNOS4
  5991. /*
  5992.   SunOS 4.0 (and maybe earlier?).  This code is dangerous because it
  5993.   prevents compilation with GNU gcc, which uses different formats for the
  5994.   _IORxxx macros than regular cc.  SunOS 4.1 and later can use the POSIX
  5995.   routines above, which work for both cc and gcc.
  5996. */
  5997. #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
  5998. #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
  5999. #define CRTSCTS 0x80000000          /* RTS/CTS flow control */
  6000.  
  6001.     struct termios {
  6002.     unsigned long c_iflag;        /* Input modes */
  6003.     unsigned long c_oflag;        /* Output modes */
  6004.     unsigned long c_cflag;        /* Control modes */
  6005.     unsigned long c_lflag;        /* Line discipline modes */
  6006.     char c_line;
  6007.     CHAR c_cc[17];
  6008.     };
  6009.     struct termios temp;
  6010. #ifdef NETCMD
  6011.     if (ttpipe) return(0);
  6012. #endif /* NETCMD */
  6013. #ifdef NETPTY
  6014.     if (ttpty) return(0);
  6015. #endif /* NETPTY */
  6016.     debug(F101,"tthflow entry status","",status);
  6017.     if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
  6018.     if (status) {            /* Turn hard flow on */
  6019.         temp.c_cflag |= CRTSCTS;    /* Add RTS/CTS to them. */
  6020.         x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
  6021.         attrs->c_cflag |= CRTSCTS;    /* Add to global info. */
  6022.     } else {            /* Turn hard flow off */
  6023.         temp.c_cflag &= ~CRTSCTS;
  6024.         x = ioctl(ttyfd,TCSETS,&temp);
  6025.         attrs->c_cflag &= ~CRTSCTS;
  6026.     }
  6027.     }
  6028. #else                    /* Not SunOS 4.0 or later */
  6029. #ifdef AIXRS                /* IBM AIX RS/6000 */
  6030. #ifndef AIX41                /* But only pre-4.x == SVR4 */
  6031. #ifdef NETCMD
  6032.     if (ttpipe) return(0);
  6033. #endif /* NETCMD */
  6034. #ifdef NETPTY
  6035.     if (ttpty) return(0);
  6036. #endif /* NETPTY */
  6037.     if (status) {
  6038.     if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
  6039.       debug(F100,"hardflow TXADDCD (rts) error", "", 0);
  6040.     } else {
  6041.     if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
  6042.       debug(F100,"hardflow TXDELCD (rts) error", "", 0);
  6043.     }
  6044. #endif /* AIX41 */
  6045. #else                    /* Not AIX RS/6000 */
  6046.  
  6047. #ifdef ATTSV                /* System V... */
  6048.  
  6049. #ifdef CK_SCOV5                /* SCO Open Server 5.0 */
  6050. #define CK_SCOUNIX
  6051. #else
  6052. #ifdef M_UNIX                /* SCO UNIX 3.2v4.x or earlier */
  6053. #define CK_SCOUNIX
  6054. #endif /* M_UNIX */
  6055. #endif /* CK_SCOV5 */
  6056.  
  6057. #ifdef SCO_FORCE_RTSXOFF
  6058. #ifdef CK_SCOUNIX            /* But not SCO OpenServer 5.0.4 */
  6059. #ifdef SCO_OSR504            /* or later... */
  6060. #undef CK_SCOUNIX
  6061. #endif /* SCO_OSR504 */
  6062. #endif /* CK_SCOUNIX */
  6063. #endif /* SCO_FORCE_RTSXOFF */
  6064.  
  6065. #ifdef CK_SCOUNIX
  6066. #ifdef POSIX
  6067.     struct termios temp;
  6068. #ifdef NETCMD
  6069.     if (ttpipe) return(0);
  6070. #endif /* NETCMD */
  6071. #ifdef NETPTY
  6072.     if (ttpty) return(0);
  6073. #endif /* NETPTY */
  6074.     debug(F101,"tthflow SCOUNIX POSIX entry status","",status);
  6075.     errno = 0;
  6076.     x = tcgetattr(ttyfd, &temp);
  6077.     debug(F111,"tthflow SCO UNIX POSIX tcgetattr",ckitoa(x),errno);
  6078. #else /* POSIX */
  6079.     struct termio temp;
  6080. #ifdef NETCMD
  6081.     if (ttpipe) return(0);
  6082. #endif /* NETCMD */
  6083. #ifdef NETPTY
  6084.     if (ttpty) return(0);
  6085. #endif /* NETPTY */
  6086.     debug(F101,"tthflow SCOUNIX non-POSIX entry status","",status);
  6087.     x = ioctl(ttyfd, TCGETA, &temp);
  6088.     debug(F111,"tthflow SCO UNIX non-POSIX TCGETA",ckitoa(x),errno);
  6089. #endif /* POSIX */
  6090. /*
  6091.   This is not really POSIX, since POSIX does not deal with hardware flow
  6092.   control, but we are using the POSIX APIs.  In fact, RTSFLOW and CTSFLOW
  6093.   are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif.  So
  6094.   let's try forcing their definitions here.
  6095. */
  6096. #ifndef CTSFLOW
  6097. #define CTSFLOW 0020000
  6098.     debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
  6099. #else
  6100.     debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
  6101. #endif /* CTSFLOW */
  6102. #ifndef RTSFLOW
  6103. #define RTSFLOW 0040000
  6104.     debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
  6105. #else
  6106.     debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
  6107. #endif /* RTSFLOW */
  6108. #ifndef ORTSFL
  6109. #define ORTSFL 0100000
  6110.     debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
  6111. #else
  6112.     debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
  6113. #endif /* ORTSFL */
  6114.  
  6115.     if (x != -1) {
  6116.     if (status) {            /* Turn it ON */
  6117.         temp.c_cflag |= RTSFLOW|CTSFLOW;
  6118.         attrs->c_cflag |= RTSFLOW|CTSFLOW;
  6119. #ifdef ORTSFL
  6120.         temp.c_cflag &= ~ORTSFL;
  6121.         attrs->c_cflag &= ~ORTSFL;
  6122. #endif /* ORTSFL */
  6123.         temp.c_iflag &= ~(IXON|IXOFF|IXANY);
  6124.         attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
  6125.     } else {            /* Turn it OFF */
  6126. #ifdef ORTSFL
  6127.         temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
  6128.         attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
  6129. #else  /* ORTSFL */
  6130.         temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
  6131.         attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
  6132. #endif /* ORTSFL */
  6133.     }
  6134. #ifdef POSIX
  6135.     x = tcsetattr(ttyfd, TCSADRAIN, &temp);
  6136. #else
  6137.     x = ioctl(ttyfd, TCSETA, &temp);
  6138. #endif /* POSIX */
  6139.     debug(F101,"tthflow SCO set modes","",x);
  6140.     }
  6141. #else /* Not SCO UNIX */
  6142. #ifdef NETCMD
  6143.     if (ttpipe) return(0);
  6144. #endif /* NETCMD */
  6145. #ifdef NETPTY
  6146.     if (ttpty) return(0);
  6147. #endif /* NETPTY */
  6148.     if (!status) {            /* Turn it OFF */
  6149. #ifdef RTSXOFF
  6150.     debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
  6151.     rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
  6152. #ifdef TCSETX
  6153.     x = ioctl(ttyfd,TCSETX,&rctsx);
  6154.     debug(F101,"tthflow ATTSV TCSETX OFF","",x);
  6155. #else
  6156.     x = -1
  6157.     debug(F100,"tthflow TCSETX not defined","",0);
  6158. #endif /* TCSETX */
  6159. #else
  6160.     debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
  6161. #endif /* RTSXOFF */
  6162. #ifdef DTRXOFF
  6163.     debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
  6164.     rctsx.x_hflag &= ~(DTRXOFF|CDXON);
  6165.     x = ioctl(ttyfd,TCSETX,&rctsx);
  6166.     debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
  6167. #else
  6168.     debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
  6169. #endif /* DTRXOFF */
  6170.     } else {                /* Turn it ON. */
  6171.     if (flow == FLO_RTSC) {    /* RTS/CTS Flow control... */
  6172.         debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
  6173. #ifdef RTSXOFF
  6174.         /* This is the preferred way, according to SVID3 */
  6175. #ifdef TCGETX
  6176.         x = ioctl(ttyfd,TCGETX,&rctsx);
  6177.         debug(F101,"tthflow TCGETX","",x);
  6178.         if (x > -1) {
  6179.         rctsx.x_hflag |= RTSXOFF | CTSXON;
  6180.         x = ioctl(ttyfd,TCSETX,&rctsx);
  6181.         debug(F100,"tthflow ATTSV ioctl","",x);
  6182.         }
  6183. #else
  6184.         debug(F100,"tthflow TCGETX not defined","",0);
  6185.         x = -1
  6186. #endif /* TCGETX */
  6187. #else
  6188.         debug(F100,"tthflow RTSXOFF not defined","",0);
  6189.         x = -1;
  6190. #endif /* RTSXOFF */
  6191.     } else if (flow == FLO_DTRC) {    /* DTR/CD Flow control... */
  6192.         debug(F100,"tthflow ATTSV DTR/CD ON","",0);
  6193. #ifdef DTRXOFF
  6194.         /* This is straight out of SVID R4 */
  6195.         if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
  6196.         rctsx.x_hflag &= ~(DTRXOFF|CDXON);
  6197.         x = ioctl(ttyfd,TCSETX,&rctsx);
  6198.         }
  6199. #else
  6200.         debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
  6201.         x = -1;
  6202. #endif /* DTRXOFF */
  6203.     }
  6204.     }
  6205. #endif /* CK_SCOUNIX */
  6206.  
  6207. #else /* not System V... */
  6208.  
  6209. #ifdef CK_DTRCTS
  6210. #ifdef LDODTR
  6211. #ifdef LDOCTS
  6212. #ifdef NETCMD
  6213.     if (ttpipe) return(0);
  6214. #endif /* NETCMD */
  6215. #ifdef NETPTY
  6216.     if (ttpty) return(0);
  6217. #endif /* NETPTY */
  6218.     x = LDODTR | LDOCTS;        /* Found only on UTEK? */
  6219.     if (flow == FLO_DTRT && status) {    /* Use hardware flow control */
  6220.     if (lmodef) {
  6221.         x = ioctl(ttyfd,TIOCLBIS,&x);
  6222.         if (x < 0) {
  6223.             debug(F100,"hardflow TIOCLBIS error","",0);
  6224.         } else {
  6225.         lmodef++;
  6226.         debug(F100,"hardflow TIOCLBIS ok","",0);
  6227.         }
  6228.     }
  6229.     } else {
  6230.     if (lmodef) {
  6231.         x = ioctl(ttyfd,TIOCLBIC,&x);
  6232.         if (x < 0) {
  6233.             debug(F100,"hardflow TIOCLBIC error","",0);
  6234.         } else {
  6235.         lmodef++;
  6236.         debug(F100,"hardflow TIOCLBIC ok","",0);
  6237.         }
  6238.     }
  6239.     }
  6240. #endif /* LDODTR */
  6241. #endif /* LDOCTS */
  6242. #endif /* CK_DTRCTS */
  6243. #endif /* ATTSV */
  6244. #endif /* AIXRS */
  6245. #endif /* SUNOS4 */
  6246. #endif /* QNX */
  6247. #endif /* POSIX_CRTSCTS */
  6248. #endif /* SUNOS41 */
  6249.  
  6250. #else /* OXOS */
  6251.  
  6252.     struct termios temp;        /* Olivetti X/OS ... */
  6253.  
  6254. #ifdef NETCMD
  6255.     if (ttpipe) return(0);
  6256. #endif /* NETCMD */
  6257. #ifdef NETPTY
  6258.     if (ttpty) return(0);
  6259. #endif /* NETPTY */
  6260.     x = ioctl(ttyfd,TCGETS,&temp);
  6261.     if (x == 0) {
  6262.     temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
  6263.     if (status) {
  6264.         switch (flow) {
  6265.           case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
  6266.         break;
  6267.           case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
  6268.         break;
  6269.         }
  6270.     }
  6271.     x = ioctl(ttyfd,TCSETS,&temp);
  6272.     }
  6273. #endif /* OXOS */
  6274.     return(x);
  6275.  
  6276. #endif /* Plan9 */
  6277. }
  6278.  
  6279. /*  T T P K T  --  Condition the communication line for packets */
  6280. /*                 or for modem dialing */
  6281.  
  6282. /*
  6283.   If called with speed > -1, also set the speed.
  6284.   Returns 0 on success, -1 on failure.
  6285.  
  6286.   NOTE: the "xflow" parameter is supposed to be the currently selected
  6287.   type of flow control, but for historical reasons, this parameter is also
  6288.   used to indicate that we are dialing.  Therefore, when the true flow
  6289.   control setting is needed, we access the external variable "flow", rather
  6290.   than trusting our "xflow" argument.
  6291. */
  6292. int
  6293. #ifdef CK_ANSIC
  6294. ttpkt(long speed, int xflow, int parity)
  6295. #else
  6296. ttpkt(speed,xflow,parity) long speed; int xflow, parity;
  6297. #endif /* CK_ANSIC */
  6298. /* ttpkt */ {
  6299. #ifndef NOLOCAL
  6300.     int s2;
  6301.     int s = -1;
  6302. #endif /* NOLOCAL */
  6303.     int x;
  6304.     extern int flow;            /* REAL flow-control setting */
  6305.  
  6306.     if (ttyfd < 0) return(-1);          /* Not open. */
  6307.  
  6308.     debug(F101,"ttpkt parity","",parity);
  6309.     debug(F101,"ttpkt xflow","",xflow);
  6310.     debug(F101,"ttpkt speed","",(int) speed);
  6311.  
  6312.     ttprty = parity;                    /* Let other tt functions see these. */
  6313.     ttspeed = speed;            /* Make global copy for this module */
  6314.     ttpmsk = ttprty ? 0177 : 0377;    /* Parity stripping mask */
  6315. #ifdef PARSENSE
  6316.     needpchk = ttprty ? 0 : 1;        /* Parity check needed? */
  6317. #else
  6318.     needpchk = 0;
  6319. #endif /* PARSENSE */
  6320.  
  6321.     debug(F101,"ttpkt ttpmsk","",ttpmsk);
  6322.     debug(F101,"ttpkt netconn","",netconn);
  6323.  
  6324. #ifdef NETCONN                /* No mode-changing for telnet */
  6325.     if (netconn) {
  6326. #ifdef TCPSOCKET
  6327. #ifdef TCP_NODELAY
  6328.         if (ttnet == NET_TCPB) {    /* But turn off Nagle */
  6329.             extern int tcp_nodelay;
  6330.             nodelay_sav = tcp_nodelay;
  6331.             no_delay(ttyfd,1);
  6332.         }
  6333. #endif /* TCP_NODELAY */
  6334. #ifdef TN_COMPORT
  6335.         if (istncomport()) {
  6336.             int rc = -1;
  6337.             if (tvtflg == 0 && speed == ttspeed && flow == ttflow
  6338.                  /* && ttcarr == curcarr */ ) {
  6339.                 debug(F100,"ttpkt modes already set, skipping...","",0);
  6340.                 return(0);        /* Already been called. */
  6341.             }
  6342.             if (flow != ttflow) {
  6343.                 if ((rc = tnsetflow(flow)) < 0)
  6344.           return(rc);
  6345.                 ttflow = flow;
  6346.             }
  6347.             if (speed != ttspeed) {
  6348.                 if (speed <= 0) 
  6349.           speed = tnc_get_baud();
  6350.                 else if ((rc = tnc_set_baud(speed)) < 0)
  6351.           return(rc);
  6352.                 ttspeed = speed;
  6353.             }
  6354.             tnc_set_datasize(8);
  6355.         tnc_set_stopsize(stopbits);
  6356.  
  6357. #ifdef HWPARITY
  6358.             if (hwparity) {
  6359.                 switch (hwparity) {
  6360.           case 'e':            /* Even */
  6361.                     debug(F100,"ttres 8 bits + even parity","",0);
  6362.                     tnc_set_parity(3);
  6363.                     break;
  6364.           case 'o':            /* Odd */
  6365.                     debug(F100,"ttres 8 bits + odd parity","",0);
  6366.                     tnc_set_parity(2);
  6367.                     break;
  6368.           case 'm':            /* Mark */
  6369.                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
  6370.                     tnc_set_parity(4);
  6371.                     break;
  6372.           case 's':            /* Space */
  6373.                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
  6374.                     tnc_set_parity(5);
  6375.                     break;
  6376.                 }
  6377.             } else 
  6378. #endif /* HWPARITY */
  6379.         {
  6380.                 tnc_set_parity(1);              /* None */
  6381.             }
  6382.             tvtflg = 0;
  6383.             return(0);
  6384.         }
  6385. #endif /* TN_COMPORT */
  6386. #endif /* TCPSOCKET */
  6387.         tvtflg = 0;
  6388.         return(0);
  6389.     }
  6390. #endif /* NETCONN */
  6391. #ifdef NETCMD
  6392.     if (ttpipe) return(0);
  6393. #endif /* NETCMD */
  6394. #ifdef NETPTY
  6395.     if (ttpty) return(0);
  6396. #endif /* NETPTY */
  6397.  
  6398. #ifndef Plan9
  6399.     if (ttfdflg && !isatty(ttyfd)) return(0);
  6400. #endif /* Plan9 */
  6401.  
  6402. #ifdef COHERENT
  6403. #define SVORPOSIX
  6404. #endif /* COHERENT */
  6405.  
  6406. #ifndef SVORPOSIX            /* Berkeley, V7, etc. */
  6407. #ifdef LPASS8
  6408. /*
  6409.  For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
  6410.  after having previously set it to NONE without closing and reopening the
  6411.  device.  Unless there's something I overlooked below...
  6412. */
  6413.     if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
  6414.     debug(F101,"ttpkt executing horrible flow kludge","",0);
  6415.     ttclos(0);            /* Close it */
  6416.     x = 0;
  6417.     ttopen(ttnmsv,&x,ttmdm,0);    /* Open it again */
  6418.     }
  6419. #endif /* LPASS8 */
  6420. #endif /* SVORPOSIX */
  6421.  
  6422. #ifdef COHERENT                /* This must be vestigial since we */
  6423. #undef SVORPOSIX            /* reverse it a few lines below... */
  6424. #endif /* COHERENT */
  6425.  
  6426.     if (xflow != FLO_DIAL && xflow != FLO_DIAX)
  6427.       ttflow = xflow;            /* Now make this available too. */
  6428.  
  6429. #ifndef NOLOCAL
  6430.     if (xlocal) {
  6431.     s2 = (int) (speed / 10L);    /* Convert bps to cps */
  6432.     debug(F101,"ttpkt calling ttsspd","",s2);
  6433.     s = ttsspd(s2);            /* Check and set the speed */
  6434.     debug(F101,"ttpkt ttsspd result","",s);
  6435.      carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
  6436.         && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
  6437.     tvtflg = 0;            /* So ttvt() will work next time */
  6438.     }
  6439. #endif /* NOLOCAL */
  6440.  
  6441. #ifdef COHERENT
  6442. #define SVORPOSIX
  6443. #endif /* COHERENT */
  6444.  
  6445. #ifndef SVORPOSIX            /* BSD section */
  6446.     if (flow == FLO_RTSC ||        /* Hardware flow control */
  6447.     flow == FLO_DTRC ||
  6448.     flow == FLO_DTRT) {
  6449.     tthflow(flow, 1, &ttraw);
  6450.     debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
  6451.     ttraw.sg_flags &= ~TANDEM;    /* Turn off software flow control */
  6452.     ttraw.sg_flags |= RAW;        /* Enter raw mode */
  6453.     } else if (flow == FLO_NONE) {    /* No flow control */
  6454.     debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
  6455.     ttraw.sg_flags &= ~TANDEM;    /* Turn off software flow control */
  6456.     tthflow(flow, 0, &ttraw);    /* Turn off any hardware f/c too */
  6457.     ttraw.sg_flags |= RAW;        /* Enter raw mode */
  6458.     } else if (flow == FLO_KEEP) {    /* Keep device's original setting */
  6459.     debug(F100,"ttpkt keeping original TANDEM","",0);
  6460.     ttraw.sg_flags &= ~TANDEM;
  6461.     ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
  6462.     /* NOTE: We should also handle hardware flow control here! */
  6463.     }
  6464.  
  6465. /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
  6466.  
  6467.     if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
  6468.     debug(F100,"ttpkt turning on TANDEM","",0);
  6469.     ttraw.sg_flags |= TANDEM;    /* So ask for it. */
  6470.  
  6471. #ifdef LPASS8                /* Can pass 8-bit data through? */
  6472. /* If the LPASS8 local mode is available, then flow control can always  */
  6473. /* be used, even if parity is none and we are transferring 8-bit data.  */
  6474. /* But we only need to do all this if Xon/Xoff is requested. */
  6475. /* BUT... this tends not to work through IP or LAT connections, terminal */
  6476. /* servers, telnet, rlogin, etc, so it is currently disabled. */
  6477.     x = LPASS8;            /* If LPASS8 defined, then */
  6478.     debug(F100,"ttpkt executing LPASS8 code","",0);
  6479.     if (lmodef) {            /* TIOCLBIS must be too. */
  6480.         x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
  6481.         if (x < 0) {
  6482.         debug(F100,"ttpkt TIOCLBIS error","",0);
  6483.         } else {
  6484.         lmodef++;
  6485.         debug(F100,"ttpkt TIOCLBIS ok","",0);
  6486.         }
  6487.     }
  6488. /*
  6489.  But if we use LPASS8 mode, we must explicitly turn off
  6490.  terminal interrupts of all kinds.
  6491. */
  6492. #ifdef TIOCGETC                /* Not rawmode, */
  6493.     if (tcharf && (xlocal == 0)) {    /* must turn off */
  6494.         tchnoi.t_intrc = -1;    /* interrupt character */
  6495.         tchnoi.t_quitc = -1;    /* and quit character. */
  6496.         tchnoi.t_startc = 17;    /* Make sure xon */
  6497.         tchnoi.t_stopc = 19;    /* and xoff not ignored. */
  6498. #ifndef NOBRKC
  6499.         tchnoi.t_eofc = -1;        /* eof character. */
  6500.         tchnoi.t_brkc = -1;        /* brk character. */
  6501. #endif /* NOBRKC */
  6502.         if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
  6503.         debug(F100,"ttpkt TIOCSETC failed","",0);
  6504.         } else {
  6505.         tcharf = 1;
  6506.         debug(F100,"ttpkt TIOCSETC ok","",0);
  6507.         }
  6508. #ifdef COMMENT
  6509. /* only for paranoid debugging */
  6510.         if (tcharf) {
  6511.         struct tchars foo;
  6512.         char tchbuf[100];
  6513.         ioctl(0,TIOCGETC,&foo);
  6514.         sprintf(tchbuf,
  6515.             "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
  6516.             foo.t_intrc, foo.t_quitc, foo.t_startc,
  6517.             foo.t_stopc, foo.t_eofc,  foo.t_brkc);
  6518.         debug(F110,"ttpkt chars",tchbuf,0);
  6519.         }
  6520. #endif /* COMMENT */
  6521.     }
  6522.     ttraw.sg_flags |= CBREAK;    /* Needed for unknown reason */
  6523. #endif /* TIOCGETC */
  6524.  
  6525. /* Prevent suspend during packet mode */
  6526. #ifdef TIOCGLTC                /* Not rawmode, */
  6527.     if (ltcharf && (xlocal == 0)) {    /* must turn off */
  6528.         ltchnoi.t_suspc = -1;    /* suspend character */
  6529.         ltchnoi.t_dsuspc = -1;    /* and delayed suspend character */
  6530.         if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
  6531.         debug(F100,"ttpkt TIOCSLTC failed","",0);
  6532.         } else {
  6533.         ltcharf = 1;
  6534.         debug(F100,"ttpkt TIOCSLTC ok","",0);
  6535.         }
  6536.     }
  6537. #endif /* TIOCGLTC */
  6538.  
  6539. #else /* LPASS8 not defined */
  6540.  
  6541. /* Previously, BSD-based implementations always */
  6542. /* used rawmode for packets.  Now, we use rawmode only if parity is NONE. */
  6543. /* This allows the flow control requested above to actually work, but only */
  6544. /* if the user asks for parity (which also means they get 8th-bit quoting). */
  6545.  
  6546.     if (parity) {            /* If parity, */
  6547.         ttraw.sg_flags &= ~RAW;    /* use cooked mode */
  6548. #ifdef COMMENT
  6549. /* WHY??? */
  6550.         if (xlocal)
  6551. #endif /* COMMENT */
  6552.           ttraw.sg_flags |= CBREAK;
  6553.         debug(F101,"ttpkt cooked, cbreak, parity","",parity);
  6554. #ifdef TIOCGETC                /* Not rawmode, */
  6555.         if (tcharf && (xlocal == 0)) { /* must turn off */
  6556.         tchnoi.t_intrc = -1;    /* interrupt character */
  6557.         tchnoi.t_quitc = -1;    /* and quit character. */
  6558.         tchnoi.t_startc = 17;    /* Make sure xon */
  6559.         tchnoi.t_stopc = 19;    /* and xoff not ignored. */
  6560. #ifndef NOBRKC
  6561.         tchnoi.t_eofc = -1;    /* eof character. */
  6562.         tchnoi.t_brkc = -1;    /* brk character. */
  6563. #endif /* NOBRKC */
  6564.         if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
  6565.             debug(F100,"ttpkt TIOCSETC failed","",0);
  6566.         } else {
  6567.             tcharf = 1;
  6568.             debug(F100,"ttpkt TIOCSETC ok","",0);
  6569.         }
  6570.         }
  6571. #endif /* TIOCGETC */
  6572. #ifdef TIOCGLTC                /* Not rawmode, */
  6573. /* Prevent suspend during packet mode */
  6574.         if (ltcharf && (xlocal == 0)) { /* must turn off */
  6575.         ltchnoi.t_suspc = -1;    /* suspend character */
  6576.         ltchnoi.t_dsuspc = -1;    /* and delayed suspend character */
  6577.         if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
  6578.             debug(F100,"ttpkt TIOCSLTC failed","",0);
  6579.         } else {
  6580.             ltcharf = 1;
  6581.             debug(F100,"ttpkt TIOCSLTC ok","",0);
  6582.         }
  6583.         }
  6584. #endif /* TIOCGLTC */
  6585.     } else {            /* If no parity, */
  6586.         ttraw.sg_flags |= RAW;    /* must use 8-bit raw mode. */
  6587.         debug(F101,"ttpkt setting rawmode, parity","",parity);
  6588.     }
  6589. #endif /* LPASS8 */
  6590.     } /* End of Xon/Xoff section */
  6591.  
  6592.     /* Don't echo, don't map CR to CRLF on output, don't fool with case */
  6593. #ifdef LCASE
  6594.     ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
  6595. #else
  6596.     ttraw.sg_flags &= ~(ECHO|CRMOD);
  6597. #endif /* LCASE */
  6598.  
  6599. #ifdef TOWER1
  6600.     ttraw.sg_flags &= ~ANYP;            /* Must set this on old Towers */
  6601. #endif /* TOWER1 */
  6602.  
  6603. #ifdef BELLV10
  6604.     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) /* Set the new modes. */
  6605.       return(-1);
  6606. #else
  6607.     errno = 0;
  6608.     if (stty(ttyfd,&ttraw) < 0) {       /* Set the new modes. */
  6609.         debug(F101,"ttpkt stty failed","",errno);
  6610.         return(-1);
  6611.     }
  6612. #endif /* BELLV10 */
  6613.     debug(F100,"ttpkt stty ok","",0);
  6614.  
  6615. #ifdef sony_news
  6616.     x = xlocal ? km_ext : km_con;    /* Put line in ASCII mode. */
  6617.     if (x != -1) {            /* Make sure we know original modes. */
  6618.     x &= ~KM_TTYPE;
  6619.     x |= KM_ASCII;
  6620.     if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
  6621.         perror("ttpkt can't set ASCII mode");
  6622.         debug(F101,"ttpkt error setting ASCII mode","",x);
  6623.         return(-1);
  6624.     }
  6625.     }
  6626.     debug(F100,"ttpkt set ASCII mode ok","",0);
  6627. #endif /* sony_news */
  6628.  
  6629.     if (xlocal == 0) {            /* Turn this off so we can read */
  6630.     signal(SIGINT,SIG_IGN);        /* Ctrl-C chars typed at console */
  6631.     sigint_ign = 1;
  6632.     }
  6633.     tvtflg = 0;                /* So ttvt() will work next time */
  6634.     debug(F100,"ttpkt success","",0);
  6635.     return(0);
  6636.  
  6637. #endif /* Not ATTSV or POSIX */
  6638.  
  6639. /* AT&T UNIX and POSIX */
  6640.  
  6641. #ifdef COHERENT
  6642. #define SVORPOSIX
  6643. #endif /* COHERENT */
  6644.  
  6645. #ifdef SVORPOSIX
  6646.     if (flow == FLO_XONX) {        /* Xon/Xoff */
  6647.     ttraw.c_iflag |= (IXON|IXOFF);
  6648.     tthflow(flow, 0, &ttraw);
  6649.     } else if (flow == FLO_NONE) {    /* None */
  6650.     /* NOTE: We should also turn off hardware flow control here! */
  6651.     ttraw.c_iflag &= ~(IXON|IXOFF);
  6652.     tthflow(flow, 0, &ttraw);
  6653.     } else if (flow == FLO_KEEP) {    /* Keep */
  6654.     ttraw.c_iflag &= ~(IXON|IXOFF);    /* Turn off Xon/Xoff flags */
  6655.     ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
  6656.     /* NOTE: We should also handle hardware flow control here! */
  6657. #ifdef POSIX_CRTSCTS
  6658. /* In Linux case, we do this, which is unlikely to be portable */
  6659.         ttraw.c_cflag &= ~CRTSCTS;    /* Turn off RTS/CTS flag */
  6660.         ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
  6661. #endif /* POSIX_CRTSCTS */
  6662.     } else if (flow == FLO_RTSC ||    /* Hardware */
  6663.            flow == FLO_DTRC ||
  6664.            flow == FLO_DTRT) {
  6665.     ttraw.c_iflag &= ~(IXON|IXOFF);    /* (190) */
  6666.     tthflow(flow, 1, &ttraw);
  6667.     }
  6668.     ttraw.c_lflag &= ~(ICANON|ECHO);
  6669.     ttraw.c_lflag &= ~ISIG;        /* Do NOT check for interrupt chars */
  6670.  
  6671. #ifndef OXOS
  6672. #ifdef QNX
  6673.     if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
  6674. #endif /* QNX */
  6675. #ifndef COHERENT
  6676.       ttraw.c_lflag &= ~IEXTEN;        /* Turn off ^O/^V processing */
  6677. #endif /* COHERENT */
  6678. #else /* OXOS */
  6679.     ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
  6680. #endif /* OXOS */
  6681.     ttraw.c_lflag |= NOFLSH;        /* Don't flush */
  6682.     ttraw.c_iflag |= IGNPAR;        /* Ignore parity errors */
  6683. #ifdef ATTSV
  6684. #ifdef BSD44
  6685.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
  6686. #else
  6687.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
  6688. #endif /* BSD44 */
  6689. #else /* POSIX */
  6690.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
  6691. #endif /* ATTSV */
  6692.     ttraw.c_oflag &= ~OPOST;
  6693.     ttraw.c_cflag &= ~(CSIZE);
  6694.     ttraw.c_cflag |= (CS8|CREAD|HUPCL);
  6695.  
  6696. #ifdef CSTOPB
  6697.     if (xlocal) {
  6698.     if (stopbits == 2) {
  6699.         ttraw.c_cflag |= CSTOPB;    /* 2 stop bits */
  6700.         debug(F100,"ttpkt 2 stopbits","",0);
  6701.     } else if (stopbits == 1) {
  6702.         ttraw.c_cflag &= ~(CSTOPB);    /* 1 stop bit */
  6703.         debug(F100,"ttpkt 1 stopbit","",0);
  6704.     }
  6705.     }
  6706. #endif /* CSTOPB */
  6707.  
  6708. #ifdef HWPARITY
  6709.     if (hwparity && xlocal) {        /* Hardware parity */
  6710.     ttraw.c_cflag |= PARENB;    /* Enable parity */
  6711. #ifdef COMMENT
  6712. /* Uncomment this only if needed -- I don't think it is */
  6713.     ttraw.c_cflag &= ~(CSIZE);    /* Clear out character-size mask */
  6714.     ttraw.c_cflag |= CS8;        /* And set it to 8 */
  6715. #endif /* COMMENT */
  6716. #ifdef IGNPAR
  6717.     ttraw.c_iflag |= IGNPAR;    /* Don't discard incoming bytes */
  6718.     debug(F100,"ttpkt IGNPAR","",0); /* that have parity errors */
  6719. #endif /* IGNPAR */
  6720.     switch (hwparity) {
  6721.       case 'e':            /* Even */
  6722.         ttraw.c_cflag &= ~(PARODD);
  6723.         debug(F100,"ttpkt 8 bits + even parity","",0);
  6724.         break;
  6725.       case 'o':            /* Odd */
  6726.         ttraw.c_cflag |= PARODD;
  6727.         debug(F100,"ttpkt 8 bits + odd parity","",0);
  6728.         break;
  6729.       case 'm':            /* Mark */
  6730.       case 's':            /* Space */
  6731.         /* PAREXT is mentioned in SVID but the details are not given. */
  6732.         /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
  6733.         debug(F100,"ttpkt 8 bits + invalid parity","",0);
  6734.         break;
  6735.     }
  6736.     } else {                /* We handle parity ourselves */
  6737. #endif /* HWPARITY */
  6738.     ttraw.c_cflag &= ~(PARENB);    /* Don't enable parity */
  6739. #ifdef HWPARITY
  6740.     }
  6741. #endif /* HWPARITY */
  6742.  
  6743. #ifdef IX370
  6744.     ttraw.c_cc[4] = 48;  /* So Series/1 doesn't interrupt on every char */
  6745.     ttraw.c_cc[5] = 1;
  6746. #else
  6747. #ifndef VEOF                /* for DGUX this is VEOF, not VMIN */
  6748.     ttraw.c_cc[4] = 1;   /* [VMIN]  return max of this many characters or */
  6749. #else
  6750. #ifndef OXOS
  6751. #ifdef VMIN
  6752.     ttraw.c_cc[VMIN] = 1;
  6753. #endif /* VMIN */
  6754. #else /* OXOS */
  6755.     ttraw.c_min = 1;
  6756. #endif /* OXOS */
  6757. #endif /* VEOF */
  6758. #ifndef VEOL                /* for DGUX this is VEOL, not VTIME */
  6759.     ttraw.c_cc[5] = 0;     /* [VTIME] when this many secs/10 expire w/no input */
  6760. #else
  6761. #ifndef OXOS
  6762. #ifdef VTIME
  6763.     ttraw.c_cc[VTIME] = 0;
  6764. #endif /* VTIME */
  6765. #else /* OXOS */
  6766.     ttraw.c_time = 0;
  6767. #endif /* OXOS */
  6768. #endif /* VEOL */
  6769. #endif /* IX370 */
  6770.  
  6771. #ifdef VINTR                /* Turn off interrupt character */
  6772.     if (xlocal == 0)            /* so ^C^C can break us out of */
  6773.       ttraw.c_cc[VINTR] = 0;        /* packet mode. */
  6774. #endif /* VINTR */
  6775.  
  6776. #ifdef Plan9
  6777.     if (p9ttyparity('n') < 0)
  6778.     return -1;
  6779. #else
  6780. #ifdef BSD44ORPOSIX
  6781.     errno = 0;
  6782. #ifdef BEOSORBEBOX
  6783.     ttraw.c_cc[VMIN] = 0;        /* DR7 can only poll. */
  6784. #endif /* BEOSORBEBOX */
  6785.  
  6786. #define TESTING234
  6787. #ifdef TESTING234
  6788.     if (1) {
  6789.     debug(F100,"ttpkt TESTING234 rawmode","",0);
  6790.  
  6791.     /* iflags */
  6792.     ttraw.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
  6793.     ttraw.c_iflag &= ~(INPCK|IGNPAR|IXON|IXOFF);
  6794.     ttraw.c_iflag |= IGNBRK;
  6795. #ifdef IMAXBEL
  6796.     ttraw.c_iflag &= ~IMAXBEL;
  6797. #endif    /* IMAXBEL */
  6798. #ifdef IXANY
  6799.     ttraw.c_iflag &= ~IXANY;
  6800. #endif    /* IXANY */
  6801. #ifdef IUCLC
  6802.     ttraw.c_iflag &= ~IUCLC;
  6803. #endif /* IUCLC */
  6804.  
  6805.     /* oflags */
  6806.     ttraw.c_oflag &= ~OPOST;
  6807. #ifdef OXTABS
  6808.     ttraw.c_oflag &= ~OXTABS;
  6809. #endif /* OXTABS */
  6810. #ifdef ONOCR
  6811.     ttraw.c_oflag &= ~ONOCR;
  6812. #endif /* ONOCR */
  6813. #ifdef ONLRET
  6814.     ttraw.c_oflag &= ~ONLRET;
  6815. #endif /* ONLRET */
  6816. #ifdef ONLCR
  6817.     ttraw.c_oflag &= ~ONLCR;
  6818. #endif /* ONLCR */
  6819.  
  6820.     /* lflags */
  6821.     ttraw.c_lflag &= ~ECHO;
  6822. #ifdef ECHOE
  6823.     ttraw.c_lflag &= ~ECHOE;
  6824. #endif /* ECHOE */
  6825. #ifdef ECHONL
  6826.     ttraw.c_lflag &= ~ECHONL;
  6827. #endif /* ECHONL */
  6828. #ifdef ECHOPRT
  6829.     ttraw.c_lflag &= ~ECHOPRT;
  6830. #endif /* ECHOPRT */
  6831. #ifdef ECHOKE
  6832.     ttraw.c_lflag &= ~ECHOKE;
  6833. #endif /* ECHOKE */
  6834. #ifdef ECHOCTL
  6835.     ttraw.c_lflag &= ~ECHOCTL;
  6836. #endif /* ECHOCTL */
  6837. #ifdef ALTWERASE
  6838.     ttraw.c_lflag &= ~ALTWERASE;
  6839. #endif /* ALTWERASE */
  6840. #ifdef EXTPROC
  6841.     ttraw.c_lflag &= ~EXTPROC;
  6842. #endif /* EXTPROC */
  6843.     ttraw.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
  6844. #ifdef NOKERNINFO
  6845.     ttraw.c_lflag |= NOKERNINFO;
  6846. #endif    /* NOKERNINFO */
  6847.     /* ttraw.c_lflag |= NOFLSH; */
  6848.     ttraw.c_lflag &= ~NOFLSH;
  6849.  
  6850.     /* cflags */
  6851.     ttraw.c_cflag &= ~(CSIZE|PARENB|PARODD);
  6852.     ttraw.c_cflag |= CS8|CREAD;
  6853. #ifdef VMIN
  6854.     ttraw.c_cc[VMIN] = 1;        /* Supposedly needed for AIX */
  6855. #endif    /* VMIN */
  6856.  
  6857.     }
  6858. #endif /* TESTING234 */
  6859.  
  6860.     debug(F100,"ttpkt calling tcsetattr(TCSETAW)","",0);
  6861.     x = tcsetattr(ttyfd,TCSADRAIN,&ttraw);
  6862.     debug(F101,"ttpkt BSD44ORPOSIX tcsetattr","",x);
  6863.     if (x < 0) {
  6864.     debug(F101,"ttpkt BSD44ORPOSIX tcsetattr errno","",errno);
  6865.         return(-1);
  6866.     }
  6867. #else /* BSD44ORPOSIX */
  6868.     x = ioctl(ttyfd,TCSETAW,&ttraw);
  6869.     debug(F101,"ttpkt ATTSV ioctl TCSETAW","",x);
  6870.     if (x < 0) {  /* set new modes . */
  6871.     debug(F101,"ttpkt ATTSV ioctl TCSETAW errno","",errno);
  6872.         return(-1);
  6873.     }
  6874. #endif /* BSD44ORPOSIX */
  6875. #endif /* Plan9 */
  6876.     tvtflg = 0;
  6877.     debug(F100,"ttpkt ok","",0);
  6878.     return(0);
  6879. #endif /* ATTSV */
  6880.  
  6881. #ifdef COHERENT
  6882. #undef SVORPOSIX
  6883. #endif /* COHERENT */
  6884.  
  6885. }
  6886.  
  6887. /*  T T S E T F L O W  --  Set flow control immediately.  */
  6888.  
  6889. #ifdef COHERENT
  6890. #define SVORPOSIX
  6891. #endif /* COHERENT */
  6892.  
  6893. int
  6894. ttsetflow(flow) int flow; {
  6895.     if (ttyfd < 0)            /* A channel must be open */
  6896.       return(-1);
  6897.  
  6898.     debug(F101,"ttsetflow flow","",flow);
  6899.  
  6900. #ifdef TN_COMPORT
  6901.     if (netconn && istncomport()) {
  6902.     debug(F101,"ttsetflow net modem","",ttmdm);
  6903.     return(tnsetflow(flow));
  6904.     }
  6905. #endif /* TN_COMPORT */
  6906. #ifdef NETCMD
  6907.     if (ttpipe) return(0);
  6908. #endif /* NETCMD */
  6909. #ifdef NETPTY
  6910.     if (ttpty) return(0);
  6911. #endif /* NETPTY */
  6912.  
  6913. #ifdef COMMENT
  6914.     /* This seems to hurt... */
  6915.     if (flow == FLO_KEEP)
  6916.       return(0);
  6917. #endif /* COMMENT */
  6918.  
  6919.     if (flow == FLO_RTSC ||        /* Hardware flow control... */
  6920.     flow == FLO_DTRC ||
  6921.     flow == FLO_DTRT) {
  6922.     tthflow(flow, 1, &ttraw);
  6923. #ifndef SVORPOSIX
  6924.     ttraw.sg_flags &= ~TANDEM;    /* Turn off software flow control */
  6925. #else
  6926.     ttraw.c_iflag &= ~(IXON|IXOFF);
  6927. #endif /* SVORPOSIX */
  6928.  
  6929.     } else if (flow == FLO_XONX) {    /* Xon/Xoff... */
  6930.  
  6931. #ifndef SVORPOSIX
  6932.     ttraw.sg_flags |= TANDEM;
  6933. #else
  6934.     ttraw.c_iflag |= (IXON|IXOFF);
  6935. #endif /* SVORPOSIX */
  6936.     tthflow(FLO_RTSC, 0, &ttraw);    /* Turn off hardware flow control */
  6937.  
  6938.     } else if (flow == FLO_NONE) {    /* No flow control */
  6939.  
  6940. #ifndef SVORPOSIX
  6941.     ttraw.sg_flags &= ~TANDEM;    /* Turn off software flow control */
  6942. #else
  6943.     ttraw.c_iflag &= ~(IXON|IXOFF);
  6944. #endif /* SVORPOSIX */
  6945.     tthflow(FLO_RTSC, 0, &ttraw);    /* Turn off any hardware f/c too */
  6946.     }
  6947.  
  6948. /* Set the new modes... */
  6949.  
  6950. #ifndef SVORPOSIX            /* BSD and friends */
  6951. #ifdef BELLV10
  6952.     if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
  6953.       return(-1);
  6954. #else
  6955. #ifndef MINIX2
  6956.     if (stty(ttyfd,&ttraw) < 0)
  6957.       return(-1);
  6958. #endif /* MINIX2 */
  6959. #endif /* BELLV10 */
  6960. #else
  6961. #ifdef BSD44ORPOSIX            /* POSIX */
  6962.     if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
  6963.       return(-1);
  6964. #else                    /* System V */
  6965.     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
  6966.       return(-1);
  6967. #endif /* BSD44ORPOSIX */
  6968. #endif /* SVORPOSIX */
  6969.     return(0);
  6970. }
  6971. #ifdef COHERENT
  6972. #undef SVORPOSIX
  6973. #endif /* COHERENT */
  6974.  
  6975. /*  T T V T -- Condition communication device for use as virtual terminal. */
  6976.  
  6977. int
  6978. #ifdef CK_ANSIC
  6979. ttvt(long speed, int flow)
  6980. #else
  6981. ttvt(speed,flow) long speed; int flow;
  6982. #endif /* CK_ANSIC */
  6983. /* ttvt */ {
  6984.     int s, s2, x;
  6985.  
  6986.     debug(F101,"ttvt ttyfd","",ttyfd);
  6987.     debug(F101,"ttvt tvtflg","",tvtflg);
  6988.     debug(F111,"ttvt speed",ckitoa(ttspeed),speed);
  6989.     debug(F111,"ttvt flow",ckitoa(ttflow),flow);
  6990.     debug(F111,"ttvt curcarr",ckitoa(ttcarr),curcarr);
  6991.  
  6992. /* Note: NetBSD and maybe other BSD44s have cfmakeraw() */
  6993. /* Maybe it would be simpler to use it... */
  6994.  
  6995.     ttpmsk = 0xff;
  6996. #ifdef NOLOCAL
  6997.     return(conbin((char)escchr));
  6998. #else
  6999.     if (ttyfd < 0) {            /* Not open. */
  7000.     if (ttchk() < 0)
  7001.       return(-1);
  7002.     else                /* But maybe something buffered. */
  7003.       return(0);
  7004.     }
  7005. #ifdef NETCMD
  7006.     if (ttpipe) return(0);
  7007. #endif /* NETCMD */
  7008. #ifdef NETPTY
  7009.     if (ttpty) return(0);
  7010. #endif /* NETPTY */
  7011. #ifdef NETCONN
  7012.     if (netconn) {
  7013. #ifdef TCPSOCKET
  7014. #ifdef TCP_NODELAY
  7015.         {
  7016.         extern int tcp_nodelay;
  7017.         if (ttnet == NET_TCPB) {
  7018.         if (nodelay_sav > -1) {
  7019.             no_delay(ttyfd,nodelay_sav);
  7020.             nodelay_sav = -1;
  7021.         }
  7022.         }
  7023.         }
  7024. #endif /* TCP_NODELAY */
  7025. #ifdef TN_COMPORT
  7026.         if (istncomport()) {
  7027.             int rc = -1;
  7028.             if (tvtflg != 0 && speed == ttspeed && flow == ttflow
  7029.                  /* && ttcarr == curcarr */ ) {
  7030.                 debug(F100,"ttvt modes already set, skipping...","",0);
  7031.                 return(0);            /* Already been called. */
  7032.             }
  7033.             if (flow != ttflow) {
  7034.                 if ((rc = tnsetflow(flow)) < 0)
  7035.           return(rc);
  7036.                 ttflow = flow;
  7037.             }
  7038.             if (speed != ttspeed) {
  7039.                 if (speed <= 0) 
  7040.           speed = tnc_get_baud();
  7041.                 else if ((rc = tnc_set_baud(speed)) < 0)
  7042.           return(rc);
  7043.                 ttspeed = speed;
  7044.             }
  7045.             tnc_set_datasize(8);
  7046.         tnc_set_stopsize(stopbits);
  7047.  
  7048. #ifdef HWPARITY
  7049.             if (hwparity) {
  7050.                 switch (hwparity) {
  7051.           case 'e':        /* Even */
  7052.                     debug(F100,"ttres 8 bits + even parity","",0);
  7053.                     tnc_set_parity(3);
  7054.                     break;
  7055.           case 'o':        /* Odd */
  7056.                     debug(F100,"ttres 8 bits + odd parity","",0);
  7057.                     tnc_set_parity(2);
  7058.                     break;
  7059.           case 'm':        /* Mark */
  7060.                     debug(F100,"ttres 8 bits + invalid parity: mark","",0);
  7061.                     tnc_set_parity(4);
  7062.                     break;
  7063.           case 's':        /* Space */
  7064.                     debug(F100,"ttres 8 bits + invalid parity: space","",0);
  7065.                     tnc_set_parity(5);
  7066.                     break;
  7067.                 }
  7068.             } else
  7069. #endif /* HWPARITY */
  7070.             {
  7071.                 tnc_set_parity(1);    /* None */
  7072.             }
  7073.             tvtflg = 1;
  7074.             return(0);
  7075.         }
  7076. #endif /* TN_COMPORT */
  7077. #endif /* TCPSOCKET */
  7078.     tvtflg = 1;            /* Network connections... */
  7079.     debug(F100,"ttvt network connection, skipping...","",0);
  7080.     return(0);            /* ... require no special setup */
  7081.     }
  7082. #endif /* NETCONN */
  7083.  
  7084.     if (tvtflg != 0 && speed == ttspeed && flow == ttflow
  7085.     /* && ttcarr == curcarr */ )
  7086.       {
  7087.       debug(F100,"ttvt modes already set, skipping...","",0);
  7088.       return(0);            /* Already been called. */
  7089.       }
  7090.  
  7091.     if (ttfdflg
  7092. #ifndef Plan9
  7093.     && !isatty(ttyfd)
  7094. #endif /* Plan9 */
  7095.     ) {
  7096.     debug(F100,"ttvt using external fd, skipping...","",0);
  7097.     return(0);
  7098.     }
  7099.  
  7100.     debug(F100,"ttvt setting modes...","",0);
  7101.  
  7102.     if (xlocal) {            /* For external lines... */
  7103.     s2 = (int) (speed / 10L);
  7104.     s = ttsspd(s2);            /* Check/set the speed */
  7105.     carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
  7106.         && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
  7107.     } else
  7108.       s = s2 = -1;
  7109.  
  7110. #ifdef COHERENT
  7111. #define SVORPOSIX
  7112. #endif /* COHERENT */
  7113.  
  7114. #ifndef SVORPOSIX
  7115.     /* Berkeley, V7, etc */
  7116.     if (flow == FLO_RTSC ||        /* Hardware flow control */
  7117.     flow == FLO_DTRC ||
  7118.     flow == FLO_DTRT) {
  7119.     tthflow(flow, 1, &tttvt);
  7120.     debug(F100,"ttvt hard flow, TANDEM off","",0);
  7121.     tttvt.sg_flags &= ~TANDEM;    /* Turn off software flow control */
  7122.     } else if (flow == FLO_XONX) {    /* Xon/Xoff flow control */
  7123.     debug(F100,"ttvt TANDEM on","",0);
  7124.     tttvt.sg_flags |= TANDEM;    /* Ask for it. */
  7125.     tthflow(flow, 0, &tttvt);    /* Turn off hardware f/c */
  7126.     } else if (flow == FLO_NONE) {
  7127.     debug(F100,"ttvt no flow, TANDEM off, RAW on","",0);
  7128.     tttvt.sg_flags &= ~TANDEM;    /* Turn off software flow control */
  7129.     tthflow(flow, 0, &tttvt);    /* Turn off any hardware f/c too */
  7130.     tttvt.sg_flags |= RAW;        /* Enter raw mode */
  7131.     } else if (flow == FLO_KEEP) {    /* Keep device's original setting */
  7132.     debug(F100,"ttvt keeping original TANDEM","",0);
  7133.     tttvt.sg_flags &= ~TANDEM;
  7134.     tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
  7135.     /* NOTE: We should also handle hardware flow control here! */
  7136.     }
  7137.     tttvt.sg_flags |= RAW;              /* Raw mode in all cases */
  7138. #ifdef TOWER1
  7139.     tttvt.sg_flags &= ~(ECHO|ANYP);     /* No echo or parity */
  7140. #else
  7141.     tttvt.sg_flags &= ~ECHO;            /* No echo */
  7142. #endif /* TOWER1 */
  7143.  
  7144. #ifdef BELLV10
  7145.     if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
  7146.       return(-1);
  7147. #else
  7148.     if (stty(ttyfd,&tttvt) < 0)        /* Set the new modes */
  7149.       return(-1);
  7150. #endif /* BELLV10 */
  7151.  
  7152. #else /* It is ATTSV or POSIX */
  7153.  
  7154.     if (flow == FLO_XONX) {        /* Software flow control */
  7155.     tttvt.c_iflag |= (IXON|IXOFF);    /* On if requested. */
  7156.     tthflow(flow, 0, &tttvt);    /* Turn off hardware f/c */
  7157.     debug(F100,"ttvt SVORPOSIX flow XON/XOFF","",0);
  7158.     } else if (flow == FLO_NONE) {    /* NONE */
  7159.     tttvt.c_iflag &= ~(IXON|IXOFF);    /* Turn off Xon/Xoff */
  7160.     tthflow(flow, 0, &tttvt);    /* Turn off hardware f/c */
  7161.     debug(F100,"ttvt SVORPOSIX flow NONE","",0);
  7162.     } else if (flow == FLO_KEEP) {
  7163.     tttvt.c_iflag &= ~(IXON|IXOFF);    /* Turn off Xon/Xoff flags */
  7164.     tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
  7165. #ifdef POSIX_CRTSCTS
  7166.         tttvt.c_cflag &= ~CRTSCTS;    /* Turn off RTS/CTS flag */
  7167.         tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
  7168. #endif /* POSIX_CRTSCTS */
  7169.     debug(F100,"ttvt SVORPOSIX flow KEEP","",0);
  7170.     } else if (flow == FLO_RTSC ||    /* Hardware flow control */
  7171.            flow == FLO_DTRC ||
  7172.            flow == FLO_DTRT) {
  7173.     tttvt.c_iflag &= ~(IXON|IXOFF);    /* (196) */
  7174.     tthflow(flow, 1, &tttvt);
  7175.     debug(F100,"ttvt SVORPOSIX flow HARD","",0);
  7176.     }
  7177. #ifndef OXOS
  7178. #ifdef COHERENT
  7179.     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
  7180. #else
  7181.     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
  7182. #endif /* COHERENT */
  7183. #ifdef QNX
  7184.     /* Needed for hwfc */
  7185.     if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
  7186.       tttvt.c_lflag |= IEXTEN;
  7187. #endif /* QNX */
  7188. #else /* OXOS */
  7189.     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
  7190.     tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
  7191. #endif /* OXOS */
  7192.  
  7193.     tttvt.c_iflag |= (IGNBRK|IGNPAR);
  7194.  
  7195. /* Stop bits */
  7196.  
  7197. #ifdef CSTOPB
  7198.     if (xlocal) {
  7199.     if (stopbits == 2) {
  7200.         tttvt.c_cflag |= CSTOPB;    /* 2 stop bits */
  7201.         debug(F100,"ttvt 2 stopbits","",0);
  7202.     } else if (stopbits == 1) {
  7203.         tttvt.c_cflag &= ~(CSTOPB);    /* 1 stop bit */
  7204.         debug(F100,"ttvt 1 stopbit","",0);
  7205.     }
  7206.     }
  7207. #endif /* CSTOPB */
  7208.  
  7209. /* Parity */
  7210.  
  7211. #ifdef HWPARITY
  7212.     if (hwparity && xlocal) {        /* Hardware parity */
  7213. #ifdef COMMENT
  7214. /* Uncomment this only if needed -- I don't think it is */
  7215.     ttraw.c_cflag &= ~(CSIZE);    /* Clear out character-size mask */
  7216.     ttraw.c_cflag |= CS8;        /* And set it to 8 */
  7217. #endif /* COMMENT */
  7218. #ifdef IGNPAR
  7219.     debug(F101,"ttvt hwparity IGNPAR","",IGNPAR);
  7220.     tttvt.c_iflag |= IGNPAR;    /* Don't discard incoming bytes */
  7221. #endif /* IGNPAR */
  7222.     tttvt.c_cflag |= PARENB;    /* Enable parity */
  7223.  
  7224.     switch (hwparity) {
  7225.       case 'e':            /* Even */
  7226.         tttvt.c_cflag &= ~(PARODD);
  7227.         debug(F100,"ttvt 8 bits + even parity","",0);
  7228.         break;
  7229.       case 'o':            /* Odd */
  7230.         tttvt.c_cflag |= PARODD;
  7231.         debug(F100,"ttvt 8 bits + odd parity","",0);
  7232.         break;
  7233.       case 'm':            /* Mark */
  7234.       case 's':            /* Space */
  7235.         /* PAREXT is mentioned in SVID but the details are not given. */
  7236.         /* PAREXT is not included in POSIX ISO/IEC 9945-1. */
  7237.         debug(F100,"ttvt 8 bits + invalid parity","",0);
  7238.         break;
  7239.     }
  7240.     } else {                /* We handle parity ourselves */
  7241. #endif /* HWPARITY */
  7242.     tttvt.c_cflag &= ~(PARENB);    /* Don't enable parity */
  7243. #ifdef HWPARITY
  7244.     }
  7245. #endif /* HWPARITY */
  7246.  
  7247. #ifdef ATTSV
  7248. #ifdef BSD44
  7249.     /* Things not to do... */
  7250.     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
  7251. #else
  7252.     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
  7253. #endif /* BSD44 */
  7254. #else /* POSIX */
  7255.     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
  7256. #endif /* ATTSV */
  7257.     tttvt.c_cflag &= ~(CSIZE);        /* Zero out the char size field */
  7258.     tttvt.c_cflag |= (CS8|CREAD|HUPCL);    /* Char size 8, enable receiver, hup */
  7259.     tttvt.c_oflag &= ~OPOST;        /* Don't postprocess output */
  7260. #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
  7261.     tttvt.c_cc[4] = 1;
  7262. #else
  7263. #ifndef OXOS
  7264. #ifdef VMIN
  7265.     tttvt.c_cc[VMIN] = 1;
  7266. #endif /* VMIN */
  7267. #else /* OXOS */
  7268.     tttvt.c_min = 1;
  7269. #endif /* OXOS */
  7270. #endif /* VEOF */
  7271. #ifndef VEOL    /* DGUX termio has VEOL at entry 5, see comment above */
  7272.     tttvt.c_cc[5] = 0;
  7273. #else
  7274. #ifndef OXOS
  7275. #ifdef VTIME
  7276.     tttvt.c_cc[VTIME] = 0;
  7277. #endif /* VTIME */
  7278. #else /* OXOS */
  7279.     tttvt.c_time = 0;
  7280. #endif /* OXOS */
  7281. #endif /* VEOL */
  7282.  
  7283. #ifdef Plan9
  7284.     if (p9ttyparity('n') < 0)
  7285.       return -1;
  7286. #else
  7287. #ifdef BSD44ORPOSIX
  7288.     errno = 0;
  7289. #ifdef BEOSORBEBOX
  7290.     tttvt.c_cc[VMIN] = 0;        /* DR7 can only poll. */
  7291. #endif /* BEOSORBEBOX */
  7292.  
  7293.     x = tcsetattr(ttyfd,TCSADRAIN,&tttvt);
  7294.     debug(F101,"ttvt BSD44ORPOSIX tcsetattr","",x);
  7295.     if (x < 0) {
  7296.     debug(F101,"ttvt BSD44ORPOSIX tcsetattr errno","",errno);
  7297.     return(-1);
  7298.     }
  7299. #else /* ATTSV */
  7300.     x = ioctl(ttyfd,TCSETAW,&tttvt);
  7301.     debug(F101,"ttvt ATTSV ioctl TCSETAW","",x);
  7302.     if (x < 0) {            /* set new modes . */
  7303.     debug(F101,"ttvt ATTSV ioctl TCSETAW errno","",errno);
  7304.     return(-1);    
  7305.     }
  7306. #endif /* BSD44ORPOSIX */
  7307. #endif /* Plan9 */
  7308. #endif /* ATTSV */
  7309.  
  7310.     ttspeed = speed;            /* Done, remember how we were */
  7311.     ttflow = flow;            /* called, so we can decide how to */
  7312.     tvtflg = 1;                /* respond next time. */
  7313.     debug(F100,"ttvt ok","",0);
  7314.     return(0);
  7315.  
  7316. #ifdef COHERENT
  7317. #undef SVORPOSIX
  7318. #endif /* COHERENT */
  7319.  
  7320. #endif /* NOLOCAL */
  7321. }
  7322.  
  7323. #ifndef NOLOCAL
  7324.  
  7325. /* Serial speed department . . . */
  7326.  
  7327. /*
  7328.   SCO OSR5.0.x might or might not support high speeds.  Sometimes they are not
  7329.   defined in the header files but they are supported (e.g. when building with
  7330.   UDK compiler rather than /bin/cc), sometimes vice versa.  Even though 5.0.4
  7331.   was the first release that came with high serial speeds standard, releases
  7332.   back to 5.0.0 could use them if certain patches (or "supplements") were
  7333.   applied to the SIO driver.  Plus a lot of SCO installations run third-party
  7334.   drivers.
  7335. */
  7336. #ifdef CK_SCOV5
  7337. #ifndef B38400
  7338. #define    B38400    0000017
  7339. #endif /* B38400 */
  7340. #ifndef B57600
  7341. #define    B57600    0000021
  7342. #endif /* B57600 */
  7343. #ifndef B76800
  7344. #define    B76800    0000022
  7345. #endif /* B76800 */
  7346. #ifndef B115200
  7347. #define    B115200    0000023
  7348. #endif /* B115200 */
  7349. #ifndef B230400
  7350. #define    B230400    0000024
  7351. #endif /* B230400 */
  7352. #ifndef B460800
  7353. #define    B460800    0000025
  7354. #endif /* B460800 */
  7355. #ifndef B921600
  7356. #define    B921600    0000026
  7357. #endif /* B921600 */
  7358. #endif /* CK_SCOV5 */
  7359. /*
  7360.   Plan 9's native speed setting interface lets you set anything you like,
  7361.   but will fail if the hardware doesn't like it, so we allow all the common
  7362.   speeds.
  7363. */
  7364. #ifdef Plan9
  7365. #ifndef B50
  7366. #define B50 50
  7367. #endif /* B50 */
  7368. #ifndef B75
  7369. #define B75 75
  7370. #endif /* B75 */
  7371. #ifndef B110
  7372. #define B110 110
  7373. #endif /* B110 */
  7374. #ifndef B134
  7375. #define B134 134
  7376. #endif /* B134 */
  7377. #ifndef B200
  7378. #define B200 200
  7379. #endif /* B200 */
  7380. #ifndef B300
  7381. #define B300 300
  7382. #endif /* B300 */
  7383. #ifndef B1200
  7384. #define B1200 1200
  7385. #endif /* B1200 */
  7386. #ifndef B1800
  7387. #define B1800 1800
  7388. #endif /* B1800 */
  7389. #ifndef B2400
  7390. #define B2400 2400
  7391. #endif /* B2400 */
  7392. #ifndef B4800
  7393. #define B4800 4800
  7394. #endif /* B4800 */
  7395. #ifndef B9600
  7396. #define B9600 9600
  7397. #endif /* B9600 */
  7398. #ifndef B14400
  7399. #define B14400 14400
  7400. #endif /* B14400 */
  7401. #ifndef B19200
  7402. #define B19200 19200
  7403. #endif /* B19200 */
  7404. #ifndef B28800
  7405. #define B28800 28800
  7406. #endif /* B28800 */
  7407. #ifndef B38400
  7408. #define B38400 38400
  7409. #endif /* B38400 */
  7410. #ifndef B57600
  7411. #define B57600 57600
  7412. #endif /* B57600 */
  7413. #ifndef B76800
  7414. #define B76800 76800
  7415. #endif /* B76800 */
  7416. #ifndef B115200
  7417. #define B115200 115200
  7418. #endif /* B115200 */
  7419. #ifndef B230400
  7420. #define B230400 230400
  7421. #endif /* B230400 */
  7422. #ifndef B460800
  7423. #define B460800 460800
  7424. #endif /* B460800 */
  7425. #ifndef B921600
  7426. #define B921600 921600
  7427. #endif /* B921600 */
  7428. #endif /* Plan9 */
  7429.  
  7430. /*  T T S S P D  --  Checks and sets transmission rate.  */
  7431.  
  7432. /*  Call with speed in characters (not bits!) per second. */
  7433. /*  Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
  7434.  
  7435. #ifdef USETCSETSPEED
  7436. /*
  7437.   The tcsetspeed() / tcgetspeed() interface lets you pass any number at all
  7438.   to be used as a speed to be set, rather than forcing a choice from a
  7439.   predefined list.  It seems to be peculiar to UnixWare 7.
  7440.  
  7441.   These are the function codes to be passed to tc[gs]etspeed(),
  7442.   but for some reason they don't seem to be picked up from termios.h.
  7443. */
  7444. #ifndef TCS_ALL
  7445. #define TCS_ALL 0
  7446. #endif /* TCS_ALL */
  7447. #ifndef TCS_IN
  7448. #define TCS_IN 1
  7449. #endif /* TCS_IN */
  7450. #ifndef TCS_OUT
  7451. #define TCS_OUT 2
  7452. #endif /* TCS_OUT */
  7453. #endif /* USETCSETSPEED */
  7454.  
  7455. int
  7456. ttsspd(cps) int cps; {
  7457.     int x;
  7458. #ifdef POSIX
  7459. /* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
  7460.     speed_t
  7461. #else
  7462.     int
  7463. #endif /* POSIX */
  7464.       s, s2;
  7465.     int ok = 1;                /* Speed check result, assume ok */
  7466.  
  7467. #ifdef OLINUXHISPEED
  7468.     unsigned int spd_flags = 0;
  7469.     struct serial_struct serinfo;
  7470. #endif /* OLINUXHISPEED */
  7471.  
  7472.     debug(F101,"ttsspd cps","",cps);
  7473.     debug(F101,"ttsspd ttyfd","",ttyfd);
  7474.     debug(F101,"ttsspd xlocal","",xlocal);
  7475.  
  7476.     if (ttyfd < 0 || xlocal == 0)    /* Don't set speed on console */
  7477.       return(0);
  7478.  
  7479. #ifdef    NETCONN
  7480.     if (netconn) {
  7481. #ifdef TN_COMPORT
  7482.         if (istncomport())
  7483.       return(tnc_set_baud(cps * 10));
  7484.         else
  7485. #endif /* TN_COMPORT */
  7486.     return(0);
  7487.   }
  7488. #endif    /* NETCONN */
  7489. #ifdef NETCMD
  7490.     if (ttpipe) return(0);
  7491. #endif /* NETCMD */
  7492. #ifdef NETPTY
  7493.     if (ttpty) return(0);
  7494. #endif /* NETPTY */
  7495.  
  7496.     if (cps < 0) return(-1);
  7497.     s = s2 = 0;                /* NB: s and s2 might be unsigned */
  7498.  
  7499. #ifdef USETCSETSPEED
  7500.  
  7501.     s = cps * 10L;
  7502.  
  7503.     x = tcgetattr(ttyfd,&ttcur);    /* Get current speed */
  7504.     debug(F101,"ttsspd tcgetattr","",x);
  7505.     if (x < 0)
  7506.       return(-1);
  7507.     debug(F101,"ttsspd TCSETSPEED speed","",s);
  7508.  
  7509.     errno = 0;
  7510.     if (s == 8880L) {            /* 75/1200 split speed requested */
  7511.     tcsetspeed(TCS_IN, &ttcur, 1200L);
  7512.     tcsetspeed(TCS_OUT, &ttcur, 75L);
  7513.     } else
  7514.       tcsetspeed(TCS_ALL, &ttcur, s);    /* Put new speed in structs */
  7515. #ifdef DEBUG
  7516.     if (errno & deblog) {
  7517.     debug(F101,"ttsspd TCSETSPEED errno","",errno);
  7518.     }
  7519. #endif /* DEBUG */
  7520.  
  7521. #ifdef COMMENT
  7522.     tcsetspeed(TCS_ALL, &ttraw, s);
  7523.     tcsetspeed(TCS_ALL, &tttvt, s);
  7524.     tcsetspeed(TCS_ALL, &ttold, s);
  7525. #else
  7526.     if (s == 8880L) {            /* 75/1200 split speed requested */
  7527.     tcsetspeed(TCS_IN, &ttraw, 1200L);
  7528.     tcsetspeed(TCS_OUT, &ttraw, 75L);
  7529.     tcsetspeed(TCS_IN, &tttvt, 1200L);
  7530.     tcsetspeed(TCS_OUT, &tttvt, 75L);
  7531.     tcsetspeed(TCS_IN, &ttold, 1200L);
  7532.     tcsetspeed(TCS_OUT, &ttold, 75L);
  7533.     } else {
  7534.     tcsetspeed(TCS_ALL, &ttraw, s);
  7535.     tcsetspeed(TCS_ALL, &tttvt, s);
  7536.     tcsetspeed(TCS_ALL, &ttold, s);
  7537.     }
  7538. #endif /* COMMENT */
  7539.  
  7540.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur); /* Set the speed */
  7541.     debug(F101,"ttsspd tcsetattr","",x);
  7542.     if (x < 0)
  7543.       return(-1);
  7544.  
  7545. #else  /* Not USETCSETSPEED */
  7546.  
  7547.     /* First check that the given speed is valid. */
  7548.  
  7549.     switch (cps) {
  7550. #ifndef MINIX
  7551.       case 0:   s = B0;    break;
  7552.       case 5:   s = B50;   break;
  7553.       case 7:   s = B75;   break;
  7554. #endif /* MINIX */
  7555.       case 11:  s = B110;  break;
  7556. #ifndef MINIX
  7557.       case 13:  s = B134;  break;
  7558.       case 15:  s = B150;  break;
  7559.       case 20:  s = B200;  break;
  7560. #endif /* MINIX */
  7561.       case 30:  s = B300;  break;
  7562. #ifndef MINIX
  7563.       case 60:  s = B600;  break;
  7564. #endif /* MINIX */
  7565.       case 120: s = B1200; break;
  7566. #ifndef MINIX
  7567.       case 180: s = B1800; break;
  7568. #endif /* MINIX */
  7569.       case 240: s = B2400; break;
  7570.       case 480: s = B4800; break;
  7571. #ifndef MINIX
  7572.       case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
  7573. #endif /* MINIX */
  7574. #ifdef B7200
  7575.       case 720: s = B7200; break;
  7576. #endif /* B7200 */
  7577.       case 960: s = B9600; break;
  7578. #ifdef B14400
  7579.       case 1440: s = B14400; break;
  7580. #endif /* B14400 */
  7581. #ifdef B19200
  7582.       case 1920: s = B19200; break;
  7583. #else
  7584. #ifdef EXTA
  7585.       case 1920: s = EXTA; break;
  7586. #endif /* EXTA */
  7587. #endif /* B19200 */
  7588. #ifdef B28800
  7589.       case 2880: s = B28800; break;
  7590. #endif /* B28800 */
  7591. #ifdef B38400
  7592.       case 3840: s = B38400;
  7593. #ifdef OLINUXHISPEED
  7594.         spd_flags = ~ASYNC_SPD_MASK;    /* Nonzero, but zero flags */
  7595. #endif /* OLINUXHISPEED */
  7596.     break;
  7597. #else /* B38400 not defined... */
  7598. #ifdef EXTB
  7599.       case 3840: s = EXTB; break;
  7600. #endif /* EXTB */
  7601. #endif /* B38400 */
  7602.  
  7603. #ifdef HPUX
  7604. #ifdef _B57600
  7605.       case 5760: s = _B57600; break;
  7606. #endif /* _B57600 */
  7607. #ifdef _B115200
  7608.       case 11520: s = _B115200; break;
  7609. #endif /* _B115200 */
  7610. #else
  7611. #ifdef OLINUXHISPEED
  7612. /*
  7613.   This bit from <carlo@sg.tn.tudelft.nl>:
  7614.   "Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
  7615.   setting the speed to 38400 will set the custom speed (and ttgspd returns
  7616.   38400), but speeds 57600 and 115200 won't work any more because I didn't
  7617.   want to mess up the speed flags when someone is doing sophisticated stuff
  7618.   like custom speeds..."
  7619. */
  7620.       case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
  7621.       case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
  7622. #else
  7623. #ifdef B57600
  7624.       case 5760: s = B57600; break;
  7625. #endif /* B57600 */
  7626. #ifdef B76800
  7627.       case 7680: s = B76800; break;
  7628. #endif /* B76800 */
  7629. #ifdef B115200
  7630.       case 11520: s = B115200; break;
  7631. #endif /* B115200 */
  7632. #endif /* OLINUXHISPEED */
  7633. #ifdef B153600
  7634.       case 15360: s = B153600; break;
  7635. #endif /* B153600 */
  7636. #ifdef B230400
  7637.       case 23040: s = B230400; break;
  7638. #endif /* B230400 */
  7639. #ifdef B307200
  7640.       case 30720: s = B307200; break;
  7641. #endif /* B307200 */
  7642. #ifdef B460800
  7643.       case 46080: s = B460800; break;
  7644. #endif /* 460800 */
  7645. #ifdef B921600
  7646.       case 92160: s = B921600; break;
  7647. #endif /* B921600 */
  7648. #endif /* HPUX */
  7649.       default:
  7650.     ok = 0;                /* Good speed not found, so not ok */
  7651.     break;
  7652.     }
  7653.     debug(F101,"ttsspd ok","",ok);
  7654.     debug(F101,"ttsspd s","",s);
  7655.  
  7656.     if (!ok) {
  7657.     debug(F100,"ttsspd fails","",0);
  7658.     return(-1);
  7659.     } else {
  7660.     if (!s2) s2 = s;        /* Set input speed */
  7661. #ifdef Plan9
  7662.     if (p9ttsspd(cps) < 0)
  7663.       return(-1);
  7664. #else
  7665. #ifdef BSD44ORPOSIX
  7666.     x = tcgetattr(ttyfd,&ttcur);    /* Get current speed */
  7667.     debug(F101,"ttsspd tcgetattr","",x);
  7668.     if (x < 0)
  7669.       return(-1);
  7670. #ifdef OLINUXHISPEED
  7671.     debug(F101,"ttsspd spd_flags","",spd_flags);
  7672.     if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
  7673.         if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
  7674.         debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
  7675.         return(-1);
  7676.         } else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
  7677.         serinfo.flags &= ~ASYNC_SPD_MASK;
  7678.         serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
  7679.         if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
  7680.           return(-1);
  7681.     }
  7682. #endif /* OLINUXHISPEED */
  7683.     cfsetospeed(&ttcur,s);
  7684.     cfsetispeed(&ttcur,s2);
  7685.     cfsetospeed(&ttraw,s);
  7686.     cfsetispeed(&ttraw,s2);
  7687.     cfsetospeed(&tttvt,s);
  7688.     cfsetispeed(&tttvt,s2);
  7689.     cfsetospeed(&ttold,s);
  7690.     cfsetispeed(&ttold,s2);
  7691.     x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
  7692.     debug(F101,"ttsspd tcsetattr","",x);
  7693.     if (x < 0) return(-1);
  7694. #else
  7695. #ifdef ATTSV
  7696.     if (cps == 888) return(-1);    /* No split speeds, sorry. */
  7697.     x = ioctl(ttyfd,TCGETA,&ttcur);
  7698.     debug(F101,"ttsspd TCGETA ioctl","",x);
  7699.     if (x < 0) return(-1);
  7700.     ttcur.c_cflag &= ~CBAUD;
  7701.     ttcur.c_cflag |= s;
  7702.     tttvt.c_cflag &= ~CBAUD;
  7703.     tttvt.c_cflag |= s;
  7704.     ttraw.c_cflag &= ~CBAUD;
  7705.     ttraw.c_cflag |= s;
  7706.     ttold.c_cflag &= ~CBAUD;
  7707.     ttold.c_cflag |= s;
  7708.     x = ioctl(ttyfd,TCSETAW,&ttcur);
  7709.     debug(F101,"ttsspd TCSETAW ioctl","",x);
  7710.     if (x < 0) return(-1);
  7711. #else
  7712. #ifdef BELLV10
  7713.     x = ioctl(ttyfd,TIOCGDEV,&tdcur);
  7714.     debug(F101,"ttsspd TIOCGDEV ioctl","",x);
  7715.     if (x < 0) return(-1);
  7716.     tdcur.ispeed = s2;
  7717.     tdcur.ospeed = s;
  7718.     errno = 0;
  7719.     ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
  7720.     debug(F101,"ttsspd BELLV10 ioctl","",ok);
  7721.     if (ok < 0) {
  7722.         perror(ttnmsv);
  7723.         debug(F101,"ttsspd BELLV10 errno","",ok);
  7724.         return(-1);
  7725.     }
  7726. #else
  7727.     x = gtty(ttyfd,&ttcur);
  7728.     debug(F101,"ttsspd gtty","",x);
  7729.     if (x < 0) return(-1);
  7730.     ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
  7731.     tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
  7732.     ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
  7733.     ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
  7734.     x = stty(ttyfd,&ttcur);
  7735.     debug(F101,"ttsspd stty","",x);
  7736.     if (x < 0) return(-1);
  7737. #endif /* BELLV10 */
  7738. #endif /* ATTSV */
  7739. #endif /* BSD44ORPOSIX */
  7740. #endif /* Plan9 */
  7741.     }
  7742.     return(1);                /* Return 1 = success. */
  7743. #endif /* USETCSETSPEED */
  7744. }
  7745.  
  7746. #endif /* NOLOCAL */
  7747.  
  7748. /* C O N G S P D  -  Get speed of console terminal  */
  7749.  
  7750. long
  7751. congspd() {
  7752. /*
  7753.   This is a disgusting hack.  The right way to do this would be to pass an
  7754.   argument to ttgspd(), but then we'd need to change the Kermit API and
  7755.   all of the ck?tio.c modules.  (Currently used only for rlogin.)
  7756. */
  7757.     int t1;
  7758.     long spd;
  7759. #ifdef NETCONN
  7760.     int t2 = netconn;
  7761.     netconn = 0;
  7762. #endif /* NETCONN */
  7763.     t1 = ttyfd;
  7764.     ttyfd = -1;
  7765.     spd = ttgspd();
  7766.     debug(F101,"congspd","",spd);
  7767. #ifdef NETCONN
  7768.     netconn = t2;
  7769. #endif /* NETCONN */
  7770.     ttyfd = t1;
  7771.     return(spd);
  7772. }
  7773.  
  7774. /*  T T S P D L I S T  -- Get list of serial speeds allowed on this platform */
  7775.  
  7776. #define NSPDLIST 64
  7777. static long spdlist[NSPDLIST];
  7778. /*
  7779.   As written, this picks up the speeds known at compile time, and thus
  7780.   apply to the system where C-Kermit was built, rather than to the one where
  7781.   it is running.  Suggestions for improvement are always welcome.
  7782. */
  7783. long *
  7784. ttspdlist() {
  7785.     int i;
  7786.     for (i = 0; i < NSPDLIST; i++)    /* Initialize the list */
  7787.       spdlist[i] = -1L;
  7788.     i = 1;
  7789.  
  7790. #ifdef USETCSETSPEED            /* No way to find out what's legal */
  7791.     debug(F100,"ttspdlist USETCSETSPEED","",0);
  7792.     spdlist[i++] = 50L;
  7793. #ifndef UW7
  7794.     spdlist[i++] = 75L;
  7795. #endif /* UW7 */
  7796.     spdlist[i++] = 110L;
  7797. #ifndef UW7
  7798.     spdlist[i++] = 134L;
  7799. #endif /* UW7 */
  7800.     spdlist[i++] = 150L;
  7801.     spdlist[i++] = 200L;
  7802.     spdlist[i++] = 300L;
  7803.     spdlist[i++] = 600L;
  7804.     spdlist[i++] = 1200L;
  7805.     spdlist[i++] = 1800L;
  7806.     spdlist[i++] = 2400L;
  7807.     spdlist[i++] = 4800L;
  7808.     spdlist[i++] = 8880L;
  7809.     spdlist[i++] = 9600L;
  7810.     spdlist[i++] = 14400L;
  7811.     spdlist[i++] = 19200L;
  7812.     spdlist[i++] = 28800L;
  7813. #ifndef UW7
  7814.     spdlist[i++] = 33600L;
  7815. #endif /* UW7 */
  7816.     spdlist[i++] = 38400L;
  7817.     spdlist[i++] = 57600L;
  7818.     spdlist[i++] = 76800L;
  7819.     spdlist[i++] = 115200L;
  7820. #ifndef UW7
  7821.     spdlist[i++] = 153600L;
  7822.     spdlist[i++] = 230400L;
  7823.     spdlist[i++] = 307200L;
  7824.     spdlist[i++] = 460800L;
  7825.     spdlist[i++] = 921600L;
  7826. #endif /* UW7 */
  7827.  
  7828. #else  /* USETCSETSPEED */
  7829.  
  7830.     debug(F100,"ttspdlist no USETCSETSPEED","",0);
  7831.  
  7832. #ifdef B50
  7833.     debug(F101,"ttspdlist B50","",B50);
  7834.     spdlist[i++] = 50L;
  7835. #endif /* B50 */
  7836. #ifdef B75
  7837.     debug(F101,"ttspdlist B75","",B75);
  7838.     spdlist[i++] = 75L;
  7839. #endif /* B75 */
  7840. #ifdef B110
  7841.     debug(F101,"ttspdlist B110","",B110);
  7842.     spdlist[i++] = 110L;
  7843. #endif /* B110 */
  7844. #ifdef B134
  7845.     debug(F101,"ttspdlist B134","",B134);
  7846.     spdlist[i++] = 134L;
  7847. #endif /* B134 */
  7848. #ifdef B150
  7849.     debug(F101,"ttspdlist B150","",B150);
  7850.     spdlist[i++] = 150L;
  7851. #endif /* B150 */
  7852. #ifdef B200
  7853.     debug(F101,"ttspdlist B200","",B200);
  7854.     spdlist[i++] = 200L;
  7855. #endif /* B200 */
  7856. #ifdef B300
  7857.     debug(F101,"ttspdlist B300","",B300);
  7858.     spdlist[i++] = 300L;
  7859. #endif /* B300 */
  7860. #ifdef B600
  7861.     debug(F101,"ttspdlist B600","",B600);
  7862.     spdlist[i++] = 600L;
  7863. #endif /* B600 */
  7864. #ifdef B1200
  7865.     debug(F101,"ttspdlist B1200","",B1200);
  7866.     spdlist[i++] = 1200L;
  7867. #endif /* B1200 */
  7868. #ifdef B1800
  7869.     debug(F101,"ttspdlist B1800","",B1800);
  7870.     spdlist[i++] = 1800L;
  7871. #endif /* B1800 */
  7872. #ifdef B2400
  7873.     debug(F101,"ttspdlist B2400","",B2400);
  7874.     spdlist[i++] = 2400L;
  7875. #endif /* B2400 */
  7876. #ifdef B4800
  7877.     debug(F101,"ttspdlist B4800","",B4800);
  7878.     spdlist[i++] = 4800L;
  7879. #endif /* B4800 */
  7880. #ifdef B9600
  7881.     debug(F101,"ttspdlist B9600","",B9600);
  7882.     spdlist[i++] = 9600L;
  7883. #endif /* B9600 */
  7884. #ifdef B14400
  7885.     debug(F101,"ttspdlist B14400","",B14400);
  7886.     spdlist[i++] = 14400L;
  7887. #endif /* B14400 */
  7888. #ifdef B19200
  7889.     debug(F101,"ttspdlist B19200","",B19200);
  7890.     spdlist[i++] = 19200L;
  7891. #else
  7892. #ifdef EXTA
  7893.     debug(F101,"ttspdlist EXTA","",EXTA);
  7894.     spdlist[i++] = 19200L;
  7895. #endif /* EXTA */
  7896. #endif /* B19200 */
  7897. #ifdef B28800
  7898.     debug(F101,"ttspdlist B28800","",B28800);
  7899.     spdlist[i++] = 28800L;
  7900. #endif /* B28800 */
  7901. #ifdef B33600
  7902.     debug(F101,"ttspdlist B33600","",B33600);
  7903.     spdlist[i++] = 33600L;
  7904. #endif /* B33600 */
  7905. #ifdef B38400
  7906.     debug(F101,"ttspdlist B38400","",B38400);
  7907.     spdlist[i++] = 38400L;
  7908. #else
  7909. #ifdef EXTB
  7910.     debug(F101,"ttspdlist EXTB","",EXTB);
  7911.     spdlist[i++] = 38400L;
  7912. #endif /* EXTB */
  7913. #endif /* B38400 */
  7914. #ifdef _B57600
  7915.     debug(F101,"ttspdlist _B57600","",_B57600);
  7916.     spdlist[i++] = 57600L;
  7917. #else
  7918. #ifdef B57600
  7919.     debug(F101,"ttspdlist B57600","",B57600);
  7920.     spdlist[i++] = 57600L;
  7921. #endif /* B57600 */
  7922. #endif /* _B57600 */
  7923. #ifdef B76800
  7924.     debug(F101,"ttspdlist B76800","",B76800);
  7925.     spdlist[i++] = 76800L;
  7926. #endif /* B76800 */
  7927. #ifdef _B115200
  7928.     debug(F101,"ttspdlist _B115200","",_B115200);
  7929.     spdlist[i++] = 115200L;
  7930. #else
  7931. #ifdef B115200
  7932.     debug(F101,"ttspdlist B115200","",B115200);
  7933.     spdlist[i++] = 115200L;
  7934. #endif /* B115200 */
  7935. #endif /* _B115200 */
  7936. #ifdef B153600
  7937.     debug(F101,"ttspdlist B153600","",B153600);
  7938.     spdlist[i++] = 153600L;
  7939. #endif /* B153600 */
  7940. #ifdef B230400
  7941.     debug(F101,"ttspdlist B230400","",B230400);
  7942.     spdlist[i++] = 230400L;
  7943. #endif /* B230400 */
  7944. #ifdef B307200
  7945.     debug(F101,"ttspdlist B307200","",B307200);
  7946.     spdlist[i++] = 307200L;
  7947. #endif /* B307200 */
  7948. #ifdef B460800
  7949.     debug(F101,"ttspdlist B460800","",B460800);
  7950.     spdlist[i++] = 460800L;
  7951. #endif /* B460800 */
  7952. #ifdef B921600
  7953.     debug(F101,"ttspdlist B921600","",B921600);
  7954.     spdlist[i++] = 921600L;
  7955. #endif /* B921600 */
  7956. #endif /* USETCSETSPEED */
  7957.     spdlist[0] = i - 1;            /* Return count in 0th element */
  7958.     debug(F111,"ttspdlist spdlist","0",spdlist[0]);
  7959.     return((long *)spdlist);
  7960. }
  7961.  
  7962. /* T T G S P D  -  Get speed of currently selected tty line  */
  7963.  
  7964. /*
  7965.   Unreliable.  After SET LINE, it returns an actual speed, but not necessarily
  7966.   the real speed.  On some systems, it returns the line's nominal speed, from
  7967.   /etc/ttytab.  Even if you SET SPEED to something else, this function might
  7968.   not notice.
  7969. */
  7970. long
  7971. ttgspd() {                /* Get current serial device speed */
  7972. #ifdef NOLOCAL
  7973.     return(-1L);
  7974. #else
  7975. #ifdef POSIX
  7976.     speed_t                /* Should be unsigned */
  7977. #else
  7978.     int                    /* Isn't unsigned */
  7979. #endif /* POSIX */
  7980.       s;
  7981.     int x;
  7982.     long ss;
  7983. #ifdef OLINUXHISPEED
  7984.     unsigned int spd_flags = 0;
  7985.     struct serial_struct serinfo;
  7986. #endif /* OLINUXHISPEED */
  7987.  
  7988. #ifdef NETCONN
  7989.     if (netconn) {
  7990. #ifdef TN_COMPORT
  7991.     if (istncomport())
  7992.       return(tnc_get_baud());
  7993.     else
  7994. #endif /* TN_COMPORT */
  7995.       return(-1);            /* -1 if network connection */
  7996.     }
  7997. #endif /* NETCONN */
  7998. #ifdef NETCMD
  7999.     if (ttpipe) return(-1);
  8000. #endif /* NETCMD */
  8001. #ifdef NETPTY
  8002.     if (ttpty) return(-1);
  8003. #endif /* NETPTY */
  8004.  
  8005.     debug(F101,"ttgspd ttyfd","",ttyfd);
  8006.  
  8007. #ifdef USETCSETSPEED
  8008.  
  8009.     x = tcgetattr(ttyfd,&ttcur);    /* Get current speed */
  8010.     debug(F101,"ttgspd tcgetattr","",x);
  8011.     if (x < 0)
  8012.       return(-1);
  8013.     errno = 0;
  8014.     s = tcgetspeed(TCS_ALL, &ttcur);
  8015.     debug(F101,"ttsspd TCGETSPEED speed","",s);
  8016.     if (s == 0) {
  8017.     long s1, s2;
  8018.     s1 = tcgetspeed(TCS_IN, &ttcur);
  8019.     s2 = tcgetspeed(TCS_OUT, &ttcur);
  8020.     if (s1 == 1200L && s2 == 75L)
  8021.       return(8880L);
  8022.     }
  8023. #ifdef DEBUG
  8024.     if (errno & deblog) {
  8025.     debug(F101,"ttsspd TCGETSPEED errno","",errno);
  8026.     }
  8027. #endif /* DEBUG */
  8028.     return(s);
  8029.  
  8030. #else  /* Not USETCSETSPEED */
  8031.  
  8032. #ifdef Plan9
  8033.     if (ttyfd < 0)
  8034.       ss = -1;
  8035.     else
  8036.       ss = ttylastspeed;
  8037. #else
  8038. #ifdef OLINUXHISPEED
  8039.     debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
  8040. #endif /* OLINUXHISPEED */
  8041.  
  8042.     if (ttyfd < 0) {
  8043. #ifdef BSD44ORPOSIX
  8044.     s = cfgetospeed(&ccold);
  8045.     debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
  8046. #else
  8047. #ifdef ATTSV
  8048.     s = ccold.c_cflag & CBAUD;
  8049.     debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
  8050. #else
  8051.     s = ccold.sg_ospeed;        /* (obtained by congm()) */
  8052.     debug(F101,"ttgspd sg_ospeed 1","",s);
  8053. #endif /* ATTSV */
  8054. #endif /* BSD44POSIX */
  8055.  
  8056.     } else {
  8057. #ifdef BSD44ORPOSIX
  8058.     if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
  8059.     s = cfgetospeed(&ttcur);
  8060.     debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
  8061. #ifdef OLINUXHISPEED
  8062.     if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
  8063.       spd_flags = serinfo.flags & ASYNC_SPD_MASK;
  8064.     debug(F101,"ttgspd spd_flags","",spd_flags);
  8065. #endif /* OLINUXHISPEED */
  8066. #else
  8067. #ifdef ATTSV
  8068.     x = ioctl(ttyfd,TCGETA,&ttcur);
  8069.     debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
  8070.     debug(F101,"ttgspd ioctl 2 ATTSV errno","",errno);
  8071.     if (x < 0) return(-1);
  8072.     s = ttcur.c_cflag & CBAUD;
  8073.     debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
  8074. #else
  8075. #ifdef BELLV10
  8076.     x = ioctl(ttyfd,TIOCGDEV,&tdcur);
  8077.     debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
  8078.     if (x < 0) return(-1);
  8079.     s = tdcur.ospeed;
  8080.     debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
  8081. #else
  8082.     x = gtty(ttyfd,&ttcur);
  8083.     debug(F101,"ttgspd gtty 2 x","",x);
  8084.     debug(F101,"ttgspd gtty 2 errno","",errno);
  8085.     if (x < 0) return(-1);
  8086.     s = ttcur.sg_ospeed;
  8087.     debug(F101,"ttgspd gtty 2 speed","",s);
  8088. #endif /* BELLV10 */
  8089. #endif /* ATTSV */
  8090. #endif /* BSD44ORPOSIX */
  8091.     }
  8092.     debug(F101,"ttgspd code","",s);
  8093. #ifdef OLINUXHISPEED
  8094.     debug(F101,"ttgspd spd_flags","",spd_flags);
  8095. #endif /* OLINUXHISPEED */
  8096.     switch (s) {
  8097. #ifdef B0
  8098.       case B0:    ss = 0L; break;
  8099. #endif /* B0 */
  8100.  
  8101. #ifndef MINIX
  8102. /*
  8103.  MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
  8104.  etc, making for many "duplicate case in switch" errors, which are fatal.
  8105. */
  8106. #ifdef B50
  8107.       case B50:   ss = 50L; break;
  8108. #endif /* B50 */
  8109. #ifdef B75
  8110.       case B75:   ss = 75L; break;
  8111. #endif /* B75 */
  8112. #endif /* MINIX */
  8113.  
  8114. #ifdef B110
  8115.       case B110:  ss = 110L; break;
  8116. #endif /* B110 */
  8117.  
  8118. #ifndef MINIX
  8119. #ifdef B134
  8120.       case B134:  ss = 134L; break;
  8121. #endif /* B134 */
  8122. #ifdef B150
  8123.       case B150:  ss = 150L; break;
  8124. #endif /* B150 */
  8125. #endif /* MINIX */
  8126.  
  8127. #ifdef B200
  8128.       case B200:  ss = 200L; break;
  8129. #endif /* B200 */
  8130.  
  8131. #ifdef B300
  8132.       case B300:  ss = 300L; break;
  8133. #endif /* B300 */
  8134.  
  8135. #ifdef B600
  8136.       case B600:  ss = 600L; break;
  8137. #endif /* B600 */
  8138.  
  8139. #ifdef B1200
  8140.       case B1200: ss = 1200L; break;
  8141. #endif /* B1200 */
  8142.  
  8143. #ifdef B1800
  8144.       case B1800: ss = 1800L; break;
  8145. #endif /* B1800 */
  8146.  
  8147. #ifdef B2400
  8148.       case B2400: ss = 2400L; break;
  8149. #endif /* B2400 */
  8150.  
  8151. #ifdef B4800
  8152.       case B4800: ss = 4800L; break;
  8153. #endif /* B4800 */
  8154.  
  8155. #ifdef B7200
  8156.       case B7200: ss = 7200L; break;
  8157. #endif /* B7200 */
  8158.  
  8159. #ifdef B9600
  8160.       case B9600: ss = 9600L; break;
  8161. #endif /* B9600 */
  8162.  
  8163. #ifdef B19200
  8164.       case B19200: ss = 19200L; break;
  8165. #else
  8166. #ifdef EXTA
  8167.       case EXTA: ss = 19200L; break;
  8168. #endif /* EXTA */
  8169. #endif /* B19200 */
  8170.  
  8171. #ifndef MINIX
  8172. #ifdef B38400
  8173.       case B38400:
  8174.         ss = 38400L;
  8175. #ifdef OLINUXHISPEED
  8176.         switch(spd_flags) {
  8177.           case ASYNC_SPD_HI:  ss =  57600L; break;
  8178.           case ASYNC_SPD_VHI: ss = 115200L; break;
  8179.     }
  8180. #endif /* OLINUXHISPEED */
  8181.         break;
  8182. #else
  8183. #ifdef EXTB
  8184.       case EXTB: ss = 38400L; break;
  8185. #endif /* EXTB */
  8186. #endif /* B38400 */
  8187. #endif /* MINIX */
  8188.  
  8189. #ifdef HPUX
  8190. #ifdef _B57600
  8191.       case _B57600: ss = 57600L; break;
  8192. #endif /* _B57600 */
  8193. #ifdef _B115200
  8194.       case _B115200: ss = 115200L; break;
  8195. #endif /* _B115200 */
  8196. #else
  8197. #ifdef B57600
  8198.       case B57600: ss = 57600L; break;
  8199. #endif /* B57600 */
  8200. #ifdef B76800
  8201.       case B76800: ss = 76800L; break;
  8202. #endif /* B76800 */
  8203. #ifdef B115200
  8204.       case B115200: ss = 115200L; break;
  8205. #endif /* B115200 */
  8206. #ifdef B153600
  8207.       case B153600: ss = 153600L; break;
  8208. #endif /* B153600 */
  8209. #ifdef B230400
  8210.       case B230400: ss = 230400L; break;
  8211. #endif /* B230400 */
  8212. #ifdef B307200
  8213.       case B307200: ss = 307200L; break;
  8214. #endif /* B307200 */
  8215. #ifdef B460800
  8216.       case B460800: ss = 460800L; break;
  8217. #endif /* B460800 */
  8218. #endif /* HPUX */
  8219. #ifdef B921600
  8220.       case B921600: ss = 921600L; break;
  8221. #endif /* B921600 */
  8222.       default:
  8223.     ss = -1; break;
  8224.     }
  8225. #endif /* Plan9 */
  8226.     debug(F101,"ttgspd speed","",ss);
  8227.     return(ss);
  8228.  
  8229. #endif /* USETCSETSPEED */
  8230. #endif /* NOLOCAL */
  8231. }
  8232. #ifdef MINIX2                /* Another hack alert */
  8233. #define MINIX
  8234. #endif /* MINIX2 */
  8235.  
  8236. /*
  8237.   FIONREAD data type...  This has been defined as "long" for many, many
  8238.   years, and it worked OK until 64-bit platforms appeared.  Thus we use
  8239.   int for 64-bit platforms, but keep long for the others.  If we changed
  8240.   the default PEEKTYPE to int, this would probably break 16-bit builds
  8241.   (note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
  8242.   of which we have no way of testing any more.  Therefore, do not change
  8243.   the default definition of PEEKTYPE -- only add exceptions to it as needed.
  8244. */
  8245. #ifdef COHERENT
  8246. #ifdef FIONREAD
  8247. #undef FIONREAD
  8248. #endif /* FIONREAD */
  8249. /* #define FIONREAD TIOCQUERY */
  8250. /* #define PEEKTYPE int */
  8251. #else  /* Not COHERENT... */
  8252.  
  8253. #ifdef OSF32                /* Digital UNIX 3.2 or higher */
  8254. #define PEEKTYPE int
  8255. #else
  8256. #define PEEKTYPE long            /* Elsewhere (see notes above) */
  8257. #endif /* OSF32 */
  8258. #endif /* COHERENT */
  8259.  
  8260. /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
  8261.  
  8262. #ifdef MYREAD
  8263.  
  8264. /* Private buffer for myread() and its companions.  Not for use by anything
  8265.  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
  8266.  * allowed to read my_count.
  8267.  *
  8268.  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
  8269.  *
  8270.  * A global parity mask variable could be useful too.  We could use it to
  8271.  * let myread() strip the parity on its own, instead of stripping sign
  8272.  * bits as it does now.
  8273.  */
  8274. #ifdef BIGBUFOK
  8275. #define MYBUFLEN 32768
  8276. #else
  8277. #ifdef pdp11
  8278. #define MYBUFLEN 256
  8279. #else
  8280. #define MYBUFLEN 1024
  8281. #endif /* pdp11 */
  8282. #endif /* BIGBUFOK */
  8283.  
  8284. #ifdef ANYX25
  8285. #undef MYBUFLEN
  8286. #define MYBUFLEN 256
  8287. /*
  8288.   On X.25 connections, there is an extra control byte at the beginning.
  8289. */
  8290. static CHAR x25buf[MYBUFLEN+1];        /* Communication device input buffer */
  8291. static CHAR  *mybuf = x25buf+1;
  8292. #else
  8293. static CHAR mybuf[MYBUFLEN];
  8294. #endif /* ANYX25 */
  8295.  
  8296. static int my_count = 0;        /* Number of chars still in mybuf */
  8297. static int my_item = -1;        /* Last index read from mybuf[]   */
  8298.  
  8299. /*  T T P E E K  --  Peek into our internal communications input buffers. */
  8300.  
  8301. /*
  8302.   NOTE: This routine is peculiar to UNIX, and is used only by the
  8303.   select()-based CONNECT module, ckucns.c.  It need not be replicated in
  8304.   the ck?tio.c of other platforms.
  8305. */
  8306. int
  8307. ttpeek() {
  8308. #ifdef TTLEBUF
  8309.     int rc = 0;
  8310.     if (ttpush >= 0)
  8311.       rc++;
  8312.     rc += le_inbuf();
  8313.     if (rc > 0)
  8314.       return(rc);
  8315.     else
  8316. #endif /* TTLEBUF */
  8317.  
  8318. #ifdef MYREAD
  8319.     return(my_count);
  8320. #else
  8321.     return(0);
  8322. #endif /* MYREAD */
  8323. }
  8324.  
  8325. /* myread() -- Efficient read of one character from communications line.
  8326.  *
  8327.  * NOTE: myread() and its helpers mygetbuf() and myfillbuf() return raw
  8328.  * bytes from connection, so when the connection is encrypted, these bytes
  8329.  * must be decrypted.
  8330.  *
  8331.  * Uses a private buffer to minimize the number of expensive read() system
  8332.  * calls.  Essentially performs the equivalent of read() of 1 character, which
  8333.  * is then returned.  By reading all available input from the system buffers
  8334.  * to the private buffer in one chunk, and then working from this buffer, the
  8335.  * number of system calls is reduced in any case where more than one character
  8336.  * arrives during the processing of the previous chunk, for instance high
  8337.  * baud rates or network type connections where input arrives in packets.
  8338.  * If the time needed for a read() system call approaches the time for more
  8339.  * than one character to arrive, then this mechanism automatically compensates
  8340.  * for that by performing bigger read()s less frequently.  If the system load
  8341.  * is high, the same mechanism compensates for that too.
  8342.  *
  8343.  * myread() is a macro that returns the next character from the buffer.  If the
  8344.  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
  8345.  * returns.
  8346.  *
  8347.  * This should be efficient enough for any one-character-at-a-time loops.
  8348.  * For even better efficiency you might use memcpy()/bcopy() or such between
  8349.  * buffers (since they are often better optimized for copying), but it may not
  8350.  * be worth it if you have to take an extra pass over the buffer to strip
  8351.  * parity and check for CTRL-C anyway.
  8352.  *
  8353.  * Note that if you have been using myread() from another program module, you
  8354.  * may have some trouble accessing this macro version and the private variables
  8355.  * it uses.  In that case, just add a function in this module, that invokes the
  8356.  * macro.
  8357.  */
  8358. #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
  8359.  
  8360. /* Specification: Push back up to one character onto myread()'s queue.
  8361.  *
  8362.  * This implementation: Push back characters into mybuf. At least one character
  8363.  * must have been read through myread() before myunrd() may be used.  After
  8364.  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
  8365.  * one character can be pushed back, but only one character is guaranteed.
  8366.  * Since a previous myread() must have read its character out of mybuf[],
  8367.  * that guarantees that there is space for at least one character.  If push
  8368.  * back was really needed after EOF, a small addition could provide that.
  8369.  *
  8370.  * As of 02/2007 myunrd() is used by ttinl().
  8371.  */
  8372. VOID
  8373. #ifdef CK_ANSIC
  8374. myunrd(CHAR ch)
  8375. #else
  8376. myunrd(ch) CHAR ch;
  8377. #endif    /* CK_ANSIC */
  8378. {
  8379.     if (my_item >= 0) {
  8380.     mybuf[my_item--] = ch;
  8381.     ++my_count;
  8382.     }
  8383. }
  8384.  
  8385. /*  T T P U S H B A C K  --  Put n bytes back into the myread buffer */
  8386.  
  8387. static CHAR * pushbuf = NULL;
  8388. /* static int pushed = 0; */
  8389.  
  8390. int
  8391. ttpushback(s,n) CHAR * s; int n; {
  8392.     debug(F101,"ttpushback n","",n);
  8393.     if (pushbuf || n > MYBUFLEN || n < 1)
  8394.       return(-1);
  8395.     debug(F101,"ttpushback my_count","",my_count);
  8396.     if (my_count > 0) {
  8397.     if (!(pushbuf = (CHAR *)malloc(n+1)))
  8398.       return(-1);
  8399.     memcpy(pushbuf,mybuf,my_count);
  8400.     /* pushed = my_count; */ /* (set but never used) */
  8401.     }
  8402.     memcpy(mybuf,s,n);
  8403.     my_count = n;
  8404.     my_item = -1;
  8405.     return(0);
  8406. }
  8407.  
  8408. /* mygetbuf() -- Fill buffer for myread() and return first character.
  8409.  *
  8410.  * This function is what myread() uses when it can't get the next character
  8411.  * directly from its buffer.  First, it calls a system dependent myfillbuf()
  8412.  * to read at least one new character into the buffer, and then it returns
  8413.  * the first character just as myread() would have done.  This function also
  8414.  * is responsible for all error conditions that myread() can indicate.
  8415.  *
  8416.  * Returns: When OK    => a positive character, 0 or greater.
  8417.  *        When EOF    => -2.
  8418.  *        When error    => -3, error code in errno.
  8419.  *
  8420.  * Older myread()s additionally returned -1 to indicate that there was nothing
  8421.  * to read, upon which the caller would call myread() again until it got
  8422.  * something.  The new myread()/mygetbuf() always gets something.  If it
  8423.  * doesn't, then make it do so!  Any program that actually depends on the old
  8424.  * behaviour will break.
  8425.  *
  8426.  * The older version also used to return -2 both for EOF and other errors,
  8427.  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
  8428.  * other errors now return different results, although Kermit currently never
  8429.  * checks to see which it was.  It just disconnects in both cases.
  8430.  *
  8431.  * Kermit lets the user use the quit key to perform some special commands
  8432.  * during file transfer.  This causes read(), and thus also mygetbuf(), to
  8433.  * finish without reading anything and return the EINTR error.  This should
  8434.  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
  8435.  * but if there is nothing to read, this could delay Kermit's reaction to
  8436.  * the command, and make Kermit appear unresponsive.
  8437.  *
  8438.  * The debug() call should be removed for optimum performance.
  8439.  */
  8440. int
  8441. mygetbuf() {
  8442.     int x;
  8443.     errno = 0;
  8444. #ifdef DEBUG
  8445.     if (deblog && my_count > 0)
  8446.       debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
  8447. #endif /* DEBUG */
  8448.     if (my_count <= 0)
  8449.       my_count = myfillbuf();
  8450.  
  8451. #ifdef DEBUG
  8452. #ifdef COMMENT
  8453.     if (deblog) debug(F101, "mygetbuf read", "", my_count);
  8454. #else /* COMMENT */
  8455.     ckhexdump("mygetbuf read", mybuf, my_count);
  8456. #endif /* COMMENT */
  8457. #endif /* DEBUG */
  8458.     x = my_count;
  8459.     if (my_count <= 0) {
  8460.     my_count = 0;
  8461.     my_item = -1;
  8462.     debug(F101,"mygetbuf errno","",errno);
  8463. #ifdef TCPSOCKET
  8464.     if (netconn && ttnet == NET_TCPB && errno != 0) {
  8465.         if (errno != EINTR) {
  8466.         debug(F101,"mygetbuf TCP error","",errno);
  8467.         ttclos(0);        /* Close the connection. */
  8468.         }
  8469.         return(-3);
  8470.     }
  8471. #endif /* TCPSOCKET */
  8472.     if (!netconn && xlocal && errno) {
  8473.         if (errno != EINTR) {
  8474.         debug(F101,"mygetbuf SERIAL error","",errno);
  8475.         x = -3;
  8476.         ttclos(0);        /* Close the connection. */
  8477.         }
  8478.     }
  8479.     return((x < 0) ? -3 : -2);
  8480.     }
  8481.     --my_count;
  8482.     return((unsigned)(0xff & mybuf[my_item = 0]));
  8483. }
  8484.  
  8485. /* myfillbuf():
  8486.  * System-dependent read() into mybuf[], as many characters as possible.
  8487.  *
  8488.  * Returns: OK => number of characters read, always more than zero.
  8489.  *          EOF => 0
  8490.  *          Error => -1, error code in errno.
  8491.  *
  8492.  * If there is input available in the system's buffers, all of it should be
  8493.  * read into mybuf[] and the function return immediately.  If no input is
  8494.  * available, it should wait for a character to arrive, and return with that
  8495.  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
  8496.  * character, but be aware that any such delay lengthens the packet turnaround
  8497.  * time during kermit file transfers.  Should never return with zero characters
  8498.  * unless EOF or irrecoverable read error.
  8499.  *
  8500.  * Correct functioning depends on the correct tty parameters being used.
  8501.  * Better control of current parameters is required than may have been the
  8502.  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
  8503.  * no longer be sometimes off and sometimes on like it used to, unless a
  8504.  * special myfillbuf() is written to handle that.  Otherwise the ordinary
  8505.  * myfillbuf()s may think they have come to EOF.
  8506.  *
  8507.  * If your system has a facility to directly perform the functioning of
  8508.  * myfillbuf(), then use it.  If the system can tell you how many characters
  8509.  * are available in its buffers, then read that amount (but not less than 1).
  8510.  * If the system can return a special indication when you try to read without
  8511.  * anything to read, while allowing you to read all there is when there is
  8512.  * something, you may loop until there is something to read, but probably that
  8513.  * is not good for the system load.
  8514.  */
  8515.  
  8516. #ifdef SVORPOSIX
  8517.     /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
  8518.      * and CLOCAL set any way you like.  This way, read() will do exactly
  8519.      * what is required by myfillbuf(): If there is data in the buffers
  8520.      * of the O.S., all available data is read into mybuf, up to the size
  8521.      * of mybuf.  If there is none, the first character to arrive is
  8522.      * awaited and returned.
  8523.      */
  8524. int
  8525. myfillbuf() {
  8526.     int fd, n;
  8527. #ifdef NETCMD
  8528.     if (ttpipe)
  8529.       fd = fdin;
  8530.     else
  8531. #endif /* NETCMD */
  8532.       fd = ttyfd;
  8533.  
  8534. #ifdef sxaE50
  8535.     /* From S. Dezawa at Fujifilm in Japan.  I don't know why this is */
  8536.     /* necessary for the sxa E50, but it is. */
  8537.     return read(fd, mybuf, 255);
  8538. #else
  8539. #ifdef BEOSORBEBOX
  8540.     while (1) {
  8541. #ifdef NETCONN
  8542.         if (netconn) {
  8543.             n = netxin(sizeof(mybuf), (char *)mybuf);
  8544.             debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
  8545.     }
  8546.         else
  8547. #endif /* NETCONN */
  8548.       n = read(fd, mybuf, sizeof(mybuf));
  8549.     debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
  8550.         if (n > 0)
  8551.       return(n);
  8552.         snooze(1000.0);
  8553.     }
  8554. #else /* BEOSORBEBOX */
  8555.     errno = 0;
  8556.     /* debug(F101,"SVORPOSIX myfillbuf calling read() fd","",fd); */
  8557. #ifdef IBMX25
  8558.     if (netconn && (nettype == NET_IX25)) {
  8559.     /* can't use sizeof because mybuf is a pointer, and not an array! */
  8560.     n = x25xin( MYBUFLEN, mybuf );
  8561.     } else
  8562. #endif /* IBMX25 */
  8563.  
  8564. #ifdef CK_SSL
  8565.       if (ssl_active_flag || tls_active_flag) {
  8566.       int error, n = 0;
  8567.       debug(F100,"myfillbuf calling SSL_read() fd","",0);
  8568.       while (n == 0) {
  8569.           if (ssl_active_flag)
  8570.                 n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
  8571.           else if (tls_active_flag)
  8572.                 n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
  8573.               else
  8574.         break;
  8575.           switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
  8576.         case SSL_ERROR_NONE:
  8577.           if (n > 0)
  8578.                     return(n);
  8579.           if (n < 0)
  8580.                     return(-2);
  8581.           msleep(50);
  8582.           break;
  8583.         case SSL_ERROR_WANT_WRITE:
  8584.         case SSL_ERROR_WANT_READ:
  8585.           return(-1);
  8586.         case SSL_ERROR_SYSCALL:
  8587.           if (n != 0)
  8588.             return(-1);
  8589.         case SSL_ERROR_WANT_X509_LOOKUP:
  8590.         case SSL_ERROR_SSL:
  8591.         case SSL_ERROR_ZERO_RETURN:
  8592.         default:
  8593.           ttclos(0);
  8594.           return(-3);
  8595.             }
  8596.         }
  8597.     }
  8598. #endif /* CK_SSL */
  8599. #ifdef CK_KERBEROS
  8600. #ifdef KRB4
  8601. #ifdef RLOGCODE
  8602.     if (ttnproto == NP_EK4LOGIN) {
  8603.     debug(F101,"myfillbuf calling krb4_des_read() fd","",ttyfd);
  8604.         if ((n = krb4_des_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
  8605.       return(-3);
  8606.         else
  8607.       return(n);
  8608.     }
  8609. #endif /* RLOGCODE */
  8610. #endif /* KRB4 */
  8611. #ifdef KRB5
  8612. #ifdef RLOGCODE
  8613.     if (ttnproto == NP_EK5LOGIN) {
  8614.     debug(F101,"myfillbuf calling krb5_des_read() fd","",ttyfd);
  8615.         if ((n = krb5_des_read(ttyfd,(char *)mybuf,sizeof(mybuf),0)) < 0)
  8616.       return(-3);
  8617.         else
  8618.       return(n);
  8619.     }
  8620. #endif /* RLOGCODE */
  8621. #ifdef KRB5_U2U
  8622.     if (ttnproto == NP_K5U2U) {
  8623.     debug(F101,"myfillbuf calling krb5_u2u_read() fd","",ttyfd);
  8624.         if ((n = krb5_u2u_read(ttyfd,(char *)mybuf,sizeof(mybuf))) < 0)
  8625.       return(-3);
  8626.         else
  8627.       return(n);
  8628.     }
  8629. #endif /* KRB5_U2U */
  8630. #endif /* KRB5 */
  8631. #endif /* CK_KERBEROS */
  8632.  
  8633. #ifdef NETPTY
  8634. #ifdef HAVE_PTYTRAP
  8635.     /* Special handling for HP-UX pty i/o */
  8636.   ptyread:
  8637.     if (ttpty && pty_trap_pending(ttyfd) > 0) {
  8638.     debug(F101,"myfillbuf calling pty_trap_handler() fd","",ttyfd);
  8639.         if (pty_trap_handler(ttyfd) > 0) {
  8640.             ttclos(0);
  8641.             return(-3);
  8642.         }
  8643.     }
  8644. #endif /* HAVE_PTYTRAP */
  8645. #endif /* NETPTY */
  8646.     debug(F101,"myfillbuf calling read() fd","",ttyfd);
  8647.     n = read(fd, mybuf, sizeof(mybuf));
  8648.     debug(F101,"SVORPOSIX myfillbuf read","",n);
  8649.     debug(F101,"SVORPOSIX myfillbuf errno","",errno);
  8650.     debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
  8651.     if (n < 1) {
  8652. #ifdef NETPTY
  8653. #ifdef HAVE_PTYTRAP
  8654.         /* When we have a PTY trap in place the connection cannot */
  8655.         /* be closed until the trap receives a close indication.  */
  8656.         if (n == 0 && ttpty)
  8657.             goto ptyread;
  8658. #endif /* HAVE_PTYTRAP */
  8659. #endif /* NETPTY */
  8660.         return(-3);
  8661.     }
  8662.     return(n);
  8663. #endif /* BEOSORBEBOX */
  8664. #endif /* sxaE50 */
  8665. }
  8666.  
  8667. #else /* not AT&T or POSIX */
  8668.  
  8669. #ifdef aegis
  8670.     /* This is quoted from the old myread().  The semantics seem to be
  8671.      * alright, but maybe errno would not need to be set even when
  8672.      * there is no error?  I don't know aegis.
  8673.      */
  8674. int
  8675. myfillbuf() {
  8676.     int count;
  8677. #ifdef NETCMD
  8678.     if (ttpipe)
  8679.       fd = fdin;
  8680.     else
  8681. #endif /* NETCMD */
  8682.       fd = ttyfd;
  8683.  
  8684.     count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
  8685.     errno = EIO;
  8686.     if (st.all == ios_$get_conditional_failed) /* get at least one */
  8687.       count = ios_$get((short)fd, 0, mybuf, 1L, st);
  8688.     if (st.all == ios_$end_of_file)
  8689.       return(-3);
  8690.     else if (st.all != status_$ok) {
  8691.     errno = EIO;
  8692.     return(-1);
  8693.     }
  8694.     return(count > 0 ? count : -3);
  8695. }
  8696. #else /* !aegis */
  8697.  
  8698. #ifdef FIONREAD
  8699.     /* This is for systems with FIONREAD.  FIONREAD returns the number
  8700.      * of characters available for reading. If none are available, wait
  8701.      * until something arrives, otherwise return all there is.
  8702.      */
  8703. int
  8704. myfillbuf() {
  8705.     PEEKTYPE avail = 0;
  8706.     int x, fd;
  8707. #ifdef NETCMD
  8708.     if (ttpipe)
  8709.       fd = fdin;
  8710.     else
  8711. #endif /* NETCMD */
  8712.       fd = ttyfd;
  8713.  
  8714. #ifdef SUNX25
  8715. /*
  8716.   SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
  8717.   Depends on SunOS having FIONREAD, not because we use it, but just so this
  8718.   code is grouped correctly within the #ifdefs.  Let's hope Solaris keeps it.
  8719.  
  8720.   We call x25xin() instead of read() so that Q-Bit packets, which contain
  8721.   X.25 service-level information (e.g. PAD parameter changes), can be processed
  8722.   transparently to the upper-level code.  This is a blocking read, and so
  8723.   we depend on higher-level code (such as ttinc()) to set any necessary alarms.
  8724. */
  8725.     extern int nettype;
  8726.     if (netconn && nettype == NET_SX25) {
  8727.     while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
  8728.     return(x - 1);            /* "-1" compensates for extra status byte */
  8729.     }
  8730. #endif /* SUNX25 */
  8731.  
  8732. #ifdef CK_SSL
  8733.     if (ssl_active_flag || tls_active_flag) {
  8734.         int error, n = 0;
  8735.         while (n == 0) {
  8736.             if (ssl_active_flag)
  8737.           n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
  8738.             else
  8739.           n = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
  8740.             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
  8741.           case SSL_ERROR_NONE:
  8742.                 if (n > 0)
  8743.           return(n);
  8744.                 if (n < 0)
  8745.           return(-2);
  8746.                 msleep(50);
  8747.                 break;
  8748.           case SSL_ERROR_WANT_WRITE:
  8749.           case SSL_ERROR_WANT_READ:
  8750.                 return(-1);
  8751.           case SSL_ERROR_SYSCALL:
  8752.         if (n != 0)
  8753.           return(-1);
  8754.           case SSL_ERROR_WANT_X509_LOOKUP:
  8755.           case SSL_ERROR_SSL:
  8756.           case SSL_ERROR_ZERO_RETURN:
  8757.           default:
  8758.                 ttclos(0);
  8759.                 return(-2);
  8760.             }
  8761.         }
  8762.     }
  8763. #endif /* CK_SSL */
  8764. #ifdef CK_KERBEROS
  8765. #ifdef KRB4
  8766. #ifdef RLOGCODE
  8767.     if (ttnproto == NP_EK4LOGIN) {
  8768.         if ((x = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
  8769.       return(-1);
  8770.         else
  8771.       return(x);
  8772.     }
  8773. #endif /* RLOGCODE */
  8774. #endif /* KRB4 */
  8775. #ifdef KRB5
  8776. #ifdef RLOGCODE
  8777.     if (ttnproto == NP_EK5LOGIN) {
  8778.         if ((x = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
  8779.       return(-1);
  8780.         else
  8781.       return(x);
  8782.     }
  8783. #endif /* RLOGCODE */
  8784. #ifdef KRB5_U2U
  8785.     if (ttnproto == NP_K5U2U) {
  8786.         if ((x = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
  8787.       return(-1);
  8788.         else
  8789.       return(x);
  8790.     }
  8791. #endif /* KRB5_U2U */
  8792. #endif /* KRB5 */
  8793. #endif /* CK_KERBEROS */
  8794.  
  8795.     errno = 0;
  8796.     debug(F101,"myfillbuf calling FIONREAD ioctl","",xlocal);
  8797.     x = ioctl(fd, FIONREAD, &avail);
  8798. #ifdef DEBUG
  8799.     if (deblog) {
  8800.     debug(F101,"myfillbuf FIONREAD","",x);
  8801.     debug(F101,"myfillbuf FIONREAD avail","",avail);
  8802.     debug(F101,"myfillbuf FIONREAD errno","",errno);
  8803.     }
  8804. #endif /* DEBUG */
  8805.     if (x < 0 || avail == 0)
  8806.       avail = 1;
  8807.  
  8808.     if (avail > MYBUFLEN)
  8809.       avail = MYBUFLEN;
  8810.  
  8811.     errno = 0;
  8812.  
  8813.     x = read(fd, mybuf, (int) avail);
  8814. #ifdef DEBUG
  8815.     if (deblog) {
  8816.     debug(F101,"myfillbuf avail","",avail);
  8817.     debug(F101,"myfillbuf read","",x);
  8818.     debug(F101,"myfillbuf read errno","",errno);
  8819.         if (x > 0)
  8820.       ckhexdump("myfillbuf mybuf",mybuf,x);
  8821.     }
  8822. #endif /* DEBUG */
  8823.     if (x < 1) x = -3;            /* read 0 == connection loss */
  8824.     return(x);
  8825. }
  8826.  
  8827. #else /* !FIONREAD */
  8828. /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
  8829. /* When there is no other possibility, read 1 character at a time. */
  8830. int
  8831. myfillbuf() {
  8832.     int x;
  8833.  
  8834. #ifdef CK_SSL
  8835.     if (ssl_active_flag || tls_active_flag) {
  8836.         int error, n = 0;
  8837.         while (n == 0) {
  8838.             if (ssl_active_flag)
  8839.           n = SSL_read(ssl_con, (char *)mybuf, sizeof(mybuf));
  8840.             else
  8841.           count = SSL_read(tls_con, (char *)mybuf, sizeof(mybuf));
  8842.             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,n)) {
  8843.           case SSL_ERROR_NONE:
  8844.                 if (n > 0)
  8845.           return(n);
  8846.                 if (n < 0)
  8847.           return(-2);
  8848.                 msleep(50);
  8849.                 break;
  8850.           case SSL_ERROR_WANT_WRITE:
  8851.           case SSL_ERROR_WANT_READ:
  8852.                 return(-1);
  8853.           case SSL_ERROR_SYSCALL:
  8854.         if (n != 0)
  8855.           return(-1);
  8856.           case SSL_ERROR_WANT_X509_LOOKUP:
  8857.           case SSL_ERROR_SSL:
  8858.           case SSL_ERROR_ZERO_RETURN:
  8859.           default:
  8860.                 ttclos(0);
  8861.                 return(-2);
  8862.             }
  8863.         }
  8864.     }
  8865. #endif /* CK_SSL */
  8866. #ifdef CK_KERBEROS
  8867. #ifdef KRB4
  8868. #ifdef RLOGCODE
  8869.     if (ttnproto == NP_EK4LOGIN) {
  8870.         if ((len = krb4_des_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
  8871.       return(-1);
  8872.         else
  8873.       return(len);
  8874.     }
  8875. #endif /* RLOGCODE */
  8876. #endif /* KRB4 */
  8877. #ifdef KRB5
  8878. #ifdef RLOGCODE
  8879.     if (ttnproto == NP_EK5LOGIN) {
  8880.         if ((len = krb5_des_read(ttyfd,mybuf,sizeof(mybuf),0)) < 0)
  8881.       return(-1);
  8882.         else
  8883.       return(len);
  8884.     }
  8885. #endif /* RLOGCODE */
  8886. #ifdef KRB5_U2U
  8887.     if (ttnproto == NP_K5U2U) {
  8888.         if ((len = krb5_u2u_read(ttyfd,mybuf,sizeof(mybuf))) < 0)
  8889.       return(-1);
  8890.         else
  8891.       return(len);
  8892.     }
  8893. #endif /* KRB5_U2U */
  8894. #endif /* KRB5 */
  8895. #endif /* CK_KERBEROS */
  8896.  
  8897. #ifdef NETCMD
  8898.     if (ttpipe)
  8899.       fd = fdin;
  8900.     else
  8901. #endif /* NETCMD */
  8902.       fd = ttyfd;
  8903.     x = read(fd, mybuf, 1);
  8904.     return(x > 0 ? x : -3);
  8905. }
  8906.  
  8907. #endif /* !FIONREAD */
  8908. #endif /* !aegis */
  8909. #endif /* !ATTSV */
  8910.  
  8911. #endif /* MYREAD */
  8912.  
  8913. /*  T T _ T N O P T  --  Handle Telnet negotions in incoming data */
  8914. /*
  8915.   Call with the IAC that was encountered.
  8916.   Returns:
  8917.    -3: If connection has dropped or gone bad.
  8918.    -2: On Telnet protocol error resulting in inconsistent states.
  8919.     0: If negotiation OK and caller has nothing to do.
  8920.     1: If packet start character has changed (new value is in global stchr).
  8921.   255: If there was a quoted IAC as data.
  8922.    or: Not at all if we got a legitimate Telnet Logout request.
  8923. */
  8924. #ifdef TCPSOCKET
  8925. static int
  8926. tt_tnopt(n) int n; {            /* Handle Telnet options */
  8927.     /* In case caller did not already check these conditions...  */
  8928.     if (n == IAC &&
  8929.     ((xlocal && netconn && IS_TELNET()) ||
  8930.      (!xlocal && sstelnet))) {
  8931.     extern int server;
  8932.     int tx = 0;
  8933.     debug(F100,"ttinl calling tn_doop()","",0);
  8934.     tx = tn_doop((CHAR)(n & 0xff),duplex,ttinc);
  8935.     debug(F111,"ttinl tn_doop() returned","tx",tx);
  8936.     switch (tx) {
  8937.       case 0:
  8938.         return(0);
  8939.       case -1:            /* I/O error */
  8940.         ttimoff();            /* Turn off timer */
  8941.         return(-3);
  8942.           case -2:            /* Connection failed. */
  8943.           case -3:
  8944.         ttimoff();            /* Turn off timer */
  8945.         ttclos(0);
  8946.         return(-3);
  8947.       case 1:            /* ECHO change */
  8948.         duplex = 1;
  8949.         return(0);
  8950.       case 2:            /* ECHO change */
  8951.         duplex = 0;
  8952.         return(0);
  8953.       case 3:            /* Quoted IAC */
  8954.         n = 255;
  8955.         return((unsigned)255);
  8956. #ifdef IKS_OPTION
  8957.       case 4: {
  8958.           if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start && server
  8959. #ifdef IKSD
  8960.           && !inserver
  8961. #endif /* IKSD */
  8962.           ) {            /* Remote in Server mode */
  8963.           ttimoff();        /* Turn off timer */
  8964.           debug(F100,"u_start and !inserver","",0);
  8965.           return(-2);        /* End server mode */
  8966.           } else if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
  8967.              server
  8968.              ) {        /* I'm no longer in Server Mode */
  8969.           debug(F100,"me_start and server","",0);
  8970.           ttimoff();
  8971.           return(-2);
  8972.           }
  8973.           return(0);
  8974.       }
  8975.       case 5: {            /* Start character change */
  8976.           /* extern CHAR stchr; */
  8977.           /* start = stchr; */
  8978.           return(1);
  8979.       }
  8980. #endif /* IKS_OPTION */
  8981.       case 6:            /* Remote Logout */
  8982.         ttimoff();
  8983.         ttclos(0);
  8984. #ifdef IKSD
  8985.         if (inserver && !local)
  8986.           doexit(GOOD_EXIT,0);
  8987.         else
  8988. #endif /* IKSD */
  8989.           return(-2);
  8990.       default:
  8991.         return(0);
  8992.     }
  8993.     } else
  8994.       return(0);
  8995. }
  8996. #endif /* TCPSOCKET */
  8997.  
  8998. /*  T T F L U I  --  Flush tty input buffer */
  8999.  
  9000. void
  9001. ttflux() {                /* But first... */
  9002. #ifdef MYREAD
  9003. /*
  9004.   Flush internal MYREAD buffer.
  9005. */
  9006. #ifdef TCPSOCKET
  9007.     int dotnopts, x;
  9008.     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
  9009.          (!xlocal && sstelnet)));
  9010. #endif /* TCPSOCKET */
  9011.     debug(F101,"ttflux my_count","",my_count);
  9012. #ifdef TCPSOCKET
  9013.     if (dotnopts) {
  9014.     CHAR ch = '\0';
  9015.         while (my_count > 0) {
  9016.         ch = myread();
  9017. #ifdef CK_ENCRYPTION
  9018.             if (TELOPT_U(TELOPT_ENCRYPTION))
  9019.           ck_tn_decrypt((char *)&ch,1);
  9020. #endif /* CK_ENCRYPTION */
  9021.             if (ch == IAC)
  9022.           x = tt_tnopt(ch);
  9023.         }
  9024.     } else
  9025. #endif /* TCPSOCKET */
  9026. #ifdef COMMENT
  9027. #ifdef CK_ENCRYPTION
  9028.     if (TELOPT_U(TELOPT_ENCRYPTION) && my_count > 0)
  9029.       ck_tn_decrypt(&mybuf[my_item+1],my_count);
  9030. #endif /* CK_ENCRYPTION */
  9031. #endif /* COMMENT */
  9032.     my_count = 0;            /* Reset count to zero */
  9033.     my_item = -1;            /* And buffer index to -1 */
  9034. #endif /* MYREAD */
  9035. }
  9036.  
  9037. int
  9038. ttflui() {
  9039.     int n, fd;
  9040. #ifdef TCPSOCKET
  9041.     int dotnopts;
  9042.     dotnopts = (((xlocal && netconn && IS_TELNET()) ||
  9043.          (!xlocal && sstelnet)));
  9044. #endif /* TCPSOCKET */
  9045.  
  9046. #ifdef NETCMD
  9047.     if (ttpipe)
  9048.       fd = fdin;
  9049.     else
  9050. #endif /* NETCMD */
  9051.       fd = ttyfd;
  9052.  
  9053. #ifdef TTLEBUF
  9054.     ttpush = -1;            /* Clear the peek-ahead char */
  9055.     while (le_data && (le_inbuf() > 0)) {
  9056.         CHAR ch = '\0';
  9057.         if (le_getchar(&ch) > 0) {    /* Clear any more... */
  9058.             debug(F101,"ttflui le_inbuf ch","",ch);
  9059.         }
  9060.     }
  9061. #endif /* TTLEBUF */
  9062.     debug(F101,"ttflui ttpipe","",ttpipe);
  9063.  
  9064. #ifdef MYREAD
  9065. /*
  9066.   Flush internal MYREAD buffer *NEXT*, in all cases.
  9067. */
  9068.     ttflux();
  9069. #endif /* MYREAD */
  9070.  
  9071. #ifdef NETCONN
  9072. /* Network flush is done specially, in the network support module. */
  9073.     if ((netconn || sstelnet) && !ttpipe && !ttpty) {
  9074.     debug(F100,"ttflui netflui","",0);
  9075. #ifdef COMMENT
  9076. #ifdef TN_COMPORT
  9077.     if (istncomport())
  9078.             tnc_send_purge_data(TNC_PURGE_RECEIVE);
  9079. #endif /* TN_COMPORT */
  9080. #endif /* COMMENT */
  9081.     return(netflui());
  9082.     }
  9083. #endif /* NETCONN */
  9084.  
  9085.     debug(F101,"ttflui ttyfd","",ttyfd); /* Not network */
  9086.     if (ttyfd < 0)
  9087.       return(-1);
  9088.  
  9089. #ifdef aegis
  9090.     sio_$control((short)yfd, sio_$flush_in, true, st);
  9091.     if (st.all != status_$ok) {
  9092.     fprintf(stderr, "flush failed: "); error_$print(st);
  9093.     } else {      /* sometimes the flush doesn't work */
  9094.         for (;;) {
  9095.         char buf[256];
  9096.             /* eat all the characters that shouldn't be available */
  9097.             ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
  9098.             if (st.all == ios_$get_conditional_failed) break;
  9099.             fprintf(stderr, "flush failed(2): "); error_$print(st);
  9100.         }
  9101.     }
  9102. #else
  9103. #ifdef BSD44                /* 4.4 BSD */
  9104.     n = FREAD;                          /* Specify read queue */
  9105.     debug(F100,"ttflui BSD44","",0);
  9106.     ioctl(fd,TIOCFLUSH,&n);
  9107. #else
  9108. #ifdef Plan9
  9109. #undef POSIX                /* Uh oh... */
  9110. #endif /* Plan9 */
  9111. #ifdef POSIX                /* POSIX */
  9112.     debug(F100,"ttflui POSIX","",0);
  9113.     tcflush(fd,TCIFLUSH);
  9114. #else
  9115. #ifdef ATTSV                /* System V */
  9116. #ifndef VXVE
  9117.     debug(F100,"ttflui ATTSV","",0);
  9118.     ioctl(fd,TCFLSH,0);
  9119. #endif /* VXVE */
  9120. #else                    /* Not BSD44, POSIX, or Sys V */
  9121. #ifdef TIOCFLUSH            /* Those with TIOCFLUSH defined */
  9122. #ifdef ANYBSD                /* Berkeley */
  9123.     n = FREAD;                          /* Specify read queue */
  9124.     debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
  9125.     ioctl(fd,TIOCFLUSH,&n);
  9126. #else                    /* Others (V7, etc) */
  9127.     debug(F100,"ttflui TIOCFLUSH","",0);
  9128.     ioctl(fd,TIOCFLUSH,0);
  9129. #endif /* ANYBSD */
  9130. #else                    /* All others... */
  9131. /*
  9132.   No system call (that we know about) for input buffer flushing.
  9133.   So see how many there are and read them in a loop, using ttinc().
  9134.   ttinc() is buffered, so we're not getting charged with a system call
  9135.   per character, just a function call.
  9136. */
  9137.     if ((n = ttchk()) > 0) {
  9138.     debug(F101,"ttflui read loop","",n);
  9139.     while ((n--) && ttinc(0) > 0) ;
  9140.     }
  9141. #endif /* TIOCFLUSH */
  9142. #endif /* ATTSV */
  9143. #endif /* POSIX */
  9144. #ifdef Plan9
  9145. #define POSIX
  9146. #endif /* Plan9 */
  9147. #endif /* BSD44 */
  9148. #endif /* aegis */
  9149.     return(0);
  9150. }
  9151.  
  9152. int
  9153. ttfluo() {                /* Flush output buffer */
  9154.     int fd;
  9155. #ifdef NETCMD
  9156.     if (ttpipe)
  9157.       fd = fdout;
  9158.     else
  9159. #endif /* NETCMD */
  9160.       fd = ttyfd;
  9161.  
  9162. #ifdef Plan9
  9163.     return 0;
  9164. #else
  9165. #ifdef POSIX
  9166.     return(tcflush(fd,TCOFLUSH));
  9167. #else
  9168. #ifdef OXOS
  9169.     return(ioctl(fd,TCFLSH,1));
  9170. #else
  9171.     return(0);                /* All others, nothing */
  9172. #endif /* OXOS */
  9173. #endif /* POSIX */
  9174. #endif /* Plan9 */
  9175. }
  9176.  
  9177. /* Interrupt Functions */
  9178.  
  9179. /* Set up terminal interrupts on console terminal */
  9180.  
  9181. #ifndef FIONREAD            /* We don't need esctrp() */
  9182. #ifndef SELECT                /* if we have any of these... */
  9183. #ifndef CK_POLL
  9184. #ifndef RDCHK
  9185.  
  9186. #ifndef OXOS
  9187. #ifdef SVORPOSIX
  9188. SIGTYP
  9189. esctrp(foo) int foo; {            /* trap console escapes (^\) */
  9190.     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
  9191.     conesc = 1;
  9192.     debug(F101,"esctrp caught SIGQUIT","",conesc);
  9193. }
  9194. #endif /* SVORPOSIX */
  9195. #endif /* OXOS */
  9196.  
  9197. #ifdef V7
  9198. #ifndef MINIX2
  9199. SIGTYP
  9200. esctrp(foo) int foo; {            /* trap console escapes (^\) */
  9201.     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
  9202.     conesc = 1;
  9203.     debug(F101,"esctrp caught SIGQUIT","",conesc);
  9204. }
  9205. #endif /* MINIX2 */
  9206. #endif /* V7 */
  9207.  
  9208. #ifdef C70
  9209. SIGTYP
  9210. esctrp(foo) int foo; {            /* trap console escapes (^\) */
  9211.     conesc = 1;
  9212.     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
  9213. }
  9214. #endif /* C70 */
  9215.  
  9216. #endif /* RDCHK */
  9217. #endif /* CK_POLL */
  9218. #endif /* SELECT */
  9219. #endif /* FIONREAD */
  9220.  
  9221. /*  C O N B G T  --  Background Test  */
  9222.  
  9223. static int jc = 0;            /* 0 = no job control */
  9224.  
  9225. /*
  9226.   Call with flag == 1 to prevent signal test, which can not be expected
  9227.   to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
  9228.  
  9229.   Call with flag == 0 to use the signal test, but only if the process-group
  9230.   test fails, as it does on some UNIX systems, where getpgrp() is buggy,
  9231.   requires an argument when the man page says it doesn't, or vice versa.
  9232.  
  9233.   If flag == 0 and the process-group test fails, then we determine background
  9234.   status simply (but not necessarily reliably) from isatty().
  9235.  
  9236.   conbgt() sets the global backgrd = 1 if we appear to be in the background,
  9237.   and to 0 if we seem to be in the foreground.  conbgt() is highly prone to
  9238.   misbehavior.
  9239. */
  9240. VOID
  9241. conbgt(flag) int flag; {
  9242.     int x = -1,                /* process group or SIGINT test */
  9243.         y = 0;                /* isatty() test */
  9244. /*
  9245.   Check for background operation, even if not running on real tty, so that
  9246.   background flag can be set correctly.  If background status is detected,
  9247.   then Kermit will not issue its interactive prompt or most messages.
  9248.   If your prompt goes away, you can blame (and fix?) this function.
  9249. */
  9250.  
  9251. /* Use process-group test if possible. */
  9252.  
  9253. #ifdef POSIX                /* We can do it in POSIX */
  9254. #define PGROUP_T
  9255. #else
  9256. #ifdef BSD4                /* and in BSD 4.x. */
  9257. #define PGROUP_T
  9258. #else
  9259. #ifdef HPUXJOBCTL            /* and in most HP-UX's */
  9260. #define PGROUP_T
  9261. #else
  9262. #ifdef TIOCGPGRP            /* and anyplace that has this ioctl. */
  9263. #define PGROUP_T
  9264. #endif /* TIOCGPGRP */
  9265. #endif /* HPUXJOBCTL */
  9266. #endif /* BSD4 */
  9267. #endif /* POSIX */
  9268.  
  9269. #ifdef MIPS                /* Except if it doesn't work... */
  9270. #undef PGROUP_T
  9271. #endif /* MIPS */
  9272.  
  9273. #ifdef MINIX
  9274. #undef PGROUP_T
  9275. #endif    /* MINIX */
  9276.  
  9277. #ifdef PGROUP_T
  9278. /*
  9279.   Semi-reliable process-group test.  Check whether this process's group is
  9280.   the same as the controlling terminal's process group.  This works if the
  9281.   getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
  9282. */
  9283.     PID_T mypgrp = (PID_T)0;        /* Kermit's process group */
  9284.     PID_T ctpgrp = (PID_T)0;        /* The terminal's process group */
  9285. #ifndef _POSIX_SOURCE
  9286. /*
  9287.   The getpgrp() prototype is obtained from system header files for POSIX
  9288.   and Sys V R4 compilations.  Other systems, who knows.  Some complain about
  9289.   a duplicate declaration here, others don't, so it's safer to leave it in
  9290.   if we don't know for certain.
  9291. */
  9292. #ifndef SVR4
  9293. #ifndef PS2AIX10
  9294. #ifndef HPUX9
  9295.     extern PID_T getpgrp();
  9296. #endif /* HPUX9 */
  9297. #endif /* PS2AIX10 */
  9298. #endif /* SVR4 */
  9299. #endif /* _POSIX_SOURCE */
  9300.  
  9301. /* Get my process group. */
  9302.  
  9303. #ifdef SVR3 /* Maybe this should be ATTSV? */
  9304. /* This function is not described in SVID R2 */
  9305.     mypgrp = getpgrp();
  9306.     /* debug(F101,"ATTSV conbgt process group","",(int) mypgrp); */
  9307. #else
  9308. #ifdef POSIX
  9309.     mypgrp = getpgrp();
  9310.     /* debug(F101,"POSIX conbgt process group","",(int) mypgrp); */
  9311. #else
  9312. #ifdef OSFPC
  9313.     mypgrp = getpgrp();
  9314.     /* debug(F101,"OSF conbgt process group","",(int) mypgrp); */
  9315. #else
  9316. #ifdef QNX
  9317.     mypgrp = getpgrp();
  9318.     /* debug(F101,"QNX conbgt process group","",(int) mypgrp); */
  9319. #else
  9320. #ifdef OSF32                /* (was OSF40) */
  9321.     mypgrp = getpgrp();
  9322.     /* debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp); */
  9323. #else /* BSD, V7, etc */
  9324. #ifdef MINIX2
  9325.     mypgrp = getpgrp();
  9326. #else
  9327.     mypgrp = getpgrp(0);
  9328. #endif /* MINIX2 */
  9329.     /* debug(F101,"BSD conbgt process group","",(int) mypgrp); */
  9330. #endif /* OSF32 */
  9331. #endif /* QNX */
  9332. #endif /* OSFPC */
  9333. #endif /* POSIX */
  9334. #endif /* SVR3 */
  9335.  
  9336. #ifdef MINIX
  9337.     /* MINIX does not support job control so Kermit is always in foreground */
  9338.     x = 0;
  9339.  
  9340. #else  /* Not MINIX */
  9341.  
  9342. /* Now get controlling tty's process group */
  9343. #ifdef BSD44ORPOSIX
  9344.     ctpgrp = tcgetpgrp(1);        /* The POSIX way */
  9345.     /* debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); */
  9346. #else
  9347.     ioctl(1, TIOCGPGRP, &ctpgrp);    /* Or the BSD way */
  9348.    /* debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); */
  9349. #endif /* BSD44ORPOSIX */
  9350.  
  9351.     if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
  9352.       x = (mypgrp == ctpgrp) ? 0 : 1;    /* If they differ, then background. */
  9353.     else x = -1;            /* If error, remember. */
  9354.     debug(F101,"conbgt process group test","",x);
  9355. #endif /* PGROUP_T */
  9356. #endif    /* MINIX */
  9357.  
  9358. /* Try to see if job control is available */
  9359.  
  9360. #ifdef NOJC                /* User override */
  9361.     jc = 0;                /* No job control allowed */
  9362.     debug(F111,"NOJC","jc",jc);
  9363. #else
  9364. #ifdef BSD44
  9365.     jc = 1;
  9366. #else
  9367. #ifdef SVR4ORPOSIX            /* POSIX actually tells us */
  9368.     debug(F100,"SVR4ORPOSIX jc test...","",0);
  9369. #ifdef _SC_JOB_CONTROL
  9370. #ifdef __bsdi__
  9371.     jc = 1;
  9372. #else
  9373. #ifdef __386BSD__
  9374.     jc = 1;
  9375. #else
  9376.     jc = sysconf(_SC_JOB_CONTROL);    /* Whatever system says */
  9377.     if (jc < 0) {
  9378.     debug(F101,"sysconf fails, jcshell","",jcshell);
  9379.     jc = (jchdlr == SIG_DFL) ? 1 : 0;
  9380.     } else
  9381.       debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
  9382. #endif /* __386BSD__ */
  9383. #endif /* __bsdi__ */
  9384. #else
  9385. #ifdef _POSIX_JOB_CONTROL
  9386.     jc = 1;                /* By definition */
  9387.     debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
  9388. #else
  9389.     jc = 0;                /* Assume job control not allowed */
  9390.     debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
  9391. #endif /* _POSIX_JOB_CONTROL */
  9392. #endif /* _SC_JOB_CONTROL */
  9393. #else
  9394. #ifdef BSD4
  9395.     jc = 1;                /* Job control allowed */
  9396.     debug(F111,"BSD job control","jc",jc);
  9397. #else
  9398. #ifdef SVR3JC
  9399.     jc = 1;                /* JC allowed */
  9400.     debug(F111,"SVR3 job control","jc",jc);
  9401. #else
  9402. #ifdef OXOS
  9403.     jc = 1;                /* JC allowed */
  9404.     debug(F111,"X/OS job control","jc",jc);
  9405. #else
  9406. #ifdef HPUX9
  9407.     jc = 1;                /* JC allowed */
  9408.     debug(F111,"HP-UX 9.0 job control","jc",jc);
  9409. #else
  9410. #ifdef HPUX10
  9411.     jc = 1;                /* JC allowed */
  9412.     debug(F111,"HP-UX 10.0 job control","jc",jc);
  9413. #else
  9414.     jc = 0;                /* JC not allowed */
  9415.     debug(F111,"job control catch-all","jc",jc);
  9416. #endif /* HPUX10 */
  9417. #endif /* HPUX9 */
  9418. #endif /* OXOS */
  9419. #endif /* SVR3JC */
  9420. #endif /* BSD4 */
  9421. #endif /* SVR4ORPOSIX */
  9422. #endif /* BSD44 */
  9423. #endif /* NOJC */
  9424.     debug(F101,"conbgt jc","",jc);
  9425. #ifndef NOJC
  9426.     debug(F101,"conbgt jcshell","",jcshell);
  9427. /*
  9428.   At this point, if jc == 1 but jcshell == 0, it means that the OS supports
  9429.   job control, but the shell or other process we are running under does not
  9430.   (jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
  9431.   will come of it.  So...
  9432. */
  9433.     if (jc < 0) jc = 0;
  9434.     if (jc > 0 && jcshell == 0) jc = 0;
  9435. #endif /* NOJC */
  9436.  
  9437. /*
  9438.   Another background test.
  9439.   Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
  9440.   which is done by the shell (sh) if the program is started with '&'.
  9441.   Unfortunately, this is NOT done by csh or ksh so watch out!
  9442.   Note, it's safe to set SIGINT to SIG_IGN here, because further down
  9443.   we always set it to something else.
  9444.   Note: as of 16 Jul 1999, we also skip this test if we set SIGINT to
  9445.   SIG_IGN ourselves.
  9446. */
  9447.     if (x < 0 && !flag && !sigint_ign) { /* Didn't get good results above... */
  9448.  
  9449.     SIGTYP (*osigint)();
  9450.  
  9451.     osigint = signal(SIGINT,SIG_IGN);    /* What is SIGINT set to? */
  9452.     sigint_ign = 1;
  9453.     x = (osigint == SIG_IGN) ? 1 : 0;    /* SIG_IGN? */
  9454.     /* debug(F101,"conbgt osigint","",osigint); */
  9455.     /* debug(F101,"conbgt signal test","",x); */
  9456.     }
  9457.  
  9458. /* Also check to see if we're running with redirected stdio. */
  9459. /* This is not really background operation, but we want to act as though */
  9460. /* it were. */
  9461.  
  9462. #ifdef IKSD
  9463.     if (inserver) {            /* Internet Kermit Server */
  9464.     backgrd = 0;            /* is not in the background */
  9465.     return;
  9466.     }
  9467. #endif /* IKSD */
  9468.  
  9469.     y = (isatty(0) && isatty(1)) ? 1 : 0;
  9470.     debug(F101,"conbgt isatty test","",y);
  9471.  
  9472. #ifdef BSD29
  9473. /* The process group and/or signal test doesn't work under these... */
  9474.     backgrd = !y;
  9475. #else
  9476. #ifdef sxaE50
  9477.     backgrd = !y;
  9478. #else
  9479. #ifdef MINIX
  9480.     backgrd = !y;
  9481. #else
  9482. #ifdef MINIX2
  9483.     backgrd = !y;
  9484. #else
  9485.     if (x > -1)
  9486.       backgrd = (x || !y) ? 1 : 0;
  9487.     else backgrd = !y;
  9488. #endif /* BSD29 */
  9489. #endif /* sxaE50 */
  9490. #endif /* MINIX */
  9491. #endif /* MINIX2 */
  9492.     debug(F101,"conbgt backgrd","",backgrd);
  9493. }
  9494.  
  9495. /*  C O N I N T  --  Console Interrupt setter  */
  9496.  
  9497. /*
  9498.   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
  9499.   Second arg is pointer to function to handle SIGTSTP (suspend).
  9500. */
  9501.  
  9502. VOID                    /* Set terminal interrupt traps. */
  9503. #ifdef CK_ANSIC
  9504. #ifdef apollo
  9505. conint(f,s) SIGTYP (*f)(), (*s)();
  9506. #else
  9507. conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
  9508. #endif /* apollo */
  9509. #else
  9510. conint(f,s) SIGTYP (*f)(), (*s)();
  9511. #endif /* CK_ANSIC */
  9512. /* conint */ {
  9513.  
  9514.     debug(F101,"conint conistate","",conistate);
  9515.  
  9516.     conbgt(0);                /* Do background test. */
  9517.  
  9518. /* Set the desired handlers for hangup and software termination. */
  9519.  
  9520. #ifdef SIGTERM
  9521.     signal(SIGTERM,f);                  /* Software termination */
  9522. #endif /* SIGTERM */
  9523.  
  9524. /*
  9525.   Prior to July 1999 we used to call sighup() here but now it's called in
  9526.   sysinit() so SIGHUP can be caught during execution of the init file or
  9527.   a kerbang script.
  9528. */
  9529.  
  9530. /* Now handle keyboard stop, quit, and interrupt signals. */
  9531. /* Check if invoked in background -- if so signals set to be ignored. */
  9532. /* However, if running under a job control shell, don't ignore them. */
  9533. /* We won't be getting any, as we aren't in the terminal's process group. */
  9534.  
  9535.     debug(F101,"conint backgrd","",backgrd);
  9536.     debug(F101,"conint jc","",jc);
  9537.  
  9538.     if (backgrd && !jc) {        /* In background, ignore signals */
  9539.     debug(F101,"conint background ignoring signals, jc","",jc);
  9540. #ifdef SIGTSTP
  9541.         signal(SIGTSTP,SIG_IGN);        /* Keyboard stop */
  9542. #endif /* SIGTSTP */
  9543.         signal(SIGQUIT,SIG_IGN);        /* Keyboard quit */
  9544.         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
  9545.     sigint_ign = 1;
  9546.     conistate = CONI_NOI;
  9547.     } else {                /* Else in foreground or suspended */
  9548.     debug(F101,"conint foreground catching signals, jc","",jc);
  9549.         signal(SIGINT,f);               /* Catch terminal interrupt */
  9550.     sigint_ign = (f == SIG_IGN) ? 1 : 0;
  9551.  
  9552. #ifdef SIGTSTP                /* Keyboard stop (suspend) */
  9553.     /* debug(F101,"conint SIGSTSTP","",s); */
  9554.     if (s == NULL) s = SIG_DFL;
  9555. #ifdef NOJC                /* No job control allowed. */
  9556.     signal(SIGTSTP,SIG_IGN);
  9557. #else                    /* Job control allowed */
  9558.     if (jc)                /* if available. */
  9559.       signal(SIGTSTP,s);
  9560.     else
  9561.       signal(SIGTSTP,SIG_IGN);
  9562. #endif /* NOJC */
  9563. #endif /* SIGTSTP */
  9564.  
  9565. #ifndef OXOS
  9566. #ifdef SVORPOSIX
  9567. #ifndef FIONREAD            /* Watch out, we don't know this... */
  9568. #ifndef SELECT
  9569. #ifndef CK_POLL
  9570. #ifndef RDCHK
  9571.         signal(SIGQUIT,esctrp);         /* Quit signal, Sys III/V. */
  9572. #endif /* RDCHK */
  9573. #endif /* CK_POLL */
  9574. #endif /* SELECT */
  9575. #endif /* FIONREAD */
  9576.         if (conesc) conesc = 0;         /* Clear out pending escapes */
  9577. #else
  9578. #ifdef V7
  9579.         signal(SIGQUIT,esctrp);         /* V7 like Sys III/V */
  9580.         if (conesc) conesc = 0;
  9581. #else
  9582. #ifdef aegis
  9583.         signal(SIGQUIT,f);              /* Apollo, catch it like others. */
  9584. #else
  9585.         signal(SIGQUIT,SIG_IGN);        /* Others, ignore like 4D & earlier. */
  9586. #endif /* aegis */
  9587. #endif /* V7 */
  9588. #endif /* SVORPOSIX */
  9589. #endif /* OXOS */
  9590.     conistate = CONI_INT;
  9591.     }
  9592. }
  9593.  
  9594.  
  9595. /*  C O N N O I  --  Reset console terminal interrupts */
  9596.  
  9597. VOID
  9598. connoi() {                              /* Console-no-interrupts */
  9599.  
  9600.     debug(F101,"connoi conistate","",conistate);
  9601. #ifdef SIGTSTP
  9602.     signal(SIGTSTP,SIG_IGN);        /* Suspend */
  9603. #endif /* SIGTSTP */
  9604.     conint(SIG_IGN,SIG_IGN);        /* Interrupt */
  9605.     sigint_ign = 1;            /* Remember we did this ourselves */
  9606. #ifdef SIGQUIT
  9607.     signal(SIGQUIT,SIG_IGN);        /* Quit */
  9608. #endif /* SIGQUIT */
  9609. #ifdef SIGTERM
  9610.     signal(SIGTERM,SIG_IGN);        /* Term */
  9611. #endif /* SIGTERM */
  9612.     conistate = CONI_NOI;
  9613. }
  9614.  
  9615. /*  I N I T R A W Q  --  Set up to read /dev/kmem for character count.  */
  9616.  
  9617. #ifdef  V7
  9618. /*
  9619.  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
  9620.  eliminates blocking on a read, because we can read /dev/kmem to get the
  9621.  number of characters available for raw input.  If your system can't
  9622.  or you won't let the world read /dev/kmem then you must figure out a
  9623.  different way to do the counting of characters available, or else replace
  9624.  this by a dummy function that always returns 0.
  9625. */
  9626. /*
  9627.  * Call this routine as: initrawq(tty)
  9628.  * where tty is the file descriptor of a terminal.  It will return
  9629.  * (as a char *) the kernel-mode memory address of the rawq character
  9630.  * count, which may then be read.  It has the side-effect of flushing
  9631.  * input on the terminal.
  9632.  */
  9633. /*
  9634.  * John Mackin, Physiology Dept., University of Sydney (Australia)
  9635.  * ...!decvax!mulga!physiol.su.oz!john
  9636.  *
  9637.  * Permission is hereby granted to do anything with this code, as
  9638.  * long as this comment is retained unmodified and no commercial
  9639.  * advantage is gained.
  9640.  */
  9641. #ifndef MINIX
  9642. #ifndef MINIX2
  9643. #ifndef COHERENT
  9644. #include <a.out.h>
  9645. #include <sys/proc.h>
  9646. #endif /* COHERENT */
  9647. #endif /* MINIX2 */
  9648. #endif /* MINIX */
  9649.  
  9650. #ifdef COHERENT
  9651. #include <l.out.h>
  9652. #include <sys/proc.h>
  9653. #endif /* COHERENT */
  9654.  
  9655. char *
  9656. initrawq(tty) int tty; {
  9657. #ifdef MINIX
  9658.     return(0);
  9659. #else
  9660. #ifdef MINIX2
  9661.     return(0);
  9662. #else
  9663. #ifdef UTS24
  9664.     return(0);
  9665. #else
  9666. #ifdef BSD29
  9667.     return(0);
  9668. #else
  9669.     long lseek();
  9670.     static struct nlist nl[] = {
  9671.         {PROCNAME},
  9672.         {NPROCNAME},
  9673.         {""}
  9674.     };
  9675.     static struct proc *pp;
  9676.     char *qaddr, *p, c;
  9677.     int m;
  9678.     PID_T pid, me;
  9679.     NPTYPE xproc;                       /* Its type is defined in makefile. */
  9680.     int catch();
  9681.  
  9682.     me = getpid();
  9683.     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
  9684.     nlist(BOOTNAME, nl);
  9685.     if (nl[0].n_type == 0) err("proc array");
  9686.  
  9687.     if (nl[1].n_type == 0) err("nproc");
  9688.  
  9689.     lseek(m, (long)(nl[1].n_value), 0);
  9690.     read (m, &xproc, sizeof(xproc));
  9691.     saval = signal(SIGALRM, catch);
  9692.     if ((pid = fork()) == 0) {
  9693.         while(1)
  9694.             read(tty, &c, 1);
  9695.     }
  9696.     alarm(2);
  9697.  
  9698.     if(setjmp(jjbuf) == 0) {
  9699.         while(1)
  9700.       read(tty, &c, 1);
  9701.     }
  9702.     signal(SIGALRM, SIG_DFL);
  9703.  
  9704. #ifdef DIRECT
  9705.     pp = (struct proc *) nl[0].n_value;
  9706. #else
  9707.     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
  9708.     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
  9709. #endif
  9710.     lseek(m, (long)(nl[1].n_value), 0);
  9711.     read(m, &xproc, sizeof(xproc));
  9712.  
  9713.     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
  9714.     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
  9715.     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
  9716.         err("read proc table");
  9717.     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
  9718.         if (pp -> p_pid == (short) pid) goto iout;
  9719.     }
  9720.     err("no such proc");
  9721.  
  9722. iout:
  9723.     close(m);
  9724.     qaddr = (char *)(pp -> p_wchan);
  9725.     free (p);
  9726.     kill(pid, SIGKILL);
  9727.     wait((WAIT_T *)0);
  9728.     return (qaddr);
  9729. #endif
  9730. #endif
  9731. #endif
  9732. #endif
  9733. }
  9734.  
  9735. /*  More V7-support functions...  */
  9736.  
  9737. static VOID
  9738. err(s) char *s; {
  9739.     char buf[200];
  9740.  
  9741.     ckmakmsg(buf,200,"fatal error in initrawq: ", s, NULL, NULL);
  9742.     perror(buf);
  9743.     doexit(1,-1);
  9744. }
  9745.  
  9746. static VOID
  9747. catch(foo) int foo; {
  9748.     longjmp(jjbuf, -1);
  9749. }
  9750.  
  9751.  
  9752. /*  G E N B R K  --  Simulate a modem break.  */
  9753.  
  9754. #ifdef MINIX
  9755. #define BSPEED B110
  9756. #else
  9757. #ifdef MINIX2
  9758. #define BSPEED B110
  9759. #else
  9760. #define BSPEED B150
  9761. #endif /* MINIX2 */
  9762. #endif /* MINIX */
  9763.  
  9764. #ifndef MINIX2
  9765. VOID
  9766. genbrk(fn,msec) int fn, msec; {
  9767.     struct sgttyb ttbuf;
  9768.     int ret, sospeed, x, y;
  9769.  
  9770.     ret = ioctl(fn, TIOCGETP, &ttbuf);
  9771.     sospeed = ttbuf.sg_ospeed;
  9772.     ttbuf.sg_ospeed = BSPEED;
  9773.     ret = ioctl(fn, TIOCSETP, &ttbuf);
  9774.     y = (int)strlen(brnuls);
  9775.     x = ( BSPEED * 100 ) / msec;
  9776.     if (x > y) x = y;
  9777.     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
  9778.     ttbuf.sg_ospeed = sospeed;
  9779.     ret = ioctl(fn, TIOCSETP, &ttbuf);
  9780.     ret = write(fn, "@", 1);
  9781.     return;
  9782. }
  9783. #endif /* MINIX2 */
  9784.  
  9785. #ifdef MINIX2
  9786. int
  9787. genbrk(fn,msec) int fn, msec; {
  9788.     struct termios ttbuf;
  9789.     int ret, x, y;
  9790.     speed_t sospeed;
  9791.  
  9792.     ret = tcgetattr(fn, &ttbuf);
  9793.     sospeed = ttbuf.c_ospeed;
  9794.     ttbuf.c_ospeed = BSPEED;
  9795.     ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
  9796.     y = (int)strlen(brnuls);
  9797.     x = ( BSPEED * 100 ) / msec;
  9798.     if (x > y) x = y;
  9799.     ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
  9800.     ttbuf.c_ospeed = sospeed;
  9801.     ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
  9802.     ret = write(fn, "@", 1);
  9803.     return ret;
  9804. }
  9805. #endif /* MINIX2 */
  9806. #endif /* V7 */
  9807.  
  9808. /*
  9809.   I N C H K  --  Check if chars waiting to be read on given file descriptor.
  9810.  
  9811.   This routine is a merger of ttchk() and conchk().
  9812.   Call with:
  9813.     channel == 0 to check console.
  9814.     channel == 1 to check communications connection.
  9815.   and:
  9816.     fd = file descriptor.
  9817.   Returns:
  9818.    >= 0: number of characters waiting, 0 or greater,
  9819.      -1: on any kind of error,
  9820.      -2: if there is (definitely) no connection.
  9821.   Note: In UNIX we don't have to call nettchk() because a socket
  9822.   file descriptor works just like in serial i/o, ioctls and all.
  9823.   (But this will change if we add non-file-descriptor channels,
  9824.   such as IBM X.25 for AIX...)
  9825. */
  9826. static int
  9827. in_chk(channel, fd) int channel, fd; {
  9828.     int x, n = 0;            /* Workers, n = return value */
  9829.     extern int clsondisc;        /* Close on disconnect */
  9830. /*
  9831.   The first section checks to make sure we have a connection,
  9832.   but only if we're in local mode.
  9833. */
  9834. #ifdef DEBUG
  9835.     if (deblog) {
  9836.     debug(F111,"in_chk entry",ckitoa(fd),channel);
  9837.     debug(F101,"in_chk ttyfd","",ttyfd);
  9838.     debug(F101,"in_chk ttpty","",ttpty);
  9839.     }
  9840. #endif /* DEBUG */
  9841. /*
  9842.   But don't say connection is gone if we have any buffered-stuff.
  9843. */
  9844. #ifdef TTLEBUF
  9845.     debug(F101,"in_chk ttpush","",ttpush);
  9846.     if (channel == 1) {
  9847.     if (ttpush >= 0)
  9848.       n++;
  9849.     n += le_inbuf();
  9850.     if (n > 0)
  9851.       return(n);
  9852.     }
  9853. #endif /* TTLEBUF */
  9854.  
  9855. #ifdef NETPTY
  9856. #ifdef HAVE_PTYTRAP
  9857.     /* Special handling for HP-UX pty i/o */
  9858.     if (ttpty && pty_trap_pending(ttyfd) > 0) {
  9859.         if (pty_trap_handler(ttyfd) > 0) {
  9860.             ttclos(0);
  9861.             return(-2);
  9862.         }
  9863.     }
  9864. #endif /* HAVE_PTYTRAP */
  9865. #endif /* NETPTY */
  9866.  
  9867.     if (channel) {            /* Checking communications channel */
  9868.     if (ttyfd < 0) {        /* No connection */
  9869.       return(-2);            /* That's what this means */
  9870.     } else if (xlocal &&        /* In local mode */
  9871.            (!netconn        /* Serial connection or */
  9872. #ifdef TN_COMPORT
  9873.             || istncomport()    /* Telnet Com Port */
  9874. #endif /* TN_COMPORT */
  9875.            ) && ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
  9876. #ifdef COMMENT
  9877. #ifdef MYREAD
  9878. /*
  9879.   Seems like this would be a good idea but it prevents C-Kermit from
  9880.   popping back to the prompt automatically when carrier drops.  However,
  9881.   commenting this out prevents us from seeing the NO CARRIER message.
  9882.   Needs more work...
  9883. */
  9884.            && my_count < 1    /* Nothing in our internal buffer */
  9885. #endif /* MYREAD */
  9886. #endif /* COMMENT */
  9887.            ) {
  9888.         int x;
  9889.         x = ttgmdm();        /* So get modem signals */
  9890.         debug(F101,"in_chk close-on-disconnect","",clsondisc);
  9891.         if (x > -1) {        /* Check for carrier */
  9892.         if (!(x & BM_DCD)) {    /* No carrier */
  9893.             debug(F101,"in_chk carrier lost","",x);
  9894.             if (clsondisc)    /* If "close-on-disconnect" */
  9895.               ttclos(0);    /* close device & release lock. */
  9896.             return(-2);        /* This means "disconnected" */
  9897.         }
  9898.         /* In case I/O to device after CD dropped always fails */
  9899.         /* as in Debian Linux 2.1 and Unixware 2.1... */
  9900.         } else {
  9901.             debug(F101,"in_chk ttgmdm I/O error","",errno);
  9902.             debug(F101,"in_chk ttgmdm gotsigs","",gotsigs);
  9903.             if (gotsigs) {        /* If we got signals before... */
  9904.             if (errno == 5 || errno == 6) { /* I/O error etc */
  9905.                 if (clsondisc)    /* like when modem hangs up */
  9906.               ttclos(0);
  9907.             return(-2);
  9908.             }
  9909.         }
  9910.         /* If we never got modem signals successfully on this */
  9911.         /* connection before, we can't conclude that THIS failure */
  9912.         /* means the connection was lost. */
  9913.         return(0);
  9914.         }
  9915.     }
  9916.     }
  9917.  
  9918. /* We seem to have a connection so now see if any bytes are waiting on it */
  9919.  
  9920. #ifdef CK_SSL
  9921.     if (ssl_active_flag || tls_active_flag) {
  9922.         n += SSL_pending(ssl_active_flag?ssl_con:tls_con);
  9923.         debug(F101,"in_chk SSL_pending","",n);
  9924.         if (n < 0) {
  9925.             ttclos(0);
  9926.             return(-1);
  9927.         } else if (n > 0) {
  9928.             return(n);
  9929.         }
  9930.     }
  9931. #endif /* CK_SSL */
  9932. #ifdef RLOGCODE
  9933. #ifdef CK_KERBEROS
  9934.     /* It is not safe to read any data when using encrypted Klogin */
  9935.     if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN) {
  9936. #ifdef KRB4
  9937.         if (ttnproto == NP_EK4LOGIN) {
  9938.             n += krb4_des_avail(ttyfd);
  9939.             debug(F101,"in_chk krb4_des_avail","",n);
  9940.         }
  9941. #endif /* KRB4 */
  9942. #ifdef KRB5
  9943.         if (ttnproto == NP_EK5LOGIN) {
  9944.             n += krb5_des_avail(ttyfd);
  9945.             debug(F101,"in_chk krb5_des_avail","",n);
  9946.         }
  9947. #ifdef KRB5_U2U
  9948.         if (ttnproto == NP_K5U2U) {
  9949.             n += krb5_u2u_avail(ttyfd);
  9950.             debug(F101,"in_chk krb5_des_avail","",n);
  9951.         }
  9952. #endif /* KRB5_U2U */
  9953. #endif /* KRB5 */
  9954.         if (n < 0)            /* Is this right? */
  9955.       return(-1);
  9956.         else
  9957.       return(n);
  9958.     }
  9959. #endif /* CK_KERBEROS */
  9960. #endif /* RLOGCODE */
  9961.  
  9962.     errno = 0;                /* Reset this so we log good info */
  9963. #ifdef FIONREAD
  9964.     x = ioctl(fd, FIONREAD, &n);    /* BSD and lots of others */
  9965. #ifdef DEBUG                /* (the more the better) */
  9966.     if (deblog) {
  9967.     debug(F101,"in_chk FIONREAD return code","",x);
  9968.     debug(F101,"in_chk FIONREAD count","",n);
  9969.     debug(F101,"in_chk FIONREAD errno","",errno);
  9970.     }
  9971. #endif /* DEBUG */
  9972. #else /* FIONREAD not defined */
  9973. /*
  9974.   Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
  9975.   with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
  9976.   portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
  9977.   that I looked at, but it is needed to prevent the call from blocking), and
  9978.   the msghdr struct differs from place to place, so we would need another
  9979.   avalanche of ifdefs.  Still, when FIONREAD is not available, this is the
  9980.   only other known method of asking the OS for the *number* of characters
  9981.   available for reading.
  9982. */
  9983. #ifdef V7                /* UNIX V7: look in kernel memory */
  9984. #ifdef MINIX
  9985.     n = 0;                /* But not in MINIX */
  9986. #else
  9987. #ifdef MINIX2
  9988.     n = 0;
  9989. #else
  9990.     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
  9991.     x = read(kmem[TTY], &n, sizeof(int));
  9992.     if (x != sizeof(int))
  9993.       n = 0;
  9994. #endif /* MINIX2 */
  9995. #endif /* MINIX */
  9996. #else /* Not V7 */
  9997. #ifdef PROVX1
  9998.     x = ioctl(fd, TIOCQCNT, &ttbuf);    /* DEC Pro/3xx Venix V.1 */
  9999.     n = ttbuf.sg_ispeed & 0377;        /* Circa 1984 */
  10000.     if (x < 0) n = 0;
  10001. #else
  10002. #ifdef MYREAD
  10003. /*
  10004.   Here we skip all the undependable and expensive calls below if we
  10005.   already have something in our internal buffer.  This tends to work quite
  10006.   nicely, so the only really bad case remaining is the one in which neither
  10007.   FIONREAD or MYREAD are defined, which is increasingly rare these days.
  10008. */
  10009.     if (channel != 0 && my_count > 0) {
  10010.     debug(F101,"in_chk buf my_count","",my_count);
  10011.     n = my_count;            /* n was 0 before we got here */
  10012.     return(n);
  10013.     }
  10014. #endif /* MYREAD */
  10015. /*
  10016.   rdchk(), select(), and poll() tell us *if* data is available to be read, but
  10017.   not how much, so these should be used only as a final resort.  Especially
  10018.   since these calls tend to add a lot overhead.
  10019. */
  10020. #ifdef RDCHK                /* This mostly SCO-specific */
  10021.     n = rdchk(fd);
  10022.     debug(F101,"in_chk rdchk","",n);
  10023. #else /* No RDCHK */
  10024. #ifdef SELECT
  10025. #ifdef Plan9
  10026.     /* Only allows select on the console ... don't ask */
  10027.     if (channel == 0)
  10028. #endif /* Plan9 */
  10029.       {
  10030.     fd_set rfds;            /* Read file descriptors */
  10031. #ifdef BELLV10
  10032.     FD_ZERO(rfds);            /* Initialize them */
  10033.     FD_SET(fd,rfds);        /* We want to look at this fd */
  10034. #else
  10035.     FD_ZERO(&rfds);            /* Initialize them */
  10036.     FD_SET(fd,&rfds);        /* We want to look at this fd */
  10037.     tv.tv_sec = tv.tv_usec = 0L;    /* A 0-valued timeval structure */
  10038. #endif /* BELLV10 */
  10039. #ifdef Plan9
  10040.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10041.     debug(F101,"in_chk Plan 9 select","",n);
  10042. #else
  10043. #ifdef BELLV10
  10044.     n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
  10045.     debug(F101,"in_chk BELLV10 select","",n);
  10046. #else
  10047. #ifdef BSD44
  10048.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10049.     debug(F101,"in_chk BSD44 select","",n);
  10050. #else
  10051. #ifdef BSD43
  10052.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10053.     debug(F101,"in_chk BSD43 select","",n);
  10054. #else
  10055. #ifdef SOLARIS
  10056.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10057.     debug(F101,"in_chk SOLARIS select","",n);
  10058. #else
  10059. #ifdef QNX6
  10060.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10061.     debug(F101,"in_chk QNX6 select","",n);
  10062. #else
  10063. #ifdef QNX
  10064.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10065.     debug(F101,"in_chk QNX select","",n);
  10066. #else
  10067. #ifdef COHERENT
  10068.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10069.     debug(F101,"in_chk COHERENT select","",n);
  10070. #else
  10071. #ifdef SVR4
  10072.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10073.     debug(F101,"in_chk SVR4 select","",n);
  10074. #else
  10075. #ifdef __linux__
  10076.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10077.     debug(F101,"in_chk LINUX select","",n);
  10078. #ifdef OSF
  10079.     n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
  10080.     debug(F101,"in_chk OSF select","",n);
  10081. #else
  10082.     n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
  10083.     debug(F101,"in_chk catchall select","",n);
  10084. #endif /* OSF */
  10085. #endif /* __linux__ */
  10086. #endif /* SVR4 */
  10087. #endif /* COHERENT */
  10088. #endif /* QNX */
  10089. #endif /* QNX6 */
  10090. #endif /* SOLARIS */
  10091. #endif /* BSD43 */
  10092. #endif /* BSD44 */
  10093. #endif /* BELLV10 */
  10094. #endif /* Plan9 */
  10095.     }
  10096. #else  /* Not SELECT */
  10097. #ifdef CK_POLL
  10098.     {
  10099.       struct pollfd pfd;
  10100.  
  10101.       pfd.fd = fd;
  10102.       pfd.events = POLLIN;
  10103.       pfd.revents = 0;
  10104.       n = poll(&pfd, 1, 0);
  10105.       debug(F101,"in_chk poll","",n);
  10106.       if ((n > 0) && (pfd.revents & POLLIN))
  10107.     n = 1;
  10108.     }
  10109. #endif /* CK_POLL */
  10110. #endif /* SELECT */
  10111. #endif /* RDCHK */
  10112. #endif /* PROVX1 */
  10113. #endif /* V7 */
  10114. #endif /* FIONREAD */
  10115.  
  10116. /* From here down, treat console and communication device differently... */
  10117.  
  10118.     if (channel == 0) {            /* Console */
  10119.  
  10120. #ifdef SVORPOSIX
  10121. #ifndef FIONREAD
  10122. #ifndef SELECT
  10123. #ifndef CK_POLL
  10124. #ifndef RDCHK
  10125. /*
  10126.   This is the hideous hack used in System V and POSIX systems that don't
  10127.   support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
  10128.   CONNECT-mode escape character is attached to SIGQUIT.  Used, obviously,
  10129.   only on the console.
  10130. */
  10131.     if (conesc) {            /* Escape character typed == SIGQUIT */
  10132.         debug(F100,"in_chk conesc","",conesc);
  10133.         conesc = 0;
  10134.         signal(SIGQUIT,esctrp);    /* Restore signal */
  10135.         n += 1;
  10136.     }
  10137. #endif /* RDCHK */
  10138. #endif /* CK_POLL */
  10139. #endif /* SELECT */
  10140. #endif /* FIONREAD */
  10141. #endif /* SVORPOSIX */
  10142.  
  10143.     return(n);            /* Done with console */
  10144.     }
  10145.  
  10146.     if (channel != 0) {            /* Communications connection */
  10147.  
  10148. #ifdef MYREAD
  10149. #ifndef FIONREAD
  10150. /*
  10151.   select() or rdchk(), etc, has told us that something is waiting, but we
  10152.   don't know how much.  So we do a read to get it and then we know.  Note:
  10153.   This read is NOT nonblocking if nothing is there (because of VMIN=1), but
  10154.   it should be safe in this case since the OS tells us at least one byte is
  10155.   waiting to be read, and MYREAD reads return as much as is there without
  10156.   waiting for any more.  Controlled tests on Solaris and Unixware (with
  10157.   FIONREAD deliberately undefined) show this to be true.
  10158. */
  10159.     debug(F101,"in_chk read my_count","",my_count);
  10160.     debug(F101,"in_chk read n","",n);
  10161.     if (n > 0 && my_count == 0) {
  10162.         /* This also catches disconnects etc */
  10163.         /* Do what mygetbuf does except don't grab a character */
  10164.         my_count = myfillbuf();
  10165.         my_item = -1;        /* ^^^ */
  10166.         debug(F101,"in_chk myfillbuf my_count","",my_count);
  10167.         if (my_count < 0)
  10168.           return(-1);
  10169.         else
  10170.           n = 0;            /* NB: n is replaced by my_count */
  10171.     }
  10172. #endif /* FIONREAD */
  10173. /*
  10174.   Here we add whatever we think is unread to what is still in our
  10175.   our internal buffer.  Thus the importance of setting n to 0 just above.
  10176. */
  10177.     debug(F101,"in_chk my_count","",my_count);
  10178.     debug(F101,"in_chk n","",n);
  10179.     if (my_count > 0)
  10180.       n += my_count;
  10181. #endif /* MYREAD */
  10182.     }
  10183.     debug(F101,"in_chk result","",n);
  10184.  
  10185.     /* Errors here don't prove the connection has dropped so just say 0 */
  10186.  
  10187.     return(n < 0 ? 0 : n);
  10188. }
  10189.  
  10190.  
  10191. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  10192.  
  10193. int
  10194. ttchk() {
  10195.     int fd;
  10196. #ifdef NETCMD
  10197.     if (ttpipe)
  10198.       fd = fdin;
  10199.     else
  10200. #endif /* NETCMD */
  10201.       fd = ttyfd;
  10202.     return(in_chk(1,fd));
  10203. }
  10204.  
  10205. /*  T T X I N  --  Get n characters from tty input buffer  */
  10206.  
  10207. /*  Returns number of characters actually gotten, or -1 on failure  */
  10208.  
  10209. /*  Intended for use only when it is known that n characters are actually */
  10210. /*  Available in the input buffer.  */
  10211.  
  10212. int
  10213. ttxin(n,buf) int n; CHAR *buf; {
  10214.     register int x = 0, c = -2;
  10215. #ifdef TTLEBUF
  10216.     register int i = 0;
  10217. #endif /* TTLEBUF */
  10218.     int fd;
  10219.  
  10220.     if (n < 1)                /* Nothing to do */
  10221.       return(0);
  10222.  
  10223. #ifdef TTLEBUF
  10224.     if (ttpush >= 0) {
  10225.         buf[0] = ttpush;        /* Put pushed char in buffer*/
  10226.         ttpush = -1;            /* Clear the push buffer */
  10227.         if (ttchk() > 0)
  10228.       return(ttxin(n-1, &buf[1]) + 1);
  10229.         else
  10230.       return(1);
  10231.     }
  10232.     if (le_data) {
  10233.         while (le_inbuf() > 0) {
  10234.         if (le_getchar(&buf[i])) {
  10235.                 i++;
  10236.                 n--;
  10237.             }
  10238.         }
  10239.         if (ttchk() > 0)
  10240.       return(ttxin(n,&buf[i])+i);
  10241.         else
  10242.       return(i);
  10243.     }
  10244. #endif /* TTLEBUF */
  10245.  
  10246. #ifdef NETCMD
  10247.     if (ttpipe)
  10248.       fd = fdin;
  10249.     else
  10250. #endif /* NETCMD */
  10251.       fd = ttyfd;
  10252.  
  10253. #ifdef SUNX25
  10254.     if (netconn && (ttnet == NET_SX25))    /* X.25 connection */
  10255.       return(x25xin(n,buf));
  10256. #endif /* SUNX25 */
  10257.  
  10258. #ifdef IBMX25
  10259.     /* riehm: possibly not needed. Test worked with normal reads and writes */
  10260.     if (netconn && (ttnet == NET_IX25))    { /* X.25 connection */
  10261.     x = x25xin(n,buf);
  10262.     if (x > 0) buf[x] = '\0';
  10263.     return(x);
  10264.     }
  10265. #endif /* IBMX25 */
  10266.  
  10267. #ifdef MYREAD
  10268.     debug(F101,"ttxin MYREAD","",n);
  10269.     while (x < n) {
  10270.     c = myread();
  10271.     if (c < 0) {
  10272.         debug(F101,"ttxin myread returns","",c);
  10273.         if (c == -3) x = -1;
  10274.         break;
  10275.         }
  10276.     buf[x++] = c & ttpmsk;
  10277. #ifdef RLOGCODE
  10278. #ifdef CK_KERBEROS
  10279.         /* It is impossible to know how many characters are waiting */
  10280.         /* to be read when you are using Encrypted Rlogin or SSL    */
  10281.         /* as the transport since the number of real data bytes     */
  10282.         /* can be greater or less than the number of bytes on the   */
  10283.         /* wire which is what ttchk() returns.                      */
  10284.         if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
  10285.       if (ttchk() <= 0)
  10286.         break;
  10287. #endif /* CK_KERBEROS */
  10288. #endif /* RLOGCODE */
  10289. #ifdef CK_SSL
  10290.         if (ssl_active_flag || tls_active_flag)
  10291.       if (ttchk() <= 0)
  10292.         break;
  10293. #endif /* CK_SSL */
  10294.     }
  10295. #else
  10296.     debug(F101,"ttxin READ","",n);
  10297.     x = read(fd,buf,n);
  10298.     for (c = 0; c < n; c++)        /* Strip any parity */
  10299.       buf[c] &= ttpmsk;
  10300. #endif /* MYREAD */
  10301.  
  10302.     debug(F101,"ttxin x","",x);        /* Done */
  10303.     if (x > 0) buf[x] = '\0';
  10304.     if (x < 0) x = -1;
  10305.     return(x);
  10306. }
  10307.  
  10308. /*  T T O L  --  Write string s, length n, to communication device.  */
  10309. /*
  10310.   Returns:
  10311.    >= 0 on success, number of characters actually written.
  10312.    -1 on failure.
  10313. */
  10314. #ifdef CK_ENCRYPTION
  10315. CHAR * xpacket = NULL;
  10316. int nxpacket = 0;
  10317. #endif /* CK_ENCRYPTION */
  10318.  
  10319. #define TTOLMAXT 5
  10320. int
  10321. ttol(s,n) int n; CHAR *s; {
  10322.     int x, len, tries, fd;
  10323. #ifdef CKXXCHAR
  10324.     extern int dblflag;            /* For SET SEND DOUBLE-CHARACTER */
  10325.     extern short dblt[];
  10326.     CHAR *p = NULL, *p2, *s2, c;
  10327.     int n2 = 0;
  10328. #endif /* CKXXCHAR */
  10329.  
  10330.     if (ttyfd < 0)            /* Not open? */
  10331.       return(-3);
  10332. #ifdef DEBUG
  10333.     if (deblog) {
  10334.     /* debug(F101,"ttol ttyfd","",ttyfd); */
  10335.     ckhexdump("ttol s",s,n);
  10336.     }
  10337. #endif /* DEBUG */
  10338.  
  10339. #ifdef NETCMD
  10340.     if (ttpipe)
  10341.       fd = fdout;
  10342.     else
  10343. #endif /* NETCMD */
  10344.       fd = ttyfd;
  10345.  
  10346. #ifdef CKXXCHAR
  10347. /*  Double any characters that must be doubled.  */
  10348.     debug(F101,"ttol dblflag","",dblflag);
  10349.     if (dblflag) {
  10350.     p = (CHAR *) malloc(n + n + 1);
  10351.     if (p) {
  10352.         s2 = s;
  10353.         p2 = p;
  10354.         n2 = 0;
  10355.         while (*s2) {
  10356.         c = *s2++;
  10357.         *p2++ = c;
  10358.         n2++;
  10359.         if (dblt[(unsigned) c] & 2) {
  10360.             *p2++ = c;
  10361.             n2++;
  10362.         }
  10363.         }
  10364.         s = p;
  10365.         n = n2;
  10366.         s[n] = '\0';
  10367.     }
  10368. #ifdef DEBUG
  10369.         ckhexdump("ttol doubled s",s,n);
  10370. #endif /* DEBUG */
  10371.     }
  10372. #endif /* CKXXCHAR */
  10373.  
  10374.     tries = TTOLMAXT;            /* Allow up to this many tries */
  10375.     len = n;                /* Remember original length */
  10376.  
  10377. #ifdef CK_ENCRYPTION
  10378. /*
  10379.   This is to avoid encrypting a packet that is already encrypted, e.g.
  10380.   when we resend a packet directly out of the packet buffer, and also to
  10381.   avoid encrypting a constant (literal) string, which can cause a memory
  10382.   fault.
  10383. */
  10384.     if (TELOPT_ME(TELOPT_ENCRYPTION)) {
  10385.     int x;
  10386.     if (nxpacket < n) {
  10387.         if (xpacket) {
  10388.         free(xpacket);
  10389.         xpacket = NULL;
  10390.         nxpacket = 0;
  10391.         }
  10392.         x = n > 10240 ? n : 10240;
  10393.         xpacket = (CHAR *)malloc(x);
  10394.         if (!xpacket) {
  10395.         fprintf(stderr,"ttol malloc failure\n");
  10396.         return(-1);
  10397.         } else
  10398.           nxpacket = x;
  10399.     }
  10400.     memcpy((char *)xpacket,(char *)s,n);
  10401.     s = xpacket;
  10402.     ck_tn_encrypt((char *)s,n);
  10403.     }
  10404. #endif /* CK_ENCRYPTION */
  10405.  
  10406.     while (n > 0 &&
  10407.        (tries-- > 0
  10408. #ifdef CK_ENCRYPTION
  10409.         /* keep trying if we are encrypting */
  10410.         || TELOPT_ME(TELOPT_ENCRYPTION)
  10411. #endif /* CK_ENCRYPTION */
  10412.             )) {            /* Be persistent */
  10413.     debug(F101,"ttol try","",TTOLMAXT - tries);
  10414. #ifdef BEOSORBEBOX
  10415.         if (netconn && !ttpipe && !ttpty)
  10416.       x = nettol((char *)s,n);    /* Write string to device */
  10417.         else
  10418. #endif /* BEOSORBEBOX */
  10419. #ifdef IBMX25
  10420.       if (ttnet == NET_IX25)
  10421.         /*
  10422.          * this is a more controlled way of writing to X25
  10423.          * STREAMS, however write should also work!
  10424.          */
  10425.         x = x25write(ttyfd, s, n);
  10426.       else
  10427. #endif /* IBMX25 */
  10428. #ifdef CK_SSL
  10429.         if (ssl_active_flag || tls_active_flag) {
  10430.         int error;
  10431.         /* Write using SSL */
  10432.                 ssl_retry:
  10433.         if (ssl_active_flag)
  10434.                   x = SSL_write(ssl_con, s, n);
  10435.         else
  10436.                   x = SSL_write(tls_con, s, n);
  10437.         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
  10438.                 case SSL_ERROR_NONE:
  10439.                     if (x == n)
  10440.               return(len);
  10441.                     s += x;
  10442.                     n -= x;
  10443.                     goto ssl_retry;
  10444.           case SSL_ERROR_WANT_WRITE:
  10445.           case SSL_ERROR_WANT_READ:
  10446.             x = 0;
  10447.             break;
  10448.           case SSL_ERROR_SYSCALL:
  10449.                     if (x != 0)
  10450.               return(-1);
  10451.           case SSL_ERROR_WANT_X509_LOOKUP:
  10452.           case SSL_ERROR_SSL:
  10453.           case SSL_ERROR_ZERO_RETURN:
  10454.           default:
  10455.             ttclos(0);
  10456.             return(-3);
  10457.         }
  10458.         } else
  10459. #endif /* CK_SSL */
  10460. #ifdef CK_KERBEROS
  10461. #ifdef KRB4
  10462. #ifdef RLOGCODE
  10463.         if (ttnproto == NP_EK4LOGIN) {
  10464.         return(krb4_des_write(ttyfd,s,n));
  10465.         } else
  10466. #endif /* RLOGCODE */
  10467. #endif /* KRB4 */
  10468. #ifdef KRB5
  10469. #ifdef RLOGCODE
  10470.             if (ttnproto == NP_EK5LOGIN) {
  10471.                 return(krb5_des_write(ttyfd,(char *)s,n,0));
  10472.             } else
  10473. #endif /* RLOGCODE */
  10474. #ifdef KRB5_U2U
  10475.             if (ttnproto == NP_K5U2U) {
  10476.                 return(krb5_u2u_write(ttyfd,(char *)s,n));
  10477.             } else
  10478. #endif /* KRB5_U2U */
  10479. #endif /* KRB5 */
  10480. #endif /* CK_KERBEROS */
  10481.           x = write(fd,s,n);    /* Write string to device */
  10482.  
  10483.     if (x == n) {            /* Worked? */
  10484.         debug(F101,"ttol ok","",x);    /* OK */
  10485. #ifdef CKXXCHAR
  10486.         if (p) free(p);
  10487. #endif /* CKXXCHAR */
  10488.         return(len);        /* Done */
  10489.     } else if (x < 0) {        /* No, got error? */
  10490.         debug(F101,"ttol write error","",errno);
  10491. #ifdef EWOULDBLOCK
  10492.         if (errno == EWOULDBLOCK) {
  10493.         msleep(10);
  10494.         continue;
  10495.         } else
  10496. #endif /* EWOULDBLOCK */
  10497. #ifdef TCPSOCKET
  10498.         if (netconn && ttnet == NET_TCPB) {
  10499.         debug(F101,"ttol TCP error","",errno);
  10500.         ttclos(0);        /* Close the connection. */
  10501.         x = -3;
  10502.         }
  10503. #endif /* TCPSOCKET */
  10504. #ifdef CKXXCHAR
  10505.         if (p) free(p);
  10506. #endif /* CKXXCHAR */
  10507.         return(x);
  10508.     } else {            /* No error, so partial success */
  10509.         debug(F101,"ttol partial","",x); /* This never happens */
  10510.         s += x;            /* Point to part not written yet */
  10511.         n -= x;            /* Adjust length */
  10512.         if (x > 0) msleep(10);    /* Wait 10 msec */
  10513.     }                /* Go back and try again */
  10514.     }
  10515. #ifdef CKXXCHAR
  10516.     if (p) free(p);
  10517. #endif /* CKXXCHAR */
  10518.     return(n < 1 ? len : -1);        /* Return the results */
  10519. }
  10520.  
  10521. /*  T T O C  --  Output a character to the communication line  */
  10522.  
  10523. /*
  10524.  This function should only be used for interactive, character-mode operations,
  10525.  like terminal connection, script execution, dialer i/o, where the overhead
  10526.  of the signals and alarms does not create a bottleneck.
  10527. */
  10528. int
  10529. #ifdef CK_ANSIC
  10530. ttoc(char c)
  10531. #else
  10532. ttoc(c) char c;
  10533. #endif /* CK_ANSIC */
  10534. /* ttoc */ {
  10535. #define TTOC_TMO 15            /* Timeout in case we get stuck */
  10536.     int xx, fd;
  10537.  
  10538.     if (ttyfd < 0)            /* Check for not open. */
  10539.       return(-1);
  10540.  
  10541. #ifdef NETCMD
  10542.     if (ttpipe)
  10543.       fd = fdout;
  10544.     else
  10545. #endif /* NETCMD */
  10546.       fd = ttyfd;
  10547.  
  10548.     c &= 0xff;
  10549.     /* debug(F101,"ttoc","",(CHAR) c); */
  10550.     saval = signal(SIGALRM,timerh);    /* Enable timer interrupt */
  10551.     xx = alarm(TTOC_TMO);        /* for this many seconds. */
  10552.     if (xx < 0) xx = 0;            /* Save old alarm value. */
  10553.     /* debug(F101,"ttoc alarm","",xx); */
  10554.     if (
  10555. #ifdef CK_POSIX_SIG
  10556.     sigsetjmp(sjbuf,1)
  10557. #else
  10558.     setjmp(sjbuf)
  10559. #endif /* CK_POSIX_SIG */
  10560.     ) {        /* Timer went off? */
  10561.     ttimoff();            /* Yes, cancel this alarm. */
  10562.     if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
  10563.         /* debug(F100,"ttoc timeout","",0); */
  10564. #ifdef NETCONN
  10565.     if (!netconn) {
  10566. #endif /* NETCONN */
  10567.         debug(F101,"ttoc timeout","",c);
  10568.         if (ttflow == FLO_XONX) {
  10569.         debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
  10570. #ifndef Plan9
  10571. #ifdef POSIX
  10572.         /* POSIX way to unstick. */
  10573.         debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
  10574. #else
  10575. #ifdef BSD4                /* Berkeley way to do it. */
  10576. #ifdef TIOCSTART
  10577. /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);".  Who knows? */
  10578.         {
  10579.           int x = 0;
  10580.           debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
  10581.         }
  10582. #endif /* TIOCSTART */
  10583. #endif /* BSD4 */
  10584.                     /* Is there a Sys V way to do this? */
  10585. #endif /* POSIX */
  10586. #endif /* Plan9 */
  10587.         }
  10588. #ifdef NETCONN
  10589.         }
  10590. #endif /* NETCONN */
  10591.     return(-1);            /* Return failure code. */
  10592.     } else {
  10593.         int rc;
  10594. #ifdef BEOSORBEBOX
  10595. #ifdef NETCONN
  10596.         if (netconn && !ttpipe && !ttpty)
  10597.       rc = nettoc(c);
  10598.         else
  10599. #endif /*  BEOSORBEBOX */
  10600. #endif /* NETCONN */
  10601. #ifdef CK_ENCRYPTION
  10602.       if (TELOPT_ME(TELOPT_ENCRYPTION))
  10603.         ck_tn_encrypt(&c,1);
  10604. #endif /* CK_ENCRYPTION */
  10605. #ifdef IBMX25
  10606.     /* riehm: maybe this isn't necessary after all. Test program
  10607.      * worked fine with data being sent and retrieved with normal
  10608.      * read's and writes!
  10609.      */
  10610.     if (ttnet == NET_IX25)
  10611.       rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
  10612.     else
  10613. #endif /* IBMX25 */
  10614. #ifdef CK_SSL
  10615.       if (ssl_active_flag || tls_active_flag) {
  10616.           int error;
  10617.           /* Write using SSL */
  10618.           if (ssl_active_flag)
  10619.                 rc = SSL_write(ssl_con, &c, 1);
  10620.           else
  10621.                 rc = SSL_write(tls_con, &c, 1);
  10622.           switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
  10623.         case SSL_ERROR_NONE:
  10624.           break;
  10625.         case SSL_ERROR_WANT_WRITE:
  10626.         case SSL_ERROR_WANT_READ:
  10627.           rc = 0;
  10628.           break;
  10629.         case SSL_ERROR_SYSCALL:
  10630.           if (rc != 0)
  10631.             return(-1);
  10632.         case SSL_ERROR_WANT_X509_LOOKUP:
  10633.         case SSL_ERROR_SSL:
  10634.         case SSL_ERROR_ZERO_RETURN:
  10635.         default:
  10636.           ttclos(0);
  10637.           return(-1);
  10638.           }
  10639.       } else
  10640. #endif /* CK_SSL */
  10641. #ifdef CK_KERBEROS
  10642. #ifdef KRB4
  10643. #ifdef RLOGCODE
  10644.       if (ttnproto == NP_EK4LOGIN) {
  10645.           rc = (krb4_des_write(ttyfd,(char *)&c,1) == 1);
  10646.       } else
  10647. #endif /* RLOGCODE */
  10648. #endif /* KRB4 */
  10649. #ifdef KRB5
  10650. #ifdef RLOGCODE
  10651.           if (ttnproto == NP_EK5LOGIN) {
  10652.               rc = (krb5_des_write(ttyfd,&c,1,0) == 1);
  10653.           } else
  10654. #endif /* RLOGCODE */
  10655. #ifdef KRB5_U2U
  10656.           if (ttnproto == NP_K5U2U) {
  10657.               rc = (krb5_u2u_write(ttyfd,&c,1) == 1);
  10658.           } else
  10659. #endif /* KRB5_U2U */
  10660. #endif /* KRB5 */
  10661. #endif /* CK_KERBEROS */
  10662.         rc = write(fd,&c,1);    /* Try to write the character. */
  10663.     if (rc < 1) {            /* Failed */
  10664.         ttimoff();            /* Turn off the alarm. */
  10665.         alarm(xx);            /* Restore previous alarm. */
  10666.         debug(F101,"ttoc errno","",errno); /* Log the error, */
  10667.         return(-1);            /* and return the error code. */
  10668.     }
  10669.     }
  10670.     ttimoff();                /* Success, turn off the alarm. */
  10671.     alarm(xx);                /* Restore previous alarm. */
  10672.     return(0);                /* Return good code. */
  10673. }
  10674.  
  10675. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  10676. /*
  10677.   Reads up to "max" characters from the connection, terminating on:
  10678.     (a) the packet length field if the "turn" argument is zero, or
  10679.     (b) on the packet-end character (eol) if the "turn" argument is nonzero
  10680.     (c) a certain number of Ctrl-C's in a row
  10681.  
  10682.   Returns:
  10683.     >= 0, the number of characters read upon success;
  10684.     -1 if "max" exceeded, timeout, or other correctable error;
  10685.     -2 on user interruption (c);
  10686.     -3 on fatal error like connection lost.
  10687.  
  10688.   The name of this routine dates from the early days when Kermit packets
  10689.   were, indeed, always lines of text.  That was before control-character
  10690.   unprefixing and length-driven packet framing were introduced, which this
  10691.   version handle.  NB: this routine is ONLY for reading incoming Kermit
  10692.   packets, nothing else.  To read other kinds of incoming material, use
  10693.   ttinc() or ttxin().
  10694.  
  10695.   The bytes that were input are copied into "dest" with their parity bits
  10696.   stripped if parity was selected.  Returns the number of bytes read.
  10697.   Bytes after the eol are available upon the next call to this function.
  10698.  
  10699.   The idea is to minimize the number of system calls per packet, and also to
  10700.   minimize timeouts.  This function is the inner loop of the protocol and must
  10701.   be as efficient as possible.  The current strategy is to use myread(), a
  10702.   macro to manage buffered (and generally nonblocking) reads.
  10703.  
  10704.   WARNING: This function calls parchk(), which is defined in another module.
  10705.   Normally, ckutio.c does not depend on code from any other module, but there
  10706.   is an exception in this case because all the other ck?tio.c modules also
  10707.   need to call parchk(), so it's better to have it defined in a common place.
  10708. */
  10709. #ifdef CTRLC
  10710. #undef CTRLC
  10711. #endif /* CTRLC */
  10712. #define CTRLC '\03'
  10713. /*
  10714.   We have four different declarations here because:
  10715.   (a) to allow Kermit to be built without the automatic parity sensing feature
  10716.   (b) one of each type for ANSI C, one for non-ANSI.
  10717. */
  10718. #ifndef NOXFER
  10719.  
  10720. static int pushedback = 0;
  10721.  
  10722. int
  10723. #ifdef PARSENSE
  10724. #ifdef CK_ANSIC
  10725. ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
  10726. #else
  10727. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
  10728. #endif /* CK_ANSIC */
  10729. #else /* not PARSENSE */
  10730. #ifdef CK_ANSIC
  10731. ttinl(CHAR *dest, int max,int timo, CHAR eol)
  10732. #else
  10733. ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  10734. #endif /* CK_ANSIC */
  10735. #endif /* PARSENSE */
  10736. /* ttinl */ {
  10737.  
  10738. #ifndef MYREAD
  10739.     CHAR ch, dum;
  10740. #endif /* MYREAD */
  10741. #ifdef PARSENSE
  10742.     int pktlen = -1;
  10743.     int lplen = 0;
  10744.     int havelen = 0;
  10745. #endif /* PARSENSE */
  10746.     int fd;
  10747.     int sopmask = 0xff;            /* Start-Of-Packet mask */
  10748. #ifdef CKXXCHAR
  10749.     extern short dblt[];        /* Ignore-character table */
  10750.     extern int ignflag;
  10751. #endif /* CKXXCHAR */
  10752. #ifdef TCPSOCKET
  10753.     extern CHAR stchr;
  10754. #endif /* TCPSOCKET */
  10755.     int x;
  10756. #ifdef STREAMING
  10757.     extern int streaming;
  10758.     extern int sndtyp;
  10759. #endif /* STREAMING */
  10760.  
  10761.     if (ttyfd < 0) return(-3);          /* Not open. */
  10762. /*
  10763.   In February 2007 I fixed ttinl() to work better under the truly awful
  10764.   conditions encountered by the AM-APEX oceanographic floats that gather
  10765.   hurricane data and phone home using Iridium satellite modems, which under
  10766.   certain conditions, can send two packets back to back after a long pause.
  10767.   In this case the second packet would be ignored because the SOH was skipped
  10768.   due to the ttflui() call.  But the reworked lookahead/pushback logic broke
  10769.   Kermit transfers on encrypted connections.  This was fixed 12-13 August
  10770.   2007.  All of this happened after 8.0.212 Dev.27 was released and before
  10771.   Dev.28, so no harm done other than the delay.
  10772. */
  10773.     debug(F101,"ttinl max","",max);
  10774.     debug(F101,"ttinl timo","",timo);
  10775.  
  10776. #ifdef NETCMD
  10777.     if (ttpipe)
  10778.       fd = fdin;
  10779.     else
  10780. #endif /* NETCMD */
  10781.       fd = ttyfd;
  10782.  
  10783. #ifdef COMMENT
  10784.     if (xlocal && conchk() > 0)        /* Allow for console interruptions */
  10785.       return(-1);
  10786. #endif /* COMMENT */
  10787.  
  10788.     *dest = '\0';                       /* Clear destination buffer */
  10789.     if (timo < 0) timo = 0;        /* Safety */
  10790.     if (timo) {                /* Don't time out if timo == 0 */
  10791.     int xx;
  10792.     saval = signal(SIGALRM,timerh);    /* Enable timer interrupt */
  10793.     xx = alarm(timo);        /* Set it. */
  10794.     debug(F101,"ttinl alarm","",xx);
  10795.     }
  10796.     if (
  10797. #ifdef CK_POSIX_SIG
  10798.     sigsetjmp(sjbuf,1)
  10799. #else
  10800.     setjmp(sjbuf)
  10801. #endif /* CK_POSIX_SIG */
  10802.     ) {                /* Timer went off? */
  10803.     debug(F100,"ttinl timout","",0); /* Get here on timeout. */
  10804.     /* debug(F110," with",(char *) dest,0); */
  10805.     ttimoff();            /* Turn off timer */
  10806.     return(-1);            /* and return error code. */
  10807.     } else {
  10808.     register int i, n = -1;        /* local variables */
  10809.     int ccn = 0;
  10810. #ifdef PARSENSE
  10811.     register int flag = 0;
  10812.     debug(F000,"ttinl start","",start);
  10813. #endif /* PARSENSE */
  10814.  
  10815.     ttpmsk = ttprty ? 0177 : 0377;    /* Set parity stripping mask. */
  10816.     sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
  10817.  
  10818. /* Now read into destination, stripping parity and looking for the */
  10819. /* the packet terminator, and also for several Ctrl-C's typed in a row. */
  10820.  
  10821.     i = 0;                /* Destination index */
  10822.     debug(F101,"ttinl eol","",eol);
  10823.  
  10824.     while (i < max-1) {
  10825. #ifdef MYREAD
  10826.         errno = 0;
  10827.         /* On encrypted connections myread returns encrypted bytes */
  10828.         n = myread();
  10829.         debug(F000,"TTINL myread char","",n);
  10830.         if (n < 0) {    /* Timeout or i/o error? */
  10831. #ifdef DEBUG
  10832.         if (deblog) {
  10833.             debug(F101,"ttinl myread failure, n","",n);
  10834.             debug(F101,"ttinl myread errno","",errno);
  10835.         }
  10836. #endif /* DEBUG */
  10837.         /* Don't let EINTR break packets. */
  10838.         if (n == -3) {
  10839.             if (errno == EINTR && i > 0) {
  10840.             debug(F111,"ttinl EINTR myread i","continuing",i);
  10841.             continue;
  10842.             } else {
  10843.             debug(F110,"ttinl non-EINTR -3","closing",0);
  10844.             wasclosed = 1;
  10845.             ttimoff();    /* Turn off timer */
  10846.             ttclos(0);
  10847.             return(n);
  10848.             }
  10849.         } else if (n == -2 && netconn /* && timo == 0 */ ) {
  10850.             /* Here we try to catch broken network connections */
  10851.             /* even when ioctl() and read() do not catch them */
  10852.             debug(F111,"ttinl network myread failure","closing",n);
  10853.             wasclosed = 1;
  10854.             ttimoff();
  10855.             ttclos(0);
  10856.             return(-3);
  10857.         }
  10858. #ifdef STREAMING
  10859.         /* Streaming and no data to read */
  10860.         else if (n == 0 && streaming && sndtyp == 'D')
  10861.           return(0);
  10862. #endif /* STREAMING */
  10863.         break;            /* Break out of while loop */
  10864.         }
  10865.  
  10866. #else /* not MYREAD (is this code used anywhere any more?) */
  10867. /*
  10868.   The non-MYREAD code dates from the 1980s and was needed on certain platforms
  10869.   where there were no nonblocking reads.  -fdc, 2007/02/22.
  10870. */
  10871.         if ((n = read(fd, &n, 1)) < 1)
  10872.           break;            /* Error - break out of while loop */
  10873.  
  10874. #endif /* MYREAD */
  10875.  
  10876.         /* Get here with char in n */
  10877.  
  10878. #ifdef CK_ENCRYPTION
  10879.         if (TELOPT_U(TELOPT_ENCRYPTION) && !pushedback) {
  10880.         CHAR ch = n;
  10881.         ck_tn_decrypt((char *)&ch,1);
  10882.         n = ch;
  10883.         debug(F000,"TTINL decryp char","",n);
  10884.         }
  10885.         pushedback = 0;
  10886. #endif /* CK_ENCRYPTION */
  10887.  
  10888. #ifdef TCPSOCKET
  10889.         if (n == IAC &&        /* Handle Telnet options */
  10890.         ((xlocal && netconn && IS_TELNET()) ||
  10891.         (!xlocal && sstelnet))) {
  10892.         n = tt_tnopt(n);
  10893.         if (n < 0)
  10894.           return(n);
  10895. #ifndef NOPARSEN
  10896.         else if (n == 1)
  10897.           start = stchr;
  10898. #endif /* NOPARSEN */
  10899.         if (n != 255)        /* No data - go back for next char */
  10900.           continue;
  10901.         }                /* Quoted IAC - keep going */
  10902. #endif /* TCPSOCKET */
  10903.  
  10904. #ifdef CKXXCHAR
  10905.         if (ignflag)
  10906.           if (dblt[(unsigned) n] & 1) /* Character to ignore? */
  10907.         continue;
  10908. #endif /* CKXXCHAR */
  10909. /*
  10910.   Use parity mask, rather than always stripping parity, to check for
  10911.   cancellation.  Otherwise, runs like \x03\x83\x03 in a packet could cancel
  10912.   the transfer when parity is NONE.  (Note that \x03\x03\x03 is extremely
  10913.   unlikely due to run-length encoding.)
  10914. */
  10915.         /* Check cancellation */
  10916.         if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
  10917.         if (++ccn >= xfrnum) {    /* If xfrnum in a row, bail out. */
  10918.             if (timo) {        /* Clear timer. */
  10919.             ttimoff();
  10920.             }
  10921.             if (xfrchr < 32)
  10922.               printf("^%c...\r\n",(char)(xfrchr+64));
  10923.             else
  10924.               printf("Canceled...\r\n");
  10925.             return(-2);
  10926.         }
  10927.         } else ccn = 0;        /* No cancellation, reset counter, */
  10928.  
  10929. #ifdef PARSENSE
  10930. /*
  10931.   Restructured code allows for a new packet to appear somewhere in the
  10932.   middle of a previous one.  -fdc, 24 Feb 2007.
  10933. */
  10934.         if ((n & sopmask) == start) { /* Start of Packet */
  10935.         debug(F101,"ttinl SOP i","",i);
  10936.         flag = 1;        /* Flag that we are in a packet */
  10937.         havelen = 0;        /* Invalidate previous length */
  10938.         pktlen = -1;        /* (if any) in case we were */
  10939.         lplen = 0;        /* alread processand a packet */
  10940.         i = 0;            /* and reset the dest buffer pointer */
  10941.         }
  10942.         if (flag == 0) {        /* No SOP yet... */
  10943.         debug(F000,"ttinl skipping","",n);
  10944.         continue;
  10945.         }
  10946.         dest[i++] = n & ttpmsk;
  10947. /*
  10948.   If we have not been instructed to wait for a turnaround character, we can go
  10949.   by the packet length field.  If turn != 0, we must wait for the end of line
  10950.   (eol) character before returning.  This is an egregious violation of all
  10951.   principles of layering...  (Less egregious in C-Kermit 9.0, in which we go
  10952.   by the length field but also look for the eol in case it arrives early,
  10953.   e.g. if the length field was corrupted upwards.)
  10954. */
  10955.         if (!havelen) {
  10956.         if (i == 2) {
  10957.             if ((dest[1] & 0x7f) < 32) /* Garbage in length field */
  10958.               return(-1);    /* fdc - 13 Apr 2010 */
  10959.             pktlen = xunchar(dest[1] & 0x7f);
  10960.                     if (pktlen > 94)    /* Rubout in length field */
  10961.               return(-1);    /* fdc - 13 Apr 2010 */
  10962.             if (pktlen > 1) {
  10963.             havelen = 1;
  10964.             debug(F101,"ttinl pktlen value","",pktlen);
  10965.             }
  10966.         } else if (i == 5 && pktlen == 0) {
  10967.             lplen = xunchar(dest[4] & 0x7f);
  10968.         } else if (i == 6 && pktlen == 0) {
  10969.             pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
  10970.             havelen = 1;
  10971.             debug(F101,"ttinl extended length","",pktlen);
  10972.         }
  10973.         }
  10974.  
  10975. /*
  10976.   Suppose we looked at the sequence number here and found it was out of
  10977.   range?  This would mean either (a) incoming packets had SOP unprefixed
  10978.   and we are out of sync, or (b) the packet is damaged.  Since (a) is bad
  10979.   practice, let's ignore it.  So what should we do here if we know the
  10980.   packet is damaged?
  10981.  
  10982.    1. Nothing -- keep trying to read the packet till we find what we think
  10983.       is the end, or we time out, and let the upper layer decide what to
  10984.       do.  But since either the packet is corrupt or we are out of sync,
  10985.       our criterion for finding the end does not apply and we are likely
  10986.       to time out (or swallow a piece of the next packet) if our assumed
  10987.       length is too long.  (This was the behavior prior to version 7.0.)
  10988.  
  10989.    2. set flag = 0 and continue?  This would force us to wait for the
  10990.       next packet to come in, and therefore (in the nonwindowing case),
  10991.       would force a timeout in the other Kermit.
  10992.  
  10993.    3. set flag = 0 and continue, but only if the window size is > 1 and
  10994.       the window is not blocked?  Talk about cheating!
  10995.  
  10996.    4. Return a failure code and let the upper layer decide what to do.
  10997.       This should be equivalent to 3, but without the cheating.  So let's
  10998.       do it that way...  But note that we must ignore the parity bit
  10999.       in case this is the first packet and we have not yet run parchk().
  11000. */
  11001.         if (i == 3) {        /* Peek at sequence number */
  11002.         x = xunchar((dest[i-1] & 0x7f)); /* If it's not in range... */
  11003.         if (x < 0 || x > 63) {
  11004.             debug(F111,"ttinl bad seq",dest,x);
  11005.             if (timo) ttimoff();
  11006.             return(-1);        /* return a nonfatal error */
  11007.         }
  11008.         }
  11009.  
  11010. #else /* PARSENSE */
  11011.         dest[i++] = n & ttpmsk;
  11012. #endif /* PARSENSE */
  11013.  
  11014.     /* Check for end of packet */
  11015.  
  11016.         if (
  11017.         ((n & ttpmsk) == eol)    /* Always break on the eol char */
  11018. #ifdef PARSENSE
  11019.          ||            /* fdc - see notes of 13 Apr 2010 */
  11020. /*
  11021.   Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
  11022.   This allows packet terminators and handshake characters to appear
  11023.   literally inside a packet data field.
  11024. */
  11025.         (havelen && (i > pktlen+1) &&
  11026.          (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
  11027.  
  11028. #endif /* PARSENSE */
  11029.         ) {
  11030. /*
  11031.   Here we have either read the last byte of the packet based on its length
  11032.   field, or else we have read the packet terminator (eol) or the half-duplex
  11033.   line-turnaround char (turn).
  11034. */
  11035. #ifndef PARSENSE
  11036.         debug(F101,"ttinl got eol","",eol); /* (or turn) */
  11037.         dest[i] = '\0';        /* Yes, terminate the string, */
  11038.         /* debug(F101,"ttinl i","",i); */
  11039.  
  11040. #else  /* PARSENSE */
  11041.  
  11042. #ifdef DEBUG
  11043.         if (deblog) {
  11044.             if ((n & ttpmsk) != eol) {
  11045.             debug(F101,"ttinl EOP length","",pktlen);
  11046.             debug(F000,"ttinl EOP current char","",n);
  11047.             debug(F101,"ttinl EOP packet buf index","",i);
  11048.             } else debug(F101,"ttinl got eol","",eol);
  11049.         }
  11050. #endif /* DEBUG */
  11051.  
  11052. #ifdef MYREAD
  11053. /*
  11054.   The packet was read based on its length.  This leaves the packet terminator
  11055.   unread, and so ttchk() will always return at least 1 because of this,
  11056.   possibly giving a false positive to the "is there another packet waiting?"
  11057.   test.  But if we know the terminator (or any other interpacket junk) is
  11058.   there, we can safely get rid of it.
  11059.  
  11060.   NOTE: This code reworked to (a) execute even if the debug log isn't active;
  11061.   and (b) actually work.  -fdc, 2007/02/22.  And again 2007/08/12-13 to also
  11062.   work on encrypted connections.
  11063. */    
  11064.         debug(F101,"TTINL my_count","",my_count);
  11065.         if ((n & ttpmsk) != eol) { /* Not the packet terminator */
  11066.             int x;
  11067.             while (my_count > 0) {
  11068.             x = myread();       /* (was ttinc(0) */
  11069.             debug(F000,"TTINL lkread char","",x);
  11070. #ifdef CK_ENCRYPTION
  11071.             if (TELOPT_U(TELOPT_ENCRYPTION)) {
  11072.                 CHAR ch = x;
  11073.                 ck_tn_decrypt((char *)&ch,1);
  11074.                 x = ch;
  11075.                 debug(F000,"TTINL lkdecr char","",x); 
  11076.             }
  11077. #endif    /* CK_ENCRYPTION */
  11078.             /*
  11079.               Note: while it might seem more elegant to simply
  11080.               push back the encrypted byte, that desynchronizes
  11081.               the decryption stream; the flag is necessary so we
  11082.               don't try to decrypt the same byte twice.
  11083.             */
  11084.             if ((x & ttpmsk) == start) { /* Start of next packet */
  11085.                 myunrd(x);    /* Push back the decrypted byte */
  11086.                 pushedback = 1; /* And set flag */
  11087.                 debug(F000,"TTINL lkpush char","",x);
  11088.                 break;
  11089.             }
  11090.             }
  11091.         }
  11092. #endif /* MYREAD */
  11093.  
  11094.         dest[i] = '\0';        /* Terminate the string, */
  11095.             if (needpchk) {        /* Parity checked yet? */
  11096.             if (ttprty == 0) {    /* No, check. */
  11097.             if ((ttprty = parchk(dest,start,i)) > 0) {
  11098.                 int j;
  11099.                 debug(F101,"ttinl senses parity","",ttprty);
  11100.                 debug(F110,"ttinl packet before",dest,0);
  11101.                 ttpmsk = 0x7f;
  11102.                 for (j = 0; j < i; j++)
  11103.                   dest[j] &= 0x7f;    /* Strip parity from packet */
  11104.                 debug(F110,"ttinl packet after ",dest,0);
  11105.             } else ttprty = 0; /* Restore if parchk error */
  11106.             }
  11107.             sopmask = ttpmsk;
  11108.             needpchk = 0;
  11109.         }
  11110. #endif /* PARSENSE */
  11111.  
  11112.         if (timo)        /* Turn off timer if it was on */
  11113.           ttimoff();
  11114.                 ckhexdump("ttinl got",dest,i);
  11115.  
  11116. #ifdef STREAMING
  11117.         /* ttinl() was called because there was non-packet */
  11118.         /* data sitting in the back channel.  Ignore it.   */
  11119.         if (streaming && sndtyp == 'D')
  11120.           return(-1);
  11121. #endif /* STREAMING */
  11122.         return(i);
  11123.         }
  11124.     } /* End of while() */
  11125.     ttimoff();
  11126.     return(n);
  11127.     }
  11128. }
  11129. #endif /* NOXFER */
  11130.  
  11131. /*  T T I N C --  Read a character from the communication line  */
  11132. /*
  11133.  On success, returns the character that was read, >= 0.
  11134.  On failure, returns -1 or other negative myread error code,
  11135.    or -2 if connection is broken or ttyfd < 0.
  11136.    or -3 if session limit has expired,
  11137.    or -4 if something or other...
  11138.  NOTE: The API does not provide for ttinc() returning a special code
  11139.  upon timeout, but we need it.  So for this we have a global variable,
  11140.  ttinctimo.
  11141. */
  11142. static int ttinctimo = 0;        /* Yuk */
  11143.  
  11144. int
  11145. ttinc(timo) int timo; {
  11146.  
  11147.     int n = 0, fd;
  11148.     int is_tn = 0;
  11149.     CHAR ch = 0;
  11150.  
  11151.     ttinctimo = 0;
  11152.  
  11153.     if (ttyfd < 0) return(-2);          /* Not open. */
  11154.  
  11155.     is_tn = (xlocal && netconn && IS_TELNET()) ||
  11156.         (!xlocal && sstelnet);
  11157.  
  11158. #ifdef TTLEBUF
  11159.     if (ttpush >= 0) {
  11160.         debug(F111,"ttinc","ttpush",ttpush);
  11161.         ch = ttpush;
  11162.         ttpush = -1;
  11163.         return(ch);
  11164.     }
  11165.     if (le_data) {
  11166.         if (le_getchar(&ch) > 0) {
  11167.             debug(F111,"ttinc le_getchar","ch",ch);
  11168.             return(ch);
  11169.         }
  11170.     }
  11171. #endif /* TTLEBUF */
  11172.  
  11173. #ifdef NETCMD
  11174.     if (ttpipe)
  11175.       fd = fdin;
  11176.     else
  11177. #endif /* NETCMD */
  11178.       fd = ttyfd;
  11179.  
  11180.     if ((timo <= 0)            /* Untimed. */
  11181. #ifdef MYREAD
  11182.     || (my_count > 0)        /* Buffered char already waiting. */
  11183. #endif /* MYREAD */
  11184.     ) {
  11185. #ifdef MYREAD
  11186.         /* Comm line failure returns -1 thru myread, so no &= 0377 */
  11187.     n = myread();            /* Wait for a character... */
  11188.     /* debug(F000,"ttinc MYREAD n","",n); */
  11189. #ifdef CK_ENCRYPTION
  11190.     /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
  11191.     if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
  11192.         ch = n;
  11193.         ck_tn_decrypt((char *)&ch,1);
  11194.         n = ch;
  11195.     }
  11196. #endif /* CK_ENCRYPTION */
  11197.  
  11198. #ifdef NETPTY
  11199.     if (ttpty && n < 0) {
  11200.         debug(F101,"ttinc error on pty","",n);
  11201.         ttclos(0);
  11202.         return(n);
  11203.     }
  11204. #endif /* NETPTY */
  11205.  
  11206. #ifdef TNCODE
  11207.     if ((n > -1) && is_tn)
  11208.       return((unsigned)(n & 0xff));
  11209.     else
  11210. #endif /* TNCODE */
  11211.       return(n < 0 ? n : (unsigned)(n & ttpmsk));
  11212.  
  11213. #else  /* MYREAD */
  11214.  
  11215.         while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
  11216.         /* Shouldn't have to loop in ver 5A. */
  11217. #ifdef NETCONN
  11218.       if (netconn) {        /* Special handling for net */
  11219.           netclos();        /* If read() returns 0 it means */
  11220.           netconn = 0;        /* the connection has dropped. */
  11221.           errno = ENOTCONN;
  11222.           return(-2);
  11223.       }
  11224. #endif /* NETCONN */
  11225.       ;
  11226.     /* debug(F101,"ttinc","",ch); */
  11227. #ifdef TNCODE
  11228.     if ((n > 0) && is_tn) {
  11229. #ifdef CK_ENCRYPTION
  11230.         if (TELOPT_U(TELOPT_ENCRYPTION)) {
  11231.         ck_tn_decrypt(&ch,1);
  11232.         n = ch;
  11233.         }
  11234. #endif /* CK_ENCRYPTION */
  11235.         return((unsigned)(ch & 0xff));
  11236.     } else
  11237. #endif /* TNCODE */
  11238.         return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
  11239. #endif /* MYREAD */
  11240.  
  11241.     } else {                /* Timed read */
  11242.  
  11243.     int oldalarm;
  11244.     saval = signal(SIGALRM,timerh);    /* Set up handler, save old one. */
  11245.     oldalarm = alarm(timo);        /* Set alarm, save old one. */
  11246.     if (
  11247. #ifdef CK_POSIX_SIG
  11248.         sigsetjmp(sjbuf,1)
  11249. #else
  11250.         setjmp(sjbuf)
  11251. #endif /* CK_POSIX_SIG */
  11252.         ) {                /* Timer expired */
  11253.         ttinctimo = 1;
  11254.         n = -1;            /* set flag */
  11255.     } else {
  11256. #ifdef MYREAD
  11257.         n = myread();        /* If managing own buffer... */
  11258.         debug(F101,"ttinc myread","",n);
  11259.         ch = n;
  11260. #else
  11261.         n = read(fd,&ch,1);        /* Otherwise call the system. */
  11262.         if (n == 0) n = -1;
  11263.         debug(F101,"ttinc read","",n);
  11264. #endif /* MYREAD */
  11265.  
  11266. #ifdef CK_ENCRYPTION
  11267.         if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
  11268.         ck_tn_decrypt((char *)&ch,1);
  11269.         }
  11270. #endif /* CK_ENCRYPTION */
  11271.         if (n >= 0)
  11272.           n = (unsigned) (ch & 0xff);
  11273.         else
  11274.           n = (n < 0) ? -4 : -2;    /* Special return codes. */
  11275.     }
  11276.     ttimoff();            /* Turn off the timer */
  11277.     if (oldalarm > 0) {
  11278.         if (n == -1)        /* and restore any previous alarm */
  11279.           oldalarm -= timo;
  11280.         if (oldalarm < 0)        /* adjusted by our timeout interval */
  11281.           oldalarm = 0;
  11282.         if (oldalarm) {
  11283.             debug(F101,"ttinc restoring oldalarm","",oldalarm);
  11284.         alarm(oldalarm);
  11285.         }
  11286.     }
  11287. #ifdef NETCONN
  11288.     if (netconn) {
  11289.         if (n == -2) {        /* read() returns 0 */
  11290.         netclos();        /* on network read failure */
  11291.         netconn = 0;
  11292.         errno = ENOTCONN;
  11293.         }
  11294.     }
  11295. #endif    /* NETCONN */
  11296. #ifdef TNCODE
  11297.     if ((n > -1) && is_tn)
  11298.       return((unsigned)(n & 0xff));
  11299.     else
  11300. #endif /* TNCODE */
  11301.       /* Return masked char or neg. */
  11302.       return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
  11303.     }
  11304. }
  11305.  
  11306. /*  S N D B R K  --  Send a BREAK signal of the given duration  */
  11307.  
  11308. static int
  11309. #ifdef CK_ANSIC
  11310. sndbrk(int msec) {            /* Argument is milliseconds */
  11311. #else
  11312. sndbrk(msec) int msec; {
  11313. #endif /* CK_ANSIC */
  11314. #ifndef POSIX
  11315.     int x, n;
  11316. #endif /* POSIX */
  11317.  
  11318. #ifdef OXOS
  11319. #define BSDBREAK
  11320. #endif /* OXOS */
  11321.  
  11322. #ifdef ANYBSD
  11323. #define BSDBREAK
  11324. #endif /* ANYBSD */
  11325.  
  11326. #ifdef BSD44
  11327. #define BSDBREAK
  11328. #endif /* BSD44 */
  11329.  
  11330. #ifdef COHERENT
  11331. #ifdef BSDBREAK
  11332. #undef BSDBREAK
  11333. #endif /* BSDBREAK */
  11334. #endif /* COHERENT */
  11335.  
  11336. #ifdef BELLV10
  11337. #ifdef BSDBREAK
  11338. #undef BSDBREAK
  11339. #endif /* BSDBREAK */
  11340. #endif /* BELLV10 */
  11341.  
  11342. #ifdef PROVX1
  11343.     char spd;
  11344. #endif /* PROVX1 */
  11345.  
  11346.     debug(F101,"ttsndb ttyfd","",ttyfd);
  11347.     if (ttyfd < 0) return(-1);          /* Not open. */
  11348.  
  11349. #ifdef Plan9
  11350.     return p9sndbrk(msec);
  11351. #else
  11352. #ifdef NETCONN
  11353. #ifdef NETCMD
  11354.     if (ttpipe)                /* Pipe */
  11355.       return(ttoc('\0'));
  11356. #endif /* NETCMD */
  11357. #ifdef NETPTY
  11358.     if (ttpty)
  11359.       return(ttoc('\0'));
  11360. #endif /* NETPTY */
  11361.     if (netconn)             /* Send network BREAK */
  11362.       return(netbreak());
  11363. #endif /* NETCONN */
  11364.  
  11365.     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
  11366.  
  11367. #ifdef POSIX                /* Easy in POSIX */
  11368.     {
  11369.     int x;
  11370.     debug(F111,"sndbrk POSIX",ckitoa(msec),(msec/375));
  11371.     errno = 0;
  11372.     x = tcsendbreak(ttyfd,msec / 375);
  11373.     debug(F111,"sndbrk tcsendbreak",ckitoa(errno),x);
  11374.     return(x);
  11375.     }
  11376. #else
  11377. #ifdef PROVX1
  11378.     gtty(ttyfd,&ttbuf);                 /* Get current tty flags */
  11379.     spd = ttbuf.sg_ospeed;              /* Save speed */
  11380.     ttbuf.sg_ospeed = B50;              /* Change to 50 baud */
  11381.     stty(ttyfd,&ttbuf);                 /*  ... */
  11382.     n = (int)strlen(brnuls);        /* Send the right number of nulls */
  11383.     x = msec / 91;
  11384.     if (x > n) x = n;
  11385.     write(ttyfd,brnuls,n);
  11386.     ttbuf.sg_ospeed = spd;              /* Restore speed */
  11387.     stty(ttyfd,&ttbuf);                 /*  ... */
  11388.     return(0);
  11389. #else
  11390. #ifdef aegis
  11391.     sio_$control((short)ttyfd, sio_$send_break, msec, st);
  11392.     return(0);
  11393. #else
  11394. #ifdef BSDBREAK
  11395.     n = FWRITE;                         /* Flush output queue. */
  11396. /* Watch out for int vs long problems in &n arg! */
  11397.     debug(F101,"sndbrk BSDBREAK","",msec);
  11398.     ioctl(ttyfd,TIOCFLUSH,&n);          /* Ignore any errors.. */
  11399.     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {  /* Turn on BREAK */
  11400.         perror("Can't send BREAK");
  11401.         return(-1);
  11402.     }
  11403.     x = msleep(msec);                    /* Sleep for so many milliseconds */
  11404.     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {  /* Turn off BREAK */
  11405.         perror("BREAK stuck!!!");
  11406.         doexit(BAD_EXIT,-1);        /* Get out, closing the line. */
  11407.                                         /*   with bad exit status */
  11408.     }
  11409.     return(x);
  11410. #else
  11411. #ifdef ATTSV
  11412. /*
  11413.   No way to send a long BREAK in Sys V, so send a bunch of regular ones.
  11414.   (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
  11415.   but there's no way for this code to know for sure.)
  11416. */
  11417.     debug(F101,"sndbrk ATTSV","",msec);
  11418.     x = msec / 275;
  11419.     for (n = 0; n < x; n++) {
  11420.     /* Reportedly the cast breaks this function on some systems */
  11421.     /* But then why was it here in the first place? */
  11422.     if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
  11423.         perror("Can't send BREAK");
  11424.         return(-1);
  11425.     }
  11426.     }
  11427.     return(0);
  11428. #else
  11429. #ifdef  V7
  11430.     debug(F101,"sndbrk V7","",msec);
  11431.     return(genbrk(ttyfd,250));        /* Simulate a BREAK */
  11432. #else
  11433.     debug(F101,"sndbrk catchall","",msec);
  11434.     ttoc(0);ttoc(0);ttoc(0);ttoc(0);
  11435.     return(0);
  11436. #endif /* V7 */
  11437. #endif /* BSDBREAK */
  11438. #endif /* ATTSV */
  11439. #endif /* aegis */
  11440. #endif /* PROVX1 */
  11441. #endif /* POSIX */
  11442. #endif /* Plan9 */
  11443. }
  11444.  
  11445. /*  T T S N D B  --  Send a BREAK signal  */
  11446.  
  11447. int
  11448. ttsndb() {
  11449. #ifdef TN_COMPORT
  11450.     if (netconn && istncomport())
  11451.       return((tnsndb(275L) >= 0) ? 0 : -1);
  11452.     else
  11453. #endif /* TN_COMPORT */
  11454.       return(sndbrk(275));
  11455. }
  11456.  
  11457. /*  T T S N D L B  --  Send a Long BREAK signal  */
  11458.  
  11459. int
  11460. ttsndlb() {
  11461. #ifdef TN_COMPORT
  11462.     if (netconn && istncomport())
  11463.       return((tnsndb(1800L) >= 0) ? 0 : -1);
  11464.     else
  11465. #endif /* TN_COMPORT */
  11466.     return(sndbrk(1500));
  11467. }
  11468.  
  11469. /*  M S L E E P  --  Millisecond version of sleep().  */
  11470.  
  11471. /*
  11472.   Call with number of milliseconds (thousandths of seconds) to sleep.
  11473.   Intended only for small intervals.  For big ones, just use sleep().
  11474.   Highly system-dependent.
  11475.   Returns 0 always, even if it didn't work.
  11476. */
  11477.  
  11478. /* Define MSLFTIME for systems that must use an ftime() loop. */
  11479. #ifdef ANYBSD                /* For pre-4.2 BSD versions */
  11480. #ifndef BSD4
  11481. #define MSLFTIME
  11482. #endif /* BSD4 */
  11483. #endif /* ANYBSD */
  11484.  
  11485. #ifdef TOWER1                /* NCR Tower OS 1.0 */
  11486. #define MSLFTIME
  11487. #endif /* TOWER1 */
  11488.  
  11489. #ifdef COHERENT         /* Coherent... */
  11490. #ifndef _I386           /* Maybe Coherent/386 should get this, too */
  11491. #define MSLFTIME        /* Opinions are divided */
  11492. #endif /* _I386 */
  11493. #endif /* COHERENT */
  11494.  
  11495. #ifdef COMMENT
  11496. #ifdef GETMSEC
  11497.  
  11498. /* Millisecond timer */
  11499.  
  11500. static long msecbase = 0L;        /* Unsigned long not portable */
  11501.  
  11502. long
  11503. getmsec() {                /* Milliseconds since base time */
  11504.     struct timeval xv;
  11505.     struct timezone xz;
  11506.     long secs, msecs;
  11507.     if (
  11508. #ifdef GTODONEARG
  11509.     gettimeofday(&tv)
  11510. #else
  11511. #ifdef PTX
  11512.     gettimeofday(&tv, NULL)
  11513. #else
  11514.     gettimeofday(&tv, &tz)
  11515. #endif /* PTX */
  11516. #endif /* GTODONEARG */
  11517.     < 0)
  11518.       return(-1);
  11519.     if (msecbase == 0L) {        /* First call, set base time. */
  11520.     msecbase = tv.tv_sec;
  11521.     debug(F101,"getmsec base","",msecbase);
  11522.     }
  11523.     return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
  11524. }
  11525. #endif /* GETMSEC */
  11526. #endif /* COMMENT */
  11527.  
  11528. #ifdef SELECT
  11529. int
  11530. ttwait(fd, secs) int fd, secs; {
  11531.     int x;
  11532.     fd_set rfds;
  11533.     FD_ZERO(&rfds);
  11534.     FD_SET(fd,&rfds);
  11535.     tv.tv_sec = secs;
  11536.     tv.tv_usec = 0L;
  11537.     errno = 0;
  11538.     if ((x = select(FD_SETSIZE,
  11539. #ifdef HPUX9
  11540.             (int *)
  11541. #else
  11542. #ifdef HPUX1000
  11543.             (int *)
  11544. #endif /* HPUX1000 */
  11545. #endif /* HPUX9 */
  11546.             &rfds,
  11547.             0, 0, &tv)) < 0) {
  11548.     debug(F101,"ttwait select errno","",errno);
  11549.     return(0);
  11550.     } else {
  11551.     debug(F101,"ttwait OK","",errno);
  11552.     x = FD_ISSET(fd, &rfds);
  11553.     debug(F101,"ttwait select x","",x);
  11554.     return(x ? 1 : 0);
  11555.     }
  11556. }
  11557. #endif /* SELECT */
  11558.  
  11559. int
  11560. msleep(m) int m; {
  11561. /*
  11562.   Other possibilities here are:
  11563.    nanosleep(), reportedly defined in POSIX.4.
  11564.    sginap(), IRIX only (back to what IRIX version I don't know).
  11565. */
  11566. #ifdef Plan9
  11567.     return _SLEEP(m);
  11568. #else
  11569. #ifdef BEOSORBEBOX
  11570.     snooze(m*1000);
  11571. #else /* BEOSORBEBOX */
  11572. #ifdef SELECT
  11573.     int t1, x;
  11574.     debug(F101,"msleep SELECT 1","",m);
  11575.     if (m <= 0) return(0);
  11576.     if (m >= 1000) {            /* Catch big arguments. */
  11577.     sleep(m/1000);
  11578.     m = m % 1000;
  11579.     if (m < 10) return(0);
  11580.     }
  11581.     debug(F101,"msleep SELECT 2","",m);
  11582. #ifdef BELLV10
  11583.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
  11584.     debug(F101,"msleep BELLV10 select","",x);
  11585. #else /* BELLV10 */
  11586. #ifdef HPUX9
  11587.     gettimeofday(&tv, &tz);
  11588. #else
  11589.  
  11590. #ifndef COHERENT
  11591. #ifdef GTODONEARG
  11592.     if (gettimeofday(&tv) < 0)
  11593. #else
  11594. #ifdef PTX
  11595.     if (gettimeofday(&tv,NULL) < 0)
  11596. #else
  11597. #ifdef NOTIMEZONE
  11598.     if (gettimeofday(&tv, NULL) < 0)    /* wonder what this does... */
  11599. #else
  11600.     if (gettimeofday(&tv, &tz) < 0)
  11601. #endif /* NOTIMEZONE */
  11602. #endif /* PTX */
  11603. #endif /* GTODONEARG */
  11604.       return(-1);
  11605.     t1 = tv.tv_sec;                     /* Seconds */
  11606. #endif /* COHERENT */
  11607. #endif /* HPUX9 */
  11608.     tv.tv_sec = 0;                      /* Use select() */
  11609.     tv.tv_usec = m * 1000L;
  11610. #ifdef BSD44
  11611.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11612.     debug(F101,"msleep BSD44 select","",x);
  11613. #else /* BSD44 */
  11614. #ifdef __linux__
  11615.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11616.     debug(F101,"msleep __linux__ select","",x);
  11617. #else /* __linux__ */
  11618. #ifdef BSD43
  11619.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11620.     debug(F101,"msleep BSD43 select","",x);
  11621. #else /* BSD43 */
  11622. #ifdef QNX6
  11623.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11624.     debug(F101,"msleep QNX6 select","",x);
  11625. #else /* QNX6 */
  11626. #ifdef QNX
  11627.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11628.     debug(F101,"msleep QNX select","",x);
  11629. #else /* QNX */
  11630. #ifdef COHERENT
  11631.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11632.     debug(F101,"msleep COHERENT select","",x);
  11633. #else /* COHERENT */
  11634. #ifdef HPUX1000                /* 10.00 only, not 10.10 or later */
  11635.     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
  11636.     debug(F101,"msleep HP-UX 10.00 select","",x);
  11637. #else /* HPUX1000 */
  11638. #ifdef SVR4
  11639.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11640.     debug(F101,"msleep SVR4 select","",x);
  11641. #else /* SVR4 */
  11642. #ifdef OSF40
  11643.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11644.     debug(F101,"msleep OSF40 select","",x);
  11645. #else /* OSF40 */
  11646. #ifdef PTX
  11647.     x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
  11648.     debug(F101,"msleep OSF40 select","",x);
  11649. #else
  11650.     x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
  11651.     debug(F101,"msleep catch-all select","",x);
  11652. #endif /* PTX */
  11653. #endif /* OSF40 */
  11654. #endif /* HP1000 */
  11655. #endif /* SVR4 */
  11656. #endif /* COHERENT */
  11657. #endif /* QNX */
  11658. #endif /* QNX6 */
  11659. #endif /* BSD43 */
  11660. #endif /* __linux__ */
  11661. #endif /* BSD44 */
  11662. #endif /* BELLV10 */
  11663.     return(0);
  11664.  
  11665. #else                    /* Not SELECT */
  11666. #ifdef CK_POLL                /* We have poll() */
  11667.     struct pollfd pfd;            /* Supply a valid address for poll() */
  11668.  
  11669. #ifdef ODT30                /* But in SCO ODT 3.0 */
  11670. #ifdef NAP                /* we should use nap() instead */
  11671.     debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
  11672.     nap((long)m);               /* seems to break dialing. */
  11673.     return(0);
  11674. #else
  11675.     debug(F101,"msleep ODT 3.0 POLL","",m);
  11676.     poll(&pfd, 0, m);
  11677.     return(0);
  11678. #endif /* NAP */
  11679. #else
  11680.     debug(F101,"msleep POLL","",m);
  11681.     poll(&pfd, 0, m);
  11682.     return(0);
  11683. #endif /* ODT30 */
  11684.  
  11685. /*
  11686.   We could handle the above more cleanly by just letting nap() always
  11687.   take precedence over poll() in this routine, but there is no way to know
  11688.   whether that would break something else.
  11689. */
  11690.  
  11691. #else                    /* Not POLL */
  11692. #ifdef USLEEP
  11693. /*
  11694.   "This routine is implemented using setitimer(2); it requires eight
  11695.   system calls...".  In other words, it might take 5 minutes to sleep
  11696.   10 milliseconds...
  11697. */
  11698.     debug(F101,"msleep USLEEP","",m);
  11699.     if (m >= 1000) {            /* Catch big arguments. */
  11700.     sleep(m/1000);
  11701.     m = m % 1000;
  11702.     if (m < 10) return(0);
  11703.     }
  11704.     usleep((unsigned int)(m * 1000));
  11705.     return(0);
  11706. #else
  11707. #ifdef aegis
  11708.     time_$clock_t dur;
  11709.     debug(F101,"msleep aegis","",m);
  11710.     dur.c2.high16 = 0;
  11711.     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
  11712.     time_$wait(time_$relative, dur, st);
  11713.     return(0);
  11714. #else
  11715. #ifdef PROVX1
  11716.     debug(F101,"msleep Venix","",m);
  11717.     if (m <= 0) return(0);
  11718.     sleep(-((m * 60 + 500) / 1000));
  11719.     return(0);
  11720. #else
  11721. #ifdef NAP
  11722.     debug(F101,"msleep NAP","",m);
  11723.     nap((long)m);
  11724.     return(0);
  11725. #else
  11726. #ifdef ATTSV
  11727. #ifndef BSD44
  11728.     extern long times();        /* Or #include <times.h> ? */
  11729. #endif /* BSD44 */
  11730.     long t1, t2, tarray[4];
  11731.     int t3;
  11732.     char *cp = getenv("HZ");
  11733.     int CLOCK_TICK;
  11734.     int hertz;
  11735.  
  11736.     if (cp && (hertz = atoi(cp))) {
  11737.         CLOCK_TICK  = 1000 / hertz;
  11738.     } else {                /* probably single user mode */
  11739. #ifdef HZ
  11740.         CLOCK_TICK  = 1000 / HZ;
  11741. #else
  11742.     static warned = 0;
  11743.     /* HZ always exists in, for instance, SCO Xenix, so you don't have to
  11744.      * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
  11745.      * have Xenix, you have should have nap(), so the best is to use -DNAP
  11746.      * in the makefile. Most systems have HZ.
  11747.      */
  11748.     CLOCK_TICK = 17;        /* 1/60 sec */
  11749.     if (!warned) {
  11750.           printf("warning: environment variable HZ bad... using HZ=%d\r\n",
  11751.          1000 / CLOCK_TICK);
  11752.           warned = 1;
  11753.     }
  11754. #endif /* !HZ */
  11755.     }
  11756.     debug(F101,"msleep ATTSV","",m);
  11757.     if (m <= 0) return(0);
  11758.     if (m >= 1000) {            /* Catch big arguments. */
  11759.     sleep(m/1000);
  11760.     m = m % 1000;
  11761.     if (m < 10) return(0);
  11762.     }
  11763.     if ((t1 = times(tarray)) < 0) return(-1);
  11764.     while (1) {
  11765.         if ((t2 = times(tarray)) < 0) return(-1);
  11766.         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
  11767.         if (t3 > m) return(t3);
  11768.     }
  11769. #else /* Not ATTSV */
  11770. #ifdef MSLFTIME                /* Use ftime() loop... */
  11771.     int t1, t3 = 0;
  11772.     debug(F101,"msleep MSLFTIME","",m);
  11773.     if (m <= 0) return(0);
  11774.     if (m >= 1000) {            /* Catch big arguments. */
  11775.     sleep(m/1000);
  11776.     m = m % 1000;
  11777.     if (m < 10) return(0);
  11778.     }
  11779. #ifdef QNX
  11780.     ftime(&ftp);            /* void ftime() in QNX */
  11781. #else
  11782.     if (ftime(&ftp) < 0) return(-1);    /* Get base time. */
  11783. #endif /* QNX */
  11784.     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
  11785.     while (1) {
  11786.         ftime(&ftp);            /* Get current time and compare. */
  11787.         t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
  11788.         if (t3 > m) return(0);
  11789.     }
  11790. #else
  11791. /* This includes true POSIX, which has no way to do this. */
  11792.     debug(F101,"msleep busy loop","",m);
  11793.     if (m >= 1000) {            /* Catch big arguments. */
  11794.     sleep(m/1000);
  11795.     m = m % 1000;
  11796.     if (m < 10) return(0);
  11797.     }
  11798.     if (m > 0) while (m > 0) m--;    /* Just a dumb busy loop */
  11799.     return(0);
  11800. #endif /* MSLFTIME */
  11801. #endif /* ATTSV */
  11802. #endif /* NAP */
  11803. #endif /* PROVX1 */
  11804. #endif /* aegis */
  11805. #endif /* CK_POLL */
  11806. #endif /* SELECT */
  11807. #endif /* BEOSORBEBOX */
  11808. #endif /* USLEEP */
  11809. #endif /* Plan9 */
  11810. }
  11811.  
  11812. /*  R T I M E R --  Reset elapsed time counter  */
  11813.  
  11814. VOID
  11815. rtimer() {
  11816.     tcount = time( (time_t *) 0 );
  11817. }
  11818.  
  11819.  
  11820. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  11821.  
  11822. int
  11823. gtimer() {
  11824.     int x;
  11825.     x = (int) (time( (time_t *) 0 ) - tcount);
  11826.     debug(F101,"gtimer","",x);
  11827.     return( (x < 0) ? 0 : x );
  11828. }
  11829.  
  11830. #ifdef GFTIMER
  11831. /*
  11832.   Floating-point timers.  Require not only floating point support, but
  11833.   also gettimeofday().
  11834. */
  11835. static struct timeval tzero;
  11836.  
  11837. VOID
  11838. rftimer() {
  11839. #ifdef GTODONEARG            /* Account for Mot's definition */
  11840.     (VOID) gettimeofday(&tzero);
  11841. #else
  11842.     (VOID) gettimeofday(&tzero, (struct timezone *)0);
  11843. #endif /* GTODONEARG */
  11844. }
  11845.  
  11846. CKFLOAT
  11847. gftimer() {
  11848.     struct timeval tnow, tdelta;
  11849.     CKFLOAT s;
  11850. #ifdef DEBUG
  11851.     char fpbuf[64];
  11852. #endif /* DEBUG */
  11853. #ifdef GTODONEARG            /* Account for Mot's definition */
  11854.     (VOID) gettimeofday(&tnow);
  11855. #else
  11856.     (VOID) gettimeofday(&tnow, (struct timezone *)0);
  11857. #endif /* GTODONEARG */
  11858.  
  11859.     tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
  11860.     tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
  11861.  
  11862.     if (tdelta.tv_usec < 0) {
  11863.     tdelta.tv_sec--;
  11864.     tdelta.tv_usec += 1000000;
  11865.     }
  11866.     s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
  11867.     if (s < GFMINTIME)
  11868.       s = GFMINTIME;
  11869. #ifdef DEBUG
  11870.     if (deblog) {
  11871.     sprintf(fpbuf,"%f",s);
  11872.     debug(F110,"gftimer",fpbuf,0);
  11873.     }
  11874. #endif /* DEBUG */
  11875.     return(s);
  11876. }
  11877. #endif /* GFTIMER */
  11878.  
  11879. /*  Z T I M E  --  Return asctime()-format date/time string  */
  11880. /*
  11881.   NOTE: as a side effect of calling this routine, we can also set the
  11882.   following two variables, giving the micro- and milliseconds (fractions of
  11883.   seconds) of the clock time.  Currently this is done only in BSD-based builds
  11884.   that use gettimeofday().  When these variables are not filled in, they are
  11885.   left with a value of -1L.
  11886. */
  11887. static char asctmbuf[64];
  11888.  
  11889. VOID
  11890. ztime(s) char **s; {
  11891.  
  11892. #ifdef GFTIMER
  11893. /*
  11894.   The gettimeofday() method, which also sets ztmsec and ztusec, works for
  11895.   all GFTIMER builds.  NOTE: ztmsec and ztusec are defined in ckcmai.c,
  11896.   and extern declarations for them are in ckcdeb.h; thus they are
  11897.   declared in this file by inclusion of ckcdeb.h.
  11898. */
  11899.     char *asctime();
  11900.     struct tm *localtime();
  11901.     struct tm *tp;
  11902.     ztmsec = -1L;
  11903.     ztusec = -1L;
  11904.  
  11905.     if (!s)
  11906.       debug(F100,"ztime s==NULL","",0);
  11907.  
  11908. #ifdef GTODONEARG
  11909.     /* No 2nd arg in Motorola SV88 and some others */
  11910.     if (gettimeofday(&tv) > -1)
  11911. #else
  11912. #ifndef COHERENT
  11913. #ifdef PTX
  11914.     if (gettimeofday(&tv,NULL) > -1)
  11915. #else
  11916. #ifdef NOTIMEZONE
  11917.     if (gettimeofday(&tv, NULL) > -1)    /* wonder what this does... */
  11918. #else
  11919.     if (gettimeofday(&tv, &tz) > -1)
  11920. #endif /* NOTIMEZONE */
  11921. #endif /* PTX */
  11922. #endif /* COHERENT */
  11923. #endif /* GTODONEARG */
  11924.       {                    /* Fill in tm struct */
  11925.     ztusec = tv.tv_usec;        /* Microseconds */
  11926.     ztmsec = ztusec / 1000L;    /* Milliseconds */
  11927. #ifdef HPUX9
  11928.     {
  11929.         time_t zz;
  11930.         zz = tv.tv_sec;
  11931.         tp = localtime(&zz);    /* Convert to local time */
  11932.     }
  11933. #else
  11934. #ifdef HPUX1000
  11935.     {
  11936.         time_t zz;
  11937.         zz = tv.tv_sec;
  11938.         tp = localtime(&zz);
  11939.     }
  11940. #else
  11941. #ifdef LINUX
  11942.     {   /* avoid unaligned access trap on 64-bit platforms */
  11943.         time_t zz;
  11944.         zz = tv.tv_sec;
  11945.         tp = localtime(&zz);
  11946.     }
  11947. #else
  11948. #ifdef MACOSX
  11949.     tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
  11950. #else
  11951.     tp = localtime(&tv.tv_sec);
  11952. #endif /* MACOSX */
  11953. #endif /* LINUX */
  11954. #endif /* HPUX1000 */
  11955. #endif /* HPUX9 */
  11956.     if (s) {
  11957.         char * s2;
  11958.         s2 = asctime(tp);        /* Convert result to ASCII string */
  11959.         asctmbuf[0] = '\0';
  11960.         if (s2) ckstrncpy(asctmbuf,s2,64);
  11961.         *s = asctmbuf;
  11962.         debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
  11963.     }
  11964.     }
  11965. #else  /* Not GFTIMER */
  11966.  
  11967. #undef ZTIMEV7                /* Which systems need to use */
  11968. #ifdef COHERENT                /* old UNIX Version 7 way... */
  11969. #define ZTIMEV7
  11970. #endif /* COHERENT */
  11971. #ifdef TOWER1
  11972. #define ZTIMEV7
  11973. #endif /* TOWER1 */
  11974. #ifdef ANYBSD
  11975. #ifndef BSD42
  11976. #define ZTIMEV7
  11977. #endif /* BSD42 */
  11978. #endif /* ANYBSD */
  11979. #ifdef V7
  11980. #ifndef MINIX
  11981. #define ZTIMEV7
  11982. #endif /* MINIX */
  11983. #endif /* V7 */
  11984. #ifdef POSIX
  11985. #define ZTIMEV7
  11986. #endif /* POSIX */
  11987.  
  11988. #ifdef HPUX1020
  11989. /*
  11990.   Prototypes are in <time.h>, included above.
  11991. */
  11992.     time_t clock_storage;
  11993.     clock_storage = time((void *) 0);
  11994.     if (s) {
  11995.     *s = ctime(&clock_storage);
  11996.     debug(F110,"ztime: HPUX 10.20",*s,0);
  11997.     }
  11998. #else
  11999. #ifdef ATTSV                /* AT&T way */
  12000. /*  extern long time(); */        /* Theoretically these should */
  12001.     char *ctime();            /* already been dcl'd in <time.h> */
  12002.     time_t clock_storage;
  12003.     clock_storage = time(
  12004. #ifdef IRIX60
  12005.              (time_t *)
  12006. #else
  12007. #ifdef BSD44
  12008.              (time_t *)
  12009. #else
  12010.              (long *)
  12011. #endif /* BSD44 */
  12012. #endif /* IRIX60 */
  12013.              0 );
  12014.     if (s) {
  12015.     *s = ctime( &clock_storage );
  12016.     debug(F110,"ztime: ATTSV",*s,0);
  12017.     }
  12018. #else
  12019. #ifdef PROVX1                /* Venix 1.0 way */
  12020.     int utime[2];
  12021.     time(utime);
  12022.     if (s) {
  12023.     *s = ctime(utime);
  12024.     debug(F110,"ztime: PROVX1",*s,0);
  12025.     }
  12026. #else
  12027. #ifdef BSD42                /* 4.2BSD way */
  12028.     char *asctime();
  12029.     struct tm *localtime();
  12030.     struct tm *tp;
  12031.     gettimeofday(&tv, &tz);
  12032.     ztusec = tv.tv_usec;
  12033.     ztmsec = tv.tv_usec / 1000L;
  12034.     tp = localtime(&tv.tv_sec);
  12035.     if (s) {
  12036.     *s = asctime(tp);
  12037.     debug(F111,"ztime: BSD42",*s,ztusec);
  12038.     }
  12039. #else
  12040. #ifdef MINIX                /* MINIX way */
  12041. #ifdef COMMENT
  12042.     extern long time();            /* Already got these from <time.h> */
  12043.     extern char *ctime();
  12044. #endif /* COMMENT */
  12045.     time_t utime[2];
  12046.     time(utime);
  12047.     if (s) {
  12048.     *s = ctime(utime);
  12049.     debug(F110,"ztime: MINIX",*s,0);
  12050.     }
  12051. #else
  12052. #ifdef ZTIMEV7                /* The regular way */
  12053.     char *asctime();
  12054.     struct tm *localtime();
  12055.     struct tm *tp;
  12056.     long xclock;            /* or unsigned long for BeBox? */
  12057.     time(&xclock);
  12058.     tp = localtime(&xclock);
  12059.     if (s) {
  12060.     *s = asctime(tp);
  12061.     debug(F110,"ztime: ZTIMEV7",*s,0);
  12062.     }
  12063. #else                    /* Catch-all for others... */
  12064.     if (s) {
  12065.     *s = "Day Mon 00 00:00:00 0000\n"; /* Dummy in asctime() format */
  12066.     debug(F110,"ztime: catch-all",*s,0);
  12067.     }
  12068. #endif /* ZTIMEV7 */
  12069. #endif /* MINIX */
  12070. #endif /* BSD42 */
  12071. #endif /* PROVX1 */
  12072. #endif /* ATTSV */
  12073. #endif /* HPUX1020 */
  12074. #endif /* GFTIMER */
  12075. }
  12076.  
  12077. /*  C O N G M  --  Get console terminal modes.  */
  12078.  
  12079. /*
  12080.   Saves initial console mode, and establishes variables for switching
  12081.   between current (presumably normal) mode and other modes.
  12082.   Should be called when program starts, but only after establishing
  12083.   whether program is in the foreground or background.
  12084.   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
  12085. */
  12086. int
  12087. congm() {
  12088.     int fd;
  12089.     if (backgrd || !isatty(0)) {    /* If in background. */
  12090.     cgmf = -1;            /* Don't bother, modes are garbage. */
  12091.     return(-1);
  12092.     }
  12093.     if (cgmf > 0) return(0);        /* Already did this. */
  12094.     debug(F100,"congm getting modes","",0); /* Need to do it. */
  12095. #ifdef aegis
  12096.     ios_$inq_type_uid(ios_$stdin, conuid, st);
  12097.     if (st.all != status_$ok) {
  12098.     fprintf(stderr, "problem getting stdin objtype: ");
  12099.     error_$print(st);
  12100.     }
  12101.     concrp = (conuid == mbx_$uid);
  12102.     conbufn = 0;
  12103. #endif /* aegis */
  12104.  
  12105. #ifndef BEBOX
  12106.     if ((fd = open(CTTNAM,2)) < 0) {    /* Open controlling terminal */
  12107. #ifdef COMMENT
  12108.     fprintf(stderr,"Error opening %s\n", CTTNAM);
  12109.     perror("congm");
  12110.     return(-1);
  12111. #else
  12112.     fd = 0;
  12113. #endif /* COMMENT */
  12114.     }
  12115. #else
  12116.     fd = 0;
  12117. #endif /* !BEBOX */
  12118. #ifdef BSD44ORPOSIX
  12119.     if (tcgetattr(fd,&ccold) < 0) return(-1);
  12120.     if (tcgetattr(fd,&cccbrk) < 0) return(-1);
  12121.     if (tcgetattr(fd,&ccraw) < 0) return(-1);
  12122. #else
  12123. #ifdef ATTSV
  12124.     if (ioctl(fd,TCGETA,&ccold)  < 0) return(-1);
  12125.     if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
  12126.     if (ioctl(fd,TCGETA,&ccraw)  < 0) return(-1);
  12127. #ifdef VXVE
  12128.     cccbrk.c_line = 0;            /* STTY line 0 for CDC VX/VE */
  12129.     if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
  12130.     ccraw.c_line = 0;            /* STTY line 0 for CDC VX/VE */
  12131.     if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
  12132. #endif /* VXVE */
  12133. #else
  12134. #ifdef BELLV10
  12135.     if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
  12136.     if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
  12137.     if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
  12138.     debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
  12139. #else
  12140.     if (gtty(fd,&ccold) < 0) return(-1);
  12141.     if (gtty(fd,&cccbrk) < 0) return(-1);
  12142.     if (gtty(fd,&ccraw) < 0) return(-1);
  12143. #endif /* BELLV10 */
  12144. #endif /* ATTSV */
  12145. #endif /* BSD44ORPOSIX */
  12146. #ifdef sony_news            /* Sony NEWS */
  12147.     if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
  12148.     perror("congm error getting Kanji mode");
  12149.     debug(F101,"congm error getting Kanji mode","",0);
  12150.     km_con = -1;            /* Make sure this stays undefined. */
  12151.     return(-1);
  12152.     }
  12153. #endif /* sony_news */
  12154.     if (fd > 0)
  12155.       close(fd);
  12156.     cgmf = 1;                /* Flag that we got them. */
  12157.     return(1);
  12158. }
  12159.  
  12160.  
  12161. static VOID
  12162. congetbuf(x) int x; {
  12163.     int n;
  12164.     n = CONBUFSIZ - (conbufp - conbuf);    /* How much room left in buffer? */
  12165.     if (x > n) {
  12166.     debug(F101,"congetbuf char loss","",x-n);
  12167.     x = n;
  12168.     }
  12169.     x = read(0,conbufp,x);
  12170.     conbufn += x;
  12171.     debug(F111,"congetbuf readahead",conbuf,x);
  12172. }
  12173.  
  12174.  
  12175. /*  C O N C B --  Put console in cbreak mode.  */
  12176.  
  12177. /*  Returns 0 if ok, -1 if not  */
  12178.  
  12179. int
  12180. #ifdef CK_ANSIC
  12181. concb(char esc)
  12182. #else
  12183. concb(esc) char esc;
  12184. #endif /* CK_ANSIC */
  12185. /* concb */ {
  12186.     int x, y = 0;
  12187.     debug(F101,"concb constate","",constate);
  12188.     debug(F101,"concb cgmf","",cgmf);
  12189.     debug(F101,"concb backgrd","",backgrd);
  12190.  
  12191.     if (constate == CON_CB)
  12192.       return(0);
  12193.  
  12194.     if (cgmf < 1)            /* Did we get console modes yet? */
  12195.       if (!backgrd)            /* No, in background? */
  12196.     congm();            /* No, try to get them now. */
  12197.     if (cgmf < 1)            /* Still don't have them? */
  12198.       return(0);            /* Give up. */
  12199.     debug(F101,"concb ttyfd","",ttyfd);
  12200.     debug(F101,"concb ttfdflg","",ttfdflg);
  12201. #ifdef COMMENT
  12202.     /* This breaks returning to prompt after protocol with "-l 0" */
  12203.     /* Commented out July 1998 */
  12204.     if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
  12205.       return(0);
  12206. #endif /* COMMENT */
  12207.     x = isatty(0);
  12208.     debug(F101,"concb isatty","",x);
  12209.     if (!x) return(0);            /* Only when running on real ttys */
  12210.     debug(F101,"concb xsuspend","",xsuspend);
  12211.     if (backgrd)            /* Do nothing if in background. */
  12212.       return(0);
  12213.     escchr = esc;                       /* Make this available to other fns */
  12214.     ckxech = 1;                         /* Program can echo characters */
  12215. #ifdef aegis
  12216.     conbufn = 0;
  12217.     if (concrp) return(write(1, "\035\002", 2));
  12218.     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
  12219. #endif /* aegis */
  12220.  
  12221. #ifdef COHERENT
  12222. #define SVORPOSIX
  12223. #endif /* COHERENT */
  12224.  
  12225. #ifdef Plan9
  12226.     x = p9concb();
  12227. #else
  12228. #ifndef SVORPOSIX            /* BSD, V7, etc */
  12229.     debug(F101,"cccbrk.sg_flags concb 1","", cccbrk.sg_flags);
  12230.     debug(F101,"concb stty CBREAK","",0);
  12231.     cccbrk.sg_flags |= (CBREAK|CRMOD);    /* Set to character wakeup, */
  12232.     cccbrk.sg_flags &= ~ECHO;           /* no echo. */
  12233.     debug(F101,"cccbrk.sg_flags concb 2","", cccbrk.sg_flags);
  12234.     errno = 0;
  12235. /*
  12236.   BSD stty() clears the console buffer.  So if anything is waiting in it,
  12237.   we have to read it now to avoid losing it.
  12238. */
  12239.     x = conchk();
  12240.     if (x > 0)
  12241.       congetbuf(x);
  12242.  
  12243. #ifdef BELLV10
  12244.     x = ioctl(0,TIOCSETP,&cccbrk);
  12245. #else
  12246.     x = stty(0,&cccbrk);
  12247.     debug(F101,"cccbrk.sg_flags concb x","", x);
  12248. #endif /* BELLV10 */
  12249. #else                    /* Sys V and POSIX */
  12250. #ifndef OXOS
  12251.     debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
  12252. #ifdef QNX
  12253.     /* Don't mess with IEXTEN */
  12254.     cccbrk.c_lflag &= ~(ICANON|ECHO);
  12255. #else
  12256. #ifdef COHERENT
  12257.     cccbrk.c_lflag &= ~(ICANON|ECHO);
  12258. #else
  12259.     cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
  12260. #endif /* COHERENT */
  12261. #endif /* QNX */
  12262.     cccbrk.c_lflag |= ISIG;        /* Allow signals in command mode. */
  12263.     cccbrk.c_iflag |= IGNBRK;        /* But ignore BREAK signal */
  12264.     cccbrk.c_iflag &= ~BRKINT;
  12265.  
  12266. #else /* OXOS */
  12267.     debug(F100,"concb OXOS is defined","",0);
  12268.     cccbrk.c_lflag &= ~(ICANON|ECHO);
  12269.     cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
  12270. #endif /* OXOS */
  12271. #ifdef COMMENT
  12272. /*
  12273.   Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
  12274.   array reference is out of bounds.  It's only a debug() call so who needs it.
  12275. */
  12276. #ifdef VSUSP
  12277.     debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
  12278. #endif /* VSUSP */
  12279. #endif /* COMMENT */
  12280. #ifndef VINTR
  12281.     debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
  12282.     cccbrk.c_cc[0] = 003;               /* Interrupt char is Control-C */
  12283. #else
  12284.     debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
  12285.     cccbrk.c_cc[VINTR] = 003;
  12286. #endif /* VINTR */
  12287. #ifndef VQUIT
  12288.     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
  12289. #else
  12290.     cccbrk.c_cc[VQUIT] = escchr;
  12291. #endif /* VQUIT */
  12292. #ifndef VEOF
  12293.     cccbrk.c_cc[4] = 1;
  12294. #else
  12295. #ifndef OXOS
  12296. #ifdef VMIN
  12297.     cccbrk.c_cc[VMIN] = 1;
  12298. #endif /* VMIN */
  12299. #else /* OXOS */
  12300.     cccbrk.c_min = 1;
  12301. #endif /* OXOS */
  12302. #endif /* VEOF */
  12303. #ifdef ZILOG
  12304.     cccbrk.c_cc[5] = 0;
  12305. #else
  12306. #ifndef VEOL
  12307.     cccbrk.c_cc[5] = 1;
  12308. #else
  12309. #ifndef OXOS
  12310. #ifdef VTIME
  12311.     cccbrk.c_cc[VTIME] = 1;
  12312. #endif /* VTIME */
  12313. #else /* OXOS */
  12314.     cccbrk.c_time = 1;
  12315. #endif /* OXOS */
  12316. #endif /* VEOL */
  12317. #endif /* ZILOG */
  12318.     errno = 0;
  12319. #ifdef BSD44ORPOSIX            /* Set new modes */
  12320.     x = tcsetattr(0,TCSADRAIN,&cccbrk);
  12321. #else /* ATTSV */                  /* or the POSIX way */
  12322.     x = ioctl(0,TCSETAW,&cccbrk);    /* the Sys V way */
  12323. #endif /* BSD44ORPOSIX */
  12324. #endif /* SVORPOSIX */
  12325.  
  12326. #ifdef COHERENT
  12327. #undef SVORPOSIX
  12328. #endif /* COHERENT */
  12329.  
  12330.     debug(F101,"concb x","",x);
  12331.     debug(F101,"concb errno","",errno);
  12332.  
  12333. #ifdef  V7
  12334. #ifndef MINIX
  12335.     if (kmem[CON] < 0) {
  12336.         qaddr[CON] = initrawq(0);
  12337.         if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
  12338.             fprintf(stderr, "Can't read /dev/kmem in concb.\n");
  12339.             perror("/dev/kmem");
  12340.             exit(1);
  12341.         }
  12342.     }
  12343. #endif /* MINIX */
  12344. #endif /* V7 */
  12345. #endif /* Plan9 */
  12346.  
  12347.     if (x > -1)
  12348.       constate = CON_CB;
  12349.  
  12350.     debug(F101,"concb returns","",x);
  12351.     return(x);
  12352. }
  12353.  
  12354. /*  C O N B I N  --  Put console in binary mode  */
  12355.  
  12356. /*  Returns 0 if ok, -1 if not  */
  12357.  
  12358. int
  12359. #ifdef CK_ANSIC
  12360. conbin(char esc)
  12361. #else
  12362. conbin(esc) char esc;
  12363. #endif /* CK_ANSIC */
  12364. /* conbin */  {
  12365.  
  12366.     int x;
  12367.  
  12368.     debug(F101,"conbin constate","",constate);
  12369.  
  12370.     if (constate == CON_BIN)
  12371.       return(0);
  12372.  
  12373.     if (!isatty(0)) return(0);          /* only for real ttys */
  12374.     congm();                /* Get modes if necessary. */
  12375.     debug(F100,"conbin","",0);
  12376.     escchr = esc;                       /* Make this available to other fns */
  12377.     ckxech = 1;                         /* Program can echo characters */
  12378. #ifdef aegis
  12379.     conbufn = 0;
  12380.     if (concrp) return(write(1, "\035\002", 2));
  12381.     if (conuid == input_pad_$uid) {
  12382.     pad_$raw(ios_$stdin, st);
  12383.     return(0);
  12384.       }
  12385. #endif /* aegis */
  12386.  
  12387. #ifdef COHERENT
  12388. #define SVORPOSIX
  12389. #endif /* COHERENT */
  12390.  
  12391. #ifdef Plan9
  12392.     return p9conbin();
  12393. #else
  12394. #ifdef SVORPOSIX
  12395. #ifndef OXOS
  12396. #ifdef QNX
  12397.     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
  12398. #else
  12399. #ifdef COHERENT
  12400.     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
  12401. #else
  12402.     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
  12403. #endif /* COHERENT */
  12404. #endif /* QNX */
  12405. #else /* OXOS */
  12406.     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
  12407.     ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
  12408. #endif /* OXOS */
  12409.     ccraw.c_iflag |= IGNPAR;
  12410. /*
  12411.   Note that for terminal sessions we disable Xon/Xoff flow control to allow
  12412.   the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
  12413.   transfers to work when C-Kermit is in the middle, etc.  Hardware flow
  12414.   control, if in use, is not affected.
  12415. */
  12416. #ifdef ATTSV
  12417. #ifdef BSD44
  12418.     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
  12419.                         |INPCK|ISTRIP);
  12420. #else
  12421.     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
  12422.                         |INPCK|ISTRIP);
  12423. #endif /* BSD44 */
  12424. #else /* POSIX */
  12425.     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
  12426. #endif /* ATTSV */
  12427.     ccraw.c_oflag &= ~OPOST;
  12428. #ifdef COMMENT
  12429. /*
  12430.   WHAT THE HECK WAS THIS FOR?
  12431.   The B9600 setting (obviously) prevents CONNECT from working at any
  12432.   speed other than 9600 when you are logged in to the 7300 on a serial
  12433.   line.  Maybe some of the other flags are necessary -- if so, put back
  12434.   the ones that are needed.  This code is supposed to work the same, no
  12435.   matter whether you are logged in to the 7300 on the real console device,
  12436.   or through a serial port.
  12437. */
  12438. #ifdef ATT7300
  12439.     ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
  12440. #endif /* ATT7300 */
  12441. #endif /* COMMENT */
  12442.  
  12443. /*** Kermit used to put the console in 8-bit raw mode, but some users have
  12444.  *** pointed out that this should not be done, since some sites actually
  12445.  *** use terminals with parity settings on their Unix systems, and if we
  12446.  *** override the current settings and stop doing parity, then their terminals
  12447.  *** will display blotches for characters whose parity is wrong.  Therefore,
  12448.  *** the following two lines are commented out (Larry Afrin, Clemson U):
  12449.  ***
  12450.  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
  12451.  ***   ccraw.c_cflag |= (CS8|CREAD);
  12452.  ***
  12453.  *** Sys III/V sites that have trouble with this can restore these lines.
  12454.  ***/
  12455. #ifndef VINTR
  12456.     ccraw.c_cc[0] = 003;        /* Interrupt char is Ctrl-C */
  12457. #else
  12458.     ccraw.c_cc[VINTR] = 003;
  12459. #endif /* VINTR */
  12460. #ifndef VQUIT
  12461.     ccraw.c_cc[1] = escchr;        /* Escape during packet mode */
  12462. #else
  12463.     ccraw.c_cc[VQUIT] = escchr;
  12464. #endif /* VQUIT */
  12465. #ifndef VEOF
  12466.     ccraw.c_cc[4] = 1;
  12467. #else
  12468. #ifndef OXOS
  12469. #ifdef VMIN
  12470.     ccraw.c_cc[VMIN] = 1;
  12471. #endif /* VMIN */
  12472. #else /* OXOS */
  12473.     ccraw.c_min = 1;
  12474. #endif /* OXOS */
  12475. #endif /* VEOF */
  12476.  
  12477. #ifdef ZILOG
  12478.     ccraw.c_cc[5] = 0;
  12479. #else
  12480. #ifndef VEOL
  12481.     ccraw.c_cc[5] = 1;
  12482. #else
  12483. #ifndef OXOS
  12484. #ifdef VTIME
  12485.     ccraw.c_cc[VTIME] = 1;
  12486. #endif /* VTIME */
  12487. #else /* OXOS */
  12488.     ccraw.c_time = 1;
  12489. #endif /* OXOS */
  12490. #endif /* VEOL */
  12491. #endif /* ZILOG */
  12492.  
  12493. #ifdef BSD44ORPOSIX
  12494.     x = tcsetattr(0,TCSADRAIN,&ccraw);    /* Set new modes. */
  12495. #else
  12496.     x = ioctl(0,TCSETAW,&ccraw);
  12497. #endif /* BSD44ORPOSIX */
  12498. #else /* Berkeley, etc. */
  12499.     x = conchk();            /* Because stty() is destructive */
  12500.     if (x > 0)
  12501.       congetbuf(x);
  12502.     ccraw.sg_flags |= (RAW|TANDEM);     /* Set rawmode, XON/XOFF (ha) */
  12503.     ccraw.sg_flags &= ~(ECHO|CRMOD);    /* Set char wakeup, no echo */
  12504. #ifdef BELLV10
  12505.     x = ioctl(0,TIOCSETP,&ccraw);
  12506. #else
  12507.     x = stty(0,&ccraw);
  12508. #endif /* BELLV10 */
  12509. #endif /* SVORPOSIX */
  12510. #endif /* Plan9 */
  12511.  
  12512.     if (x > -1)
  12513.       constate = CON_BIN;
  12514.  
  12515.     debug(F101,"conbin returns","",x);
  12516.     return(x);
  12517.  
  12518. #ifdef COHERENT
  12519. #undef SVORPOSIX
  12520. #endif /* COHERENT */
  12521.  
  12522. }
  12523.  
  12524.  
  12525. /*  C O N R E S  --  Restore the console terminal  */
  12526.  
  12527. int
  12528. conres() {
  12529.     int x;
  12530.     debug(F101,"conres cgmf","",cgmf);
  12531.     debug(F101,"conres constate","",constate);
  12532.  
  12533.     if (cgmf < 1)            /* Do nothing if modes unchanged */
  12534.       return(0);
  12535.     if (constate == CON_RES)
  12536.       return(0);
  12537.  
  12538.     if (!isatty(0)) return(0);          /* only for real ttys */
  12539.     debug(F100,"conres isatty ok","",0);
  12540.     ckxech = 0;                         /* System should echo chars */
  12541.  
  12542. #ifdef aegis
  12543.     conbufn = 0;
  12544.     if (concrp) return(write(1, "\035\001", 2));
  12545.     if (conuid == input_pad_$uid) {
  12546.     pad_$cooked(ios_$stdin, st);
  12547.     constate = CON_RES;
  12548.     return(0);
  12549.     }
  12550. #endif /* aegis */
  12551.  
  12552. #ifdef Plan9
  12553.     p9conres();
  12554. #else
  12555. #ifdef BSD44ORPOSIX
  12556.     debug(F100,"conres restoring tcsetattr","",0);
  12557.     x = tcsetattr(0,TCSADRAIN,&ccold);
  12558. #else
  12559. #ifdef ATTSV
  12560.     debug(F100,"conres restoring ioctl","",0);
  12561.     x = ioctl(0,TCSETAW,&ccold);
  12562. #else /* BSD, V7, and friends */
  12563. #ifdef sony_news            /* Sony NEWS */
  12564.     if (km_con != -1)
  12565.       ioctl(0,TIOCKSET,&km_con);    /* Restore console Kanji mode */
  12566. #endif /* sony_news */
  12567.     msleep(100);
  12568.     debug(F100,"conres restoring stty","",0);
  12569.     x = conchk();            /* Because stty() is destructive */
  12570.     if (x > 0)
  12571.       congetbuf(x);
  12572. #ifdef BELLV10
  12573.     x = ioctl(0,TIOCSETP,&ccold);
  12574. #else
  12575.     x = stty(0,&ccold);
  12576. #endif /* BELLV10 */
  12577. #endif /* ATTSV */
  12578. #endif /* BSD44ORPOSIX */
  12579. #endif /* Plan9 */
  12580.     if (x > -1)
  12581.       constate = CON_RES;
  12582.  
  12583.     debug(F101,"conres returns","",x);
  12584.     return(x);
  12585. }
  12586.  
  12587. /*  C O N O C  --  Output a character to the console terminal  */
  12588.  
  12589. int
  12590. #ifdef CK_ANSIC
  12591. conoc(char c)
  12592. #else
  12593. conoc(c) char c;
  12594. #endif /* CK_ANSIC */
  12595. /* conoc */ {
  12596.  
  12597. #ifdef IKSD
  12598.     if (inserver && !local)
  12599.       return(ttoc(c));
  12600.  
  12601. #ifdef CK_ENCRYPTION
  12602.     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
  12603.         ck_tn_encrypt(&c,1);
  12604. #endif /* CK_ENCRYPTION */
  12605. #endif /* IKSD */
  12606.  
  12607. #ifdef Plan9
  12608.     return conwrite(&c,1);
  12609. #else
  12610.     return(write(1,&c,1));
  12611. #endif /* Plan9 */
  12612. }
  12613.  
  12614. /*  C O N X O  --  Write x characters to the console terminal  */
  12615.  
  12616. int
  12617. conxo(x,s) int x; char *s; {
  12618.  
  12619. #ifdef IKSD
  12620.     if (inserver && !local)
  12621.       return(ttol((CHAR *)s,x));
  12622.  
  12623. #ifdef CK_ENCRYPTION
  12624.     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
  12625.         ck_tn_encrypt(s,x);
  12626. #endif /* CK_ENCRYPTION */
  12627. #endif /* IKSD */
  12628.  
  12629. #ifdef Plan9
  12630.     return(conwrite(s,x));
  12631. #else
  12632.     return(write(1,s,x));
  12633. #endif /* Plan9 */
  12634. }
  12635.  
  12636. /*  C O N O L  --  Write a line to the console terminal  */
  12637.  
  12638. int
  12639. conol(s) char *s; {
  12640.     int len;
  12641.     if (!s) s = "";            /* Always do this! */
  12642.     len = strlen(s);
  12643.     if (len == 0)
  12644.       return(0);
  12645.  
  12646. #ifdef IKSD
  12647.     if (inserver && !local)
  12648.       return(ttol((CHAR *)s,len));
  12649.  
  12650. #ifdef CK_ENCRYPTION
  12651.     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION)) {
  12652.     if (nxpacket < len) {
  12653.         if (xpacket) {
  12654.         free(xpacket);
  12655.         xpacket = NULL;
  12656.         nxpacket = 0;
  12657.         }
  12658.         len = len > 10240 ? len : 10240;
  12659.         xpacket = (CHAR *)malloc(len);
  12660.         if (!xpacket) {
  12661.         fprintf(stderr,"ttol malloc failure\n");
  12662.         return(-1);
  12663.         } else
  12664.           nxpacket = len;
  12665.     }
  12666.     memcpy(xpacket,s,len);
  12667.     s = (char *)xpacket;
  12668.     ck_tn_encrypt(s,len);
  12669.     }
  12670. #endif /* CK_ENCRYPTION */
  12671. #endif /* IKSD */
  12672.  
  12673. #ifdef Plan9
  12674.     return(conwrite(s,len));
  12675. #else
  12676.     return(write(1,s,len));
  12677. #endif /* Plan9 */
  12678. }
  12679.  
  12680. /*  C O N O L A  --  Write an array of lines to the console terminal */
  12681.  
  12682. int
  12683. conola(s) char *s[]; {
  12684.     char * p;
  12685.     int i, x;
  12686.  
  12687.  
  12688.     if (!s) return(0);
  12689.     for (i = 0; ; i++) {
  12690.     p = s[i];
  12691.     if (!p) p = "";            /* Let's not dump core shall we? */
  12692.     if (!*p)
  12693.       break;
  12694. #ifdef IKSD
  12695.     if (inserver && !local)
  12696.       x = ttol((CHAR *)p,(int)strlen(p));
  12697.     else
  12698. #endif /* IKSD */
  12699.       x = conol(p);
  12700.     if (x < 0)
  12701.       return(-1);
  12702.     }
  12703.     return(0);
  12704. }
  12705.  
  12706. /*  C O N O L L  --  Output a string followed by CRLF  */
  12707.  
  12708. int
  12709. conoll(s) char *s; {
  12710.     CHAR buf[3];
  12711.     buf[0] = '\r';
  12712.     buf[1] = '\n';
  12713.     buf[2] = '\0';
  12714.     if (!s) s = "";
  12715.  
  12716. #ifdef IKSD
  12717.     if (inserver && !local) {
  12718.     if (*s) ttol((CHAR *)s,(int)strlen(s));
  12719.     return(ttol(buf,2));
  12720.     }
  12721. #endif /* IKSD */
  12722.  
  12723.     if (*s) conol(s);
  12724. #ifdef IKSD
  12725. #ifdef CK_ENCRYPTION
  12726.     if (inserver && TELOPT_ME(TELOPT_ENCRYPTION))
  12727.       ck_tn_encrypt((char *)buf,2);
  12728. #endif /* CK_ENCRYPTION */
  12729. #endif /* IKSD */
  12730.  
  12731. #ifdef Plan9
  12732.     return(conwrite(buf, 2));
  12733. #else
  12734.     return(write(1,buf,2));
  12735. #endif /* Plan9 */
  12736. }
  12737.  
  12738. /*  C O N C H K  --  Return how many characters available at console  */
  12739. /*
  12740.   We could also use select() here to cover a few more systems that are not
  12741.   covered by any of the following, e.g. HP-UX 9.0x on the model 800.
  12742. */
  12743. int
  12744. conchk() {
  12745.     static int contyp = 0;        /* +1 for isatty, -1 otherwise */
  12746.  
  12747.     if (contyp == 0)            /* This prevents unnecessary */
  12748.       contyp = (isatty(0) ? 1 : -1);    /* duplicated calls to isatty() */
  12749.     debug(F101,"conchk contyp","",contyp);
  12750.     if (backgrd || (contyp < 0))
  12751.       return(0);
  12752.  
  12753. #ifdef aegis
  12754.     if (conbufn > 0) return(conbufn);   /* use old count if nonzero */
  12755.  
  12756.     /* read in more characters */
  12757.     conbufn = ios_$get(ios_$stdin,
  12758.               ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
  12759.     if (st.all != status_$ok) conbufn = 0;
  12760.     conbufp = conbuf;
  12761.     return(conbufn);
  12762. #else
  12763. #ifdef IKSD
  12764.     if (inserver && !local)
  12765.       return(in_chk(1,ttyfd));
  12766.     else
  12767. #endif /* IKSD */
  12768.       return(in_chk(0,0));
  12769. #endif /* aegis */
  12770. }
  12771.  
  12772. /*  C O N I N C  --  Get a character from the console  */
  12773. /*
  12774.   Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
  12775.   read.  Upon success, returns the character.  Upon failure, returns -1.
  12776.   A timed read that does not complete within the timeout period returns -2.
  12777. */
  12778. int
  12779. coninc(timo) int timo; {
  12780.     int n = 0; CHAR ch;
  12781.     int xx;
  12782.  
  12783.     if (conbufn > 0) {            /* If something already buffered */
  12784.     --conbufn;
  12785.     return((unsigned)(*conbufp++ & 0xff));
  12786.     }
  12787.  
  12788.     errno = 0;                /* Clear this */
  12789. #ifdef IKSD
  12790.     if (inserver && !local) {
  12791.     xx = ttinc(timo);
  12792.     if (xx < 0)
  12793.       return(ttinctimo ? -2 : -1);
  12794.     else
  12795.       return(xx);
  12796.     }
  12797. #endif /* IKSD */
  12798.  
  12799. #ifdef aegis                /* Apollo Aegis only... */
  12800.     debug(F101,"coninc timo","",timo);
  12801.     fflush(stdout);
  12802.     if (conchk() > 0) {
  12803.     --conbufn;
  12804.     return((unsigned)(*conbufp++ & 0xff));
  12805.     }
  12806. #endif /* aegis */
  12807.  
  12808. #ifdef TTLEBUF
  12809.     if (
  12810. #ifdef IKSD
  12811.     inserver &&
  12812. #endif /* IKSD */
  12813.     !xlocal
  12814.     ) {
  12815.     if (ttpush >= 0) {
  12816.         debug(F111,"ttinc","ttpush",ttpush);
  12817.         ch = ttpush;
  12818.         ttpush = -1;
  12819.         return(ch);
  12820.     }
  12821.     if (le_data) {
  12822.         if (le_getchar(&ch) > 0) {
  12823.         debug(F111,"ttinc LocalEchoInBuf","ch",ch);
  12824.         return(ch);
  12825.         }
  12826.     }
  12827.     }
  12828. #endif /* TTLEBUF */
  12829.  
  12830.     if (timo <= 0) {            /* Untimed, blocking read. */
  12831.     while (1) {            /* Keep trying till we get one. */
  12832.         n = read(0, &ch, 1);    /* Read a character. */
  12833.         if (n == 0) continue;    /* Shouldn't happen. */
  12834.         if (n > 0) {        /* If read was successful, */
  12835. #ifdef IKSD
  12836. #ifdef CK_ENCRYPTION
  12837.                 debug(F100,"coninc decrypt 1","",0);
  12838.                 if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
  12839.           ck_tn_decrypt((char *)&ch,1);
  12840. #endif /* CK_ENCRYPTION */
  12841. #endif /* IKSD */
  12842.         return((unsigned)(ch & 0xff)); /* return the character. */
  12843.             }
  12844.  
  12845. /* Come here if read() returned an error. */
  12846.  
  12847.         debug(F101, "coninc(0) errno","",errno); /* Log the error. */
  12848. #ifndef OXOS
  12849. #ifdef SVORPOSIX
  12850. #ifdef CIE                             /* CIE Regulus has no EINTR symbol? */
  12851. #ifndef EINTR
  12852. #define EINTR 4
  12853. #endif /* EINTR */
  12854. #endif /* CIE */
  12855. /*
  12856.   This routine is used for several different purposes.  In CONNECT mode, it is
  12857.   used to do an untimed, blocking read from the keyboard in the lower CONNECT
  12858.   fork.  During local-mode file transfer, it reads a character from the
  12859.   console to interrupt the file transfer (like A for a status report, X to
  12860.   cancel a file, etc).  Obviously, we don't want the reads in the latter case
  12861.   to be blocking, or the file transfer would stop until the user typed
  12862.   something.  Unfortunately, System V does not allow the console device input
  12863.   buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
  12864.   used instead.  During local-mode file transfer, the SIGQUIT signal is armed
  12865.   and trapped by esctrp(), and this routine pretends to have read the quit
  12866.   character from the keyboard normally.  But, kludge or no kludge, the read()
  12867.   issued by this command, under System V only, can fail if a signal -- ANY
  12868.   signal -- is caught while the read is pending.  This can occur not only when
  12869.   the user types the quit character, but also during telnet negotiations, when
  12870.   the lower CONNECT fork signals the upper one about an echoing mode change.
  12871.   When this happens, we have to post the read() again.  This is apparently not
  12872.   a problem in BSD-based UNIX versions.
  12873. */
  12874.         if (errno == EINTR)        /* Read interrupted. */
  12875.           if (conesc)  {        /* If by SIGQUIT, */
  12876.           conesc = 0;        /* the conesc variable is set, */
  12877.           return(escchr);    /* so return the escape character. */
  12878.          } else continue;        /* By other signal, try again. */
  12879. #else
  12880. /*
  12881.   This might be dangerous, but let's do this on non-System V versions too,
  12882.   since at least one SunOS 4.1.2 user complains of immediate disconnections
  12883.   upon first making a TELNET connection.
  12884. */
  12885.         if (errno == EINTR)        /* Read interrupted. */
  12886.           continue;
  12887. #endif /* SVORPOSIX */
  12888. #else /* OXOS */
  12889.         if (errno == EINTR)        /* Read interrupted. */
  12890.           continue;
  12891. #endif /* OXOS */
  12892.         return(-1);            /* Error */
  12893.     }
  12894.     }
  12895. #ifdef DEBUG
  12896.     if (deblog && timo <= 0) {
  12897.     debug(F100,"coninc timeout logic error","",0);
  12898.     timo = 1;
  12899.     }
  12900. #endif /* DEBUG */
  12901.  
  12902. /* Timed read... */
  12903.  
  12904.     saval = signal(SIGALRM,timerh);    /* Set up timeout handler. */
  12905.     xx = alarm(timo);            /* Set the alarm. */
  12906.     debug(F101,"coninc alarm set","",timo);
  12907.     if (
  12908. #ifdef CK_POSIX_SIG
  12909.     sigsetjmp(sjbuf,1)
  12910. #else
  12911.     setjmp(sjbuf)
  12912. #endif /* CK_POSIX_SIG */
  12913.     )                /* The read() timed out. */
  12914.       n = -2;                /* Code for timeout. */
  12915.     else
  12916.       n = read(0, &ch, 1);
  12917.     ttimoff();                /* Turn off timer */
  12918.     if (n > 0) {            /* Got character OK. */
  12919. #ifdef IKSD
  12920. #ifdef CK_ENCRYPTION
  12921.         debug(F100,"coninc decrypt 2","",0);
  12922.         if (inserver && !local && TELOPT_U(TELOPT_ENCRYPTION))
  12923.       ck_tn_decrypt((char *)&ch,1);
  12924. #endif /* CK_ENCRYPTION */
  12925. #endif /* IKSD */
  12926.     return((unsigned)(ch & 0xff));    /* Return it. */
  12927.     }
  12928. /*
  12929.   read() returned an error.  Same deal as above, but without the loop.
  12930. */
  12931.     debug(F101, "coninc(timo) n","",n);
  12932.     debug(F101, "coninc(timo) errno","",errno);
  12933. #ifndef OXOS
  12934. #ifdef SVORPOSIX
  12935.     if (n == -1 && errno == EINTR && conesc != 0) {
  12936.     conesc = 0;
  12937.     return(escchr);            /* User entered escape character. */
  12938.     }
  12939. #endif /* SVORPOSIX */
  12940.     if (n == 0 && errno > 0) {        /* It's an error */
  12941.     return(-1);
  12942.     }
  12943. #endif /* ! OXOS */
  12944.     return(n);
  12945. }
  12946.  
  12947. /*  C O N G K S  --  Console Get Keyboard Scancode  */
  12948.  
  12949. #ifndef congks
  12950. /*
  12951.   This function needs to be filled in with the various system-dependent
  12952.   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
  12953.   keyboard scan code.  Unfortunately there aren't any.
  12954. */
  12955. int
  12956. congks(timo) int timo; {
  12957.  
  12958. #ifdef IKSD
  12959.     if (inserver && !local)
  12960.       return(ttinc(timo));
  12961. #endif /* IKSD */
  12962.  
  12963.     return(coninc(timo));
  12964. }
  12965. #endif /* congks */
  12966.  
  12967. #ifdef ATT7300
  12968.  
  12969. /*  A T T D I A L  --  Dial up the remote system using internal modem
  12970.  * Purpose: to open and dial a number on the internal modem available on the
  12971.  * ATT7300 UNIX PC.  Written by Joe Doupnik. Superceeds version written by
  12972.  * Richard E. Hill, Dickinson, TX. which employed dial(3c).
  12973.  * Uses information in <sys/phone.h> and our status int attmodem.
  12974.  */
  12975. attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
  12976.     char *telnum;
  12977.  
  12978.     attmodem &= ~ISMODEM;                       /* modem not in use yet */
  12979.                     /* Ensure O_NDELAY is set, else i/o traffic hangs */
  12980.                     /* We turn this flag off once the dial is complete */
  12981.     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
  12982.  
  12983.     /* Condition line, check availability & DATA mode, turn on speaker */
  12984.     if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
  12985.         printf("cannot access phone\n");
  12986.         ttclos(0);
  12987.         return (-2);
  12988.     }
  12989.     ioctl(ttyfd,PIOCGETP,&dialer);      /* get phone dialer parameters */
  12990.  
  12991.     if (dialer.c_lineparam & VOICE) {    /* phone must be in DATA mode */
  12992.         printf(" Should not dial with modem in VOICE mode.\n");
  12993.         printf(" Exit Kermit, switch to DATA and retry call.\n");
  12994.         ttclos(0);
  12995.         return (-2);
  12996.     }
  12997. #ifdef ATTTONED                /* Old way, tone dialing only. */
  12998.     dialer.c_lineparam = DATA | DTMF;    /* Dial with tones, */
  12999.     dialer.c_lineparam &= ~PULSE;    /* not with pulses. */
  13000. #else
  13001.     /* Leave current pulse/tone state alone. */
  13002.     /* But what about DATA?  Add it back if you have trouble. */
  13003.     /* sys/phone says you get DATA automatically by opening device RDWR */
  13004. #endif
  13005.     dialer.c_waitdialtone = 5;                  /* wait 5 sec for dialtone */
  13006. #ifdef COMMENT
  13007.     dialer.c_feedback = SPEAKERON|NORMSPK|RINGON;  /* control speaker */
  13008. #else
  13009.     /* sys/phone says RINGON used only for incoming voice calls */
  13010.     dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
  13011.     dialer.c_feedback |= SPEAKERON|NORMSPK;
  13012. #endif
  13013.     dialer.c_waitflash = 500;                   /* 0.5 sec flash hook */
  13014.     if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) {   /* set phone parameters */
  13015.         printf("Cannot set modem characteristics\n");
  13016.         ttclos(0);
  13017.         return (-2);
  13018.     }
  13019.     ioctl(ttyfd,PIOCRECONN,0);        /* Turns on speaker for pulse */
  13020.  
  13021. #ifdef COMMENT
  13022.     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
  13023. line_status:%o feedback:%o\n",
  13024.     dialer.c_lineparam, dialer.c_waitdialtone,
  13025.     dialer.c_linestatus, dialer.c_feedback);
  13026. #endif
  13027.  
  13028.     attmodem |= ISMODEM;                        /* modem is now in-use */
  13029.     sleep(1);
  13030.     for (telnum = telnbr; *telnum != '\0'; telnum++)    /* dial number */
  13031. #ifdef ATTTONED
  13032.       /* Tone dialing only */
  13033.       if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
  13034.       perror("Error in dialing");
  13035.       ttclos(0);
  13036.       return(-2);
  13037.       }
  13038. #else /* Allow Pulse or Tone dialing */
  13039.     switch (*telnum) {
  13040.       case 't': case 'T': case '%':    /* Tone dialing requested */
  13041.     dialer.c_lineparam |= DTMF;
  13042.     dialer.c_lineparam &= ~PULSE;
  13043.     if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
  13044.         printf("Cannot set modem to tone dialing\n");
  13045.         ttclos(0);
  13046.         return(-2);
  13047.     }
  13048.     break;
  13049.       case 'd': case 'D': case 'p': case 'P': case '^':
  13050.     dialer.c_lineparam |= PULSE;
  13051.     dialer.c_lineparam &= ~DTMF;
  13052.     if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
  13053.         printf("Cannot set modem to pulse dialing\n");
  13054.         ttclos(0);
  13055.         return(-2);
  13056.     }
  13057.     break;
  13058.       default:
  13059.         if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
  13060.         perror("Dialing error");
  13061.         ttclos(0);
  13062.         return(-2);
  13063.     }
  13064.     break;
  13065.     }
  13066. #endif
  13067.  
  13068.     ioctl(ttyfd,PIOCDIAL,"@");        /* terminator for data call */
  13069.     do {                /* wait for modems to Connect */
  13070.         if (ioctl(ttyfd,PIOCGETP,&dialer) != 0)    { /* get params */
  13071.         perror("Cannot get modems to connect");
  13072.         ttclos(0);
  13073.         return(-2);
  13074.     }
  13075.     } while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
  13076.     /* Turn off O_NDELAY flag now. */
  13077.     fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
  13078.     signal(SIGHUP, sighup);             /* hangup on loss of carrier */
  13079.     return(0);                          /* return success */
  13080. }
  13081.  
  13082. /*
  13083.   Offgetty, ongetty functions. These function get the 'getty(1m)' off
  13084.   and restore it to the indicated line.  Shell's return codes are:
  13085.     0: Can't do it.  Probably a user logged on.
  13086.     1: No need.  No getty on that line.
  13087.     2: Done, you should restore the getty when you're done.
  13088.   DOGETY System(3), however, returns them as 0, 256, 512, respectively.
  13089.   Thanks to Kevin O'Gorman, Anarm Software Systems.
  13090.  
  13091.    getoff.sh looks like:   geton.sh looks like:
  13092.      setgetty $1 0           setgetty $1 1
  13093.      err=$?                  exit $?
  13094.      sleep 2
  13095.      exit $err
  13096. */
  13097.  
  13098. /*  O F F G E T T Y  --  Turn off getty(1m) for the communications tty line
  13099.  * and get status so it can be restarted after the line is hung up.
  13100.  */
  13101. int
  13102. offgetty(ttname) char *ttname; {
  13103.     char temp[30];
  13104.     while (*ttname != '\0') ttname++;       /* seek terminator of path */
  13105.     ttname -= 3;                            /* get last 3 chars of name */
  13106.     sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
  13107.     return(zsyscmd(temp));
  13108. }
  13109.  
  13110. /*  O N G E T T Y  --  Turn on getty(1m) for the communications tty line */
  13111.  
  13112. int
  13113. ongetty(ttname) char *ttname; {
  13114.     char temp[30];
  13115.     while (*ttname != '\0') ttname++;       /* comms tty path name */
  13116.     ttname -= 3;
  13117.     sprintf(temp,"/usr/bin/geton.sh %s",ttname);
  13118.     return(zsyscmd(temp));
  13119. }
  13120. #endif /* ATT7300 */
  13121.  
  13122. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  13123.  *
  13124.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  13125.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  13126.  *  2 = Auto: For "modem direct": The same as "Off".
  13127.  *            For real modem types: Heed carrier during connect, but ignore
  13128.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  13129.  *
  13130.  * As you can see, this setting does not affect dialing, which always ignores
  13131.  * carrier (unless there is some special exception for some modem type).  It
  13132.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  13133.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  13134.  * (or should be) always called before any communications is tried, which
  13135.  * means that, practically speaking, the effect is immediate.
  13136.  *
  13137.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  13138.  *
  13139.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  13140.  * environment (or any non-termio using environment).  Until that time, this
  13141.  * will simply be a no-op for BSD.
  13142.  *
  13143.  * Note that in previous versions, the carrier was most often left unchanged
  13144.  * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX.  This
  13145.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  13146.  * modes.
  13147.  */
  13148. int
  13149. ttscarr(carrier) int carrier; {
  13150.     ttcarr = carrier;
  13151.     debug(F101, "ttscarr","",ttcarr);
  13152.     return(ttcarr);
  13153. }
  13154.  
  13155. /* C A R R C T L  --  Set tty modes for carrier treatment.
  13156.  *
  13157.  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
  13158.  * (actually, there are no bits in sgttyb for that), or performs any other
  13159.  * operations needed to control this on the current system.  The function does
  13160.  * not do the actual TCSETA or stty, since often we want to set other bits too
  13161.  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
  13162.  *
  13163.  * We don't know how to do anything like carrier control on non-ATTSV systems,
  13164.  * except, apparently, ultrix.  See above.  It is also known that this doesn't
  13165.  * have much effect on a Xenix system.  For Xenix, one should switch back and
  13166.  * forth between the upper and lower case device files.  Maybe later.
  13167.  * Presently, Xenix will stick to the mode it was opened with.
  13168.  *
  13169.  * carrier: 0 = ignore carrier, 1 = require carrier.
  13170.  * The current state is saved in curcarr, and checked to save labour.
  13171.  */
  13172. #ifdef SVORPOSIX
  13173. int
  13174. #ifdef BSD44ORPOSIX
  13175. carrctl(ttpar, carrier)    struct termios *ttpar; int carrier;
  13176. #else /* ATTSV */
  13177. carrctl(ttpar, carrier)    struct termio *ttpar; int carrier;
  13178. #endif /* BSD44ORPOSIX */
  13179. /* carrctl */ {
  13180.     debug(F101, "carrctl","",carrier);
  13181.     if (carrier)
  13182.       ttpar->c_cflag &= ~CLOCAL;
  13183.     else
  13184.       ttpar->c_cflag |= CLOCAL;
  13185.     return(0);
  13186. }
  13187. #else /* Berkeley, V7, et al... */
  13188. int
  13189. carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
  13190.     debug(F101, "carrctl","",carrier);
  13191.     if (carrier == curcarr)
  13192.       return(0);
  13193.     curcarr = carrier;
  13194. #ifdef ultrix
  13195. #ifdef COMMENT
  13196. /*
  13197.   Old code from somebody at DEC that tends to get stuck, time out, etc.
  13198. */
  13199.     if (carrier) {
  13200.     ioctl(ttyfd, TIOCMODEM, &temp);
  13201.     ioctl(ttyfd, TIOCHPCL, 0);
  13202.     } else {
  13203.     /* (According to the manuals, TIOCNCAR should be preferred */
  13204.     /* over TIOCNMODEM...) */
  13205.     ioctl(ttyfd, TIOCNMODEM, &temp);
  13206.     }
  13207. #else
  13208. /*
  13209.   New code from Jamie Watson that, he says, eliminates the problems.
  13210. */
  13211.     if (carrier) {
  13212.     ioctl(ttyfd, TIOCCAR);
  13213.     ioctl(ttyfd, TIOCHPCL);
  13214.     } else {
  13215.     ioctl(ttyfd, TIOCNCAR);
  13216.     }
  13217. #endif /* COMMENT */
  13218. #endif /* ultrix */
  13219.     return(0);
  13220. }
  13221. #endif /* SVORPOSIX */
  13222.  
  13223.  
  13224. /*  T T G M D M  --  Get modem signals  */
  13225. /*
  13226.  Looks for RS-232 modem signals, and returns those that are on in as its
  13227.  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
  13228.  Returns:
  13229.  -3 Not implemented
  13230.  -2 if the communication device does not have modem control (e.g. telnet)
  13231.  -1 on error.
  13232.  >= 0 on success, with a bit mask containing the modem signals that are on.
  13233. */
  13234.  
  13235. /*
  13236.   Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
  13237.   modem control, namely the TIOCMGET ioctl.
  13238. */
  13239.  
  13240. #ifdef BSD43
  13241. #define K_MDMCTL
  13242. #endif /* BSD43 */
  13243.  
  13244. #ifdef SUNOS4
  13245. #define K_MDMCTL
  13246. #endif /* SUNOS4 */
  13247.  
  13248. /*
  13249.   SCO OpenServer R5.0.4.  The TIOCMGET definition is hardwired in because it
  13250.   is skipped in termio.h when _POSIX_SOURCE is defined.  But _POSIX_SOURCE
  13251.   must be defined in order to get the high serial speeds that are new to
  13252.   5.0.4.  However, the regular SCO drivers do not implement TIOCMGET, so the
  13253.   ioctl() returns -1 with errno 22 (invalid function).  But third-party
  13254.   drivers, e.g. for Digiboard, do implement it, and so it should work on ports
  13255.   driven by those drivers.
  13256. */
  13257. #ifdef SCO_OSR504
  13258. #ifndef TIOCMGET
  13259. #define TIOCMGET (('t'<<8)|29)
  13260. #endif /* TIOCMGET */
  13261. #endif /* SCO_OSR504 */
  13262.  
  13263. #ifdef CK_SCOV5
  13264. /* Because POSIX strictness in <sys/termio.h> won't let us see these. */
  13265. #ifndef TIOCM_DTR
  13266. #define TIOCM_DTR    0x0002        /* data terminal ready */
  13267. #define TIOCM_RTS    0x0004        /* request to send */
  13268. #define TIOCM_CTS    0x0020        /* clear to send */
  13269. #define TIOCM_CAR    0x0040        /* carrier detect */
  13270. #define TIOCM_RNG    0x0080        /* ring */
  13271. #define TIOCM_DSR    0x0100        /* data set ready */
  13272. #define TIOCM_CD    TIOCM_CAR
  13273. #define TIOCM_RI    TIOCM_RNG
  13274. #endif /* TIOCM_DTR */
  13275. #endif /* CK_SCOV5 */
  13276.  
  13277. #ifdef QNX
  13278. #define K_MDMCTL
  13279. #else
  13280. #ifdef TIOCMGET
  13281. #define K_MDMCTL
  13282. #endif /* TIOCMGET */
  13283. #endif /* QNX */
  13284. /*
  13285.   "A serial communication program that can't read modem signals
  13286.    is like a car without windows."
  13287. */
  13288. int
  13289. ttgmdm() {
  13290.  
  13291. #ifdef QNX
  13292. #include <sys/qioctl.h>
  13293.  
  13294.     unsigned long y, mdmbits[2];
  13295.     int x, z = 0;
  13296.  
  13297.     if (xlocal && ttyfd < 0)
  13298.       return(-1);
  13299.  
  13300. #ifdef NETCONN
  13301.     if (netconn) {            /* Network connection */
  13302. #ifdef TN_COMPORT
  13303.         if (istncomport()) {
  13304.         gotsigs = 1;
  13305.         return(tngmdm());
  13306.     } else
  13307. #endif /* TN_COMPORT */
  13308.       return(-2);            /* No modem signals */
  13309.     }
  13310. #endif /* NETCONN */
  13311.  
  13312. #ifdef NETCMD
  13313.     if (ttpipe) return(-2);
  13314. #endif /* NETCMD */
  13315. #ifdef NETPTY
  13316.     if (ttpty) return(-2);
  13317. #endif /* NETPTY */
  13318.  
  13319.     mdmbits[0] = 0L;
  13320.     mdmbits[1] = 0L;
  13321. /*
  13322.  * From <sys/qioctl.h>:
  13323.  *
  13324.  * SERIAL devices   (all Dev.ser versions)
  13325.  * 0 : DTR           8 = Data Bits 0  16 - reserved     24 - reserved
  13326.  * 1 : RTS           9 = Data Bits 1  17 - reserved     25 - reserved
  13327.  * 2 = Out 1        10 = Stop Bits    18 - reserved     26 - reserved
  13328.  * 3 = Int Enable   11 = Par Enable   19 - reserved     27 - reserved
  13329.  * 4 = Loop         12 = Par Even     20 = CTS          28 - reserved
  13330.  * 5 - reserved     13 = Par Stick    21 = DSR          29 - reserved
  13331.  * 6 - reserved     14 : Break        22 = RI           30 - reserved
  13332.  * 7 - reserved     15 = 0            23 = CD           31 - reserved
  13333.  */
  13334.     errno = 0;
  13335.     x = qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4);
  13336.     debug(F101,"ttgmdm qnx_ioctl","",x);
  13337.     debug(F101,"ttgmdm qnx_ioctl errno","",errno);
  13338.     if (!x) {
  13339.     debug(F101,"ttgmdm qnx_ioctl mdmbits[0]","",mdmbits[0]);
  13340.     debug(F101,"ttgmdm qnx_ioctl mdmbits[1]","",mdmbits[1]);
  13341.     y = mdmbits[0];
  13342.     if (y & 0x000001L) z |= BM_DTR;    /* Bit  0 */
  13343.     if (y & 0x000002L) z |= BM_RTS;    /* Bit  1 */
  13344.     if (y & 0x100000L) z |= BM_CTS;    /* Bit 20 */
  13345.     if (y & 0x200000L) z |= BM_DSR;    /* Bit 21 */
  13346.     if (y & 0x400000L) z |= BM_RNG;    /* Bit 22 */
  13347.     if (y & 0x800000L) z |= BM_DCD;    /* Bit 23 */
  13348.     debug(F101,"ttgmdm qnx result","",z);
  13349.     debug(F110,"ttgmdm qnx CD = ",(z & BM_DCD) ? "On" : "Off", 0);
  13350.     gotsigs = 1;
  13351.     return(z);
  13352.     } else return(-1);
  13353. #else /* QNX */
  13354. #ifdef HPUX                /* HPUX has its own way */
  13355.     int x, z;
  13356.  
  13357. #ifdef HPUX10                /* Modem flag word */
  13358.     mflag y;                /* mflag typedef'd in <sys/modem.h> */
  13359. #else
  13360. #ifdef HPUX9
  13361.     mflag y;
  13362. #else
  13363. #ifdef HPUX8
  13364.     mflag y;
  13365. #else
  13366.     unsigned long y;            /* Not sure about pre-8.0... */
  13367. #endif /* HPUX8 */
  13368. #endif /* HPUX9 */
  13369. #endif /* HPUX10 */
  13370.  
  13371.     if (xlocal && ttyfd < 0)
  13372.       return(-1);
  13373.  
  13374. #ifdef NETCONN
  13375.     if (netconn) {            /* Network connection */
  13376. #ifdef TN_COMPORT
  13377.         if (istncomport()) {
  13378.         gotsigs = 1;
  13379.         return(tngmdm());
  13380.     } else
  13381. #endif /* TN_COMPORT */
  13382.       return(-2);            /* No modem signals */
  13383.     }
  13384. #endif /* NETCONN */
  13385.  
  13386. #ifdef NETCMD
  13387.     if (ttpipe) return(-2);
  13388. #endif /* NETCMD */
  13389. #ifdef NETPTY
  13390.     if (ttpty) return(-2);
  13391. #endif /* NETPTY */
  13392.  
  13393.     if (xlocal)                /* Get modem signals */
  13394.       x = ioctl(ttyfd,MCGETA,&y);
  13395.     else
  13396.       x = ioctl(0,MCGETA,&y);
  13397.     if (x < 0) return(-1);
  13398.     debug(F101,"ttgmdm","",y);
  13399.  
  13400.     z = 0;                /* Initialize return value */
  13401.  
  13402. /* Now set bits for each modem signal that is reported to be on. */
  13403.  
  13404. #ifdef MCTS
  13405.     /* Clear To Send */
  13406.     debug(F101,"ttgmdm HPUX CTS","",y & MCTS);
  13407.     if (y & MCTS) z |= BM_CTS;
  13408. #endif
  13409. #ifdef MDSR
  13410.     /* Data Set Ready */
  13411.     debug(F101,"ttgmdm HPUX DSR","",y & MDSR);
  13412.     if (y & MDSR) z |= BM_DSR;
  13413. #endif
  13414. #ifdef MDCD
  13415.     /* Carrier */
  13416.     debug(F101,"ttgmdm HPUX DCD","",y & MDCD);
  13417.     if (y & MDCD) z |= BM_DCD;
  13418. #endif
  13419. #ifdef MRI
  13420.     /* Ring Indicate */
  13421.     debug(F101,"ttgmdm HPUX RI","",y & MRI);
  13422.     if (y & MRI) z |= BM_RNG;
  13423. #endif
  13424. #ifdef MDTR
  13425.     /* Data Terminal Ready */
  13426.     debug(F101,"ttgmdm HPUX DTR","",y & MDTR);
  13427.     if (y & MDTR) z |= BM_DTR;
  13428. #endif
  13429. #ifdef MRTS
  13430.     /* Request To Send */
  13431.     debug(F101,"ttgmdm HPUX RTS","",y & MRTS);
  13432.     if (y & MRTS) z |= BM_RTS;
  13433. #endif
  13434.     gotsigs = 1;
  13435.     return(z);
  13436.  
  13437. #else /* ! HPUX */
  13438.  
  13439. #ifdef K_MDMCTL
  13440. /*
  13441.   Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
  13442.   If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
  13443.   are needed.
  13444. */
  13445. #ifndef TIOCMGET
  13446. #include <sys/ttycom.h>
  13447. #endif /* TIOCMGET */
  13448.  
  13449.     int x, y, z;
  13450.  
  13451.     debug(F100,"ttgmdm K_MDMCTL defined","",0);
  13452.  
  13453. #ifdef NETCONN
  13454.     if (netconn) {            /* Network connection */
  13455. #ifdef TN_COMPORT
  13456.         if (istncomport()) {
  13457.         gotsigs = 1;
  13458.         return(tngmdm());
  13459.     } else
  13460. #endif /* TN_COMPORT */
  13461.       return(-2);            /* No modem signals */
  13462.     }
  13463. #endif /* NETCONN */
  13464.  
  13465. #ifdef NETCMD
  13466.     if (ttpipe) return(-2);
  13467. #endif /* NETCMD */
  13468. #ifdef NETPTY
  13469.     if (ttpty) return(-2);
  13470. #endif /* NETPTY */
  13471.  
  13472.     if (xlocal && ttyfd < 0)
  13473.       return(-1);
  13474.  
  13475.     if (xlocal)
  13476.       x = ioctl(ttyfd,TIOCMGET,&y);    /* Get modem signals. */
  13477.     else
  13478.       x = ioctl(0,TIOCMGET,&y);
  13479.     debug(F101,"ttgmdm TIOCMGET ioctl","",x);
  13480.     if (x < 0) {
  13481.     debug(F101,"ttgmdm errno","",errno);
  13482.     return(-1);
  13483.     }
  13484.     debug(F101,"ttgmdm bits","",y);
  13485.  
  13486.     z = 0;                /* Initialize return value. */
  13487. #ifdef TIOCM_CTS
  13488.     /* Clear To Send */
  13489.     if (y & TIOCM_CTS) z |= BM_CTS;
  13490.     debug(F101,"ttgmdm TIOCM_CTS defined","",TIOCM_CTS); 
  13491. #else
  13492.     debug(F100,"ttgmdm TIOCM_CTS not defined","",0);
  13493. #endif
  13494. #ifdef TIOCM_DSR
  13495.     /* Data Set Ready */
  13496.     if (y & TIOCM_DSR) z |= BM_DSR;
  13497.     debug(F101,"ttgmdm TIOCM_DSR defined","",TIOCM_DSR); 
  13498. #else
  13499.     debug(F100,"ttgmdm TIOCM_DSR not defined","",0);
  13500. #endif
  13501. #ifdef TIOCM_CAR
  13502.     /* Carrier */
  13503.     if (y & TIOCM_CAR) z |= BM_DCD;
  13504.     debug(F101,"ttgmdm TIOCM_CAR defined","",TIOCM_CAR); 
  13505. #else
  13506.     debug(F100,"ttgmdm TIOCM_CAR not defined","",0);
  13507. #endif
  13508. #ifdef TIOCM_RNG
  13509.     /* Ring Indicate */
  13510.     if (y & TIOCM_RNG) z |= BM_RNG;
  13511.     debug(F101,"ttgmdm TIOCM_RNG defined","",TIOCM_RNG); 
  13512. #else
  13513.     debug(F100,"ttgmdm TIOCM_RNG not defined","",0);
  13514. #endif
  13515. #ifdef TIOCM_DTR
  13516.     /* Data Terminal Ready */
  13517.     if (y & TIOCM_DTR) z |= BM_DTR;
  13518.     debug(F101,"ttgmdm TIOCM_DTR defined","",TIOCM_DTR); 
  13519. #else
  13520.     debug(F100,"ttgmdm TIOCM_DTR not defined","",0);
  13521. #endif
  13522. #ifdef TIOCM_RTS
  13523.     /* Request To Send */
  13524.     if (y & TIOCM_RTS) z |= BM_RTS;
  13525.     debug(F101,"ttgmdm TIOCM_RTS defined","",TIOCM_RTS); 
  13526. #else
  13527.     debug(F100,"ttgmdm TIOCM_RTS not defined","",0);
  13528. #endif
  13529.     gotsigs = 1;
  13530.     return(z);
  13531.  
  13532. #else /* !K_MDMCTL catch-All */
  13533.  
  13534.     debug(F100,"ttgmdm K_MDMCTL not defined","",0);
  13535. #ifdef TIOCMGET
  13536.     debug(F100,"ttgmdm TIOCMGET defined","",0);
  13537. #else
  13538.     debug(F100,"ttgmdm TIOCMGET not defined","",0);
  13539. #endif /* TIOCMGET */
  13540. #ifdef _SVID3
  13541.     debug(F100,"ttgmdm _SVID3 defined","",0);
  13542. #else
  13543.     debug(F100,"ttgmdm _SVID3 not defined","",0);
  13544. #endif /* _SVID3 */
  13545.  
  13546. #ifdef NETCONN
  13547.     if (netconn) {            /* Network connection */
  13548. #ifdef TN_COMPORT
  13549.         if (istncomport()) {
  13550.         gotsigs = 1;
  13551.         return(tngmdm());
  13552.     } else
  13553. #endif /* TN_COMPORT */
  13554.       return(-2);            /* No modem signals */
  13555.     }
  13556. #endif /* NETCONN */
  13557.  
  13558. #ifdef NETCMD
  13559.     if (ttpipe) return(-2);
  13560. #endif /* NETCMD */
  13561. #ifdef NETPTY
  13562.     if (ttpty) return(-2);
  13563. #endif /* NETPTY */
  13564.  
  13565.     return(-3);                /* Sorry, I don't know how... */
  13566.  
  13567. #endif /* K_MDMCTL */
  13568. #endif /* HPUX */
  13569. #endif /* QNX */
  13570. }
  13571.  
  13572. /*  P S U S P E N D  --  Put this process in the background.  */
  13573.  
  13574. /*
  13575.   Call with flag nonzero if suspending is allowed, zero if not allowed.
  13576.   Returns 0 on apparent success, -1 on failure (flag was zero, or
  13577.   kill() returned an error code.
  13578. */
  13579. int
  13580. psuspend(flag) int flag; {
  13581.  
  13582. #ifdef RTU
  13583.     extern int rtu_bug;
  13584. #endif /* RTU */
  13585.  
  13586.     if (flag == 0) return(-1);
  13587.  
  13588. #ifdef NOJC
  13589.     return(-1);
  13590. #else
  13591. #ifdef SIGTSTP
  13592. /*
  13593.   The big question here is whether job control is *really* supported.
  13594.   There's no way Kermit can know for sure.  The fact that SIGTSTP is
  13595.   defined does not guarantee the Unix kernel supports it, and the fact
  13596.   that the Unix kernel supports it doesn't guarantee that the user's
  13597.   shell (or other process that invoked Kermit) supports it.
  13598. */
  13599. #ifdef RTU
  13600.     rtu_bug = 1;
  13601. #endif /* RTU */
  13602.     if (kill(0,SIGSTOP) < 0
  13603. #ifdef MIPS
  13604. /* Let's try this for MIPS too. */
  13605.     && kill(getpid(),SIGSTOP) < 0
  13606. #endif /* MIPS */
  13607.     ) {                /* If job control, suspend the job */
  13608.     perror("suspend");
  13609.     debug(F101,"psuspend error","",errno);
  13610.     return(-1);
  13611.     }
  13612.     debug(F100,"psuspend ok","",0);
  13613.     return(0);
  13614. #else
  13615.     return(-1);
  13616. #endif /* SIGTSTP */
  13617. #endif /* NOJC */
  13618. }
  13619.  
  13620. /*
  13621.   setuid package, by Kristoffer Eriksson, with contributions from Dean
  13622.   Long and fdc.
  13623. */
  13624.  
  13625. /* The following is for SCO when CK_ANSILIBS is defined... */
  13626. #ifdef M_UNIX
  13627. #ifdef CK_ANSILIBS
  13628. #ifndef NOGETID_PROTOS
  13629. #define NOGETID_PROTOS
  13630. #endif /* NOGETID_PROTOS */
  13631. #endif /* CK_ANSILIBS */
  13632. #endif /* M_UNIX */
  13633.  
  13634. #ifndef _POSIX_SOURCE
  13635. #ifndef SUNOS4
  13636. #ifndef NEXT
  13637. #ifndef PS2AIX10
  13638. #ifndef sequent
  13639. #ifndef HPUX9
  13640. #ifndef HPUX10
  13641. #ifndef COHERENT
  13642. #ifndef NOGETID_PROTOS
  13643. _PROTOTYP( UID_T getuid, (void) );
  13644. _PROTOTYP( UID_T geteuid, (void) );
  13645. _PROTOTYP( UID_T getreuid, (void) );
  13646. _PROTOTYP( UID_T getgid, (void) );
  13647. _PROTOTYP( UID_T getegid, (void) );
  13648. _PROTOTYP( UID_T getregid, (void) );
  13649. #endif /* NOGETID_PROTOS */
  13650. #else
  13651. _PROTOTYP( UID_T getreuid, (void) );
  13652. _PROTOTYP( UID_T getregid, (void) );
  13653. #endif /* COHERENT */
  13654. #endif /* HPUX10 */
  13655. #endif /* HPUX9 */
  13656. #endif /* sequent */
  13657. #endif /* PS2AIX10 */
  13658. #endif /* NEXT */
  13659. #endif /* SUNOS4 */
  13660. #endif /* _POSIX_SOURCE */
  13661.  
  13662. /*
  13663. Subject: Set-user-id
  13664. To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
  13665. Date: Sat, 21 Apr 90 4:48:25 MES
  13666. From: Kristoffer Eriksson <ske@pkmab.se>
  13667.  
  13668. This is a set of functions to be used in programs that may be run set-user-id
  13669. and/or set-group-id. They handle both the case where the program is not run
  13670. with such privileges (nothing special happens then), and the case where one
  13671. or both of these set-id modes are used.  The program is made to run with the
  13672. user's real user and group ids most of the time, except for when more
  13673. privileges are needed.  Don't set-user-id to "root".
  13674.  
  13675. This works on System V and POSIX.  In BSD, it depends on the
  13676. "saved-set-user-id" feature.
  13677. */
  13678.  
  13679. #define UID_ROOT 0            /* Root user and group ids */
  13680. #define GID_ROOT 0
  13681.  
  13682. /*
  13683.   The following code defines the symbol SETEUID for UNIX systems based
  13684.   on BSD4.4 (either -Encumbered or -Lite).  This program will then use
  13685.   seteuid() and setegid() instead of setuid() and setgid(), which still
  13686.   don't allow arbitrary switching.  It also avoids setreuid() and
  13687.   setregid(), which are included in BSD4.4 for compatibility only, are
  13688.   insecure, and print warnings to stderr under at least one system (NetBSD
  13689.   1.0).  Note that POSIX systems should still use setuid() and setgid();
  13690.   the seteuid() and setegid() functions are BSD4.4 extensions to the
  13691.   POSIX model.  Mike Long <mike.long@analog.com>, 8/94.
  13692. */
  13693. #ifdef BSD44
  13694. #define SETEUID
  13695. #endif /* BSD44 */
  13696.  
  13697. /*
  13698.   The following construction automatically defines the symbol SETREUID for
  13699.   UNIX versions based on Berkeley Unix 4.2 and 4.3.  If this symbol is
  13700.   defined, then this program will use getreuid() and getregid() calls in
  13701.   preference to getuid() and getgid(), which in Berkeley-based Unixes do
  13702.   not allow arbitrary switching back and forth of real & effective uid.
  13703.   This construction also allows -DSETREUID to be put on the cc command line
  13704.   for any system that has and wants to use setre[ug]id().  It also prevents
  13705.   automatic definition of SETREUID if -DNOSETREU is included on the cc
  13706.   command line (or otherwise defined).
  13707. */
  13708. #ifdef FT18                /* None of this for Fortune. */
  13709. #define NOSETREU
  13710. #endif /* FT18 */
  13711.  
  13712. #ifdef ANYBSD
  13713. #ifndef BSD29
  13714. #ifndef BSD41
  13715. #ifndef SETREUID
  13716. #ifndef NOSETREU
  13717. #ifndef SETEUID
  13718. #define SETREUID
  13719. #endif /* SETEUID */
  13720. #endif /* NOSETREU */
  13721. #endif /* SETREUID */
  13722. #endif /* !BSD41 */
  13723. #endif /* !BSD29 */
  13724. #endif /* ANYBSD */
  13725.  
  13726. /* Variables for user and group IDs. */
  13727.  
  13728. static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
  13729. static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
  13730.  
  13731.  
  13732. /* P R I V _ I N I  --  Initialize privileges package  */
  13733.  
  13734. /* Called as early as possible in a set-uid or set-gid program to store the
  13735.  * set-to uid and/or gid and step down to the users real uid and gid. The
  13736.  * stored id's can be temporarily restored (allowed in System V) during
  13737.  * operations that require the privilege.  Most of the time, the program
  13738.  * should execute in unpriviliged state, to not impose any security threat.
  13739.  *
  13740.  * Note: Don't forget that access() always uses the real id:s to determine
  13741.  * file access, even with privileges restored.
  13742.  *
  13743.  * Returns an error mask, with error values or:ed together:
  13744.  *   1 if setuid() fails,
  13745.  *   2 if setgid() fails, and
  13746.  *   4 if the program is set-user-id to "root", which can't be handled.
  13747.  *
  13748.  * Only the return value 0 indicates real success. In case of failure,
  13749.  * those privileges that could be reduced have been, at least, but the
  13750.  * program should be aborted none-the-less.
  13751.  *
  13752.  * Also note that these functions do not expect the uid or gid to change
  13753.  * without their knowing. It may work if it is only done temporarily, but
  13754.  * you're on your own.
  13755.  */
  13756. int
  13757. priv_ini() {
  13758.     int err = 0;
  13759.  
  13760. #ifndef HAVE_LOCKDEV
  13761.  
  13762.     /* Save real ID:s. */
  13763.     realuid = getuid();
  13764.     realgid = getgid();
  13765.  
  13766.     /* Save current effective ID:s, those set to at program exec. */
  13767.     privuid = geteuid();
  13768.     privgid = getegid();
  13769.  
  13770.     /* If running set-uid, go down to real uid, otherwise remember that
  13771.      * no privileged uid is available.
  13772.      *
  13773.      * Exceptions:
  13774.      *
  13775.      * 1) If the real uid is already "root" and the set-uid uid (the
  13776.      * initial effective uid) is not "root", then we would have trouble
  13777.      * if we went "down" to "root" here, and then temporarily back to the
  13778.      * set-uid uid (not "root") and then again tried to become "root". I
  13779.      * think the "saved set-uid" is lost when changing uid from effective
  13780.      * uid "root", which changes all uid, not only the effective uid. But
  13781.      * in this situation, we can simply go to "root" and stay there all
  13782.      * the time. That should give sufficient privilege (understatement!),
  13783.      * and give the right uids for subprocesses.
  13784.      *
  13785.      * 2) If the set-uid (the initial effective uid) is "root", and we
  13786.      * change uid to the real uid, we can't change it back to "root" when
  13787.      * we need the privilege, for the same reason as in 1). Thus, we can't
  13788.      * handle programs that are set-user-id to "root" at all. The program
  13789.      * should be stopped.  Use some other uid.  "root" is probably too
  13790.      * privileged for such things, anyway. (The uid is reverted to the
  13791.      * real uid until termination.)
  13792.      *
  13793.      * These two exceptions have the effect that the "root" uid will never
  13794.      * be one of the two uids that are being switched between, which also
  13795.      * means we don't have to check for such cases in the switching
  13796.      * functions.
  13797.      *
  13798.      * Note that exception 1) is handled by these routines (by constantly
  13799.      * running with uid "root", while exception 2) is a serious error, and
  13800.      * is not provided for at all in the switching functions.
  13801.      */
  13802.     if (realuid == privuid)
  13803.     privuid = (UID_T) -1;        /* Not running set-user-id. */
  13804.  
  13805.     /* If running set-gid, go down to real gid, otherwise remember that
  13806.      * no privileged gid is available.
  13807.      *
  13808.      * There are no exception like there is for the user id, since there
  13809.      * is no group id that is privileged in the manner of uid "root".
  13810.      * There could be equivalent problems for group changing if the
  13811.      * program sometimes ran with uid "root" and sometimes not, but
  13812.      * that is already avoided as explained above.
  13813.      *
  13814.      * Thus we can expect always to be able to switch to the "saved set-
  13815.      * gid" when we want, and back to the real gid again. You may also
  13816.      * draw the conclusion that set-gid provides for fewer hassles than
  13817.      * set-uid.
  13818.      */
  13819.  
  13820. #ifdef SUIDDEBUG
  13821.     fprintf(stderr,"UID_ROOT=%d\n",UID_ROOT);
  13822.     fprintf(stderr,"realuid=%d\n",realuid);
  13823.     fprintf(stderr,"privuid=%d\n",privuid);
  13824. #endif /* SUIDDEBUG */
  13825.  
  13826.     if (realgid == privgid)        /* If not running set-user-id, */
  13827.       privgid = (GID_T) -1;        /*  remember it this way. */
  13828.  
  13829.     err = priv_off();            /* Turn off setuid privilege. */
  13830.  
  13831.     if (privuid == UID_ROOT)        /* If setuid to root, */
  13832.       err |= 4;                /* return this error. */
  13833.  
  13834.     if (realuid == UID_ROOT) {        /* If real id is root, */
  13835.     privuid = (UID_T) -1;        /* stay root at all times. */
  13836. #ifdef ATT7300
  13837.     /* If Kermit installed SUID uucp and user is running as root */
  13838.     err &= ~1;            /* System V R0 does not save UID */
  13839. #endif /* ATT7300 */
  13840.     }
  13841. #endif /* HAVE_LOCKDEV */
  13842.     return(err);
  13843. }
  13844.  
  13845.  
  13846. /* Macros for hiding the differences in UID/GID setting between various Unix
  13847.  * systems. These macros should always be called with both the privileged ID
  13848.  * and the non-privileged ID. The one in the second argument, will become the
  13849.  * effective ID. The one in the first argument will be retained for later
  13850.  * retrieval.
  13851.  */
  13852. #ifdef SETREUID
  13853. #ifdef SAVEDUID
  13854. /* On BSD systems with the saved-UID feature, we just juggle the effective
  13855.  * UID back and forth, and leave the real UID at its true value.  The kernel
  13856.  * allows switching to both the current real UID, the effective UID, and the
  13857.  * UID which the program is set-UID to.  The saved set-UID always holds the
  13858.  * privileged UID for us, and the real UID will always be the non-privileged,
  13859.  * and we can freely choose one of them for the effective UID at any time.
  13860.  */
  13861. #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
  13862. #define switchgid(hidden,active) setregid( (GID_T) -1, active)
  13863.  
  13864. #else   /* SETREUID,!SAVEDUID */
  13865.  
  13866. /* On systems with setreXid() but without the saved-UID feature, notably
  13867.  * BSD 4.2, we swap the real and effective UIDs each time.  It's
  13868.  * the effective UID that we are interested in, but we have to retain the
  13869.  * unused UID somewhere to enable us to restore it later, and we do this
  13870.  * in the real UID.  The kernel only allows switching to either the current
  13871.  * real or the effective UID, unless you're "root".
  13872.  */
  13873. #define switchuid(hidden,active)    setreuid(hidden,active)
  13874. #define switchgid(hidden,active)    setregid(hidden,active)
  13875. #endif
  13876.  
  13877. #else /* !SETREUID, !SAVEDUID */
  13878.  
  13879. #ifdef SETEUID
  13880. /*
  13881.   BSD 4.4 works similarly to System V and POSIX (see below), but uses
  13882.   seteXid() instead of setXid() to change effective IDs.  In addition, the
  13883.   seteXid() functions work the same for "root" as for other users.
  13884. */
  13885. #define switchuid(hidden,active)    seteuid(active)
  13886. #define switchgid(hidden,active)    setegid(active)
  13887.  
  13888. #else /* !SETEUID */
  13889.  
  13890. /* On System V and POSIX, the only thing we can change is the effective UID
  13891.  * (unless the current effective UID is "root", but initsuid() avoids that for
  13892.  * us).  The kernel allows switching to the current real UID or to the saved
  13893.  * set-UID.  These are always set to the non-privileged UID and the privileged
  13894.  * UID, respectively, and we only change the effective UID.  This breaks if
  13895.  * the current effective UID is "root", though, because for "root" setuid/gid
  13896.  * becomes more powerful, which is why initsuid() treats "root" specially.
  13897.  * Note: That special treatment maybe could be ignored for BSD?  Note: For
  13898.  * systems that don't fit any of these four cases, we simply can't support
  13899.  * set-UID.
  13900.  */
  13901. #define switchuid(hidden,active)    setuid(active)
  13902. #define switchgid(hidden,active)    setgid(active)
  13903.  
  13904. #endif /* SETEUID */
  13905. #endif /* SETREUID */
  13906.  
  13907.  
  13908. /* P R I V _ O N  --  Turn on the setuid and/or setgid */
  13909.  
  13910. /* Go to the privileged uid (gid) that the program is set-user-id
  13911.  * (set-group-id) to, unless the program is running unprivileged.
  13912.  * If setuid() fails, return value will be 1. If getuid() fails it
  13913.  * will be 2.  Return immediately after first failure, and the function
  13914.  * tries to restore any partial work done.  Returns 0 on success.
  13915.  * Group id is changed first, since it is less serious than user id.
  13916.  */
  13917. int
  13918. priv_on() {
  13919. #ifndef HAVE_LOCKDEV
  13920.     if (privgid != (GID_T) -1)
  13921.       if (switchgid(realgid,privgid))
  13922.         return(2);
  13923.  
  13924.     if (privuid != (UID_T) -1)
  13925.       if (switchuid(realuid,privuid)) {
  13926.       if (privgid != (GID_T) -1)
  13927.         switchgid(privgid,realgid);
  13928.       return(1);
  13929.       }
  13930. #endif /* HAVE_LOCKDEV */
  13931.     return(0);
  13932. }
  13933.  
  13934. /* P R I V _ O F F  --  Turn on the real uid and gid */
  13935.  
  13936. /* Return to the unprivileged uid (gid) after an temporary visit to
  13937.  * privileged status, unless the program is running without set-user-id
  13938.  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
  13939.  * in setgid() or:ed together. The functions tries to return both uid
  13940.  * and gid to unprivileged state, regardless of errors. Returns 0 on
  13941.  * success.
  13942.  */
  13943. int
  13944. priv_off() {
  13945.     int err = 0;
  13946. #ifndef HAVE_LOCKDEV
  13947.     if (privuid != (UID_T) -1)
  13948.        if (switchuid(privuid,realuid))
  13949.       err |= 1;
  13950.  
  13951.     if (privgid != (GID_T) -1)
  13952.        if (switchgid(privgid,realgid))
  13953.     err |= 2;
  13954. #endif /* HAVE_LOCKDEV */
  13955.     return(err);
  13956. }
  13957.  
  13958. /* Turn off privilege permanently.  No going back.  This is necessary before
  13959.  * a fork() on BSD43 machines that don't save the setUID or setGID, because
  13960.  * we swap the real and effective ids, and we don't want to let the forked
  13961.  * process swap them again and get the privilege back. It will work on other
  13962.  * machines too, such that you can rely on its effect always being the same,
  13963.  * for instance, even when you're in priv_on() state when this is called.
  13964.  * (Well, that part about "permanent" is on System V only true if you follow
  13965.  * this with a call to exec(), but that's what we want it for anyway.)
  13966.  * Added by Dean Long -- dlong@midgard.ucsc.edu
  13967.  */
  13968. int
  13969. priv_can() {
  13970. #ifndef HAVE_LOCKDEV
  13971. #ifdef SETREUID
  13972.     int err = 0;
  13973.     if (privuid != (UID_T) -1)
  13974.        if (setreuid(realuid,realuid))
  13975.       err |= 1;
  13976.  
  13977.     if (privgid != (GID_T) -1)
  13978.         if (setregid(realgid,realgid))
  13979.        err |= 2;
  13980.  
  13981.     return(err);
  13982.  
  13983. #else
  13984. #ifdef SETEUID
  13985.     int err = 0;
  13986.     if (privuid != (UID_T) -1)
  13987.     if (setuid(realuid)) {
  13988.         debug(F101,"setuid failed","",errno);
  13989.         err |= 1;
  13990.         debug(F101,"ruid","",getuid());
  13991.         debug(F101,"euid","",geteuid());
  13992.     }
  13993.     debug(F101,"setuid","",realuid);
  13994.     if (privgid != (GID_T) -1)
  13995.         if (setgid(realgid)) {
  13996.         debug(F101,"setgid failed","",errno);
  13997.         err |= 2;
  13998.         debug(F101,"rgid","",getgid());
  13999.         debug(F101,"egid","",getegid());
  14000.     }
  14001.     debug(F101,"setgid","",realgid);
  14002.     return(err);
  14003. #else
  14004.     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
  14005.     return(priv_off());
  14006. #endif /* SETEUID */
  14007. #endif /* SETREUID */
  14008. #else
  14009.     return(0);
  14010. #endif /* HAVE_LOCKDEV */
  14011. }
  14012.  
  14013. /* P R I V _ O P N  --  For opening protected files or devices. */
  14014.  
  14015. int
  14016. priv_opn(name, modes) char *name; int modes; {
  14017.     int x;
  14018.     priv_on();                /* Turn privileges on */
  14019.     debug(F111,"priv_opn",name,modes);
  14020.     errno = 0;
  14021.     x = open(name, modes);        /* Try to open the device */
  14022.     debug(F101,"priv_opn result","",x);
  14023.     debug(F101,"priv_opn errno","",errno);
  14024.     priv_off();                /* Turn privileges off */
  14025.     return(x);                /* Return open's return code */
  14026. }
  14027.  
  14028. /*  P R I V _ C H K  --  Check privileges.  */
  14029.  
  14030. /*  Try to turn them off.  If turning them off did not succeed, cancel them */
  14031.  
  14032. int
  14033. priv_chk() {
  14034.     int x, y = 0;
  14035.     x = priv_off();            /* Turn off privs. */
  14036.     if (x != 0 || getuid() == privuid || geteuid() == privuid)
  14037.       y = priv_can();
  14038.     if (x != 0 || getgid() == privgid || getegid() == privgid)
  14039.       y = y | priv_can();
  14040.     return(y);
  14041. }
  14042.  
  14043. UID_T
  14044. real_uid() {
  14045.     return(realuid);
  14046. }
  14047.  
  14048. VOID
  14049. ttimoff() {                /* Turn off any timer interrupts */
  14050.     /* int xx; */
  14051. /*
  14052.   As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
  14053.   SIG_DFL (to catch alarms, or if there is no handler, to exit).  This is to
  14054.   cure (mask, really) a deeper problem with stray alarms that occurs on some
  14055.   systems, possibly having to do with sleep(), that caused core dumps.  It
  14056.   should be OK to do this, because no code in this module uses nested alarms.
  14057.   (But we still have to watch out for SCRIPT and DIAL...)
  14058. */
  14059.     /* xx = */ alarm(0);
  14060.     /* debug(F101,"ttimoff alarm","",xx); */
  14061.     if (saval) {            /* Restore any previous */
  14062.     signal(SIGALRM,saval);        /* alarm handler. */
  14063.     /* debug(F101,"ttimoff alarm restoring saval","",saval); */
  14064.     saval = NULL;
  14065.     } else {
  14066.     signal(SIGALRM,SIG_IGN);    /* Used to be SIG_DFL */
  14067.     /* debug(F100,"ttimoff alarm SIG_IGN","",0); */
  14068.     }
  14069. }
  14070.  
  14071.  
  14072. int
  14073. tt_is_secure() {      /* Tells whether the current connection is secure */
  14074.  
  14075.     if (ttyfd == -1)
  14076.       return(0);
  14077.  
  14078.     if (0
  14079. #ifdef SSHBUILTIN
  14080.     || IS_SSH()
  14081. #endif /* SSHBUILTIN */
  14082. #ifdef CK_ENCRYPTION
  14083.     || ck_tn_encrypting() && ck_tn_decrypting()
  14084. #endif /* CK_ENCRYPTION */
  14085. #ifdef CK_SSL
  14086.     || tls_active_flag || ssl_active_flag
  14087. #endif /* CK_SSL */
  14088. #ifdef RLOGCODE
  14089. #ifdef CK_KERBEROS
  14090. #ifdef CK_ENCRYPTION
  14091.     || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
  14092. #endif /* CK_ENCRYPTION */
  14093. #endif /* CK_KERBEROS */
  14094. #endif /* RLOGCODE */
  14095.     )
  14096.       return(1);
  14097.     return(0);
  14098. }
  14099.  
  14100. #ifdef CK_REDIR
  14101.   
  14102. /* External protocol handler parameters from ckuus3.c */
  14103. extern int exp_handler, exp_stderr, exp_timo;
  14104.  
  14105. #ifdef SELECT
  14106. #ifdef NETPTY
  14107.  
  14108. /* The right size is 24576 */
  14109.  
  14110. #ifndef PTY_PBUF_SIZE            /* Size of buffer to read from pty */
  14111. #define PTY_PBUF_SIZE 24576        /* and write to net. */
  14112. #endif    /* PTY_PBUF_SIZE */
  14113.  
  14114. #ifndef PTY_TBUF_SIZE            /* Size of buffer to read from net */
  14115. #define PTY_TBUF_SIZE 24576        /* and write to pty. */
  14116. #endif    /* PTY_TBUF_SIZE */
  14117.  
  14118. #ifdef O_NDELAY                /* Whether to use nonblocking */
  14119. #ifndef PTY_NO_NDELAY            /* reads on the pseudoterminal */
  14120. #ifndef PTY_USE_NDELAY
  14121. #define PTY_USE_NDELAY
  14122. #endif    /* PTY_USE_NDELAY */
  14123. #endif    /* PTY_NO_NDELAY */
  14124. #endif    /* O_NDELAY */
  14125.  
  14126. #ifndef HAVE_OPENPTY
  14127. #ifndef USE_CKUPTY_C
  14128. #define USE_CKUPTY_C
  14129. #endif /* USE_CKUPTY_C */
  14130. #endif /* HAVE_OPENPTY */
  14131.  
  14132. VOID
  14133. pty_make_raw(fd) int fd; {
  14134.     int x = -23, i;
  14135.  
  14136. #ifdef BSD44ORPOSIX            /* POSIX */
  14137.     struct termios tp;
  14138. #else
  14139. #ifdef ATTSV                /* AT&T UNIX */
  14140. #ifdef CK_ANSIC
  14141.     struct termio tp = {0};
  14142. #else
  14143.     struct termio tp;
  14144. #endif    /* CK_ANSIC */
  14145. #else
  14146.     struct sgttyb tp;            /* Traditional */
  14147. #endif /* ATTSV */
  14148. #endif /* BSD44ORPOSIX */
  14149.  
  14150.     debug(F101,"pty_make_raw fd","",fd);
  14151.     errno = 0;
  14152.  
  14153. #ifdef BSD44ORPOSIX            /* POSIX */
  14154.     x = tcgetattr(fd,&tp);
  14155.     debug(F101,"pty_make_raw tcgetattr","",x);
  14156. #else
  14157. #ifdef ATTSV                /* AT&T UNIX */
  14158.     x = ioctl(fd,TCGETA,&tp);
  14159.     debug(F101,"pty_make_raw TCGETA ioctl","",x);
  14160. #else
  14161.     x = gtty(fd,&tp);
  14162.     debug(F101,"pty_make_raw ttty","",x);
  14163. #endif /* ATTSV */
  14164. #endif /* BSD44ORPOSIX */
  14165.     debug(F101,"pty_make_raw GET errno","",errno);
  14166.  
  14167. #ifdef USE_CFMAKERAW
  14168.     errno = 0;
  14169.     cfmakeraw(&tp);
  14170.     debug(F101,"pty_make_raw cfmakeraw errno","",errno);
  14171. #else  /* USE_CFMAKERAW */
  14172.  
  14173. #ifdef COMMENT
  14174.  
  14175. /* This very simple version recommended by Serg Iakolev doesn't work */
  14176.  
  14177.     tp.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
  14178.     tp.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
  14179.     tp.c_cflag &= ~(CSIZE|PARENB);
  14180.     tp.c_cflag |= CS8;
  14181.     tp.c_oflag &= ~(OPOST);
  14182.     tp.c_cc[VMIN] = 1;
  14183.     tp.c_cc[VTIME] = 0;
  14184.  
  14185.     debug(F101,"pty_make_raw 1 c_cc[] NCCS","",NCCS);
  14186.     debug(F101,"pty_make_raw 1 iflags","",tp.c_iflag);
  14187.     debug(F101,"pty_make_raw 1 oflags","",tp.c_oflag);
  14188.     debug(F101,"pty_make_raw 1 lflags","",tp.c_lflag);
  14189.     debug(F101,"pty_make_raw 1 cflags","",tp.c_cflag);
  14190.  
  14191. #else
  14192. #ifdef COMMENT
  14193. /*
  14194.   In this version we unset everything and then set only the
  14195.   bits we know we need.
  14196. */
  14197.     /* iflags */
  14198.     tp.c_iflag = 0L;
  14199.     tp.c_iflag |= IGNBRK;
  14200. #ifdef IMAXBEL
  14201.     tp.c_iflag |= IMAXBEL;
  14202. #endif /* IMAXBEL */
  14203.  
  14204.     /* oflags */
  14205.     tp.c_oflag = 0L;
  14206.  
  14207.     /* lflags */
  14208.     tp.c_lflag = 0L;
  14209. #ifdef NOKERNINFO
  14210.     tp.c_lflag |= NOKERNINFO;
  14211. #endif    /* NOKERNINFO */
  14212.  
  14213.     /* cflags */
  14214.     tp.c_cflag = 0L;
  14215.     tp.c_cflag |= CS8|CREAD;
  14216.  
  14217.     for (i = 0; i < NCCS; i++) {    /* No special characters */
  14218.     tp.c_cc[i] = 0;
  14219.     }
  14220. #ifdef VMIN
  14221.     tp.c_cc[VMIN] = 1;            /* But always wait for input */
  14222. #endif    /* VMIN */
  14223.     debug(F101,"pty_make_raw 2 c_cc[] NCCS","",NCCS);
  14224.     debug(F101,"pty_make_raw 2 iflags","",tp.c_iflag);
  14225.     debug(F101,"pty_make_raw 2 oflags","",tp.c_oflag);
  14226.     debug(F101,"pty_make_raw 2 lflags","",tp.c_lflag);
  14227.     debug(F101,"pty_make_raw 2 cflags","",tp.c_cflag);
  14228.  
  14229. #else  /* COMMENT */
  14230. /*
  14231.   In this version we set or unset every single flag explicitly.  It works a
  14232.   bit better than the simple version just above, but it's still far from
  14233.   adequate.
  14234. */
  14235.     /* iflags */
  14236.     tp.c_iflag &= ~(PARMRK|ISTRIP|BRKINT|INLCR|IGNCR|ICRNL);
  14237.     tp.c_iflag &= ~(INPCK|IGNPAR|IXANY|IXON|IXOFF);
  14238.     tp.c_iflag |= IGNBRK;
  14239. #ifdef IMAXBEL
  14240. #ifdef COMMENT
  14241.     tp.c_iflag |= IMAXBEL;
  14242. #else
  14243.     tp.c_iflag &= ~IMAXBEL;
  14244. #endif /* COMMENT */
  14245. #endif /* IMAXBEL */
  14246. #ifdef IUCLC
  14247.     tp.c_iflag &= ~IUCLC;
  14248. #endif /* IUCLC */
  14249.  
  14250.     /* oflags */
  14251. #ifdef BSDLY
  14252.     tp.c_oflag &= ~BSDLY;
  14253. #endif /* BSDLY */
  14254. #ifdef CRDLY
  14255.     tp.c_oflag &= ~CRDLY;
  14256. #endif /* CRDLY */
  14257. #ifdef FFDLY
  14258.     tp.c_oflag &= ~FFDLY;
  14259. #endif /* FFDLY */
  14260. #ifdef NLDLY
  14261.     tp.c_oflag &= ~NLDLY;
  14262. #endif /* NLDLY */
  14263. #ifdef TABDLY
  14264.     tp.c_oflag &= ~TABDLY;
  14265. #endif /* TABDLY */
  14266. #ifdef VTDLY
  14267.     tp.c_oflag &= ~VTDLY;
  14268. #endif /* VTDLY */
  14269. #ifdef OFDEL
  14270.     tp.c_oflag &= ~OFDEL;
  14271. #endif /* OFDEL */
  14272. #ifdef OFILL
  14273.     tp.c_oflag &= ~OFILL;
  14274. #endif /* OFILL */
  14275. #ifdef OLCUC
  14276.     tp.c_oflag &= ~OLCUC;
  14277. #endif /* OLCUC */
  14278. #ifdef CMSPAR
  14279.     tp.c_oflag &= ~CMSPAR;
  14280. #endif /* CMSPAR */
  14281.     tp.c_oflag &= ~OPOST;
  14282. #ifdef OXTABS
  14283.     tp.c_oflag &= ~OXTABS;
  14284. #endif /* OXTABS */
  14285. #ifdef COMMENT
  14286. #ifdef ONOCR
  14287.     tp.c_oflag &= ~ONOCR;        /* Maybe should be |=? */
  14288.     tp.c_oflag |= ONOCR;        /* makes no difference either way */
  14289. #endif /* ONOCR */
  14290. #endif /* COMMENT */
  14291. #ifdef ONOEOT
  14292.     tp.c_oflag &= ~ONOEOT;
  14293. #endif /* ONOEOT */
  14294. #ifdef ONLRET
  14295.     tp.c_oflag &= ~ONLRET;
  14296. #endif /* ONLRET */
  14297. #ifdef ONLCR
  14298.     tp.c_oflag &= ~ONLCR;
  14299. #endif /* ONLCR */
  14300. #ifdef OCRNL
  14301.     tp.c_oflag &= ~OCRNL;
  14302. #endif /* OCRNL */
  14303.  
  14304.     /* lflags */
  14305.     tp.c_lflag &= ~ECHO;
  14306. #ifdef ECHOE
  14307.     tp.c_lflag &= ~ECHOE;
  14308. #endif /* ECHOE */
  14309. #ifdef ECHONL
  14310.     tp.c_lflag &= ~ECHONL;
  14311. #endif /* ECHONL */
  14312. #ifdef ECHOPRT
  14313.     tp.c_lflag &= ~ECHOPRT;
  14314. #endif /* ECHOPRT */
  14315. #ifdef ECHOKE
  14316.     tp.c_lflag &= ~ECHOKE;
  14317. #endif /* ECHOKE */
  14318. #ifdef ECHOCTL
  14319.     tp.c_lflag &= ~ECHOCTL;
  14320. #endif /* ECHOCTL */
  14321. #ifdef XCASE
  14322.     tp.c_lflag &= ~XCASE;
  14323. #endif /* XCASE */
  14324. #ifdef ALTWERASE
  14325.     tp.c_lflag &= ~ALTWERASE;
  14326. #endif /* ALTWERASE */
  14327. #ifdef EXTPROC
  14328.     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN|EXTPROC);
  14329. #else
  14330.     tp.c_lflag &= ~(ICANON|ISIG|IEXTEN|TOSTOP|FLUSHO|PENDIN);
  14331. #endif    /* EXTPROC */
  14332. #ifdef NOKERNINFO
  14333.     tp.c_lflag |= NOKERNINFO;
  14334. #endif    /* NOKERNINFO */
  14335. #ifndef COMMENT
  14336.     tp.c_lflag &= ~NOFLSH;        /* TRY IT THE OTHER WAY? */
  14337. #else
  14338.     tp.c_lflag |= NOFLSH;        /* No, this way is worse */
  14339. #endif /* COMMENT */
  14340.  
  14341.     /* cflags */
  14342.     tp.c_cflag &= ~(CSIZE|PARENB|PARODD);
  14343.     tp.c_cflag |= CS8|CREAD;
  14344.  
  14345. #ifdef MDMBUF
  14346.     tp.c_cflag &= ~(MDMBUF);
  14347. #else
  14348. #ifdef CCAR_OFLOW
  14349.     tp.c_cflag &= ~(CCAR_OFLOW);    /* two names for the same thing */
  14350. #endif /* CCAR_OFLOW */
  14351. #endif /* MDMBUF */
  14352.  
  14353. #ifdef CCTS_OFLOW
  14354.     tp.c_cflag &= ~(CCTS_OFLOW);
  14355. #endif /* CCTS_OFLOW */
  14356. #ifdef CDSR_OFLOW
  14357.     tp.c_cflag &= ~(CDSR_OFLOW);
  14358. #endif /* CDSR_OFLOW */
  14359. #ifdef CDTR_IFLOW
  14360.     tp.c_cflag &= ~(CDTR_IFLOW);
  14361. #endif /* CDTR_IFLOW */
  14362. #ifdef CRTS_IFLOW
  14363.     tp.c_cflag &= ~(CRTS_IFLOW);
  14364. #endif /* CRTS_IFLOW */
  14365. #ifdef CRTSXOFF
  14366.     tp.c_cflag &= ~(CRTSXOFF);
  14367. #endif /* CRTSXOFF */
  14368. #ifdef CRTSCTS
  14369.     tp.c_cflag &= ~(CRTSCTS);
  14370. #endif /* CRTSCTS */
  14371. #ifdef CLOCAL
  14372.     tp.c_cflag &= ~(CLOCAL);
  14373. #endif /* CLOCAL */
  14374. #ifdef CSTOPB
  14375.     tp.c_cflag &= ~(CSTOPB);
  14376. #endif /* CSTOPB */
  14377. #ifdef HUPCL
  14378.     tp.c_cflag &= ~(HUPCL);
  14379. #endif /* HUPCL */
  14380.  
  14381.     for (i = 0; i < NCCS; i++) {    /* No special characters */
  14382.     tp.c_cc[i] = 0;
  14383.     }
  14384. #ifdef VMIN
  14385.     tp.c_cc[VMIN] = 1;            /* But always wait for input */
  14386. #endif    /* VMIN */
  14387.     debug(F101,"pty_make_raw 3 c_cc[] NCCS","",NCCS);
  14388.     debug(F101,"pty_make_raw 3 iflags","",tp.c_iflag);
  14389.     debug(F101,"pty_make_raw 3 oflags","",tp.c_oflag);
  14390.     debug(F101,"pty_make_raw 3 lflags","",tp.c_lflag);
  14391.     debug(F101,"pty_make_raw 3 cflags","",tp.c_cflag);
  14392. #endif /* COMMENT */
  14393. #endif /* COMMENT */
  14394.  
  14395.     errno = 0;
  14396. #ifdef BSD44ORPOSIX            /* POSIX */
  14397.     x = tcsetattr(fd,TCSANOW,&tp);
  14398.     debug(F101,"pty_make_raw tcsetattr","",x);
  14399. #else
  14400. #ifdef ATTSV                /* AT&T UNIX */
  14401.     x = ioctl(fd,TCSETA,&tp);
  14402.     debug(F101,"pty_make_raw ioctl","",x);
  14403. #else
  14404.     x = stty(fd,&tp);            /* Traditional */
  14405.     debug(F101,"pty_make_raw stty","",x);
  14406. #endif /* ATTSV */
  14407. #endif /* BSD44ORPOSIX */
  14408.     debug(F101,"pty_make_raw errno","",errno);
  14409.  
  14410. #endif /* __NetBSD__ */
  14411. }
  14412.  
  14413. static int
  14414. pty_chk(fd) int fd; {
  14415.     int x, n = 0;
  14416.     errno = 0;
  14417. #ifdef FIONREAD
  14418.     x = ioctl(fd, FIONREAD, &n);    /* BSD and most others */
  14419.     ckmakmsg(msgbuf,500,
  14420.          "pty_chk ioctl FIONREAD errno=",
  14421.          ckitoa(errno),
  14422.          " count=",
  14423.          ckitoa(n));
  14424.     debug(F100,msgbuf,"",0);
  14425. #else
  14426. #ifdef RDCHK
  14427.     n = rdchk(fd);
  14428.     debug(F101,"pty_chk rdchk","",n);
  14429. #else
  14430.     n = 1;
  14431. #endif    /* RDCHK */
  14432. #endif    /* FIONREAD */
  14433.     return((n > -1) ? n : 0);
  14434. }
  14435.  
  14436. static int
  14437. pty_get_status(fd,pid) int fd; PID_T pid; {
  14438.     int x, status = -1;
  14439.     PID_T w;
  14440.  
  14441.     debug(F101,"pty_get_status fd","",fd);
  14442.     debug(F101,"pty_get_status pid","",pid);
  14443.  
  14444.     if (pexitstat > -1)
  14445.       return(pexitstat);
  14446.  
  14447. #ifdef COMMENT
  14448.     /* Not only unnecessary but harmful */
  14449.     errno = 0;
  14450.     x = kill(pty_fork_pid,0);
  14451.     debug(F101,"pty_get_status kill value","",x);
  14452.     debug(F101,"pty_get_status kill errno","",errno);
  14453.     if (x > -1 && errno != ESRCH)
  14454.       return(-1);            /* Fork still there */
  14455.     /* Fork seems to be gone */
  14456. #endif    /* COMMENT */
  14457.  
  14458.     errno = 0;
  14459.     x = waitpid(pty_fork_pid,&status,WNOHANG);
  14460.     debug(F111,"pty_get_status waitpid",ckitoa(errno),x);
  14461.     if (x <= 0 && errno == 0) {
  14462.     debug(F101,"pty_get_status waitpid return","",-1);
  14463.     return(-1);
  14464.     }
  14465.     if (x > 0) {
  14466.     if (x != pty_fork_pid)
  14467.       debug(F101,
  14468.         "pty_get_status waitpid pid doesn't match","",pty_fork_pid); 
  14469.     debug(F101,"pty_get_status waitpid status","",status);
  14470.     debug(F101,"pty_get_status waitpid errno","",errno);
  14471.     if (WIFEXITED(status)) {
  14472.         debug(F100,"pty_get_status WIFEXITED","",0);
  14473.         status = WEXITSTATUS(status);
  14474.         debug(F101,"pty_get_status fork exit status","",status);
  14475. #ifdef COMMENT
  14476.         end_pty();
  14477. #endif    /* COMMENT */
  14478.         close(fd);
  14479.         pexitstat = status;
  14480.     } else {
  14481.         debug(F100,"pty_get_status waitpid unexpected status","",0);
  14482.     }
  14483.     }
  14484.     debug(F101,"pty_get_status return status","",status);
  14485.     return(status);
  14486. }
  14487.  
  14488. /* t t p t y c m d  --  Run command on pty and forward to net */
  14489.  
  14490. /*
  14491.   Needed for running external protocols on secure connections.
  14492.   For example, if C-Kermit has made an SSL/TLS or Kerberos Telnet
  14493.   connection, and then needs to transfer a file with Zmodem, which is
  14494.   an external program, this routine reads Zmodem's output, encrypts it,
  14495.   and then forwards it out the connection, and reads the encrypted data
  14496.   stream coming in from the connection, decrypts it, and forwards it to
  14497.   Zmodem.
  14498.  
  14499.   Works like a TCP/IP port forwarder except one end is a pty rather
  14500.   than a socket, which introduces some complications:
  14501.  
  14502.    . On most platforms, select() always indicates the output side of
  14503.      the pty has characters waiting to be read, even when it doesn't,
  14504.      even when the pty process has already exited.
  14505.  
  14506.    . Nonblocking reads must be used on the pty, because there is no
  14507.      way on certain platforms (e.g. NetBSD) to find out how many characters
  14508.      are available to be read (the FIONREAD ioctl always says 0).  The code
  14509.      also allows for blocking reads (if O_NDELAY and O_NONBLOCK are not
  14510.      defined, or if PTY_NO_NDELAY is defined), but on some platforms this can
  14511.      result in single-byte reads and writes (NetBSD again).
  14512.  
  14513.    . Testing for "EOF" on the pty is problematic.  select() never gives
  14514.      any indication.  After the pty process has exited and the fork has
  14515.      disappeared, read() can still return with 0 bytes read but without an
  14516.      error (NetBSD); no known test on the pty file descriptor will indicate
  14517.      that it is no longer valid.  The process ID of the pty fork can be
  14518.      tested on some platforms (NetBSD, luckily) but not others (Solaris,
  14519.      Linux).
  14520.  
  14521.   On the network side, we use ttinc() and ttoc(), which, for network 
  14522.   connections, handle any active security methods.
  14523.  
  14524.   Call with s = command.
  14525.   Returns 0 on failure, 1 on success.
  14526.   fdc - December 2006 - August 2007.
  14527.  
  14528.   NOTE: This code defaults to nonblocking reads if O_NDELAY or O_NONBLOCK are
  14529.   defined in the header files, which should be true of every recent Unix
  14530.   platform.  If this causes trouble somewhere, define PTY_NO_NDELAY, e.g. when
  14531.   building C-Kermit:
  14532.  
  14533.     touch ckutio.c
  14534.     make platformname KFLAGS=-DPTY_NO_NODELAY
  14535. */
  14536. static int have_pty = 0;        /* Do we have a pty? */
  14537.  
  14538. static SIGTYP (*save_sigchld)() = NULL;    /* For catching SIGCHLD */
  14539.  
  14540. static VOID
  14541. sigchld_handler(sig) int sig; {
  14542.     have_pty = 0;            /* We don't have a pty */
  14543. #ifdef DEBUG
  14544.     if (save_sigchld) {
  14545.     (VOID) signal(SIGCHLD,save_sigchld);
  14546.     save_sigchld = NULL;
  14547.     }
  14548.     if (deblog) {
  14549.     debug(F100,"**************","",0);
  14550.     debug(F100,"SIGCHLD caught","",0);
  14551.     debug(F100,"**************","",0);
  14552.     }
  14553. #endif    /* DEBUG */
  14554. }
  14555. #define HAVE_IAC 1
  14556. #define HAVE_CR  2
  14557.  
  14558. int
  14559. ttptycmd(s) char *s; {
  14560.     CHAR tbuf[PTY_TBUF_SIZE];        /* Read from net, write to pty */
  14561.     int tbuf_avail = 0;            /* Pointers for tbuf */
  14562.     int tbuf_written = 0;
  14563.     static int in_state = 0;        /* For TELNET IAC and NVT in */
  14564.     static int out_prev = 0;        /* Simpler scheme for out */
  14565.  
  14566.     CHAR pbuf[PTY_PBUF_SIZE];        /* Read from pty, write to net */
  14567.     CHAR dbuf[PTY_PBUF_SIZE + PTY_PBUF_SIZE + 1]; /* Double-size buffer */
  14568.     int pbuf_avail = 0;            /* Pointers for pbuf */
  14569.     int pbuf_written = 0;
  14570.  
  14571.     int ptyfd = -1;            /* Pty file descriptor */
  14572.     int have_net = 0;            /* We have a network connection */
  14573.     int pty_err = 0;            /* Got error on pty */
  14574.     int net_err = 0;            /* Got error on net */
  14575.     int status = -1;            /* Pty process exit status */
  14576.     int rc = 0;                /* Our return code */
  14577.  
  14578.     int x1 = 0, x2 = 0;            /* Workers... */
  14579.     int c, n, m, t, x;            /* Workers */
  14580.  
  14581.     long seconds_to_wait = 0L;        /* select() timeout */
  14582.     struct timeval tv, *tv2;        /* For select() */
  14583. #ifdef INTSELECT
  14584.     int in, out, err;            /* For select() */
  14585. #else
  14586.     fd_set in, out, err;
  14587. #endif /* INTSELECT */
  14588.     int nfds = 0;            /* For select() */
  14589.  
  14590.     int pset = 0, tset = 0, pnotset = 0, tnotset = 0; /* stats/debuggin only */
  14591.     int read_net_bytes = 0;        /* Stats */
  14592.     int write_net_bytes = 0;        /* Stats */
  14593.     int read_pty_bytes = 0;        /* Stats */
  14594.     int write_pty_bytes = 0;        /* Stats */
  14595.     int is_tn = 0;            /* TELNET protocol is active */
  14596.  
  14597.     int masterfd = -1;
  14598.     int slavefd = -1;
  14599. #ifndef USE_CKUPTY_C
  14600.     struct termios term;
  14601.     struct winsize twin;
  14602.     struct stringarray * q;
  14603.     char ** args = NULL;
  14604. #endif /* USE_CKUPTY_C */
  14605.  
  14606.     in_state = 0;            /* No previous character yet */
  14607.  
  14608.     if (ttyfd == -1) {
  14609.     printf("?Sorry, communication channel is not open\n");
  14610.     return(0);
  14611.     } else {
  14612.     have_net = 1;
  14613.     }
  14614.     if (nopush) {
  14615.     debug(F100,"ttptycmd fail: nopush","",0);
  14616.     return(0);
  14617.     }
  14618.     if (!s) s = "";            /* Defense de bogus arguments */
  14619.     if (!*s) return(0);
  14620.     pexitstat = -1;            /* Fork process exit status */
  14621.  
  14622. #ifdef TNCODE
  14623.     is_tn = (xlocal && netconn && IS_TELNET()) || /* Telnet protocol active */
  14624.         (!xlocal && sstelnet);
  14625. #endif /* TNCODE */
  14626.  
  14627.     debug(F110,"ttptycmd command",s,0);
  14628.     debug(F101,"ttptycmd ttyfd","",ttyfd);
  14629.     debug(F101,"ttptycmd is_tn","",is_tn);
  14630.     debug(F101,"ttptycmd ckermit pid","",getpid());
  14631.  
  14632. #ifdef USE_CKUPTY_C
  14633.     /* Call ckupty.c module to get and set up the pty fork */
  14634.     /* fc 1 == "run an external protocol" */
  14635.     debug(F100,"ttptycmd using ckupty.c","",0);
  14636.     if (do_pty(&ptyfd,s,1) < 0) {    /* Start the command on a pty */
  14637.     debug(F100,"ttptycmd do_pty fails","",0);
  14638.     return(0);
  14639.     }
  14640.     masterfd = ptyfd;
  14641.     pty_master_fd = ptyfd;
  14642. #ifdef COMMENT
  14643.     slavefd = pty_slave_fd;        /* This is not visible to us */
  14644. #endif /* COMMENT */
  14645.     debug(F111,"ttptycmd ptyfd","USE_CKUPTY_C",ptyfd);
  14646.     debug(F111,"ttptycmd masterfd","USE_CKUPTY_C",masterfd);
  14647.     debug(F111,"ttptycmd fork pid","USE_CKUPTY_C",pty_fork_pid);
  14648. #ifndef SOLARIS
  14649.     /* "ioctl inappropriate on device" for pty master */
  14650.     pty_make_raw(masterfd);
  14651. #endif /* SOLARIS */
  14652.  
  14653. #else /* USE_CKUPTY_C */
  14654.  
  14655.     debug(F100,"ttptycmd OPENPTY","",0);
  14656.     if (tcgetattr(0, &term) == -1) {    /* Get controlling terminal's modes */
  14657.     perror("tcgetattr");
  14658.     return(0);
  14659.     }
  14660.     if (ioctl(0, TIOCGWINSZ, (char *) &twin) == -1) { /* and window size */
  14661.     perror("ioctl TIOCGWINSZ");
  14662.     return(0);
  14663.     }
  14664.     if (openpty(&masterfd, &slavefd, NULL, NULL, NULL) == -1) {
  14665.     debug(F101,"ttptycmd openpty failed errno","",errno);
  14666.     perror("opentpy");
  14667.     return(0);
  14668.     }
  14669.     debug(F101,"ttptycmd openpty masterfd","",masterfd);
  14670.     debug(F101,"ttptycmd openpty slavefd","",slavefd);
  14671.     pty_master_fd = masterfd;
  14672.     pty_slave_fd = slavefd;
  14673.     debug(F101,"ttptycmd openpty pty_master_fd","",pty_master_fd);
  14674.  
  14675.     /* Put pty master in raw mode but let forked app control the slave */
  14676.     pty_make_raw(masterfd);
  14677.  
  14678. #ifdef COMMENT
  14679. #ifdef TIOCREMOTE
  14680.     /* TIOCREMOTE,0 = disable all termio processing */
  14681.     x = ioctl(masterfd, TIOCREMOTE, 1);
  14682.     debug(F111,"ttptycmd ioctl TIOCREMOTE",ckitoa(x),errno);
  14683. #endif    /* TIOCREMOTE */
  14684. #ifdef TIOCTTY
  14685.     /* TIOCTTY,0 = disable all termio processing */
  14686.     x = ioctl(masterfd, TIOCTTY, 0);
  14687.     debug(F111,"ttptycmd ioctl TIOCTTY",ckitoa(x),errno);
  14688. #endif    /* TIOCTTY */
  14689. #endif /* COMMENT */
  14690.  
  14691.     have_pty = 1;            /* We have an open pty */
  14692.     save_sigchld = signal(SIGCHLD, sigchld_handler); /* Catch fork quit */
  14693.  
  14694.     pty_fork_pid = fork();        /* Make fork for external protocol */
  14695.     debug(F101,"ttptycmd pty_fork_pid","",pty_fork_pid);
  14696.     if (pty_fork_pid == -1) {
  14697.     perror("fork");
  14698.     return(0);
  14699.     } else if (pty_fork_pid == 0) {    /* In new fork */
  14700.     int x;
  14701.     debug(F101,"ttptycmd new fork pid","",getpid());
  14702.     close(masterfd);        /* Slave quarters no masters allowed */
  14703.     x = setsid();
  14704.     debug(F101,"ttptycmd new fork setsid","",x);
  14705.     if (x == -1) {
  14706.         perror("ttptycmd setsid");
  14707.         exit(1);
  14708.     }
  14709.     signal(SIGINT,SIG_IGN);        /* Let upper fork catch this */
  14710.     
  14711. #ifdef COMMENT
  14712. #ifdef TIOCSCTTY
  14713.     /* Make pty the controlling terminal for the process */
  14714.     /* THIS CAUSES AN INFINITE SIGWINCH INTERRUPT LOOP */
  14715.     x = ioctl(slavefd, TIOCSCTTY, NULL);
  14716.     debug(F101,"ttptycmd TIOCSCTTY","",x);
  14717. #endif    /* TIOCSCTTY */
  14718. #endif    /* COMMENT */
  14719.  
  14720.     /* Initialize slave pty modes and size to those of our terminal */
  14721.     if (tcsetattr(slavefd, TCSANOW, &term) == -1) {
  14722.         perror("ttptycmd tcsetattr");
  14723.         exit(1);
  14724.     }
  14725.     if (ioctl(slavefd, TIOCSWINSZ, &twin) == -1) {
  14726.         perror("ttptycmd ioctl");
  14727.         exit(1);
  14728.     }
  14729. #ifdef COMMENT
  14730. #ifdef TIOCNOTTY
  14731.     /* Disassociate this process from its terminal */
  14732.     /* THIS HAS NO EFFECT */
  14733.     x = ioctl(slavefd, TIOCNOTTY, NULL);
  14734.     debug(F101,"ttptycmd TIOCNOTTY","",x);
  14735. #endif    /* TIOCNOTTY */
  14736. #endif    /* COMMENT */
  14737.  
  14738. #ifdef COMMENT
  14739. #ifdef SIGTTOU    
  14740.     /* Ignore terminal output interrupts */
  14741.     /* THIS HAS NO EFFECT */
  14742.     debug(F100,"ttptycmd ignoring SIGTTOU","",0);
  14743.     signal(SIGTTOU, SIG_IGN);
  14744. #endif    /* SIGTTOU */
  14745. #ifdef SIGTSTP    
  14746.     /* Ignore terminal output interrupts */
  14747.     /* THIS HAS NO EFFECT */
  14748.     debug(F100,"ttptycmd ignoring SIGTSTP","",0);
  14749.     signal(SIGTSTP, SIG_IGN);
  14750. #endif    /* SIGTSTP */
  14751. #endif    /* COMMENT */
  14752.  
  14753.     pty_make_raw(slavefd);        /* Put it in rawmode */
  14754.  
  14755.     errno = 0;
  14756.     if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO ||
  14757.         dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO) {
  14758.         debug(F101,"ttptycmd new fork dup2 error","",errno);
  14759.         perror("ttptycmd dup2");
  14760.         exit(1);
  14761.     }
  14762.     debug(F100,"ttptycmd new fork dup2 ok","",0);
  14763.  
  14764.     /* Parse external protocol command line */
  14765.     q = cksplit(1,0,s,NULL,"\\%[]&$+-/=*^_@!{}/<>|.#~'`:;?",7,0,0);
  14766.     if (!q) {
  14767.         debug(F100,"ttptycmd cksplit failed","",0);
  14768.         exit(1);
  14769.     } else {
  14770.         int i, n;
  14771.         debug(F100,"ttptycmd cksplit ok","",0);
  14772.         n = q->a_size;
  14773.         args = q->a_head + 1;
  14774.         for (i = 0; i <= n; i++) {
  14775.         if (!args[i]) {
  14776.             break;
  14777.         } else {
  14778.             /* sometimes cksplit() doesn't terminate the list */
  14779.             if ((i == n) && args[i]) {
  14780.             if ((int)strlen(args[i]) == 0)
  14781.               makestr(&(args[i]),NULL);
  14782.             }
  14783.         }
  14784.         }        
  14785.     }
  14786. #ifdef COMMENT
  14787. /*
  14788.   Putting the slave pty in rawmode should not be necessary because the
  14789.   external protocol program is supposed to do that itself.  Yet doing this
  14790.   here cuts down on Zmodem binary-file transmission errors by 30-50% but
  14791.   still doesn't eliminate them.
  14792. */
  14793.     pty_make_raw(STDIN_FILENO);
  14794.     pty_make_raw(STDOUT_FILENO);
  14795. #endif /* COMMENT */
  14796.  
  14797.     debug(F100,"ttptycmd execvp'ing external protocol","",0);
  14798.     execvp(args[0],args);
  14799.     perror("execvp failed");
  14800.     debug(F101,"ttptycmd execvp failed","",errno);
  14801.     close(slavefd);
  14802.     exit(1);
  14803.     } 
  14804.     /* (there are better ways to do this...) */
  14805.     msleep(1000);          /* Make parent wait for child to be ready */
  14806.     ptyfd = masterfd;            /* We talk to the master */
  14807.  
  14808. #endif /* USE_CKUPTY_C */
  14809.  
  14810.     debug(F101,"ttptycmd ptyfd","",ptyfd);
  14811.     if (ptyfd < 0) {
  14812.     printf("?Failure to get pty\n");
  14813.     return(-9);
  14814.     }
  14815.     have_pty = 1;          /* We have an open pty or we wouldn't he here */
  14816.  
  14817.     debug(F101,"ttptycmd PTY_PBUF_SIZE","",PTY_PBUF_SIZE);
  14818.     debug(F101,"ttptycmd PTY_TBUF_SIZE","",PTY_TBUF_SIZE);
  14819.  
  14820. #ifdef PTY_USE_NDELAY
  14821.     /* 
  14822.        NOTE: If select() and ioctl(ptyfd,FIONREAD,&n) return true indications
  14823.        on the pty, we don't need nonblocking reads.  Performance of either
  14824.        method seems to be about the same, so use whatever works.
  14825.     */
  14826.     errno = 0;
  14827.     x = fcntl(ptyfd,F_SETFL,fcntl(ptyfd,F_GETFL, 0)|O_NDELAY);
  14828.     ckmakmsg(msgbuf,500,
  14829.          "ttptycmd set O_NDELAY errno=",
  14830.          ckitoa(errno),
  14831.          " fcntl=",
  14832.          ckitoa(x));
  14833.     debug(F100,msgbuf,"",0);
  14834. #endif /* PTY_USE_NDELAY */
  14835.  
  14836. #ifdef COMMENT
  14837. /* Not necessary, the protocol module already did this */
  14838.  
  14839. #ifdef USE_CFMAKERAW
  14840.     if (tcgetattr(ttyfd, &term) > -1) {
  14841.     cfmakeraw(&term);
  14842.     debug(F101,"ttptycmd net cfmakeraw errno","",errno);
  14843.     x tcsetattr(ttyfd, TCSANOW, &term);
  14844.     debug(F101,"ttptycmd net tcsetattr","",x);
  14845.     debug(F101,"ttptycmd net tcsetattr","",errno);
  14846.     }
  14847. #else
  14848.     if (local)                /* Put network connection in */
  14849.       ttpkt(ttspeed,ttflow,ttprty);    /* "packet mode". */
  14850.     else
  14851.       conbin((char)escchr);        /* OR... pty_make_raw(0) */
  14852. #endif /* USE_CFMAKERAW */
  14853. #endif /* COMMENT */
  14854.  
  14855. #ifdef TNCODE
  14856.     if (is_tn) {
  14857.       debug(F101,"<<< ttptycmd TELOPT_ME_BINARY","",TELOPT_ME(TELOPT_BINARY));
  14858.       debug(F101,"<<< ttptycmd TELOPT_U_BINARY","",TELOPT_U(TELOPT_BINARY));
  14859.     }
  14860. #endif /* TNCODE */
  14861.  
  14862.     debug(F101,"ttptycmd entering loop - seconds_to_wait","",seconds_to_wait);
  14863.  
  14864.     while (have_pty || have_net) {
  14865.     FD_ZERO(&in);            /* Initialize select() structs */
  14866.     FD_ZERO(&out);
  14867.     FD_ZERO(&err);            /* (not used because useless) */
  14868.     nfds = -1;
  14869.  
  14870.     debug(F101,"ttptycmd loop top have_pty","",have_pty);
  14871.     debug(F101,"ttptycmd loop top have_net","",have_net);
  14872.  
  14873.     /* Pty is open and we have room to read from it? */
  14874.     if (have_pty && pbuf_avail < PTY_PBUF_SIZE) {
  14875.         debug(F100,"ttptycmd FD_SET ptyfd in","",0);
  14876.             FD_SET(ptyfd, &in);
  14877.         nfds = ptyfd;
  14878.         }
  14879.     /* Network is open and we have room to read from it? */
  14880.         if (have_net && have_pty && tbuf_avail < PTY_TBUF_SIZE) {
  14881.         debug(F100,"ttptycmd FD_SET ttyfd in","",0);
  14882.             FD_SET(ttyfd, &in);
  14883.         if (ttyfd > nfds) nfds = ttyfd;
  14884.         }
  14885.     /* Pty is open and we have stuff to write to it? */
  14886.         if (have_pty && tbuf_avail - tbuf_written > 0) {
  14887.         debug(F100,"ttptycmd FD_SET ptyfd out","",0);
  14888.             FD_SET (ptyfd, &out);
  14889.         if (ptyfd > nfds) nfds = ptyfd;
  14890.         }
  14891.     /* Net is open and we have stuff to write to it? */
  14892.     debug(F101,"ttptycmd pbuf_avail-pbuf_written","",
  14893.           pbuf_avail - pbuf_written);
  14894.         if (have_net && pbuf_avail - pbuf_written > 0) {
  14895.         debug(F100,"ttptycmd FD_SET ttyfd out","",0);
  14896.             FD_SET (ttyfd, &out);
  14897.         if (ttyfd > nfds) nfds = ttyfd;
  14898.         }
  14899.     /* We don't use err because it's not really for errors, */
  14900.     /* but for out of band data on the TCP socket, which, if it is */
  14901.     /* to be handled at all, is handled in the tt*() routines */
  14902.  
  14903.     nfds++;                /* 0-based to 1-based */
  14904.     debug(F101,"ttptycmd nfds","",nfds);
  14905.     if (!nfds) {
  14906.         debug(F100,"ttptycmd NO FDs set for select","",0);
  14907.         if (have_pty) {
  14908.         /* This is not right -- sleeping won't accomplish anything */
  14909.         debug(F101,"ttptycmd msleep","",100);
  14910.         msleep(100);        
  14911.         } else {
  14912.         debug(F100,"ttptycmd no pty - quitting loop","",0);
  14913.         break;
  14914.         }
  14915.     }
  14916.     errno = 0;
  14917.  
  14918.     if (seconds_to_wait > 0L) {    /* Timeout in case nothing happens */
  14919.         tv.tv_sec = seconds_to_wait; /* for a long time */
  14920.         tv.tv_usec = 0L;        
  14921.         tv2 = &tv;
  14922.         } else {
  14923.             tv2 = NULL;
  14924.     }
  14925.     x = select(nfds, &in, &out, NULL, tv2);
  14926.     debug(F101,"ttptycmd select","",x);
  14927.     if (x < 0) {
  14928.         if (errno == EINTR)
  14929.           continue;
  14930.         debug(F101,"ttptycmd select error","",errno);
  14931.         break;
  14932.     }
  14933.     if (x == 0) {
  14934.         debug(F101,"ttptycmd +++ select timeout","",seconds_to_wait); 
  14935.         if (have_pty) {
  14936.         status = pty_get_status(ptyfd,pty_fork_pid);
  14937.         debug(F101,"ttptycmd pty_get_status A","",status);
  14938.         if (status > -1) pexitstat = status;
  14939.         have_pty = 0;
  14940.         }
  14941.         break;
  14942.     }
  14943.     /* We want to handle any pending writes first to make room */
  14944.     /* for new incoming. */
  14945.  
  14946.     if (FD_ISSET(ttyfd, &out)) {    /* Can write to net? */
  14947.         CHAR * s;
  14948.         s = pbuf + pbuf_written;    /* Current spot for sending */
  14949. #ifdef TNCODE
  14950.         if (is_tn) {        /* ttol() doesn't double IACs */
  14951.         CHAR c;            /* Rewrite string with IACs doubled */
  14952.         int i;
  14953.         s = pbuf + pbuf_written; /* Source */
  14954.         x = 0;              /* Count */
  14955.         for (i = 0; i < pbuf_avail - pbuf_written; i++) {
  14956.             c = s[i];        /* Next character */
  14957.             if (c == IAC) {    /* If it's IAC */
  14958.             dbuf[x++] = c;    /* put another one */
  14959.             debug(F000,">>> QUOTED IAC","",c);
  14960.             } else if (c != 0x0a && out_prev == 0x0d) {    /* Bare CR */
  14961.             if (!TELOPT_ME(TELOPT_BINARY)) { /* NVT rule */
  14962.                 c = 0x00;
  14963.                 dbuf[x++] = c;
  14964.                 debug(F000,">>> CR-NUL","",c);
  14965.             }            
  14966.             }
  14967.             dbuf[x++] = c;    /* Copy and count it */
  14968.             debug(F000,">>> char",ckitoa(in_state),c);
  14969.             out_prev = c;
  14970.         }
  14971.         s = dbuf;        /* New source */
  14972.         } else
  14973. #endif /* TNCODE */
  14974.           x = pbuf_avail - pbuf_written; /* How much to send */
  14975.  
  14976.         debug(F101,"ttptycmd bytes to send","",x);
  14977.         x = ttol(s, x);
  14978.         debug(F101,">>> ttol","",x);
  14979.         if (x < 0) {
  14980.         net_err++;
  14981.         debug(F111,"ttptycmd ttol error",ckitoa(x),errno);
  14982.         x = 0;
  14983.         }
  14984.         write_net_bytes += x;
  14985.         pbuf_written += x;
  14986.     }
  14987.     if (FD_ISSET(ptyfd, &out)) {    /* Can write to pty? */
  14988.         debug(F100,"ttptycmd FD_ISSET ptyfd out","",0);
  14989.         errno = 0;
  14990. #ifndef COMMENT
  14991.         x = write(ptyfd,tbuf + tbuf_written,tbuf_avail - tbuf_written);
  14992. #else
  14993.         /* Byte loop to rule out data overruns in the pty */
  14994.         /* (it makes no difference) */
  14995.         {
  14996.         char *p = tbuf+tbuf_written;
  14997.         int n = tbuf_avail - tbuf_written;
  14998.         for (x = 0; x < n; x++) {
  14999.             msleep(10);
  15000.             if (write(ptyfd,&(p[x]),1) < 0)
  15001.               break;
  15002.         }
  15003.         }
  15004. #endif /* COMMENT */
  15005.         debug(F111,"ttptycmd ptyfd write",ckitoa(errno),x);
  15006.         if (x > 0) {
  15007.         tbuf_written += x;
  15008.         write_pty_bytes += x;
  15009.         } else {
  15010.         x = 0;
  15011.         pty_err++;
  15012.         if (pexitstat < 0) {
  15013.             status = pty_get_status(ptyfd,pty_fork_pid);
  15014.             debug(F101,"ttptycmd pty_get_status B","",status);
  15015.             if (status > -1) pexitstat = status;
  15016.             have_pty = 0;
  15017.         }
  15018.         debug(F100,"ttptycmd +++ ptyfd write error","",0);
  15019.         }
  15020.     }
  15021.     if (FD_ISSET(ttyfd, &in)) {    /* Can read from net? */
  15022.         tset++;
  15023.         debug(F100,"ttptycmd FD_ISSET ttyfd in","",0);
  15024.         n = in_chk(1,ttyfd);
  15025.         debug(F101,"ttptycmd in_chk(ttyfd)","",n); 
  15026.         if (n < 0 || ttyfd == -1) {
  15027.         debug(F101,"ttptycmd +++ ttyfd errno","",errno);
  15028.         net_err++;
  15029.         } else if (n > 0) {
  15030.         if (n > PTY_TBUF_SIZE - tbuf_avail)
  15031.           n = PTY_TBUF_SIZE - tbuf_avail;
  15032.         debug(F101,"ttptycmd net read size adjusted","",n); 
  15033.         if (xlocal && netconn) {
  15034.             /*
  15035.               We have to use a byte loop here because ttxin()
  15036.               does not decrypt or, for that matter, handle Telnet.
  15037.             */
  15038.             int c;
  15039.             CHAR * p;
  15040.             p = tbuf + tbuf_avail;
  15041.             for (x = 0; x < n; x++) {
  15042.             if ((c = ttinc(0)) < 0)
  15043.               break;
  15044.             if (!is_tn) {    /* Not Telnet - keep all bytes */
  15045.                 *p++ = (CHAR)c;
  15046.                 debug(F000,"<<< char","",c);
  15047. #ifdef TNCODE
  15048.             } else {    /* Telnet - must handle IAC and NVT */
  15049.                 debug(F000,"<<< char",ckitoa(in_state),c);
  15050.                 switch (c) {
  15051.                   case 0x00: /* NUL */
  15052.                 if (in_state == HAVE_CR) {
  15053.                     debug(F000,"<<< SKIP","",c);
  15054.                 } else {
  15055.                     *p++ = c;
  15056.                     debug(F000,"<<< Keep","",c);
  15057.                 }
  15058.                 in_state = 0;
  15059.                 break;
  15060.                   case 0x0d: /* CR */
  15061.                 if (!TELOPT_U(TELOPT_BINARY))
  15062.                   in_state = HAVE_CR;
  15063.                 *p++ = c;
  15064.                 debug(F000,"<<< Keep","",c);
  15065.                 break;
  15066. #ifdef COMMENT
  15067.                   case 0x0f: /* Ctrl-O */
  15068.                   case 0x16: /* Ctrl-V */
  15069.                 *p++ = 0x16;
  15070.                 *p++ = c;
  15071.                 debug(F000,"<<< QUOT","",c);
  15072.                 break;
  15073. #endif /* COMMENT */
  15074.                   case 0xff: /* IAC */
  15075.                 if (in_state == HAVE_IAC) {
  15076.                     debug(F000,"<<< KEEP","",c);
  15077.                     *p++ = c;
  15078.                     in_state = 0;
  15079.                 } else {
  15080.                     debug(F000,"<<< SKIP","",c);
  15081.                     in_state = HAVE_IAC;
  15082.                 }
  15083.                 break;
  15084.                   default:    /* All others */
  15085.                 if (in_state == HAVE_IAC) {
  15086. #ifdef COMMENT
  15087. /*
  15088.   tn_doop() will consume an unknown number of bytes and we'll overshoot
  15089.   the for-loop.  The only Telnet command I've ever seen arrive here is
  15090.   a Data Mark, which comes when the remote protocol exits and the remote
  15091.   job returns to its shell prompt.  On the assumption it's a 1-byte command,
  15092.   we don't write out the IAC or the command, and we clear the state.  If
  15093.   we called tn_doop() we'd have no way of knowing how many bytes it took
  15094.   from the input stream.
  15095. */
  15096.                     int xx;
  15097.                     xx = tn_doop((CHAR)c,duplex,ttinc);
  15098.                     debug(F111,"<<< DOOP",ckctoa(c),xx);
  15099. #else
  15100.                     debug(F101,"<<< DOOP","",c);
  15101. #endif    /* COMMENT */
  15102.                     in_state = 0;
  15103.                 } else {
  15104.                     *p++ = c;
  15105.                     debug(F000,"<<< keep","",c);
  15106.                     in_state = 0;
  15107.                 }
  15108.                 }
  15109. #endif    /* TNCODE */
  15110.             }
  15111.             }
  15112.             ckmakmsg(msgbuf,500,
  15113.                  "ttptycmd read net [ttinc loop] errno=",
  15114.                  ckitoa(errno),
  15115.                  " count=",
  15116.                  ckitoa(x));
  15117.             debug(F100,msgbuf,"",0);
  15118.         } else {
  15119.             x = ttxin(n,tbuf+tbuf_avail);
  15120.             debug(F101,"ttptycmd ttxin x","",x); 
  15121.         }
  15122.  
  15123.         if (x < 0) {
  15124.             debug(F101,"ttptycmd read net error","",x);
  15125.             net_err++;
  15126.         }
  15127.         tbuf_avail += x;
  15128.         read_net_bytes += x;
  15129.         }
  15130.  
  15131.     } else
  15132.       tnotset++;
  15133.  
  15134.     if (FD_ISSET(ptyfd, &in)) {    /* Read from pty? */
  15135.         pset++;
  15136.         debug(F100,"ttptycmd FD_ISSET ptyfd in","",0);
  15137. #ifdef PTY_USE_NDELAY
  15138.         n = PTY_PBUF_SIZE;
  15139. #else
  15140.         /*
  15141.           This does not work on nonblocking channels
  15142.           on certain platforms such as NetBSD.
  15143.         */
  15144.         n = pty_chk(ptyfd);
  15145. #endif /* PTY_USE_NDELAY */
  15146.         debug(F101,"ttptycmd pty_chk() n","",n); 
  15147.  
  15148.         if (n < 0)
  15149.           n = 0;
  15150.         if (n > 0) {
  15151.         if (n > PTY_PBUF_SIZE - pbuf_avail)
  15152.           n = PTY_PBUF_SIZE - pbuf_avail;
  15153.         debug(F101,"ttptycmd pty read size adjusted","",n); 
  15154.         errno = 0;
  15155.         x = read(ptyfd,pbuf+pbuf_avail,n);
  15156. #ifdef DEBUG
  15157.         if (deblog) {
  15158.             ckmakmsg(msgbuf,500,
  15159.                  "ttptycmd read pty errno=",
  15160.                  ckitoa(errno),
  15161.                  " count=",
  15162.                  ckitoa(x));
  15163.             debug(F100,msgbuf,"",0);
  15164.         }
  15165. #endif    /* DEBUG */
  15166.  
  15167.         if (x < 0 && errno == EAGAIN)
  15168.           x = 0;
  15169.  
  15170.         if (x < 0) {        /* This works on Solaris and Linux */
  15171.             pty_err++;        /* but not NetBSD */
  15172.             debug(F100,"TERMINATION TEST A","",0);
  15173. #ifdef COMMENT
  15174.             if (errno == EIO)
  15175.               rc = 1;
  15176. #endif    /* COMMENT */
  15177.             if (pexitstat < 0) {
  15178.             status = pty_get_status(ptyfd,pty_fork_pid);
  15179.             debug(F101,"ttptycmd pty_get_status C","",status);
  15180.             if (status > -1) pexitstat = status;
  15181.             }
  15182.             have_pty = 0;
  15183.             x = 0;
  15184.         }
  15185.         if (x == 0 && !pty_err) { /* This works on NetBSD but */
  15186.             debug(F100,"TERMINATION TEST B","",0);
  15187.             status = pexitstat > -1 ? pexitstat :
  15188.             pty_get_status(ptyfd,pty_fork_pid);
  15189.             debug(F101,"ttptycmd pty_get_status D","",status);
  15190.             if (status > -1) {
  15191.             pexitstat = status;
  15192.             pty_err++;
  15193.             have_pty = 0;
  15194.             } else {        /* Select() lied */
  15195.             pty_err = 0;    /* pty still there but has nothing */
  15196.             msleep(100);    /* sleep a bit */
  15197.             }
  15198.             x = 0;
  15199.         } 
  15200.         /* Hopefully the next two are no longer needed... */
  15201.         if (!pty_err && (
  15202. #ifndef PTY_USE_NDELAY
  15203.             x < 1 || errno
  15204. #else
  15205.             errno != 0 && errno != EAGAIN
  15206. #endif /* PTY_USE_NDELAY */
  15207.             )) {
  15208.             debug(F100,"TERMINATION TEST C","",0);
  15209.             pty_err++;
  15210.             debug(F101,"ttptycmd SET pty_err","",pty_err);
  15211.             if (errno == EIO)    /* errno == EIO is like EOF */
  15212.               rc = 1;
  15213.             if (x < 0)
  15214.               x = 0;
  15215.         }
  15216. #ifdef COMMENT
  15217. #ifdef DEBUG
  15218.         if (deblog) {
  15219.             pbuf[pbuf_avail + x] = '\0';
  15220.             debug(F111,"ttptycmd added to pty buffer",
  15221.               pbuf+pbuf_avail,x);
  15222.         }
  15223. #endif    /* DEBUG */
  15224. #endif    /* COMMENT */
  15225.         pbuf_avail += x;
  15226.         read_pty_bytes += x;
  15227.         } else {            /* n == 0 with blocking reads */
  15228.         debug(F100,
  15229.               "PTY READ RETURNED ZERO BYTES - SHOULD NOT HAPPEN",
  15230.               "",0);
  15231.         }
  15232.     } else
  15233.       pnotset++;
  15234.  
  15235.     /* If writes have caught up to reads, reset the buffers */
  15236.  
  15237.     if (pbuf_written == pbuf_avail)
  15238.       pbuf_written = pbuf_avail = 0;
  15239.     if (tbuf_written == tbuf_avail)
  15240.       tbuf_written = tbuf_avail = 0;
  15241.  
  15242.     /* See if we can exit */
  15243.  
  15244.     x1 = pbuf_avail - pbuf_written; 
  15245.     x2 = tbuf_avail - tbuf_written;
  15246.  
  15247.     debug(F101,"ttptycmd pty_err LOOP EXIT TEST pty_err","",pty_err);
  15248.     debug(F101,"ttptycmd pty_err LOOP EXIT TEST x1 [write to net]","",x1);
  15249.     debug(F101,"ttptycmd pty_err LOOP EXIT TEST x2 [write to pty]","",x2);
  15250.     debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc","",rc);
  15251.     debug(F101,"ttptycmd pty_err LOOP EXIT TEST status","",status);
  15252.     debug(F101,"ttptycmd pty_err LOOP EXIT TEST pexitstat","",pexitstat);
  15253.  
  15254.     if (net_err) {            /* Net error? */
  15255.         debug(F101,"ttptycmd net_err LOOP EXIT TEST net_err","",net_err);
  15256.         if (have_net) {
  15257.         if (local) {
  15258.             ttclos(0);
  15259.             printf("?Connection closed\n");
  15260.         }
  15261.         have_net = 0;
  15262.         }
  15263.         debug(F101,"ttptycmd net_err LOOP EXIT TEST x1","",x1);
  15264.         if (x1 == 0)
  15265.           break;
  15266.     }
  15267.     if (pty_err) {            /* Pty error? */
  15268.         if (have_pty) {
  15269.         if (pexitstat < 0) {        
  15270.             status = pty_get_status(ptyfd,pty_fork_pid);
  15271.             debug(F101,"ttptycmd pty_get_status E","",status);
  15272.             if (status > -1) pexitstat = status;
  15273.         }
  15274.         have_pty = 0;
  15275.         }
  15276.         if (x1 == 0 && x2 == 0) {    /* If buffers are caught up */
  15277.         rc = 1;            /* set preliminary return to success */
  15278.         debug(F101,"ttptycmd pty_err LOOP EXIT TEST rc 2","",rc);
  15279.         break;            /* and exit the loop */
  15280.         }
  15281.     }
  15282.     }
  15283.     debug(F101,"ttptycmd +++ have_pty","",have_pty);
  15284.     if (have_pty) {            /* In case select() failed */
  15285. #ifdef USE_CKUPTY_C
  15286.     end_pty();
  15287.     close(ptyfd);
  15288. #else
  15289.     close(slavefd);
  15290.     close(masterfd);
  15291. #endif /* USE_CKUPTY_C */
  15292.     }
  15293.     pty_master_fd = -1;
  15294.     debug(F101,"ttptycmd +++ pexitstat","",pexitstat);
  15295.     if (pexitstat < 0) {        /* Try one last time to get status */
  15296.     status = pty_get_status(ptyfd,pty_fork_pid);
  15297.     debug(F101,"ttptycmd pty_get_status F","",status);
  15298.     if (status > -1) pexitstat = status;
  15299.     }
  15300.     debug(F101,"ttptycmd +++ final pexitstat","",pexitstat);
  15301.     if (deblog) {            /* Stats for debug log */
  15302.     debug(F101,"ttptycmd +++ pset    ","",pset);
  15303.     debug(F101,"ttptycmd +++ pnotset","",pnotset);
  15304.     debug(F101,"ttptycmd +++ tset    ","",tset);
  15305.     debug(F101,"ttptycmd +++ tnotset","",tnotset);
  15306.  
  15307.     debug(F101,"ttptycmd +++  read_pty_bytes","",read_pty_bytes);
  15308.     debug(F101,"ttptycmd +++ write_net_bytes","",write_net_bytes);
  15309.     debug(F101,"ttptycmd +++  read_net_bytes","",read_net_bytes);
  15310.     debug(F101,"ttptycmd +++ write_pty_bytes","",write_pty_bytes);
  15311.     }
  15312. /*
  15313.   If we got the external protocol's exit status from waitpid(), we use that
  15314.   to set our return code.  If not, we fall back on whatever rc was previously
  15315.   set to, namely 1 (success) if the pty fork seemed to terminate, 0 otherwise.
  15316. */
  15317.     if (save_sigchld) {            /* Restore this if we changed it */
  15318.     (VOID) signal(SIGCHLD,save_sigchld);
  15319.     save_sigchld = NULL;
  15320.     }
  15321.     msleep(500);
  15322.     x = kill(pty_fork_pid,SIGHUP);    /* In case it's still there */
  15323.     pty_fork_pid = -1;
  15324.     debug(F101,"ttptycmd fork kill SIGHUP","",x);
  15325.     if (pexitstat > -1)
  15326.       rc = (pexitstat == 0 ? 1 : 0);
  15327.     debug(F101,"ttptycmd +++ rc","",rc);
  15328.     if (!local) {            /* If in remote mode */
  15329.     conres();            /* restore console to CBREAK mode */
  15330.     concb((char)escchr);
  15331.     }
  15332.     return(rc);
  15333. }
  15334. #endif    /* NETPTY */
  15335. #endif    /* SELECT */
  15336.  
  15337. /* T T R U N C M D  --  Redirect an external command over the connection. */
  15338.  
  15339. /*
  15340.   TTRUNCMD is the routine that was originally used for running external
  15341.   protocols.  It is very simple and works fine provided (a) the connection
  15342.   is not encrypted, and (b) the external protocol uses standard i/o
  15343.   (file descriptors 0 and 1) for file transfer.
  15344. */
  15345.  
  15346. int
  15347. ttruncmd(s) char *s; {
  15348.     PID_T pid;                /* pid of lower fork */
  15349.     int wstat;                /* for wait() */
  15350.     int x;
  15351.     int statusp;
  15352.  
  15353.     if (ttyfd == -1) {
  15354.     printf("?Sorry, device is not open\n");
  15355.     return(0);
  15356.     }
  15357.     if (nopush) {
  15358.     debug(F100,"ttruncmd fail: nopush","",0);
  15359.     return(0);
  15360.     }
  15361.  
  15362. #ifdef NETPTY
  15363. /***************
  15364.   It might also be necessary to use the pty routine for other reasons,
  15365.   e.g. because the external program does not use stdio.
  15366. */
  15367. #ifdef NETCONN
  15368. /*
  15369.   If we have a network connection we use a different routine because
  15370.   (a) if the connection is encrypted, the mechanism used here can't deal
  15371.   with it; and (b) it won't handle any network protocols either, e.g.
  15372.   Telnet, Rlogin, K5 U-to-U, etc.  However, this routine works much
  15373.   better (faster, more transparent) on serial connections and when
  15374.   C-Kermit is in remote mode (i.e. is on the far end).
  15375. */
  15376.     /* For testing always use this */
  15377.     if (netconn)
  15378.       return(ttptycmd(s));
  15379. #endif /* NETCONN */
  15380.  
  15381. /***************/
  15382. #else  /* NETPTY */
  15383.     if (tt_is_secure()) {
  15384.     printf("?Sorry, \
  15385. external protocols over secure connections not supported in this OS.\n"
  15386.               );
  15387.         return(0);
  15388.     }
  15389. #endif    /* NETPTY */
  15390.  
  15391.     conres();                /* Make console normal  */
  15392.     pexitstat = -4;
  15393.     if ((pid = fork()) == 0) {        /* Make a child fork */
  15394.     if (priv_can())            /* Child: turn off privs. */
  15395.       exit(1);
  15396.     dup2(ttyfd, 0);            /* Give stdin/out to the line */
  15397.     dup2(ttyfd, 1);
  15398.     x = system(s);
  15399.     debug(F101,"ttruncmd system",s,x);
  15400.     _exit(x ? BAD_EXIT : 0);
  15401.     } else {
  15402.     SIGTYP (*istat)(), (*qstat)();
  15403.     if (pid == (PID_T) -1)        /* fork() failed? */
  15404.       return(0);
  15405.     istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
  15406.     qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
  15407.  
  15408. #ifdef COMMENT
  15409.         while (((wstat = wait(&statusp)) != pid) && (wstat != -1)) ;
  15410. #else  /* Not COMMENT */
  15411.         while (1) {
  15412.         wstat = wait(&statusp);
  15413.         debug(F101,"ttruncmd wait","",wstat);
  15414.         if (wstat == pid || wstat == -1)
  15415.           break;
  15416.     }
  15417. #endif /* COMMENT */
  15418.  
  15419.     pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
  15420.     debug(F101,"ttruncmd wait statusp","",statusp);
  15421.     debug(F101,"ttruncmd wait pexitstat","",pexitstat);
  15422.     signal(SIGINT,istat);        /* Restore interrupts */
  15423.     signal(SIGQUIT,qstat);
  15424.     }
  15425.     concb((char)escchr);        /* Restore console to CBREAK mode */
  15426.     return(statusp == 0 ? 1 : 0);
  15427. }
  15428. #endif    /* CK_REDIR */
  15429.  
  15430. struct tm *
  15431. #ifdef CK_ANSIC
  15432. cmdate2tm(char * date, int gmt)         /* date as "yyyymmdd hh:mm:ss" */
  15433. #else
  15434. cmdate2tm(date,gmt) char * date; int gmt;
  15435. #endif
  15436. {
  15437.     /* date as "yyyymmdd hh:mm:ss" */
  15438.     static struct tm _tm;
  15439.     time_t now;
  15440.  
  15441.     if (strlen(date) != 17 ||
  15442.     date[8] != ' ' ||
  15443.     date[11] != ':' ||
  15444.     date[14] != ':')
  15445.       return(NULL);
  15446.  
  15447.     time(&now);
  15448.     if (gmt)
  15449.       _tm = *gmtime(&now);
  15450.     else
  15451.       _tm = *localtime(&now);
  15452.     _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
  15453.                   (date[2]-'0')*10   + (date[3]-'0')-1900;
  15454.     _tm.tm_mon  = (date[4]-'0')*10   + (date[5]-'0')-1;
  15455.     _tm.tm_mday = (date[6]-'0')*10   + (date[7]-'0');
  15456.     _tm.tm_hour = (date[9]-'0')*10   + (date[10]-'0');
  15457.     _tm.tm_min  = (date[12]-'0')*10  + (date[13]-'0');
  15458.     _tm.tm_sec  = (date[15]-'0')*10  + (date[16]-'0');
  15459.  
  15460.     /* Should we set _tm.tm_isdst to -1 here? */
  15461.  
  15462.     _tm.tm_wday = 0;
  15463.     _tm.tm_yday = 0;
  15464.  
  15465.     return(&_tm);
  15466. }
  15467.  
  15468. #ifdef OXOS
  15469. #undef kill
  15470. #endif /* OXOS */
  15471.  
  15472. #ifdef OXOS
  15473. int
  15474. priv_kill(pid, sig) int pid, sig; {
  15475.     int    i;
  15476.  
  15477.     if (priv_on())
  15478.     debug(F100,"priv_kill priv_on failed","",0);
  15479.     i = kill(pid, sig);
  15480.     if (priv_off())
  15481.     debug(F100,"priv_kill priv_off failed","",0);
  15482.     return(i);
  15483. }
  15484. #endif /* OXOS */
  15485.  
  15486. #ifdef BEOSORBEBOX
  15487. /* #ifdef BE_DR_7 */
  15488. /*
  15489.   alarm() function not supplied with Be OS DR7 - this one contributed by
  15490.   Neal P. Murphy.
  15491. */
  15492.  
  15493. /*
  15494.   This should mimic the UNIX/POSIX alarm() function well enough, with the
  15495.   caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
  15496.   and wait for the alarm thread to finish.
  15497. */
  15498. unsigned int
  15499. alarm(unsigned int seconds) {
  15500.     long time_left = 0;
  15501.  
  15502. /* If an alarm is active, turn it off, saving the unused time */
  15503.     if (alarm_thread != -1) {
  15504.         /* We'll be generous and count partial seconds as whole seconds. */
  15505.         time_left = alarm_struct.time -
  15506.       ((system_time() - time_started) / 1000000.0);
  15507.  
  15508.         /* Kill the alarm thread */
  15509.         kill_thread (alarm_thread);
  15510.  
  15511.         /* We need to clean up as though the alarm occured. */
  15512.         time_started = 0;
  15513.         alarm_struct.thread = -1;
  15514.         alarm_struct.time = 0;
  15515.         alarm_expired();
  15516.     }
  15517.  
  15518. /* Set a new alarm clock, if requested. */
  15519.     if (seconds > 0) {
  15520.         alarm_struct.thread = find_thread(NULL);
  15521.         alarm_struct.time = seconds;
  15522.         time_started = system_time();
  15523.         alarm_thread = spawn_thread (do_alarm,
  15524.                                      "alarm_thread",
  15525.                                      B_NORMAL_PRIORITY,
  15526.                                      (void *) &alarm_struct
  15527.                      );
  15528.         resume_thread (alarm_thread);
  15529.     }
  15530.  
  15531. /* Now return [unused time | 0] */
  15532.     return ((unsigned int) time_left);
  15533. }
  15534.  
  15535. /*
  15536.   This function is the departure from UNIX/POSIX alarm handling. In the case
  15537.   of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
  15538.   handler. When Be implements alarm(), this function call can be eliminated
  15539.   from user's SIGALRM signal handlers.
  15540. */
  15541.  
  15542. void
  15543. alarm_expired(void) {
  15544.     long ret_val;
  15545.  
  15546.     if (alarm_thread != -1) {
  15547.         wait_for_thread (alarm_thread, &ret_val);
  15548.         alarm_thread = -1;
  15549.     }
  15550. }
  15551.  
  15552. /*
  15553.   This is the function that snoozes the requisite number of seconds and then
  15554.   SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
  15555.   uses thread_id; currently they are both typdef'ed as long, but I'll do the
  15556.   cast anyway. This function is run in a separate thread.
  15557. */
  15558.  
  15559. long
  15560. do_alarm (void *alarm_struct) {
  15561.     snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
  15562.     kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
  15563.     time_started = 0;
  15564.     ((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
  15565.     ((struct ALARM_STRUCT *) alarm_struct)->time = 0;
  15566. }
  15567. /* #endif */ /* BE_DR_7 */
  15568. #endif /* BEOSORBEBOX */
  15569.  
  15570. #ifdef Plan9
  15571.  
  15572. int
  15573. p9ttyctl(char letter, int num, int param) {
  15574.     char cmd[20];
  15575.     int len;
  15576.  
  15577.     if (ttyctlfd < 0)
  15578.       return -1;
  15579.  
  15580.     cmd[0] = letter;
  15581.     if (num)
  15582.       len = sprintf(cmd + 1, "%d", param) + 1;
  15583.     else {
  15584.     cmd[1] = param;
  15585.     len = 2;
  15586.     }
  15587.     if (write(ttyctlfd, cmd, len) == len) {
  15588.     cmd[len] = 0;
  15589.     /* fprintf(stdout, "wrote '%s'\n", cmd); */
  15590.     return 0;
  15591.     }
  15592.     return -1;
  15593. }
  15594.  
  15595. int
  15596. p9ttyparity(char l) {
  15597.     return p9ttyctl('p', 0, l);
  15598. }
  15599.  
  15600. int
  15601. p9tthflow(int flow, int status) {
  15602.     return p9ttyctl('m', 1, status);
  15603. }
  15604.  
  15605. int
  15606. p9ttsspd(int cps) {
  15607.     if (p9ttyctl('b', 1, cps * 10) < 0)
  15608.       return -1;
  15609.     ttylastspeed = cps * 10;
  15610.     return 0;
  15611. }
  15612.  
  15613. int
  15614. p9openttyctl(char *ttname) {
  15615.     char name[100];
  15616.  
  15617.     if (ttyctlfd >= 0) {
  15618.     close(ttyctlfd);
  15619.     ttyctlfd = -1;
  15620.     ttylastspeed = -1;
  15621.     }
  15622.     sprintf(name, "%sctl", ttname);
  15623.     ttyctlfd = open(name, 1);
  15624.     return ttyctlfd;
  15625. }
  15626.  
  15627. int
  15628. p9concb() {
  15629.     if (consctlfd >= 0) {
  15630.     if (write(consctlfd, "rawon", 5) == 5)
  15631.       return 0;
  15632.     }
  15633.     return -1;
  15634. }
  15635.  
  15636. int
  15637. p9conbin() {
  15638.     return p9concb();
  15639. }
  15640.  
  15641. int
  15642. p9conres() {
  15643.     if (consctlfd >= 0) {
  15644.     if (write(consctlfd, "rawoff", 6) == 6)
  15645.       return 0;
  15646.     }
  15647.     return -1;
  15648. }
  15649.  
  15650. int
  15651. p9sndbrk(int msec) {
  15652.     if (ttyctlfd >= 0) {
  15653.     char cmd[20];
  15654.     int i = sprintf(cmd, "k%d", msec);
  15655.     if (write(ttyctlfd, cmd, i) == i)
  15656.       return 0;
  15657.     }
  15658.     return -1;
  15659. }
  15660.  
  15661. int
  15662. conwrite(char *buf, int n) {
  15663.     int x;
  15664.     static int length = 0;
  15665.     static int holdingcr = 0;
  15666.     int normal = 0;
  15667.     for (x = 0; x < n; x++) {
  15668.     char c = buf[x];
  15669.     if (c == 007) {
  15670.         if (normal) {
  15671.         write(1, buf + (x - normal), normal);
  15672.         length += normal;
  15673.         normal = 0;
  15674.         }
  15675.         /* write(noisefd, "1000 300", 8); */
  15676.         holdingcr = 0;
  15677.     } else if (c == '\r') {
  15678.         if (normal) {
  15679.         write(1, buf + (x - normal), normal);
  15680.         length += normal;
  15681.         normal = 0;
  15682.         }
  15683.         holdingcr = 1;
  15684.     } else if (c == '\n') {
  15685.         write(1, buf + (x - normal), normal + 1);
  15686.         normal = 0;
  15687.         length = 0;
  15688.         holdingcr = 0;
  15689.     } else if (c == '\b') {
  15690.         if (normal) {
  15691.         write(1, buf + (x - normal), normal);
  15692.         length += normal;
  15693.         normal = 0;
  15694.         }
  15695.         if (length) {
  15696.         write(1, &c, 1);
  15697.         length--;
  15698.         }
  15699.         holdingcr = 0;
  15700.     } else {
  15701.         if (holdingcr) {
  15702.         char b = '\b';
  15703.         while (length-- > 0)
  15704.           write(1, &b, 1);
  15705.         length = 0;    /* compiler bug */
  15706.         }
  15707.         holdingcr = 0;
  15708.         normal++;
  15709.     }
  15710.     }
  15711.     if (normal) {
  15712.     write(1, buf + (x - normal), normal);
  15713.     length += normal;
  15714.     }
  15715.     return n;
  15716. }
  15717.  
  15718. void
  15719. conprint(char *fmt, ...) {
  15720.     static char buf[1000];        /* not safe if on the stack */
  15721.  
  15722.     va_list ap;
  15723.     int i;
  15724.  
  15725.     va_start(ap, fmt);
  15726.     i = vsprintf(buf, fmt, ap);
  15727.     conwrite(buf, i);
  15728. }
  15729. #endif /* Plan9 */
  15730.  
  15731. /* fprintf, printf, perror replacements... */
  15732.  
  15733. /* f p r i n t f */
  15734.  
  15735. #ifdef UNIX
  15736. #ifdef CK_ANSIC
  15737. #include <stdarg.h>
  15738. #else /* CK_ANSIC */
  15739. #ifdef __GNUC__
  15740. #include <stdarg.h>
  15741. #else
  15742. #include <varargs.h>
  15743. #endif    /* __GNUC__ */
  15744. #endif /* CK_ANSIC */
  15745. #ifdef fprintf
  15746. #undef fprintf
  15747. static char str1[4096];
  15748. static char str2[4096];
  15749. int
  15750. #ifdef CK_ANSIC
  15751. ckxfprintf(FILE * file, const char * format, ...)
  15752. #else /* CK_ANSIC */
  15753. ckxfprintf(va_alist) va_dcl
  15754. #endif /* CK_ANSIC */
  15755. /* ckxfprintf */ {
  15756.     int i, j, len, got_cr;
  15757.     va_list args;
  15758.     int rc = 0;
  15759.  
  15760. #ifdef CK_ANSIC
  15761.     va_start(args, format);
  15762. #else /* CK_ANSIC */
  15763.     char * format;
  15764.     FILE * file;
  15765.     va_start(args);
  15766.     file = va_arg(args,FILE *);
  15767.     format = va_arg(args,char *);
  15768. #endif /* CK_ANSIC */
  15769.  
  15770.     if (!inserver || (file != stdout && file != stderr && file != stdin)) {
  15771.     rc = vfprintf(file,format,args);
  15772.     } else {
  15773.     unsigned int c;
  15774.         rc = vsprintf(str1, format, args);
  15775.         len = strlen(str1);
  15776.         if (len >= sizeof(str1)) {
  15777.             debug(F101,"ckxfprintf() buffer overflow","",len);
  15778.             doexit(BAD_EXIT,1);
  15779.         }
  15780.         for (i = 0, j = 0, got_cr = 0;
  15781.          i < len && j < sizeof(str1)-2;
  15782.          i++, j++ ) {
  15783.         /* We can't use 255 as a case label because of signed chars */
  15784.         c = (unsigned)(str1[i] & 0xff);
  15785. #ifdef TNCODE
  15786.         if (c == 255) {
  15787.         if (got_cr && !TELOPT_ME(TELOPT_BINARY))
  15788.           str2[j++] = '\0';
  15789.         str2[j++] = IAC;
  15790.         str2[j] = IAC;
  15791.         got_cr = 0;
  15792.         } else
  15793. #endif /* TNCODE */
  15794.         switch (c) {
  15795.           case '\r':
  15796.                 if (got_cr
  15797. #ifdef TNCODE
  15798.             && !TELOPT_ME(TELOPT_BINARY)
  15799. #endif /* TNCODE */
  15800.             )
  15801.           str2[j++] = '\0';
  15802.                 str2[j] = str1[i];
  15803.                 got_cr = 1;
  15804.                 break;
  15805.           case '\n':
  15806.                 if (!got_cr)
  15807.           str2[j++] = '\r';
  15808.                 str2[j] = str1[i];
  15809.                 got_cr = 0;
  15810.                 break;
  15811.           default:
  15812.                 if (got_cr
  15813. #ifdef TNCODE
  15814.             && !TELOPT_ME(TELOPT_BINARY)
  15815. #endif /* TNCODE */
  15816.             )
  15817.           str2[j++] = '\0';
  15818.                 str2[j] = str1[i];
  15819.                 got_cr = 0;
  15820.             }
  15821.         }
  15822.         if (got_cr
  15823. #ifdef TNCODE
  15824.              && !TELOPT_ME(TELOPT_BINARY)
  15825. #endif /* TNCODE */
  15826.              )
  15827.             str2[j++] = '\0';
  15828. #ifdef CK_ENCRYPTION
  15829. #ifdef TNCODE
  15830.         if (TELOPT_ME(TELOPT_ENCRYPTION))
  15831.       ck_tn_encrypt(str2,j);
  15832. #endif /* TNCODE */
  15833. #endif /* CK_ENCRYPTION */
  15834. #ifdef CK_SSL
  15835.     if (inserver && (ssl_active_flag || tls_active_flag)) {
  15836.         /* Write using SSL */
  15837.             char * p = str2;
  15838.           ssl_retry:
  15839.             if (ssl_active_flag)
  15840.           rc = SSL_write(ssl_con, p, j);
  15841.             else
  15842.           rc = SSL_write(tls_con, p, j);
  15843.         debug(F111,"ckxfprintf","SSL_write",rc);
  15844.             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
  15845.           case SSL_ERROR_NONE:
  15846.                 if (rc == j)
  15847.           break;
  15848.                 p += rc;
  15849.                 j -= rc;
  15850.                 goto ssl_retry;
  15851.           case SSL_ERROR_WANT_WRITE:
  15852.           case SSL_ERROR_WANT_READ:
  15853.           case SSL_ERROR_SYSCALL:
  15854.                 if (rc != 0)
  15855.           return(-1);
  15856.           case SSL_ERROR_WANT_X509_LOOKUP:
  15857.           case SSL_ERROR_SSL:
  15858.           case SSL_ERROR_ZERO_RETURN:
  15859.           default:
  15860.                 rc = 0;
  15861.             }
  15862.     } else
  15863. #endif /* CK_SSL */
  15864.         fwrite(str2,sizeof(char),j,stdout);
  15865.     }
  15866.     va_end(args);
  15867.     return(rc);
  15868. }
  15869. #endif /* fprintf */
  15870.  
  15871. /* p r i n t f */
  15872.  
  15873. #ifdef printf
  15874. #undef printf
  15875. int
  15876. #ifdef CK_ANSIC
  15877. ckxprintf(const char * format, ...)
  15878. #else /* CK_ANSIC */
  15879. ckxprintf(va_alist) va_dcl
  15880. #endif /* CK_ANSIC */
  15881. /* ckxprintf */ {
  15882.     int i, j, len, got_cr;
  15883.     va_list args;
  15884.     int rc = 0;
  15885.  
  15886. #ifdef CK_ANSIC
  15887.     va_start(args, format);
  15888. #else /* CK_ANSIC */
  15889.     char * format;
  15890.     va_start(args);
  15891.     format = va_arg(args,char *);
  15892. #endif /* CK_ANSIC */
  15893.  
  15894.     if (!inserver) {
  15895.     rc = vprintf(format, args);
  15896.     } else {
  15897.     unsigned int c;
  15898.         rc = vsprintf(str1, format, args);
  15899.         len = strlen(str1);
  15900.         if (len >= sizeof(str1)) {
  15901.             debug(F101,"ckxprintf() buffer overflow","",len);
  15902.             doexit(BAD_EXIT,1);
  15903.         }
  15904.         for (i = 0, j = 0, got_cr=0;
  15905.          i < len && j < sizeof(str1)-2;
  15906.          i++, j++ ) {
  15907.         c = (unsigned)(str1[i] & 0xff);
  15908. #ifdef TNCODE
  15909.         if (c == 255) {
  15910.         if (got_cr && !TELOPT_ME(TELOPT_BINARY))
  15911.           str2[j++] = '\0';
  15912.         str2[j++] = IAC;
  15913.         str2[j] = IAC;
  15914.         got_cr = 0;
  15915.         } else
  15916. #endif /* TNCODE */
  15917.         switch (c) {
  15918.           case '\r':
  15919.                 if (got_cr
  15920. #ifdef TNCODE
  15921.             && !TELOPT_ME(TELOPT_BINARY)
  15922. #endif /* TNCODE */
  15923.             )
  15924.           str2[j++] = '\0';
  15925.                 str2[j] = str1[i];
  15926.                 got_cr = 1;
  15927.                 break;
  15928.           case '\n':
  15929.                 if (!got_cr)
  15930.           str2[j++] = '\r';
  15931.                 str2[j] = str1[i];
  15932.                 got_cr = 0;
  15933.                 break;
  15934.           default:
  15935.                 if (got_cr
  15936. #ifdef TNCODE
  15937.             && !TELOPT_ME(TELOPT_BINARY)
  15938. #endif /* TNCODE */
  15939.             )
  15940.           str2[j++] = '\0';
  15941.                 str2[j] = str1[i];
  15942.                 got_cr = 0;
  15943.                 break;
  15944.         }
  15945.         }
  15946.         if (got_cr
  15947. #ifdef TNCODE
  15948.              && !TELOPT_ME(TELOPT_BINARY)
  15949. #endif /* TNCODE */
  15950.              )
  15951.             str2[j++] = '\0';
  15952. #ifdef CK_ENCRYPTION
  15953. #ifdef TNCODE
  15954.         if (TELOPT_ME(TELOPT_ENCRYPTION))
  15955.       ck_tn_encrypt(str2,j);
  15956. #endif /* TNCODE */
  15957. #endif /* CK_ENCRYPTION */
  15958. #ifdef CK_SSL
  15959.     if (inserver && (ssl_active_flag || tls_active_flag)) {
  15960.             char * p = str2;
  15961.         /* Write using SSL */
  15962.           ssl_retry:
  15963.             if (ssl_active_flag)
  15964.           rc = SSL_write(ssl_con, p, j);
  15965.             else
  15966.           rc = SSL_write(tls_con, p, j);
  15967.         debug(F111,"ckxprintf","SSL_write",rc);
  15968.             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)) {
  15969.           case SSL_ERROR_NONE:
  15970.                 if (rc == j)
  15971.           break;
  15972.                 p += rc;
  15973.                 j -= rc;
  15974.                 goto ssl_retry;
  15975.           case SSL_ERROR_WANT_WRITE:
  15976.           case SSL_ERROR_WANT_READ:
  15977.           case SSL_ERROR_SYSCALL:
  15978.                 if (rc != 0)
  15979.           return(-1);
  15980.           case SSL_ERROR_WANT_X509_LOOKUP:
  15981.           case SSL_ERROR_SSL:
  15982.           case SSL_ERROR_ZERO_RETURN:
  15983.           default:
  15984.                 rc = 0;
  15985.             }
  15986.     } else
  15987. #endif /* CK_SSL */
  15988.       rc = fwrite(str2,sizeof(char),j,stdout);
  15989.     }
  15990.     va_end(args);
  15991.     return(rc);
  15992. }
  15993. #endif /* printf */
  15994.  
  15995. /*  p e r r o r  */
  15996.  
  15997. #ifdef perror
  15998. #undef perror
  15999. _PROTOTYP(char * ck_errstr,(VOID));
  16000. #ifdef NEXT
  16001. void
  16002. #else
  16003. #ifdef CK_SCOV5
  16004. void
  16005. #else
  16006. int
  16007. #endif /* CK_SCOV5 */
  16008. #endif /* NEXT */
  16009. #ifdef CK_ANSIC
  16010. ckxperror(const char * str)
  16011. #else /* CK_ANSIC */
  16012. ckxperror(str) char * str;
  16013. #endif /* CK_ANSIC */
  16014. /* ckxperror */ {
  16015.     char * errstr = ck_errstr();
  16016. #ifndef NEXT
  16017. #ifndef CK_SCOV5
  16018.     return
  16019. #endif /* CK_SCOV5 */
  16020. #endif /* NEXT */
  16021.       ckxprintf("%s%s %s\n",str,*errstr?":":"",errstr);
  16022. }
  16023. #endif /* perror */
  16024. #endif /* UNIX */
  16025.  
  16026. #ifdef MINIX2
  16027.  
  16028. /* Minix doesn't have a gettimeofday call (but MINIX3 does).
  16029.  * We fake one here using time(2)
  16030.  */
  16031.  
  16032. #ifndef MINIX3
  16033. int
  16034. gettimeofday(struct timeval *tp, struct timezone *tzp) {
  16035.     tp->tv_usec = 0L;            /* Close enough for horseshoes */
  16036.     if(time(&(tp->tv_sec))==-1)
  16037.       return(-1);
  16038.     return(0);
  16039. }
  16040. #endif    /* MINIX3 */
  16041.  
  16042. #ifndef MINIX3
  16043. int
  16044. readlink(const char *path, void *buf, size_t bufsiz) {
  16045.     errno = ENOSYS;
  16046.     return(-1);
  16047. }
  16048. #endif    /* MINIX3 */
  16049.  
  16050. #endif /* MINIX2 */
  16051.