home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckvtio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  153KB  |  4,306 lines

  1. #ifndef VMS
  2. # error -- CKVTIO.C is used only on the VMS(tm) or OpenVMS(tm) Operating System
  3. #endif /* VMS */
  4.  
  5. /* REMINDER: "help system $blah" gives help about sys$blah() */
  6.  
  7. #if defined(__ia64) || defined(__ia64__)
  8. # define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) IA64"
  9.  
  10. #else
  11. # if defined(__ALPHA) || defined(__alpha)
  12. #  define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) Alpha(tm)"
  13.          /* do nothing */
  14. #else
  15. # ifdef VAX
  16. #  define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) VAX(tm)"
  17. # else
  18. #  ifdef __GNUC__
  19. #     define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) VAX(tm) (GCC)"
  20. #  else
  21. #     ERROR -- CKVTIO.C unknown architecture - Not VAX ALPHA or IA64
  22. #  endif /* __GNUC__ */
  23. # endif /* VAX */
  24. #endif /* __ALPHA */
  25. #endif /* __IA64 */
  26. /*
  27.   Module version number and date.
  28.   Also update the module number above accordingly.
  29. */
  30. char *ckxv = "Communications I/O 9.0.124, 16 Oct 2009";
  31.  
  32. /*
  33.   This is the default architecture and operating system herald string.
  34.   It is redetermined dynamically in sysinit() below.
  35. */
  36. char *ckxsys = CKVTIO_OS_ARCH_STRING;
  37.  
  38. /*  C K V T I O  --  Terminal and Interrupt Functions for VAX/VMS  */
  39.  
  40. /* C-Kermit interrupt, terminal control & i/o functions for VMS systems */
  41.  
  42. /*
  43.   Author: Frank da Cruz <fdc@columbia.edu>
  44.   The Kermit Project, Columbia University, New York City.
  45.  
  46.   Copyright (C) 1985, 2009,
  47.     Trustees of Columbia University in the City of New York.
  48.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  49.     copyright text in the ckcmai.c module for disclaimer and permissions.
  50. */
  51.  
  52. /* Edit History
  53.  *
  54.  * Originally adapted to VMS by:
  55.  * Stew Rubenstein, Harvard University Chemical Labs, 1985.
  56.  *
  57.  * Cast of characters
  58.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  59.  * cdh  Charles Don Hall  The Wollongong Group
  60.  * cf   Carl Friedberg    Comet & Co., NYC
  61.  * dbs  David B Sneddon
  62.  * DS   Dan Schullman     Digital
  63.  * fdc  Frank da Cruz     Columbia U
  64.  * HG   Hunter Goatley    Western Kentucky University and Process Software
  65.  * jea  Jeffrey Altman    Columbia U
  66.  * jh   James Harvey      Indiana / Purdue University
  67.  * js   James Sturdevant  (thru 1994)
  68.  * js   John Santos       (1996-...)
  69.  * lh   Lucas Hart        Oregon State University
  70.  * LT   Lee Tibbert       Digital
  71.  * mab  Mark Buda         Digital
  72.  * mlo  Mike O'Malley     Digital
  73.  * MM   Martin Minow      Digital (died 21 Dec 2000)
  74.  * mpjz Martin PJ Zinzer  Gesellschaft fuer Schwerionenforschung GSI Darmstadt
  75.  * tmk  Terry Kennedy     Saint Peters College and tmk.com
  76.  * ttj  Tarjei T. Jensen  Norwegian Hydrographic Service
  77.  * wb   William Bader     Lehigh University
  78.  * wjm  Wolfgang J Moeller DECUS Germany
  79.  * mv   Mortin Vorlaender PDV-Systeme Goslar Germany
  80.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  81.  * 006  8-May-85 MM   Got rid of "typeahead buffer" code as it didn't
  82.  *                    solve the problem of data overruns at 4800 Baud.
  83.  *                    Added vms "read a char" routine that checks for
  84.  *                    CTRL/C, CTRL/Z, etc.
  85.  * 007 16-May-85 fdc  Changed calling convention of ttopen(), make it
  86.  *                    set value of its argument "lcl", to tell whether
  87.  *                    C-Kermit is in local or remote mode.
  88.  * 008 11 Jun 85 MM   Fix definition of CTTNAM
  89.  * 009 18 Jun 85 fdc  Move def of CTTNAM to ckcdeb.h so it can be shared.
  90.  * 010 25 Jun 85 MM   Added sysinit() to open console.
  91.  * 011  5 Jul 85 DS   Treat hangup of closed line as success.
  92.  * 012 11 Jul 85 fdc  Add gtimer(), rtimer() for timing statistics.
  93.  * 013 14 Sep 87 fdc  Add parity strip to ttinl(), add syscleanup().
  94.  * 014 14 Feb 89 mab  Make break REALLY work.  Add IOSB's to all QIO's.
  95.  * 015 26 Feb 89 mab  Add dcl exit handler and minor cleanup
  96.  * 016 23-Mar-89 mab  Add IO$M_BREAKTHRU to IO$_WRITEVBLK.
  97.  *                    Add zchkspd() function to check for valid speed.
  98.  * 017 04-Apr-89 mab  Fix some minor bugs to local/remote code
  99.  * 018 23-Apr-89 mab  Add some of Valerie Mates' parity changes.
  100.  * 019 25-Apr-89 mab  Change baud to 110 for V4.x break routine as
  101.  *                    50 baud is not supported on most Muxes by VMS.
  102.  * 020 13-Jun-89 mab  Fix on exquota problem on qiow(readvblk)
  103.  * 021 08-Jul-89 mab  Add ^C/^Y abort server mode code.
  104.  * 022 11-May-90 mab  Add V5A code
  105.  * 023 20-Jul-90 wb   Add support for old VAX C and VMS versions
  106.  * 024 22-Sep-90 wb   Fixes to cps/bps confusion
  107.  * 025 26-Sep-90 tmk  Fix the ztime() function
  108.  * 026 29-Sep-90 tmk  Edit 024 cause a server command to give some blither-
  109.  *                    ings about unsupported line speeds.  Added a simple hack
  110.  *                    to exit quietly if the passed speed is 0.  Adventurous
  111.  *                    maintainers may want to look in ttpkt(), where ttsspd()
  112.  *                    is being called with a value of -1/10.
  113.  * 027 11-Oct-90 fdc  Made ttol return number of chars successfully written.
  114.  *                    Made ztime() use ctime() in all cases.
  115.  *                    Another fix (from tmk) for bps/cps confusion.
  116.  *                    Wrapped source lines longer than 80 characters.
  117.  * 028 18-Oct-90 fdc  Added comments to concb() and vms_getchar() to show
  118.  *                    how to make Ctrl-C trap work.  Didn't actually do it,
  119.  *                    though, because Ctrl-Y apparently still can't be caught.
  120.  *                    Also, more minor reformatting.  Adjust time() declare.
  121.  *                    Added support for automatic parity sense in ttinl(),
  122.  *                    within #ifdef PARSENSE conditionals.  Built with PARSENSE
  123.  *                    defined, works ok.
  124.  * 029  5-Apr-91 fdc  Extensive reworking of many routines to allow for
  125.  *                    network connections, addition of TGV MultiNet support.
  126.  * 030 31-Aug-91 tmk  Fix problem with INPUT statements not timing out due to
  127.  *                    extraneous rtimer() inside gtimer().
  128.  * 032  6-Nov-91 fdc  Correct parity problem.
  129.  * 032  6-Nov-91 fdc  Cosmetic cleanup in sysinit().
  130.  * 033 14-Jan-91 fdc  Fix to get_qio_maxbuf_size to prevent crashes:
  131.  *                    remove "&" from "!test_qio(ttychn,max,&tmpbuf)",
  132.  *                    from John Schultz at 3M.
  133.  * 034  8-Feb-92 fdc  Don't change EIGHTBIT setting in ttvt, concb, or conbin.
  134.  *                    Set EIGHTBIT in ttpkt only if parity is not NONE.  From
  135.  *                    Alan Robiette, Oxford U, UK.
  136.  * 035 10-Jun-92 fdc  Added code from Ray Hunter of The Wollongong Group to
  137.  *                    support both WIN/TCP and TGV Multinet.  Network section
  138.  *                    of contti() redone to eliminate polling loop.  It's
  139.  *                    infinitely faster.
  140.  * 036 11-Jun-92 tmk  Fixed up edit 034 so 8-bit characters could be passed
  141.  *                    in connect mode.
  142.  * 037 19-Jun-92 fdc  Totally rewrote all the serial input and mode-setting
  143.  *                    routines in this module to use nonblocking, fully
  144.  *                    buffered input and to share a common buffer.  All
  145.  *                    serial-line input is localized to a single routine,
  146.  *                    txbufr(), which, in turn is known only to ttinc().  The
  147.  *                    other input routines, ttxin() and ttinl(), simply call
  148.  *                    ttinc().  ttchk() and ttflui() are totally cognizant of
  149.  *                    the buffer.  ttinl() now recognizes packets with
  150.  *                    printable start characters and/or lacking terminators,
  151.  *                    so VMS C-Kermit can now engage in "Doomsday Kermit"
  152.  *                    protocol.  ttvt() and ttpkt() were merged into a single
  153.  *                    new (static) routine, ttbin(), which no longer puts the
  154.  *                    device into PASALL mode (which defeats flow control).
  155.  *                    Added ttsndlb() to send a Long BREAK.  Much fine-tuning,
  156.  *                    testing, and filling-in remains to be done, including
  157.  *                    (a) make ttopen() and ttclos() aware of LAT devices; (b)
  158.  *                    check remaining BYTLM quota before issuing a read, (c)
  159.  *                    integrate network and serial buffers, and much more.
  160.  *                    Anyway, this code seems to run faster than ever before,
  161.  *                    and for the first time I can actually use sliding
  162.  *                    windows AND long packets on my 8-year old MicroVAX-II.
  163.  * 038 28-Jun-92 tmk  Additional work on edit 37, general cleanup of old defs.
  164.  * 039  1-Jul-92 wb   Changes for VMS 4.4.
  165.  * 040  4-Jul-92 tmk  Add modem signal support (ttgmdm routine).
  166.  * 041  4-Jul-92 tmk  Add tgetent(), worker routine for el-cheapo curses.
  167.  * 042  4-Jul-92 jh   Enable typeahead in ttbin().
  168.  * 043 21-Aug-92 fdc  Make default flow control be KEEP instead of Xon/Xoff.
  169.  * 044  6-Sep-92 fdc  Put default flow back to Xon/Xoff, but allow KEEP to be
  170.  *                    used to restore device's original flow-control setting.
  171.  * 045 23-Sep-92 fdc  Add sleep(1) to tthang().  Seems to fix HANGUP command.
  172.  *                    Suggested by Lee Tibbert.  Change ttbin() to use global
  173.  *                    flow variable rather than its flow parameter for setting
  174.  *                    flow control, to ensure the desired type of flow control
  175.  *                    is used during DIAL operations.
  176.  * 046 26-Sep-92 fdc  Change sleep(1) in tthang() to sleep(3).  Annoying but
  177.  *                    necessary.  IO$M_HANGUP takes about 3 seconds, but the
  178.  *                    sys$qiow() function returns immediately instead of
  179.  *                    waiting for the action to complete.
  180.  * 047 08-Oct-92 HG   Add call to sys$alloc in ttopen() to prevent user with
  181.  *                    SHARE from getting port in use.  Some add'l cleanup.
  182.  * 048 12-Oct-92 LT   Minor changes to support DEC TCP/IP (nee UCX).
  183.  * 049 25-Oct-92 fdc  Adapt (ck_)cancio() to DEC TCP/IP.
  184.  *                    Remove superfluous ttflui() call from ttpkt().
  185.  *                    Add code from Lee Tibbert to sysinit() to figure out OS
  186.  *                    and architecture name at runtime.
  187.  * 050 18-Nov-92 fdc  Read from comm device in 1024-byte chunks, rather than
  188.  *                    trusting the qio_maxbuf_size.  This should reduce BYTLM
  189.  *                    quota-exceeded errors.  Suggested by tmk as a temporary
  190.  *                    workaround.
  191.  * 051 10-May-93 fdc  Add support for SET TRANSFER CANCELLATION.
  192.  * 052 16-May-93 fdc  Change VMSTCPIP to TCPIPLIB to agree with new CKCNET.H.
  193.  * 053 16-May-93 fdc  ANSIfication for GNU CC, from James Sturdevant.
  194.  * 054 08-Jun-83 fdc  Add TT$M_LOCALECHO and TT$M_ESCAPE to the terminal modes
  195.  *                    we handle, to prevent "getty babble" with modems, VAX
  196.  *                    PSI, etc.
  197.  * 055 16-Jun-93 fdc  Edit 054 only affected ttbin().  This edit does the same
  198.  *                    for conbin() and concb().  Fixes double echoing in
  199.  *                    command mode when coming in via VAX PSI.
  200.  * 056  8-Aug-93 fdc  Add types to all function declarations.
  201.  * 057 17-Aug-93 fdc  Add GET_SDC macro as in CKVIOC.C, accounting for GCC.
  202.  *                    From Tarjei T. Jensen <tarjeij@extern.uio.no>.
  203.  * 058 27-Sep-93 HG   Fix for real the SHARE issue when allocating terminal
  204.  *                    by dropping SHARE before trying to assign the channel.
  205.  * 059  7-Oct-93 mlo  Added support for CMU-OpenVMS/IP ("CMU/Tek").  Requires
  206.  *                    CMU-OpenVMS/IP sockets library, also by mlo.
  207.  * 060  9-Oct-93 HG   Fix improper call to vms_assign_channel in edit 058,
  208.  *                    noticed by Fritz@GEMS.VCU.EDU.
  209.  * 061  9-Oct-93 fdc  For some reason, conbin() was turning off flow control.
  210.  *                    This caused massive data loss during CONNECT mode when
  211.  *                    running C-Kermit from a low-speed connection through
  212.  *                    a DECserver.  Now conbin() leaves the console flow
  213.  *                    control setting alone.
  214.  * 062 10-Oct-93 ttj  Change parameters to time() and ctime() from long to
  215.  *                    time_t (pointers).  Made prototype for vms_assign_channel
  216.  *                    and caught an erroneous function call.
  217.  * 063  9-Nov-93 fdc  In sysinit(), don't run sys$getdviw() on the "console"
  218.  *                    if the console is not a terminal (from tcwkw@sf.msc.edu).
  219.  *                    And (blame this one on me) _never_ set the backgrd flag.
  220.  * 064 25-Nov-93 fdc  Fixed coninc(n) to return -1 on timeout.
  221.  * 065  9-Dec-93 fdc  Fix transfer cancellation to account for parity, and
  222.  *                    allow it only in remote mode.
  223.  * 066 13-Dec-93 fdc  Make debug logging in ttol() show why packet writes fail.
  224.  * 067 15-Dec-93 fdc  New, MAXBUF-proof ttol() recovers from failures by
  225.  *                    writing the packet in chunks, whose size is computed
  226.  *                    dynamically.  This seems to cause no noticable slowdown
  227.  *                    in the transfer rate.
  228.  * 068 31-Dec-93 fdc  Fix bug in parity-detection code in ttinl().
  229.  * 069 14-Dec-93 fdc  Add ttgwsiz() routine, code from John Berryman.
  230.  * 070 14-MAR-94 mlo  CMU_TCPIP modifications: contti - return error (-1)
  231.  *                    if number of characters read is zero; (ck_)cancio - pass
  232.  *                    correct i/o channel for ttyfd to sys$cancel.
  233.  * 071 15-MAR-94 mlo  ttol() - add #ifdef DEBUG for compiles with NODEBUG
  234.  * 072 27-Mar-94 fdc  Straighten out some ttsspd()/ttgspd() confusion.
  235.  * 073 11-AUG-94 fdc  Make conoll() return a proper return code.
  236.  * 074 12-AUG-94 fdc  Make syscleanup() handle conres() error.  Make
  237.  * 075 20-AUG-94 js   Make congm() get terminal type, etc, to remove annoying
  238.  *                    "Sorry, terminal type not supported" messages when
  239.  *                    running from a .COM file, etc.
  240.  * 076 02-Sep-94 fdc  Call con_cancel() in syscleanup() to cancel any pending
  241.  *                    console i/o, hopefully eliminating zombies after
  242.  *                    after disconnection, etc.
  243.  * 077 22-Sep-94 mlo  Don't call sys$cancel() in (ck_k)cancio() on CMU/Tek
  244.  *                    network connections - it breaks the connection.
  245.  * 078 24-Feb-95 mpjz Fix for DECC on VAX.
  246.  * 079 08-Feb-96 fdc  Add symbols for higher serial speeds.
  247.  * 080 30-May-96 fdc  Fix netopen() to work with Rlogin.
  248.  * 081 25-Aug-96 mpjz More DECC/VAXC fixups.
  249.  * 082 05-Sep-96 fdc  Remove #module, change (ck_)cancio() declaration.
  250.  * 083 06-Sep-96 fdc  Fix loss of parity setting on network connections.
  251.  * 084 06-Sep-96 cf   Add missing speeds to ttspeeds[] (Carl Freidberg)
  252.  * 085 06-Sep-96 fdc  Add conspd() routine (for use by RLOGIN).
  253.  * 086 06-Sep-96 fdc  Try to fix parity confusion again.
  254.  * 087 06-Sep-96 fdc  And again: culprit is DECC sign-extension: see ttinc, etc
  255.  * 088 06-Sep-96 fdc  Unravel the network-file-descriptor reusability tangle
  256.  * 089 23-May-97 wjm  CMUIP & related fixes from Wolfgang Moeller
  257.  * 090 23-May-97 cdh  Patches for Wollongong/Attachmate Pathway
  258.  * 091 12-Jul-97 fdc  Try to avoid or at least identify terrible things that
  259.                       happen when (a) we have made a serial connection and the
  260.                       other side hangs it up (and so C-Kermit hangs in ttclos),
  261.                       and (b) when running in a DECwindow and user closes the
  262.                       DECwindow and so any attempt access to the console gets
  263.                       a DEVOFFLINE error, which in turn causes an error msg,
  264.                       which in turn gets another DEVOFFLINE error, etc, until
  265.                       the system grinds to halt.
  266.  * 092  6-Sep-97 fdc  Add ttspdlist() and startupdir[].
  267.  * 093 20-Sep-97 js   CMU/IP fixes (applied by fdc, hopefully correctly).
  268.  * 094 11-Dec-97 fdc  In ttgmdm(), omit controller-type test for Alpha.
  269.  *                    In txbufr(), treat hangup synchronously.
  270.  * 095 22-Dec-97 fdc  Add rftimer() and gftimer(), with help from James Puzzo.
  271.  *                    Fix ttclos() not to set network == 0, which makes
  272.  *                    subsequent ttchk() take the wrong path.
  273.  * 096  1-Jan-98 fdc  Add ok_to_share variable for ttopen() to get around
  274.  *                    an otherwise insuperable problem with DECIntact.
  275.  *                    Turn off broadcasts in conbin().  Set program name.
  276.  * 097 15-Jan-98 fdc  Don't set program name after all.  Use sys$getjpiw()
  277.  *                    instead of sys$getdviw("sys$login:") to get batch /
  278.  *                    interactive status.  More corrections to txbufr() carrier
  279.  *                    treatment.  Ditto for ttchk().
  280.  * 098  1-Feb-98 fdc  Fix contti() to not return a spurious character when
  281.  *                    CARRIER-WATCH is OFF and and sys$qiow() gives SS$_HANGUP
  282.  *                    and no character; return special code -2 and set up to
  283.  *                    queue a new read.
  284.  * 099  8-Apr-98 fdc  Add uname info in sysinit().  Commented out #includes
  285.  *                    for gftimer() in OLD_VMS (from lh).
  286.  * 100  3-May-98 fdc  Fix out-of-bounds tt_fulldevnam[]array reference.
  287.  * 101  7-May-98 lh   Improvements in hardware-name getting.
  288.  * 102  5-Jul-98 fdc  Illegal to take address of constant in GCC, reworked in
  289.  *                    gftimer() (from Kevin Handy).
  290.  * 103 25-Nov-98 fdc  Add support for CLOSE-ON-DISCONNECT.
  291.  * 104  9-Dec-98 fdc  Add support for NETLEBUF (see ckcnet.h).
  292.  * 105  5-Mar-99 fdc  Parameterize device name length TTNAMLEN.
  293.  *                    Fix ttchk() to avoid spurious "OK to exit?" after
  294.  *                    remote has hung up on us.
  295.  * 106 27-Apr-99 lh   Fix GCC warnings in gftimer().
  296.  * 107 22-Jul-99 fdc  Add code to sysinit() to get username.
  297.  * 108 23-Sep-99 fdc  Fix batch echoing & DCL image data execution.
  298.  * 109 18-Oct-99 fdc  Add setting of wasclosed variable.
  299.  * 110  3-Dec-00 fdc  Add Telnet Com Port Option.
  300.  * 111  7-Jun-01 lh   Fix off-by one ckstrncpy() into unm_mch[] in sysinit().
  301.  * 112 21-Jul-01 hg   Improved congm() detects better if console is terminal.
  302.  * 113  2-Nov-01 fdc  Allow REDIAL Telnet terminal server in ttopen().
  303.  * 114 10-Nov-01 lh   Fix bad pointer reference at end of ztime().
  304.  * 115 31-Dec-01 lh   Fix checks for batch/background again.
  305.  * 116  1-Jan-02 fdc  Check for -z and -B command-line option in congm().
  306.  * 117  3-Jan-02 dbs  Changed testing of batch to use itsatty.  There seemed
  307.  *                    to be some inconsistency about the testing of batch and
  308.  *                    itsatty which both appear to be indicating the same
  309.  *                    thing.  Changed the intial setting of itsatty to 1 since
  310.  *                    the initial setting of batch was 0.  Also modify the
  311.  *                    setting of backgrd to match batch - not quite sure why
  312.  *                    there are three flags to indicate the same thing.
  313.  *                    congm sets the three flags, but on return from congm
  314.  *                    they were reset based on isatty(0) - commented out this
  315.  *                    second attempt.  Commented out the CK_USEGETJPI stuff
  316.  *                    to set interactive determination to use sys$input rather
  317.  *                    than JPI$_TERMINAL.
  318.  * 118  8-Feb-02 fdc  Version string.
  319.  * 119 24-Oct-02 jea  SSL support code (not complete).
  320.  * 120 24-Oct-02 jea  More SSL support code (still not complete).
  321.  * 121-122 ???        (not sure -- probably finishing up SSL support?).
  322.  * 123 15-Jun-03 mv   cmdate2tm() function (for HTTP).
  323.  * 124 05-Apr-04 fdc  Add __ia64 arch_string.
  324.  */
  325.  
  326. /*
  327.  Variables available to outside world:
  328.  
  329.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  330.    dfloc  -- 0 if dftty is console(remote), 1 if external line(local).
  331.    dfprty -- Default parity
  332.    dfflow -- Default flow control
  333.    ckxech -- Flag for who echoes console typein:
  334.      1 - The program (system echo is turned off)
  335.      0 - The system (or front end, or terminal).
  336.    functions that want to do their own echoing should check this flag
  337.    before doing so.
  338.  
  339.    backgrd
  340.      Flag indicating program not executing interactively.
  341.      Used to ignore INT and QUIT signals, suppress messages, etc.
  342.    vms_status
  343.      Status returned by most recent VMS system service,
  344.      can be used for error reporting.
  345.    batch
  346.      Nonzero if running in batch job, 0 otherwise.
  347.    itsatty
  348.      Nonzero if sys$input is the terminal, 0 if batch job or started with @.
  349.  
  350.  Functions for assigned communication line (either external or console tty):
  351.  
  352.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  353.    ttclos()                -- Close & reset the tty, releasing any access lock.
  354.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  355.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  356.                                 or in DIALING or CONNECTED modem control state.
  357.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  358.    ttinc(timo)             -- Timed read character from tty.
  359.    ttchk()                 -- See how many characters in tty input buffer.
  360.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  361.    ttol(string,length)     -- Write a string to the tty.
  362.    ttoc(c)                 -- Write a character to the tty.
  363.    ttflui()                -- Flush tty input buffer.
  364.    tt_cancel()             -- Cancel any asynch I/O to tty
  365. */
  366.  
  367. /*
  368. Functions for console terminal:
  369.    congm()   -- Get console terminal modes.
  370.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  371.    conbin(esc) -- Put the console in binary (raw) mode.
  372.    conres()  -- Restore the console to mode obtained by congm().
  373.    conoc(c)  -- Unbuffered output, one character to console.
  374.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  375.    conola(s) -- Unbuffered output, array of lines to the console, CRLFs added.
  376.    conxo(n,s) -- Unbuffered output, n characters to the console.
  377.    conchk()  -- Check if characters available at console (bsd 4.2).
  378.                 Check if escape char (^\) typed at console (System III/V).
  379.    coninc(timo)  -- Timed get a character from the console.
  380.    conint()  -- Enable terminal interrupts on the console if not background.
  381.    connoi()  -- Disable terminal interrupts on the console if not background.
  382.    contti()  -- Get a character from either console or tty, whichever is first.
  383.  
  384. Time functions
  385.  
  386.    msleep(m) -- Millisecond sleep
  387.    ztime(&s) -- Return pointer to date/time string
  388.    rtimer()  -- Reset elapsed time counter
  389.    gtimer()  -- Get elapsed time
  390. */
  391.  
  392. /* Includes */
  393. #include "ckcdeb.h"                     /* Formats for debug() */
  394. #include "ckcasc.h"
  395. #include "ckcker.h"
  396.  
  397. #include "ckvvms.h"
  398. #ifdef CK_SSL
  399. #include "ck_ssl.h"
  400. #endif /* CK_SSL */
  401.  
  402. #include <stdio.h>                      /* Unix Standard i/o */
  403. #include <jpidef.h>
  404. #include <signal.h>                     /* Interrupts */
  405. #include <setjmp.h>                     /* Longjumps */
  406. #include <iodef.h>
  407. #include <ttdef.h>
  408. #include <tt2def.h>
  409. #include <ssdef.h>
  410. #include <descrip.h>
  411. #include <dvidef.h>
  412. #include <dcdef.h>
  413. #include <devdef.h>
  414.  
  415. #ifdef CMU_TCPIP          /* in case CMU types.h is in search list, rather */
  416. #include <types.h>        /* than added to SYS$LIBRARY:VAXCDEF.TLB, include */
  417. #endif /* CMU_TCPIP */    /* it before <time.h> includes the TLB types.h */
  418.  
  419. #include <time.h>
  420. #include <syidef.h>
  421. #include <prvdef.h>
  422.  
  423. typedef struct {
  424.     int val[2];
  425. } QUAD;
  426.  
  427. /* lt 1992-10-08 Begin
  428.  */
  429. #ifndef __DECC                          /* (was __ALPHA) */
  430. # ifndef __GNUC__
  431. #  define void int
  432. # endif /* __GNUC__ */
  433. #endif /* __DECC */
  434. /* lt 1992-10-08 End
  435.  */
  436.  
  437. #ifdef OLD_VMS
  438. #define IO$_TTY_PORT 41
  439. #ifdef COMMENT
  440. /* Now it's tested -- so don't */
  441. #include <libdtdef.h>                   /* For gftimer() - Not tested! */
  442. #include <lib$routines.h>               /* ditto */
  443. #endif /* COMMENT */
  444. #else
  445. #include <starlet.h>
  446. #include <libdtdef.h>                   /* OK in VMS 5.x & above */
  447. #include <lib$routines.h>               /* ditto */
  448. #endif /* OLD_VMS */
  449.  
  450. /* Macros */
  451.  
  452. #define xx_inc(timo) (--ttxbn>=0?(unsigned)(ttxbuf[ttxbp++]&0xff):txbufr(timo))
  453.  
  454. /* Declarations */
  455.  
  456. #ifndef VMS64BIT
  457. #ifndef MULTINET
  458.     time_t time();
  459. #endif    /* MULTINET */
  460. #endif    /* VMS64BIT */
  461.     char *ctime();                      /* Convert to asctime() string */
  462.  
  463.     void dcl_exit_h();                  /* Exit handler */
  464.     unsigned short vms_assign_channel(struct dsc$descriptor_s *ttname);
  465.     VOID tt_cancel();
  466. /*
  467.   This is the device name for the console.  When we use TT: it evidently fouls
  468.   us up under Batch, in DCL, SPAWN'd, etc.  When we use SYS$INPUT, it prevents
  469.   CONNECT from working in DCL procedures that do not "$ DEFINE SYS$INPUT
  470.   SYS$COMMAND".  When we use SYS$COMMAND, it allows CONNECT to work in DCL
  471.   procedures, but it forces the command parser to read from the terminal, and
  472.   therefore prevents inclusion of Kermit commands as "image data" in DCL
  473.   procedures.  (Dave Sneddon, January 2002.)
  474. */
  475. #define CONDEVICE    "SYS$INPUT"
  476. #define CONDEV_COLON "SYS$INPUT:"
  477.  
  478. /* Note: another approach might be to get JPI$_TERMINAL from SYS$GETJPI */
  479.  
  480. #ifdef VMSV60                /* i.e. VMS 6.0 or later */
  481. /*
  482.   The #ifdef was added in 8.0.201 (Feb 2002).  The aforementioned change seems
  483.   to work fine in later VMS versions, but in 5.5 (and presumably other pre-6.0
  484.   versions) it totally breaks Kermit, to the point it won't even start.  The
  485.   scheme used here was tested successfully on VMS 5.5 and 7.1 on VAX, and
  486.   VMS 6.2, 7.1, 7.2, and 7.3 on Alpha.
  487. */
  488.     char *dftty = CTTNAM;
  489. #else
  490.     char *dftty = "TT:";
  491. #endif /* VMSV60 */
  492.     int dfloc = 0;                      /* Default location is local */
  493.     int dfprty = 0;                     /* Parity (0 = none) */
  494.     int ttprty = 0;                     /* Parity in use */
  495.     int ttpflg = 0;                     /* Parity not sensed yet. */
  496.     static int ttpmsk = 0xff;           /* Communication device parity mask */
  497.     int ttmdm = 0;                      /* Modem in use. */
  498.     int dfflow = FLO_XONX;              /* Default flow control is Xon/Xoff */
  499.     int backgrd = 0;                    /* Running in "background" (no tty) */
  500.     int batch = 0;                      /* Assume not batch */
  501.     int itsatty = 1;                    /* isatty(0) result */
  502.     int ttcarr = CAR_AUT;               /* Carrier Handling Mode */
  503.     int tvtflg = 0;                     /* Flag that ttvt has been called */
  504.     long ttspeed = -1;                  /* For saving speed */
  505.     long conspd = -1;                   /* Console terminal speed */
  506.     int ttflow = -9;                    /* For saving flow */
  507.     static int ttdialing = 0;           /* Flag on when dialing */
  508.  
  509. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  510.  
  511. static int xhangup = 0;                 /* Nonzero if hangup detected */
  512. int overruns = 0;                       /* Data overruns detected */
  513.  
  514. unsigned int vms_status = SS$_NORMAL;   /* System service return status */
  515. unsigned int vms_lasterr = SS$_NORMAL;  /* Last error */
  516.  
  517. /* Structures used within this module */
  518.  
  519. #ifndef TT$C_BAUD_38400                 /* For VMS versions higher than */
  520. #define TT$C_BAUD_38400 17              /* the one I'm compiling on... */
  521. #endif /* TT$C_BAUD_38400 */
  522.  
  523. #ifndef TT$C_BAUD_57600
  524. #define TT$C_BAUD_57600 18
  525. #endif /* TT$C_BAUD_57600 */
  526.  
  527. #ifndef TT$C_BAUD_76800
  528. #define TT$C_BAUD_76800 19
  529. #endif /* TT$C_BAUD_76800 */
  530.  
  531. #ifndef TT$C_BAUD_115200
  532. #define TT$C_BAUD_115200 20
  533. #endif /* TT$C_BAUD_115200 */
  534.  
  535. static struct {
  536.     unsigned char dec;
  537.     unsigned short int line;
  538.     } ttspeeds[] = {  /* Comments show TT$C_BAUD_xx symbol values */
  539.         {TT$C_BAUD_50,       5},        /*  1 */
  540.         {TT$C_BAUD_75,       7},        /*  2 */
  541.         {TT$C_BAUD_110,     11},        /*  3 */
  542.         {TT$C_BAUD_134,     13},        /*  4 */
  543.         {TT$C_BAUD_150,     15},        /*  5 */
  544.         {TT$C_BAUD_300,     30},        /*  6 */
  545.         {TT$C_BAUD_600,     60},        /*  7 */
  546.         {TT$C_BAUD_1200,   120},        /*  8 */
  547.         {TT$C_BAUD_1800,   180},        /*  9 */
  548.         {TT$C_BAUD_2000,   200},        /* 10 */
  549.         {TT$C_BAUD_2400,   240},        /* 11 */
  550.         {TT$C_BAUD_3600,   360},        /* 12 */
  551.         {TT$C_BAUD_4800,   480},        /* 13 */
  552.         {TT$C_BAUD_7200,   720},        /* 14 */
  553.         {TT$C_BAUD_9600,   960},        /* 15 */
  554.         {TT$C_BAUD_19200, 1920},        /* 16 */
  555.         {TT$C_BAUD_38400, 3840},        /* 17 */
  556.         {TT$C_BAUD_57600, 5760},        /* 18 */
  557.         {TT$C_BAUD_76800, 7680},        /* 19 */
  558.         {TT$C_BAUD_115200,11520},       /* 20 */
  559.         {0,                   0} };
  560.  
  561. /* Declarations of variables global within this module */
  562.  
  563. /* was long... */
  564. #define TIME_T time_t
  565. #ifdef __ALPHA
  566. #ifdef WINTCP
  567. #include <socket_aliases.h>
  568. #undef TIME_T
  569. #define TIME_T long
  570. #endif /* WINTCP */
  571. #endif /* __ALPHA */
  572.  
  573. static TIME_T tcount = 0;               /* For timing statistics */
  574.  
  575. static char brkarray[] = {              /* For simulating BREAK */
  576.  
  577.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  578.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  579.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  580.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
  581. };
  582.  
  583. int ttyfd = -1;                         /* TTY file descriptor */
  584.  
  585. #ifdef COMMENT /* old */
  586. static int conif = 0,                   /* Console interrupts on/off flag */
  587.     conclass = 0,                       /* Console device type */
  588.     cgmf = 0,                           /* Flag that console modes saved */
  589.     xlocal = 0,                         /* Flag for tty local or remote */
  590.     ttychn = 0,                         /* TTY i/o channe; */
  591.     conchn = 0,                         /* Console i/o channel */
  592.     con_queued = 0,                     /* console i/o queued in contti() */
  593.     tt_queued = 0,                      /* tty i/o queued in contti() */
  594.     conch,                              /* console input character buffer  */
  595.     curcarr = 0,                        /* Carrier mode: require/ignore */
  596.     ttch;                               /* tty input character buffer */
  597. #else /* new */
  598. static unsigned short
  599.     ttychn = 0,                         /* TTY i/o channe; */
  600.     conchn = 0,                         /* Console i/o channel */
  601.     con_queued = 0,                     /* console i/o queued in contti() */
  602.     tt_queued = 0;                      /* tty i/o queued in contti() */
  603.  
  604. static int conif = 0,                   /* Console interrupts on/off flag */
  605.     conclass = 0,                       /* Console device type */
  606.     cgmf = 0,                           /* Flag that console modes saved */
  607.     xlocal = 0,                         /* Flag for tty local or remote */
  608.     conch,                              /* console input character buffer  */
  609.     curcarr = 0,                        /* Carrier mode: require/ignore */
  610.     ttch;                               /* tty input character buffer */
  611. #endif /* COMMENT */
  612.  
  613. static unsigned char escchr;            /* Escape or attn character */
  614. static char ttnmsv[TTNAMLEN+1];         /* copy of open path for tthang */
  615. char cttnam[TTNAMLEN+1];                /* Controlling terminal name */
  616. static char tt_fulldevnam[TTNAMLEN+1];
  617. static struct dsc$descriptor_s tt_fulldevnam_d; /* Descriptor for line name */
  618.  
  619. static long int qio_maxbuf_size;        /* Maximum size of QIO to succeed */
  620. static long dclexh_status;              /* Exit status for DCL exit handler */
  621. static struct iosb_struct coniosb, ttiosb, wrk_iosb;
  622. static struct tt_mode
  623.     ttold, ttraw, tttvt,                /* for communication line */
  624.     ccold, ccraw, cccbrk,               /* and for console */
  625.     cctmp;
  626.  
  627. /* Network support */
  628.  
  629. #include "ckcnet.h"                     /* Network type symbols */
  630. extern int ttnet;                       /* Network type */
  631. static int network = 0;                 /* 1 if network connection */
  632. #ifdef TCPSOCKET
  633. extern int ttnproto;
  634. #endif /* TCPSOCKET */
  635. extern int xfrcan, xfrchr, xfrnum;      /* Transfer cancellation */
  636. extern int initflg, wasclosed;
  637.  
  638. /*
  639.   Select proper library function for getting socket device channel.
  640. */
  641. #ifdef TCPIPLIB
  642. #if defined (__DECC)
  643. # define GET_SDC (short)decc$get_sdc
  644. #elif (defined (VAXC) || defined (__VAXC) || defined (__GNUC__))
  645. # define GET_SDC vaxc$get_sdc
  646. #else
  647. # error unknown compiler, not DECC and not VAXC
  648. #endif /* __DECC */
  649. #endif /* TCPIPLIB */
  650.  
  651. /* Needed for parity fixes in edit 036 */
  652. extern int parity;                      /* current parity setting */
  653.  
  654. /*
  655.   New buffered input scheme.
  656. */
  657. #define TTXBUF
  658.  
  659. #ifdef TTXBUF
  660. #define TTXBUFL RBSIZ                   /* Internal buffer size */
  661.  
  662. CHAR    ttxbuf[TTXBUFL+1];              /* The buffer */
  663. int     ttxbp = 0, ttxbn = 0;           /* Buffer pointer and count */
  664. int     ok_to_share = 0;                /* Can be set by user interface */
  665.  
  666. int get_qio_maxbuf_size(unsigned long int ttychn);
  667. int test_qio(unsigned long int ttychn, long int max, unsigned char *dest);
  668. int ttispd();
  669.  
  670. /*
  671.   T X B U F R
  672.  
  673.   Read bytes from communication device into internal buffer ttxbuf[].
  674.   To be called only when input buffer is empty, i.e. when ttxbn == 0.
  675.  
  676.   Other comm-device reading routines, like ttinc, ttinl, ttxin, should check
  677.   the internal buffer first, and call this routine for a refill if necessary.
  678.  
  679.   When data is read successfully, the first character is returned and
  680.   the global buffer count, ttxbn, is set to the number of characters remaining
  681.   in ttxbuf after it, and the global buffer offset, ttxbp, is set to 1.
  682.  
  683.   When data is not read successfully, -1 is returned indicating a timeout,
  684.   or -2 indicating disconnection.
  685. */
  686. int
  687. txbufr(timo) int timo; {                /* TT Buffer Read */
  688.     int i, count;
  689.     int func;                           /* Read function code */
  690.     int mask;                           /* Event mask */
  691.     int vms_status;                     /* Read QIO return code */
  692.     static int trmmsk[2] = {0,0};       /* Terminal read break mask */
  693.     static int trmlong[8] = {0,0,0,0,0,0,0,0}; /* Break on nothing */
  694.     char tmpbuf[16];
  695.  
  696.     debug(F101,"txbufr entry, ttxbn","",ttxbn);
  697.     if (ttxbn > 0) {                    /* Should not be called */
  698.         debug(F101,"txbufr called with ttxbn","",ttxbn); /* if ttxbn > 0! */
  699.         ttxbn--;
  700.         return(ttxbuf[ttxbp++] & 0xff);
  701.     }
  702.     ttxbp = ttxbn = 0;                  /* Reset buffer pointer and count */
  703.     ttxbuf[0] = NUL;                    /* and the buffer itself */
  704.  
  705.     if (timo < 0)                       /* Be safe */
  706.       timo = 0;
  707.     debug(F101,"txbufr timo","",timo);
  708.  
  709.     func = IO$_READVBLK | IO$M_NOFILTR; /* Read virtual block, no filtering */
  710.     trmmsk[0] = sizeof(trmlong);        /* No terminators */
  711.     trmmsk[1] = (int)&trmlong;          /* Keep all characters */
  712. /*
  713.   We try to scoop up as many as we can in a nonblocking read (timed, but with
  714.   timeout value of 0).  This is supposed to return immediately with up to
  715.   "count" characters placed in our buffer.
  716. */
  717.     count = TTXBUFL;                    /* Maximum characters to read */
  718.  
  719. #ifdef COMMENT
  720. /*
  721.   This causes problems because we are not adjusting according to the CURRENT
  722.   BYTLM quota, but rather to the one that was obtained when Kermit started.
  723.   Since the quota is dynamic, it might have been reduced since then.
  724. */
  725.     if (count > qio_maxbuf_size)
  726.         count = qio_maxbuf_size;
  727. #else
  728. /*
  729.   So for now we use 1024, which tends to be smaller than the value obtained
  730.   above.  Later, this should be changed to find out the remaining BYTLM quota
  731.   and use that instead (unless that is too expensive).  This size can be
  732.   overridden at compile time by defining the symbol...
  733. */
  734. #ifndef CKV_IO_SIZE
  735. #define CKV_IO_SIZE 1024
  736. #endif /* CKV_IO_SIZE */
  737.     if (count > CKV_IO_SIZE)
  738.         count = CKV_IO_SIZE;
  739. #endif /* COMMENT */
  740.  
  741.     debug(F101,"txbufr count","",count);
  742.  
  743.     for (i = 0; i < 2; i++) {           /* Two tries... */
  744.         sprintf(tmpbuf,"txbufr %d",i);
  745.         if (i == 0)
  746.           /* First read is nonblocking, timed, with timeout of 0 */
  747.           vms_status = sys$qiow(QIOW_EFN, ttychn,
  748.                                 func|IO$M_TIMED, &wrk_iosb, 0, 0,
  749.                                 ttxbuf, count, 0, &trmmsk, 0, 0);
  750.         else
  751.           /* Second read is blocking, for 1 byte, using the timeout given */
  752.           vms_status = sys$qiow(QIOW_EFN, ttychn,
  753.                                 func, &wrk_iosb, 0, 0,
  754.                                 ttxbuf, 1, timo, &trmmsk, 0, 0);
  755.  
  756.         if (!(vms_status & 1)) vms_lasterr = vms_status;
  757.         debug(F111,tmpbuf,"sys$qiow status",vms_status);
  758.  
  759. #ifdef SS$_DATAOVERUN
  760.         if (vms_status == SS$_DATAOVERUN) { /* This shouldn't be fatal */
  761.             overruns++;
  762.             debug(F111,tmpbuf,"data overrun",overruns);
  763.         } else
  764. #endif /* SS$_DATAOVERUN */
  765.         if (vms_status != SS$_NORMAL && vms_status != SS$_HANGUP) {
  766.             debug(F111,tmpbuf,"fatal error",vms_status);
  767.             return(-2);
  768.         }
  769.         if (vms_status == SS$_HANGUP && ttcarr != CAR_OFF) {
  770.             xhangup = 1;                /* Remember for next time */
  771.             debug(F111,tmpbuf,"sys$qiow SS$_HANGUP",SS$_HANGUP);
  772.             debug(F111,tmpbuf,"sets xhangup",xhangup);
  773.         }
  774.         debug(F011,"txbufr ttxbuf",ttxbuf,wrk_iosb.size);
  775.         debug(F101,"txbufr iosb.size","",wrk_iosb.size);
  776.         debug(F101,"txbufr iosb.status","",wrk_iosb.status);
  777. /*
  778.   Did we get some data?  Even if SS$_HANGUP was indicated, we might also have
  779.   received some data at the same time (like a NO CARRIER message); if we did,
  780.   return it now and catch the HANGUP next time around.
  781. */
  782.         if (wrk_iosb.size > 0) {
  783.             ttxbn = wrk_iosb.size;      /* Set buffer count. */
  784.             ttxbn--;                    /* Less one for the one we return */
  785.             return(ttxbuf[ttxbp++] & 0xff); /* Return it, bump offset */
  786.         }
  787. /*
  788.   Check for hangup only if no data was obtained.  Reports indicate that
  789.   that SS$_HANGUP is not indicated more than once, hence the flag.
  790. */
  791.         if (xhangup > 0) {              /* Hangup detected last time */
  792.             debug(F110,tmpbuf,"xhangup return",0);
  793.             return(-2);
  794.         } else if (wrk_iosb.status == SS$_HANGUP) { /* Or detected this time */
  795.             debug(F111,tmpbuf,"SS$_HANGUP: ttcarr",ttcarr);
  796.             debug(F111,tmpbuf,"SS$_HANGUP: ttdialing",ttdialing);
  797.             if (ttcarr != CAR_OFF && !ttdialing) {
  798.                 /* Don't set xhangup here because apparently VMS returns */
  799.                 /* this error even when the connection has not hung up. */
  800.                 /* Experimentation shows that setting xhangup here prevents */
  801.                 /* file transfer from working on dialout connections. */
  802.                 /* (VMS 7.1, Alpha PWX 433/au) */
  803.                 /* xhangup = 1; */
  804.                 debug(F110,tmpbuf,"fatal: hangup and CARRIER-WATCH not OFF",0);
  805.                 return(-2);
  806.             }
  807.         } else if (wrk_iosb.status != SS$_TIMEOUT) {
  808.             debug(F111,tmpbuf,"fatal: unexpected iosb status",wrk_iosb.status);
  809.             return(-2);                 /* Call it a hangup */
  810.         }
  811. /*
  812.   No error and no characters either, so next time around try a blocking,
  813.   possibly timed, read for a single character.  Since this routine will be
  814.   called again very soon, the first read with a zero timeout will have the
  815.   rest of the user data in it.  Thus, this isn't as inefficient as it first
  816.   appears.
  817. */
  818.         if (timo > 0)
  819.           func |= IO$M_TIMED;
  820.     } /* Go back for second loop iteration */
  821.  
  822. /* Get here only if second read timed out - i.e. no characters arrived. */
  823.  
  824.     debug(F101, "txbufr timed out","",timo);
  825.     return(-1);
  826. }
  827.  
  828. /*  T T I N C  --  Read a character from the communication device  */
  829. /*
  830.   ttinc() maintains an internal buffer to minimize system calls.
  831.   Returns the next character, or -1 if there is a timeout, or -2
  832.   on communications disconnect.  Calls txbufr() to refill its buffer
  833.   when necessary.
  834. */
  835. int
  836. ttinc(timo) int timo; {
  837.     int x; unsigned char c;
  838.  
  839. #ifdef NETCONN
  840.     if (network) {
  841. #ifdef COMMENT
  842.         int x;
  843.         x = netinc(timo);
  844.         if ((ttnproto == NP_TELNET) && (x > -1))
  845.           return((unsigned)(x & 0xff));
  846.         else
  847.           return(x < 0 ? x : (unsigned)(x & ttpmsk));
  848. #else
  849.         return(netinc(timo));
  850. #endif /* COMMENT */
  851.     }
  852. #endif /* NETCONN */
  853.  
  854.     debug(F101,"ttinc ttxbn","",ttxbn);
  855.     if (ttxbn > 0) {                    /* Something in internal buffer? */
  856.         ttxbn--;                        /* Yes, deduct one from count. */
  857.         c = ttxbuf[ttxbp++];            /* Return the next character. */
  858.         debug(F101,"ttinc returns c","",c);
  859.         return((unsigned)(c & 0xff));
  860.     } else if ((x = txbufr(timo)) < 0) { /* No, fill buffer */
  861.         debug(F101,"ttinc txbufr failed","",x); /* Pass along failure. */
  862.         return(x);
  863.     } else {                            /* Success. */
  864.         debug(F101,"ttinc returns x","",x);
  865.         return((unsigned)(x & 0xff));   /* Return the character */
  866.     }
  867. }
  868.  
  869. /*  T T X I N  --  Get n bytes from tty input buffer  */
  870. /*
  871.   Call with n = number of bytes to get, buf = where to put them.
  872.  
  873.   This routine assumes that the given number of bytes is available
  874.   and will not return until they are gotten.  You should only call this
  875.   routine after calling ttchk to find out how many bytes are waiting to
  876.   to be read.
  877.  
  878.   Returns:
  879.   -1 on error, number of chars gotten on success.
  880. */
  881. int
  882. ttxin(n,buf) int n; CHAR *buf; {
  883.     int i, x;
  884.  
  885.     debug(F101,"ttxin","",n);
  886.  
  887. #ifdef NETCONN
  888.     if (network) {
  889.         for (i = 0; i < n; i++) {
  890.             if ((x = ttinc(0)) < 0) return(-1);
  891.             buf[i] = (char) x;
  892.         }
  893.     } else {
  894. #endif /* NETCONN */
  895. /* xx_inc() is a macro */
  896.         for (i = 0; i < n; i++) {
  897.             if ((x = xx_inc(0)) < 0) return(-1);
  898.             buf[i] = (char) x;
  899.         }
  900. #ifdef NETCONN
  901.     }
  902. #endif /* NETCONN */
  903.     buf[i] = NUL;
  904.     return(i);
  905. }
  906.  
  907. /*  T T F L U I  --  Flush communication device input buffer  */
  908.  
  909. int
  910. ttflui() {
  911.     int n;
  912.     debug(F100,"ttflui","",0);
  913. #ifdef NETCONN
  914.     if (network)
  915.       return(netflui());
  916. #endif /* NETCONN */
  917.  
  918.     ttxbn = ttxbp = 0;                  /* Flush internal buffer *FIRST* */
  919.     if ((n = ttchk()) > 0) {
  920.         debug(F101,"ttflui count","",n);
  921.         while ((n--) && xx_inc(2) >= 0) ; /* Ignore Warning - see comments */
  922.     }
  923.     return(0);
  924.     /*
  925.        NOTE: the comparison of xx_inc(2) with -1 reportedly causes problems
  926.        with overzealous compilers because xx_inc() is a macro that can
  927.        return a value that is cast as (unsigned).  But it can also return
  928.        the return value of txbufr(), which is signed.  Changing the comparison
  929.        to >= 0 makes no difference.  It's a warning we'll have to live with.
  930.     */
  931. }
  932.  
  933. /*  T T C H K  --  Check how many bytes are waiting to be read */
  934. /*
  935.   Returns number of bytes waiting, or < 0 if connection has dropped.
  936.   The number of bytes waiting includes those in our internal buffer plus
  937.   those in VMS's internal input buffer.
  938. */
  939. int                                     /* Check how many bytes are ready */
  940. ttchk() {                               /* for reading from network */
  941.     static struct {
  942.         unsigned short count;
  943.         unsigned char first;
  944.         unsigned char reserved1;
  945.         long reserved2;
  946.     } ttchk_struct;
  947.  
  948. #ifdef NETCONN
  949.     if (network) {                      /* Network connection */
  950.         debug(F101,"ttchk network ttyfd","",ttyfd);
  951.         if (ttyfd < 0)
  952.           return(-2);
  953.         else
  954.           return(nettchk());
  955.     }
  956. #endif /* NETCONN */
  957.  
  958.     debug(F101,"ttchk ttxbn","",ttxbn);
  959.     debug(F101,"ttchk xhangup","",xhangup);
  960.  
  961.     if (xlocal && xhangup)
  962.       return(-2);
  963.  
  964.     if (!ttychn) {
  965.         debug(F101,"ttchk called with no ttychn","",0);
  966.         return(0);
  967.     }
  968.  
  969.     if (
  970. #ifdef COMMENT
  971. /*
  972.   I tried something like this in UNIX and it didn't work at all so I'm
  973.   leaving it as a comment here until it can be tested.  - fdc, Jan 98.
  974. */
  975.         ttxbn < 1 &&
  976. #endif /* COMMENT */
  977.         xlocal && ttcarr != CAR_OFF) { /* No data in buffer */
  978.         int x;                  /* Serial connection */
  979.         extern int clsondisc;
  980.         x = ttgmdm();           /* with carrier checking */
  981.         debug(F101,"ttchk ttgmdm","",x);
  982.         if (x > -1) {           /* Then we better have carrier */
  983.             if (!(x & BM_DCD)) {
  984.                 debug(F101,"ttchk carrier lost","",x);
  985.                 if (clsondisc) {        /* If "close-on-disconnect" */
  986.                     debug(F100,"ttchk close-on-disconnect","",0);
  987.                     ttclos(0);  /* close device & release it. */
  988.                 }
  989.                 return(-2);
  990.             }
  991.         }
  992.     }
  993.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE|IO$M_TYPEAHDCNT,
  994.                           &wrk_iosb, 0, 0, &ttchk_struct,
  995.                           sizeof(ttchk_struct), 0, 0, 0, 0
  996.                           );
  997.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  998. #ifdef DEBUG
  999.     if (deblog) {
  1000.         debug(F101,"ttchk sys$qiow status","",vms_status);
  1001.         debug(F101,"ttchk count","",(int)ttchk_struct.count);
  1002.         if (ttchk_struct.count)
  1003.           debug(F101,"ttchk first","",(int)ttchk_struct.first);
  1004.     }
  1005. #endif /* DEBUG */
  1006.     return(vms_status & 1 ? ttchk_struct.count + ttxbn : ttxbn);
  1007. }
  1008.  
  1009. #ifdef CTRLC
  1010. #undef CTRLC
  1011. #endif /* CTRLC */
  1012. #define CTRLC '\03'
  1013.  
  1014. #ifndef NOXFER
  1015. /*  T T I N L  --  Read a packet from the communications connection.  */
  1016. /*
  1017.   Reads up to "max" characters from the communication line, terminating on:
  1018.  
  1019.     (a) the packet length field if the "turn" argument is zero, or
  1020.     (b) on the turnaround character (turn) if the "turn" argument is nonzero
  1021.     (c) n repetitions of the interruption character (3 ^C's by default)
  1022.  
  1023.   and returns the number of characters read upon success, or if "max" was
  1024.   exceeded or the timeout interval expired before (a) or (b), returns -1.
  1025.  
  1026.   The characters that were input are copied into "dest" with their parity bits
  1027.   stripped if parity was selected.  Returns the number of characters read.
  1028.   Characters after end of packet are available upon the next call to this
  1029.   function.
  1030. */
  1031. int
  1032. #ifdef CK_ANSIC
  1033. ttinl(CHAR *dest, int max, int timo, CHAR eol, CHAR start, int turn)
  1034. #else
  1035. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest,eol,start;
  1036. #endif /* CK_ANSIC */
  1037. /* ttinl */ {
  1038.     int x, y, c, i, j;
  1039.     int ccn = 0;                /* Control C counter */
  1040.     int flag;
  1041.     int cc;
  1042.     unsigned char *cp;
  1043.     int pktlen = -1;
  1044.     int lplen = 0;
  1045.     int havelen = 0;
  1046.  
  1047.     debug(F101,"ttinl start","",start);
  1048.     debug(F101,"ttinl turn","",turn);
  1049.     debug(F101,"ttinl timo","",timo);
  1050.     i = j = flag = 0;
  1051. #ifdef COMMENT
  1052.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask. */
  1053. #endif /* COMMENT */
  1054.     debug(F101,"ttinl loop entry, network","",network);
  1055.     while (i < max) {
  1056.         cc = network ? netinc(timo) : xx_inc(timo); /* Read a byte */
  1057.         if (cc < 0) {
  1058.             debug(F101,"ttinl cc","",cc);
  1059.             if (cc == -1 || cc == -2) {
  1060.                 return(cc);
  1061.             } else {                    /* I hate C ... */
  1062.                 debug(F100,
  1063.                       "ttinl: SIGN EXTENSION BOTCH - FIX SOURCE CODE","",0
  1064.                       );
  1065.                 /* This doesn't really help because 255 becomes -1, etc. */
  1066.                 cc &= 0xff;
  1067.             }
  1068.         }
  1069.  
  1070.         /* Check for cancellation */
  1071.         if (!xlocal && xfrcan && ((cc & ttpmsk) == xfrchr)) {
  1072.             if (++ccn >= xfrnum) {      /* If xfrnum in a row, bail out. */
  1073.                 fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
  1074.                 return(-2);
  1075.             }
  1076.         } else ccn = 0;                 /* No cancel, so reset counter, */
  1077.  
  1078.         if ((flag == 0) && ((cc & 0x7f) == start)) {
  1079.             debug(F100,"ttinl got start","",0);
  1080.             flag = 1;                   /* Got packet start. */
  1081.         }
  1082.         if (flag) {                     /* If we're in a packet... */
  1083.             dest[i++] = cc & ttpmsk;
  1084.             if ((cc & 0x7f) == eol) { /* Stop at eol. */
  1085.                 debug(F101,"ttinl got eol, i","",i);
  1086.                 break;
  1087.             }
  1088.         }
  1089. /*
  1090.   If we have not been instructed to wait for a turnaround character, we
  1091.   can go by the packet length field.  If turn != 0, we must wait for the
  1092.   end of line (eol) character before returning.
  1093. */
  1094. #ifndef xunchar
  1095. #define xunchar(ch) (((ch) - 32 ) & 0xFF )      /* Character to number */
  1096. #endif /* xunchar */
  1097.  
  1098.         if (i == 2) {
  1099.             pktlen = xunchar(dest[1] & 0x7f);
  1100.             havelen = (pktlen > 1);
  1101.             debug(F101,"ttinl length","",pktlen);
  1102.         } else if (i == 5 && pktlen == 0) {
  1103.             lplen = xunchar(dest[4] & 0x7f);
  1104.         } else if (i == 6 && pktlen == 0) {
  1105.             pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
  1106.             havelen = 1;
  1107.             debug(F101,"ttinl length","",pktlen);
  1108.         }
  1109.         if (havelen && !turn && (i > pktlen+1)) { /* Use length field */
  1110.             debug(F101,"ttinl break on length","",i);
  1111.             break;
  1112.         }
  1113.     }
  1114.     dest[i] = '\0';                     /* Terminate the string */
  1115.     debug(F101,"ttinl loop done, i","",i);
  1116.     debug(F101,"ttinl max","",max);
  1117.     debug(F101,"ttinl dest[i-1]","",dest[i-1]);
  1118.     debug(F101,"ttinl eol","",eol);
  1119.  
  1120.     if (i >= max) {
  1121.         debug(F100,"ttinl buffer overflow","",0);
  1122.         return(-1);     /* Overflowed dest buffer without getting eol */
  1123.     }
  1124.     x = i;                              /* Size. */
  1125.     dest[x] = '\0';                     /* Terminate with null */
  1126.  
  1127.     debug(F110,"ttinl packet",dest,0);
  1128.     debug(F101,"ttinl size","",x);      /* Log the size */
  1129.     debug(F101,"ttinl ttprty 1","",ttprty);
  1130.  
  1131.     if (ttpflg++ == 0 && ttprty == 0) { /* Check and adjust the parity. */
  1132.         if ((ttprty = parchk(dest,start,x)) > 0) {
  1133.             debug(F000,"ttinl parchk senses parity","",ttprty);
  1134.             ttpmsk = 0x7f;
  1135.             for (i = 0; i < x; i++)     /* Strip parity from this packet */
  1136.               dest[i] &= 0x7f;
  1137.         }
  1138.         if (ttprty < 0) ttprty = 0;     /* Restore if parchk error */
  1139.         debug(F101,"ttinl ttprty 2","",ttprty);
  1140.     }
  1141.     return(x);                          /* Return length */
  1142. }
  1143. #endif /* NOXFER */
  1144. #endif /* TTXBUF */
  1145.  
  1146. SIGTYP (*saval)() = NULL;               /* For saving alarm handler */
  1147.  
  1148. VOID
  1149. ttimoff() {                             /* Turn off any timer interrupts */
  1150.     alarm(0);
  1151.     if (saval) {
  1152.         signal(SIGALRM,saval);
  1153.         saval = NULL;
  1154.     } else {
  1155.         signal(SIGALRM,SIG_IGN);        /* (was SIG_DFL) */
  1156.     }
  1157. }
  1158.  
  1159. /*  P R I N T _ M S G  --  Log an error message from VMS  */
  1160.  
  1161. int
  1162. print_msg(s) char *s; {
  1163.     long int blen = 0;
  1164.     char buf[PMSG_BUF_SIZE], msg[PMSG_MSG_SIZE];
  1165.     struct dsc$descriptor_s b = {
  1166.         PMSG_BUF_SIZE-1,
  1167.         DSC$K_DTYPE_T,
  1168.         DSC$K_CLASS_S,NULL
  1169.     };
  1170.  
  1171.     b.dsc$a_pointer = (char *)&buf;
  1172.     vms_status = sys$getmsg(vms_status, &blen, &b, 0, 0);
  1173.     if (!(vms_status & 1)) {
  1174.         vms_lasterr = vms_status;
  1175.         fprintf(stderr,"print_msg; sys$getmsg\n");
  1176.         return(-1);
  1177.     }
  1178.     buf[blen] = '\0';
  1179.     sprintf(msg, "%s: %s\n", s, buf);
  1180.     debug(F100,s,"",0);
  1181.     ermsg(msg);
  1182.     return(0);
  1183. }
  1184.  
  1185. /*  S Y S I N I T  --  System-dependent program initialization.  */
  1186.  
  1187. #ifndef DVI$_FULLDEVNAM
  1188. #define DVI$_FULLDEVNAM 232
  1189. #endif /* DVI$_FULLDEVNAM */
  1190.  
  1191. #ifndef DVI$_STS
  1192. #define DVI$_STS 226
  1193. #endif /* DVI$_STS */
  1194.  
  1195. int
  1196. ttgwsiz() {                             /* Get console window (screen) size */
  1197.     int x = -1;
  1198.     extern int tt_rows, tt_cols;
  1199.     typedef struct {                    /* define an item list struct */
  1200.         short length;                   /* length of buffer */
  1201.         short code;                     /* item code */
  1202.         void *ptr;                      /* ptr to buffer */
  1203.         void *retlen;                   /* ptr to return length */
  1204.     } item_list;
  1205.     int status, iosb[2];
  1206.     item_list tt_dvi[] = {              /* Item list for GETDVI */
  1207.         {4,DVI$_DEVBUFSIZ,&tt_cols,0},
  1208.         {4,DVI$_TT_PAGE,&tt_rows,0},
  1209.         {0,0,0,0}
  1210.     };
  1211.     $DESCRIPTOR(sysin,CONDEVICE);
  1212.     status = sys$getdviw(0,0,&sysin,&tt_dvi,&iosb,0,0,0);
  1213.     if (!(status & 1)) {
  1214.         vms_lasterr = status;
  1215.         return(-1);
  1216.     }
  1217.     if (tt_rows < 1 || tt_cols < 1) return(0);
  1218.     return(1);
  1219. }
  1220.  
  1221. #define CK_SYSNMLN 31
  1222. char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
  1223. char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
  1224. char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
  1225. char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
  1226. char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
  1227.  
  1228. int
  1229. sysinit() {
  1230.     extern int speed;
  1231.     extern char ttname[], uidbuf[];
  1232. #ifdef CK_ENVIRONMENT
  1233.     extern char tn_env_sys[];
  1234. #endif /* CK_ENVIRONMENT */
  1235.     extern char startupdir[];
  1236.     extern char *ckzsys, *ck_s_name, *ck_s_ver;
  1237.     int i, x, n;
  1238.     char * p;
  1239.     struct dsc$descriptor_s prcname;
  1240.     char ckname[24];
  1241.  
  1242.     static struct desblk {
  1243.         long int *fl;                   /* Forward link.  Used by VMS only */
  1244.         void (*fncpnt)();               /* Function to call */
  1245.         unsigned char argcnt;           /* Only one arg allowed */
  1246.         unsigned char filler[3];        /* Filler.  Must be zero */
  1247.         long int *sts;                  /* Address of sts (written by VMS) */
  1248.     } dclexh_ = {0,dcl_exit_h,1,{0,0,0},&dclexh_status};
  1249.  
  1250. #define GETCKXSYS
  1251. /*
  1252.   Get architecture and operating system name.
  1253. */
  1254. #ifdef GETCKXSYS
  1255.  
  1256. /* OK, we have a VAX so what is the name of the OS? */
  1257.  
  1258. #ifndef SYI$_ARCH_NAME    /* Should be in syidef.h but is not there yet */
  1259. # define SYI$_ARCH_NAME 4454
  1260. #endif /* SYI$_ARCH_NAME */
  1261.  
  1262.     struct iosb_t {
  1263.         short int status;               /* System service status */
  1264.         short int unused[3];
  1265.     } iosb;
  1266.  
  1267.     struct itmlst_t {
  1268.         short unsigned int buffer_len;  /* Buffer length */
  1269.         short unsigned int item_code;   /* Item code */
  1270.         char *buffer;                   /* Where to write SYI info */
  1271.         long unsigned int *ret_len;     /* Pointer to returned length */
  1272.         long unsigned int mbz;          /* Must Be Zero */
  1273.  
  1274.     } itmlst;
  1275.  
  1276.     struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,(char *)&cttnam,0},
  1277.                         {sizeof(conclass),DVI$_DEVCLASS,(char *)&conclass,0},
  1278.                                 {0,0,0,0}};
  1279.  
  1280.     long unsigned int ret_len;          /* Returned length */
  1281. /*
  1282.   $getsyi of "hw_arch" will fail prior to VMS 5.5.  This failure indicates that
  1283.   the OS name is "VAX/VMS" (sic).  Use success or failure of $getsyi "hw_arch"
  1284.   rather than the more straight forward $getsyi "node_swvers" because latter
  1285.   is defined as four (4) characters and will get strange representing VMS
  1286.   10.0.
  1287. */
  1288.  
  1289. /*  Default */
  1290.  
  1291. #ifdef __ia64
  1292.     ckxsys = " OpenVMS IA64";
  1293. #else
  1294. #ifdef __ALPHA
  1295.     ckxsys = " OpenVMS Alpha";
  1296. #else
  1297.     /* Not strictly correct but traditional & familiar... */
  1298.     ckxsys = " VAX/VMS";
  1299. #endif /* __ALPHA */
  1300. #endif /* __ia64 */
  1301.  
  1302.     itmlst.buffer_len = CK_SYSNMLN;
  1303.     itmlst.item_code = SYI$_ARCH_NAME;
  1304.     itmlst.buffer = unm_mch;
  1305.     itmlst.ret_len = &ret_len;
  1306.     itmlst.mbz = 0;
  1307.  
  1308.     if ((sys$getsyiw (0, 0, 0, &itmlst, &iosb, 0, 0) & 1) == 1)
  1309.       if ((iosb.status & 1) == 1)
  1310. #ifdef __ia64
  1311.     ckxsys = " OpenVMS IA64";
  1312. else
  1313. #ifdef __ALPHA
  1314.         ckxsys = " OpenVMS Alpha";
  1315. #else
  1316.         ckxsys = " OpenVMS VAX";
  1317. #endif /* __ALPHA */
  1318. #endif /* __ia64 */
  1319.  
  1320.     if (unm_mch[0] == '\0') {           /* supply a default */
  1321.         for (p = ckxsys; *p == ' '; p++) ;
  1322.         ckstrncpy(unm_mch,p,4);
  1323.     }
  1324.     for (p = ckxsys; *p == ' '; p++) ;  /* Strip leading blanks */
  1325.     ckstrncpy(unm_nam,p,CK_SYSNMLN);    /* For uname info */
  1326.     ckzsys = ckxsys;                    /* Same deal for file module */
  1327.  
  1328. #ifdef CK_ENVIRONMENT
  1329.     strcpy(tn_env_sys,"VMS");
  1330. #ifdef CK_SNDLOC
  1331.     {
  1332.         extern char * tn_loc;
  1333.         char *p;
  1334.         if (p = getenv("LOCATION"))
  1335.           if (tn_loc = (char *)malloc((int)strlen(p)+1))
  1336.             strcpy(tn_loc,p);
  1337.     }
  1338. #endif /* CK_SNDLOC */
  1339. #endif /* CK_ENVIRONMENT */
  1340.  
  1341.     itmlst.buffer_len = CK_SYSNMLN;     /* Get hardware model */
  1342. #ifdef SYI$_HW_NAME                     /* as of V5.0 ? */
  1343.     itmlst.item_code = SYI$_HW_NAME;
  1344. #else
  1345. #ifdef SYI$_NODE_HWTYPE
  1346.     itmlst.item_code = SYI$_NODE_HWTYPE;
  1347. #else
  1348.     itmlst.item_code = 0;               /* shouldn't happen... */
  1349. #endif /* SYI$_NODE_HWTYPE */
  1350. #endif /* SYI$_HW_NAME */
  1351.     itmlst.buffer = unm_mod;
  1352.     itmlst.ret_len = &ret_len;
  1353.     itmlst.mbz = 0;
  1354.     x = sys$getsyiw (0, 0, 0, &itmlst, &iosb, 0, 0);
  1355.  
  1356.     itmlst.buffer_len = CK_SYSNMLN;     /* Get VMS release */
  1357.     itmlst.item_code = SYI$_VERSION;
  1358.     itmlst.buffer = unm_rel;
  1359.     itmlst.ret_len = &ret_len;
  1360.     itmlst.mbz = 0;
  1361.     x = sys$getsyiw (0, 0, 0, &itmlst, &iosb, 0, 0);
  1362.  
  1363.     if ((x & 1) && unm_rel[0]) {        /* Just the major version number */
  1364.         for (p = unm_rel; *p && !isdigit(*p); p++) ;
  1365.         ckstrncpy(unm_ver,p,CK_SYSNMLN);
  1366.         p = unm_ver;
  1367.         while (isdigit(*p++)) ;
  1368.         *(p-1) = '\0';
  1369.     }
  1370. #endif /* GETCKXSYS */
  1371.  
  1372. /*
  1373.  * Set up DCL Exit handler.  This allows us to reset terminal
  1374.  * and any other modifications we have done.
  1375.  */
  1376.     debug(F101,"sysinit ttychn","",ttychn);
  1377.     debug(F101,"sysinit conchn","",conchn);
  1378.     if (!CHECK_ERR("sysinit: sys$dclexh",
  1379.                    sys$dclexh(&dclexh_))) {
  1380.         debug(F100,"sysinit failed to declare exit handler","",0);
  1381. #ifdef COMMENT
  1382.         return(0);
  1383. #endif /* COMMENT */
  1384.     }
  1385.  
  1386.     {                                   /* Get username */
  1387.         struct itmlstdef {
  1388.             short int buflen;           /* Length of buffer */
  1389.             short int itmcod;           /* Function code */
  1390.             char *bufaddr;              /* Address of buffer */
  1391.             long int *retlen;           /* Address to return actual length */
  1392.         };
  1393.         int i;
  1394.         char userbuf[UIDBUFLEN];        /* The book says 12 is max */
  1395.         long buflen = 0;                /* And it's 12 in VMS 7.1  */
  1396.         unsigned long user_flags;
  1397.         struct itmlstdef gjiitm[] = {
  1398.             UIDBUFLEN-1, JPI$_USERNAME, NULL, 0, 0, 0, 0, 0
  1399.         };
  1400.         gjiitm[0].bufaddr = userbuf;
  1401.         gjiitm[0].retlen = &buflen;
  1402.         for (i = 0; i < UIDBUFLEN; i++) userbuf[i] = 0;
  1403.         vms_status = sys$getjpiw(0, 0, 0, &gjiitm, 0, 0, 0);
  1404.         if (!(vms_status & 1)) vms_lasterr = vms_status;
  1405.         if (vms_status != SS$_NORMAL) {
  1406.             debug(F101,"sysinit sys$getjpiw error","",vms_status);
  1407.         } else {
  1408.             char c;
  1409.             debug(F111,"sysinit sys$getjpiw ok",userbuf,vms_status);
  1410.             for (i = 0; i < UIDBUFLEN; i++) {
  1411.                 c = userbuf[i];
  1412.                 if (c == ' ') c = '\0';
  1413.                 uidbuf[i] = c;
  1414.                 if (!c)
  1415.                   break;
  1416.             }
  1417.             debug(F111,"sysinit sys$getjpiw uidbuf",uidbuf,buflen);
  1418.         }
  1419.     }
  1420.     if (ttychn)                         /* if comms line already opened */
  1421.       return(0);                        /* (how could it be???) */
  1422.  
  1423.     if (!conchn) {                      /* Get console channel */
  1424. #ifdef CMU_TCPIP
  1425.       /* need to open console using libcmu routine to enable `select' call on
  1426.        * file descriptor zero.
  1427.        */
  1428.       cmu_stdin_open(dftty);
  1429.       conchn = cmu_get_sdc(0);
  1430. #else
  1431.       struct dsc$descriptor_s devnam =
  1432.                 {sizeof(dftty)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL};
  1433.       devnam.dsc$a_pointer = dftty;
  1434.       conchn = vms_assign_channel(&devnam);
  1435. #endif /* CMU_TCPIP */
  1436.     }
  1437.     congm();                            /* Get and save its modes */
  1438. /*
  1439.  * Parse console terminal device name.
  1440.  */
  1441. /*    itsatty = 0;
  1442.     if (isatty(0))
  1443.       {
  1444.       itsatty = 1;
  1445.       batch = 0;
  1446.       backgrd = 0;
  1447.       }
  1448.  */
  1449.     debug(F101,"sysinit itsatty","",itsatty);
  1450.  
  1451.     if (itsatty)
  1452.         {
  1453.         CHECK_ERR("sysinit: sys$getdviw",
  1454.                   sys$getdviw(0, conchn, 0, &dviitm, &wrk_iosb, 0, 0, 0));
  1455.         debug(F110,"sysinit cttnam",cttnam,0);
  1456.  
  1457.         if (!CHECK_ERR("sysinit: sys$qiow",
  1458.                        sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE,
  1459.                                 &wrk_iosb, 0, 0,
  1460.                                 &ccold, sizeof(ccold), 0, 0, 0, 0)))
  1461.           return(-1);
  1462.         ttspeed = speed = ttispd((unsigned char) wrk_iosb.size);
  1463.         conspd = ttspeed;
  1464.         debug(F111,"sysinit speed",cttnam,speed);
  1465.         ckstrncpy(ttname,cttnam,TTNAMLEN);
  1466.     }
  1467.  
  1468.     /* Initialize descriptor */
  1469.     tt_fulldevnam_d.dsc$b_dtype = DSC$K_DTYPE_T;
  1470.     tt_fulldevnam_d.dsc$b_class = DSC$K_CLASS_S;
  1471.  
  1472.     strcpy(startupdir, zgtdir());       /* Default directory at startup */
  1473.  
  1474. #ifdef CK_VMSSETNAME                    /* (Which is not defined) */
  1475. /*
  1476.   The problem with this is that it stays there even after Kermit exits.
  1477.   If anybody really cares to have "C-Kermit 6.1" show up in SHOW SYSTEM, etc,
  1478.   then we'll need to get the current name, save it, and then restore it in
  1479.   the exit handler.
  1480. */
  1481.     ckname[0] = '\0';                   /* Process name */
  1482.     ckstrncpy(ckname,ck_s_name,22);     /* Copy program name from main() */
  1483.     strncat(ckname,"_",22);             /* Separator */
  1484.     strncat(ckname,ck_s_ver,22);        /* Version number */
  1485.     for (n = 0,i = 0; i < 24; i++) {    /* Chop off edit number */
  1486.         if (ckname[i] == '.')
  1487.           n++;
  1488.         if (n == 2) {
  1489.             ckname[i] = '\0';
  1490.             break;
  1491.         }
  1492.     }
  1493.     ckname[15] = '\0';                  /* Max length is 15 */
  1494.     n = strlen(ckname);
  1495.     prcname.dsc$w_length = n;           /* Convert to descriptor */
  1496.     prcname.dsc$a_pointer = (char *)ckname;
  1497.     prcname.dsc$b_class = DSC$K_CLASS_S;
  1498.     prcname.dsc$b_dtype = DSC$K_DTYPE_T;
  1499.     for (i = 1; i <= 9; i++) {          /* Try to set it */
  1500.         x = sys$setprn(&prcname);
  1501.         if (!(x & 1)) vms_lasterr = x;
  1502.         debug(F111,"sysinit sys$setprn",ckname,x);
  1503.         if (x == SS$_NORMAL)            /* Worked, done */
  1504.           break;
  1505.         if (x != SS$_DUPLNAM)           /* Anything else but duplicate name */
  1506.           break;
  1507.         if (n > 13)                     /* Add a suffix, 1..9, to name */
  1508.           break;
  1509.         ckname[n] = '_';
  1510.         ckname[n+1] = (char) (i + '0');
  1511.         ckname[n+2] = '\0';
  1512.         prcname.dsc$w_length = n+2;     /* Let VMS know the new length */
  1513.     }
  1514. #endif /* CK_VMSSETNAME */
  1515.     debug(F100,"sysinit done","",0);
  1516.     return(0);
  1517. }
  1518.  
  1519. char *
  1520. whoami() {
  1521.     extern char uidbuf[];
  1522.     return(uidbuf[0] ? (char *)uidbuf : "UNKNOWN");
  1523. }
  1524.  
  1525.  
  1526. /*
  1527.  * DCL Exit handler.  This is the cleanup handler for program.
  1528.  * Any final cleanup (closing channels etc) should be done at this
  1529.  * point.
  1530.  */
  1531. VOID
  1532. dcl_exit_h(sts) unsigned long int *sts; {
  1533.     syscleanup();
  1534.     return;
  1535. }
  1536.  
  1537. /*  S Y S C L E A N U P -- System-dependent program epilog.  */
  1538.  
  1539. int
  1540. syscleanup() {
  1541.     int x;
  1542.     extern int zclosf();
  1543.     extern void zrestoredir();
  1544.     void con_cancel();
  1545.     debug(F101,"syscleanup entry","",ttyfd);
  1546.     con_cancel();               /* Cancel pending console i/o. */
  1547.     ttclos(ttyfd);              /* Do the cleanup no matter what... */
  1548.     zclosf(ZSYSFN);             /* Close various files and kill child procs */
  1549. #ifdef COMMENT
  1550.     /* This is a bit extreme... */
  1551.     /*
  1552.        No it isn't.  Scenario: user closes DECwindow with Alt-F4 or whatever.
  1553.        The sys$qiow() call in conres() fails with %SYSTEM-F-DEVOFFLINE.
  1554.        If we don't exit now, this error will recur infinitely after we return,
  1555.        when we try to print any kind of message.  But we still keep this
  1556.        commented out because now (July 1997) we test for this in conres().
  1557.     */
  1558.     if ((x = conres()) < 0) exit(SS$_ABORT);
  1559. #else
  1560.     conres();
  1561. #endif /* COMMENT */
  1562.     zrestoredir();                      /* Restore startup directory */
  1563.     printf("\r");
  1564.     return(0);
  1565. }
  1566.  
  1567. /*  T T O P E N  --  Open a tty for exclusive access.  */
  1568.  
  1569. /*  Returns 0 on success, -1 on failure.  */
  1570. /*
  1571.   If called with lcl < 0, sets value of lcl as follows:
  1572.   0: the terminal named by ttname is the job's controlling terminal.
  1573.   1: the terminal named by ttname is not the job's controlling terminal.
  1574.   But watch out: if a line is already open, or if requested line can't
  1575.   be opened, then lcl remains (and is returned as) -1.
  1576. */
  1577. static int ismodem = 0;
  1578. static int isremote = 0;
  1579. static int isdialup = 0;
  1580. static int isdisconnect = 0;
  1581. static int issecure = 0;
  1582. static int ishangup = 0;
  1583. static int ismodhangup = 0;
  1584.  
  1585. int
  1586. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
  1587.     extern int speed;
  1588.     int s, x;
  1589.     unsigned long int no_share_priv[2], prev_privs[2];
  1590.     unsigned long int devchar, devclass, devsts;
  1591.  /* char dvibuf[65]; */
  1592.     struct dsc$descriptor_s devnam = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1593.     struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,(char *)&tt_fulldevnam,0},
  1594.                         {sizeof(devchar),DVI$_DEVCHAR,NULL,0},
  1595.                         {sizeof(devclass),DVI$_DEVCLASS,NULL,0},
  1596.                         {sizeof(devsts),DVI$_STS,NULL,0},
  1597.                         {0,0,0,0}};
  1598.  
  1599. #ifdef DEBUG
  1600.     if (deblog) {
  1601.         debug(F110,"ttopen ttname",ttname,0);
  1602.         debug(F110,"ttopen ttnmsv",ttnmsv,0);
  1603.         debug(F101,"ttopen modem","",modem);
  1604.         debug(F101,"ttopen network","",network);
  1605.         debug(F101,"ttopen ttychn","",ttychn);
  1606.         debug(F101,"ttopen ttyfd","",ttyfd);
  1607.     }
  1608. #endif /* DEBUG */
  1609.  
  1610.     dviitm[1].adr = (char *)&devchar;
  1611.     dviitm[2].adr = (char *)&devclass;
  1612.     dviitm[3].adr = (char *)&devsts;
  1613.  
  1614.     wasclosed = 1;
  1615.  
  1616. #ifdef NETCONN
  1617.     if (network && ttyfd > -1) {        /* if device already opened */
  1618.         if (!strncmp(ttname,ttnmsv,TTNAMLEN-1)) /* new & old names equal? */
  1619.           return(0);                    /* Nothing to do. */
  1620.         ttnmsv[0] = '\0';               /* No, poke this */
  1621.         network = 0;                    /* Undo this */
  1622.         ttclos(ttyfd);                  /* Close old connection. */
  1623.     }
  1624.     /* This is for REDIALing Telnet terminal servers... */
  1625.  
  1626.     if (!strcmp(ttname,ttnmsv) &&       /* Old and new names the same? */
  1627.         (network > 0) &&                /* Previous connection was network? */
  1628.         (ttmdm < 0)) {                  /* And we remember the network type? */
  1629.         int rc;
  1630.         rc = netopen(ttname, lcl, -ttmdm);
  1631.         debug(F111,"ttopen REOPEN netopen",ttname,rc);
  1632.         if (rc > -1) {
  1633.             xlocal = *lcl = 1;
  1634.         } else {
  1635.             network = 0;
  1636.         }
  1637.         return(rc);
  1638.     }
  1639.     /* General case - open a new network connection */
  1640.  
  1641.     if (modem < 0) {                    /* modem < 0 = special code for net */
  1642.         int x;
  1643.         ttmdm = modem;
  1644.         modem = -modem;                 /* Positive network type number */
  1645.         debug(F111,"ttopen net",ttname,modem);
  1646.         network = 1;                    /* Because rlog_ini() uses ttoc() */
  1647.         x = netopen(ttname, lcl, modem);
  1648.         if (x > -1) {                   /* Success... */
  1649.             ckstrncpy(ttnmsv,ttname,TTNAMLEN);
  1650.             ttnet = modem;
  1651.         } else                          /* Failed, unset network flag */
  1652.           network = 0;
  1653.         return(x);
  1654.     }
  1655. #endif /* NETCONN */
  1656.  
  1657.     if (ttychn) return(0);              /* Close channel if open */
  1658.  
  1659. /* Now we know we're opening a serial device */
  1660.  
  1661.     network = 0;                        /* So set this to zero */
  1662.  
  1663.     devnam.dsc$w_length  = strlen(ttname); /* Get real name of device */
  1664.     devnam.dsc$a_pointer = ttname;
  1665.     sys$getdviw(0, 0, &devnam, &dviitm, &wrk_iosb, 0, 0, 0);
  1666.     tt_fulldevnam[TTNAMLEN] = '\0';     /* Make sure name has an end... */
  1667.  
  1668.     if (devclass != DC$_TERM) {         /* Is it a terminal? */
  1669.         fprintf(stderr,
  1670.                 "%%CKERMIT-W-NOTTERM, %s is not a terminal\n",ttname);
  1671.         return(-1);
  1672.     }
  1673.     if (!(devchar & DEV$M_AVL)) {       /* Is it available? */
  1674.         fprintf(stderr,
  1675.                 "%%CKERMIT-W-NOTAVAL, %s is not available\n",tt_fulldevnam);
  1676.         return(-5);
  1677.     }
  1678.     if (!(devsts & UCB$M_ONLINE)) {     /* Is it online? */
  1679.         fprintf(stderr,
  1680.                 "%%CKERMIT-W-OFFLINE, %s is not online\n",tt_fulldevnam);
  1681.         return(-5);
  1682.     }
  1683.     ttmdm = modem;                      /* Make this available to other fns */
  1684.     xlocal = *lcl;                      /* Make this available to other fns */
  1685.     xhangup = 0;                        /* New conneciton - no hangup yet */
  1686.     overruns = 0;                       /* Reset overrun counter */
  1687. /*
  1688.  *  Set up the tt_fulldevnam_d descriptor for use by ttclos() later.
  1689.  */
  1690.     tt_fulldevnam_d.dsc$w_length  = strlen(tt_fulldevnam);
  1691.     tt_fulldevnam_d.dsc$a_pointer = tt_fulldevnam;
  1692. /*
  1693.   In the old days, we just tried to assign the device, but this could result
  1694.   in two people having the same serial device open, which does nobody any
  1695.   good.  Starting in 1993, we dropped SHARE privilege before allocating the
  1696.   device to prevent this.  But in 1997 we found that this prevented C-Kermit
  1697.   from being used in remote mode under DECIntact, which allocates the TT:
  1698.   device for itself first, so a /SHARE qualifier was added to SET LINE, which,
  1699.   if given, sets ok_to_share to 1, and if not given sets it to 0.  Now we set
  1700.   or unset SHARE privilege based on this variable.  -fdc, 31 Dec 1997.
  1701. */
  1702.     no_share_priv[0] = PRV$M_SHARE;
  1703.     debug(F101,"ttopen ok_to_share","",ok_to_share);
  1704.     vms_status = sys$setprv(ok_to_share ? 1 : 0, &no_share_priv,0,&prev_privs);
  1705.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  1706.     debug(F101,"ttopen sys$setprv 1","",vms_status);
  1707.     ttychn = vms_assign_channel(&devnam); /* Get a channel for it. */
  1708.     debug(F101,"ttopen ttychn","",ttychn);
  1709.     vms_status = sys$setprv (1, &prev_privs, 0, 0); /* Restore old privs */
  1710.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  1711.     debug(F101,"ttopen sys$setprv 2","",vms_status);
  1712.     if (!ttychn) return(-1);            /* Couldn't open, fail */
  1713.     wasclosed = 0;
  1714. /*
  1715.  * Check for maximum size of QIO, so as to not get the dreaded quota exceeded
  1716.  * status returned.  When doing a QIO that has a larger buffer than
  1717.  * MAXBUF, exceeded quota is returned.
  1718.  *
  1719.  * Example: MAXBUF = 2048, QIO = 1936, overhead is 112: will succeed.
  1720.  *          QIO of 1937 will fail.
  1721.  *
  1722.  * This can change for different versions of VMS.
  1723.  */
  1724.     qio_maxbuf_size = get_qio_maxbuf_size(ttychn);
  1725.  
  1726.     ckstrncpy(ttname,tt_fulldevnam,TTNAMLEN); /* Copy true name to main() */
  1727.     ckstrncpy(ttnmsv,ttname,TTNAMLEN);  /* Keep a copy of the name locally */
  1728.     ttxbn = ttxbp = 0;                  /* Initialize input buffer */
  1729.  
  1730. /* Caller wants us to figure out if line is controlling tty */
  1731.  
  1732.     debug(F111,"ttopen ok",ttname,*lcl);
  1733.     if (*lcl < 0) {
  1734.         if (conclass == DC$_TERM)
  1735.           xlocal = (strncmp(ttname,cttnam,TTNAMLEN) == 0) ? 0 : 1;
  1736.         else
  1737.           xlocal = 1;                /* If not a term, then we must be local */
  1738.         debug(F111,"ttopen controlling terminal",cttnam,xlocal);
  1739.     }
  1740.     if (!CHECK_ERR("ttopen: sys$qiow",
  1741.         sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1742.                  &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  1743.  
  1744.     ttspeed = speed = ttispd((unsigned char) wrk_iosb.size);
  1745.     debug(F101,"ttopen speed","",speed);
  1746.  
  1747. /* Got the line, now set the desired value for local. */
  1748.  
  1749.     if (*lcl) *lcl = xlocal;
  1750.  
  1751.     tttvt = ttold;
  1752.     ttraw = ttold;
  1753.  
  1754. #ifdef TT$M_MODEM
  1755.     debug(F101,"ttopen TT$M_MODEM","",TT$M_MODEM);
  1756.     if (ttold.basic & TT$M_MODEM)
  1757.       ismodem = 1;
  1758. #endif /* TT$M_MODEM */
  1759.     debug(F101,"ttopen ismodem","",ismodem);
  1760. #ifdef TT$M_REMOTE
  1761.     debug(F101,"ttopen TT$M_REMOTE","",TT$M_REMOTE);
  1762.     if (ttold.basic & TT$M_REMOTE)      /* This really means "has carrier" */
  1763.       isremote = 1;                     /* if TT$M_MODEM */
  1764. #endif /* TT$M_REMOTE */
  1765.     debug(F101,"ttopen isremote","",isremote);
  1766. #ifdef TT2$M_DIALUP
  1767.     debug(F101,"ttopen TT2$M_DIALUP","",TT2$M_DIALUP);
  1768.     if (ttold.basic & TT2$M_DIALUP)
  1769.       isdialup = 1;
  1770. #endif /* TT$2M_DIALUP */
  1771.     debug(F101,"ttopen isdialup","",isdialup);
  1772. #ifdef TT2$M_DISCONNECT
  1773.     debug(F101,"ttopen TT2$M_DISCONNECT","",TT2$M_DISCONNECT);
  1774.     if (ttold.basic & TT2$M_DISCONNECT)
  1775.       isdisconnect = 1;
  1776. #endif /* TT$2M_DISCONNECT */
  1777.     debug(F101,"ttopen isdisconnect","",isdisconnect);
  1778. #ifdef TT2$M_SECURE
  1779.     debug(F101,"ttopen TT2$M_SECURE","",TT2$M_SECURE);
  1780.     if (ttold.basic & TT2$M_SECURE)
  1781.       issecure = 1;
  1782. #endif /* TT$2M_SECURE */
  1783.     debug(F101,"ttopen issecure","",issecure);
  1784. #ifdef TT2$M_HANGUP
  1785.     debug(F101,"ttopen TT2$M_HANGUP","",TT2$M_HANGUP);
  1786.     if (ttold.basic & TT2$M_HANGUP)
  1787.       ishangup = 1;
  1788. #endif /* TT$2M_HANGUP */
  1789.     debug(F101,"ttopen ishangup","",ishangup);
  1790. #ifdef TT2$M_MODHANGUP
  1791.     debug(F101,"ttopen TT2$M_MODHANGUP","",TT2$M_MODHANGUP);
  1792.     if (ttold.basic & TT2$M_MODHANGUP)
  1793.       ismodhangup = 1;
  1794. #endif /* TT$2M_MODHANGUP */
  1795.     debug(F101,"ttopen ismodhangup","",ismodhangup);
  1796.  
  1797.     debug(F101,"ttopen lcl","",*lcl);
  1798.     ttpmsk = 0xff;
  1799.     return(0);
  1800. }
  1801.  
  1802. #ifdef COMMENT
  1803. /*
  1804.   Old version.
  1805. */
  1806. unsigned long int
  1807. vms_assign_channel(ttname) char *ttname;  {
  1808.     unsigned int channel = 0;
  1809.     struct dsc$descriptor_s d = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1810.  
  1811.     d.dsc$w_length  = strlen(ttname);
  1812.     d.dsc$a_pointer = ttname;
  1813.     if (!CHECK_ERR("vms_assign_channel: sys$assign",
  1814.         sys$assign(&d, &channel, 0, 0))) return(0);
  1815.     return(channel);
  1816. }
  1817. #else
  1818. /*
  1819.   New version from Hunter Goatley.
  1820. */
  1821. unsigned short int
  1822. vms_assign_channel(ttname) struct dsc$descriptor_s *ttname; {
  1823.     unsigned short channel = 0;
  1824.  
  1825. #ifdef COMMENT
  1826. /* what's all this then ... */
  1827.     struct dsc$descriptor_s d = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1828.     d.dsc$w_length  = strlen(ttname);
  1829.     d.dsc$a_pointer = ttname;
  1830. #endif /* COMMENT */
  1831.  
  1832.     debug(F110,"vms_assign_channel device",ttname,0);
  1833.  
  1834.     if (!CHECK_ERR("vms_assign_channel: sys$assign",
  1835.         sys$assign(ttname, &channel, 0, 0))) return(0);
  1836.  
  1837. #ifdef NEW_STUFF_FROM_BRUCE_DAY
  1838. /*
  1839.   Which is not presently defined...
  1840.   This is supposed to allow C-Kermit to go into protocol mode on an LTA
  1841.   device without a prior CONNECT command.
  1842. */
  1843. #ifdef IO$M_LT_CONNECT
  1844.     vms_status = sys$qiow(QIOW_EFN, channel, IO$_TTY_PORT|IO$M_LT_CONNECT,
  1845.                           &wrk_iosb, 0, 0, 0, 0, 0, 0, 0, 0);
  1846.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  1847.     debug(F101, "vms_assign_channel LAT connect status","",vms_status);
  1848.     debug(F101, "vms_assign_channel LAT connect iosb","",wrk_iosb.status);
  1849. #endif /* IO$M_LT_CONNECT */
  1850. #endif /* NEW_STUFF_FROM_BRUCE_DAY */
  1851.  
  1852.     return(channel);
  1853. }
  1854. #endif /* COMMENT */
  1855.  
  1856. /*  T T C L O S  --  Close the communication device.  */
  1857.  
  1858. int
  1859. ttclos(dummy) int dummy; {
  1860.     int channel;
  1861. #ifdef DEBUG
  1862.     if (deblog) {
  1863.         debug(F101,"ttclos 1: ttyfd","",ttyfd);
  1864.         debug(F101,"ttclos 1: ttychn","",ttychn);
  1865.         debug(F101,"ttclos 1: network","",network);
  1866.         debug(F101,"ttclos 1: overruns","",overruns);
  1867.     }
  1868. #endif /* DEBUG */
  1869.  
  1870. #ifdef NETCONN
  1871.     if (network) {                      /* Network connection. */
  1872.         netclos();                      /* Close it. */
  1873.         debug(F101,"ttclos 2: network","",network);
  1874.         debug(F101,"ttclos 2: ttychn","",ttychn);
  1875.         debug(F101,"ttclos 2: ttyfd","",ttyfd);
  1876.         /* network = 0; */
  1877.         return(0);
  1878.     }
  1879. #endif /* NETCONN */
  1880.  
  1881. /* The rest is for serial connections, in which ttychn is nonzero. */
  1882.  
  1883.     if (!ttychn)
  1884.       return(0);
  1885. /*
  1886.   Observations indicate that it can take 20-30 seconds for DTR to drop
  1887.   after closing the device.  Perhaps a call to tthang() should go here.
  1888. */
  1889.     debug(F100,"ttclos calling ck_cancio","",0);
  1890.     ck_cancio();                        /* Cancel any pending i/o. */
  1891.     debug(F100,"ttclos calling ttres","",0);
  1892.     ttres();                            /* Reset modes. */
  1893. /*
  1894.   Assume it's a LAT device and try to do a LAT disconnect on it.
  1895.   If it fails, then it's not a LAT device and no harm is done.
  1896. */
  1897. #ifdef IO$M_LT_DISCON
  1898.     debug(F100,"ttclos calling sys$qiow for LAT disconnect","",0);
  1899.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_TTY_PORT|IO$M_LT_DISCON,
  1900.                           &wrk_iosb, 0, 0, 0, 0, 0, 0, 0, 0);
  1901.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  1902.     debug(F101, "ttclos LAT disconnect, status", "", vms_status);
  1903.     debug(F101, "ttclos LAT disconnect, iosb", "", wrk_iosb.status);
  1904. #else
  1905.     debug(F100, "ttclos LAT disconnect not supported", "", 0);
  1906. #endif /* IO$M_LT_DISCON */
  1907.     debug(F100,"ttclos calling sys$dassgn","",0);
  1908.     channel = ttychn;
  1909.     ttychn = 0;                         /* Mark it as closed */
  1910.     wasclosed = 1;
  1911.     /* xhangup = 0; */
  1912.     if (!CHECK_ERR("ttclos: sys$dassgn", sys$dassgn(channel)))
  1913.       return(-1);
  1914.     debug(F101,"ttclos done - ttychn","",ttychn);
  1915.     return(0);
  1916. }
  1917.  
  1918. /*  T T R E S  --  Restore terminal to its original modes.  */
  1919.  
  1920. int
  1921. ttres() {                               /* Restore the tty to normal. */
  1922.     ttpmsk = 0xff;
  1923. #ifdef NETCONN
  1924.     if (network) return (0);            /* Network connection, do nothing */
  1925. #endif /* NETCONN */
  1926.  
  1927.     if (!ttychn) return(-1);            /* Not open. */
  1928.  
  1929. #ifdef COMMENT
  1930. /* ck_cancio() does exactly the same thing */
  1931.     tt_cancel();                        /* Cancel outstanding I/O */
  1932. #endif /* COMMENT */
  1933.     msleep(250);                        /* Wait for pending i/o to finish. */
  1934.     debug(F101,"ttres, ttychn","",ttychn);
  1935.     if (!CHECK_ERR("ttres: sys$qiow",
  1936.         sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1937.                  &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  1938.     debug(F100,"ttres still going after sys$qiow","",0);
  1939.     return(0);
  1940. }
  1941.  
  1942. /*  T T B I N  --  Code shared by ttpkt() and ttvt()  */
  1943. /*
  1944.   Puts communication device in "binary" mode.  In VMS there's no distinction
  1945.   between device modes for terminal connection, packet operation, and dialing.
  1946.   BUT THERE SHOULD BE!  We need to get SET CARRIER-WATCH working...
  1947. */
  1948. static int
  1949. ttbin(speed, xflow, xparity) int speed, xflow, xparity; {
  1950.     int s;
  1951.     extern int flow;                    /* Global flow control variable */
  1952.  
  1953.     debug(F101,"ttbin entry xparity","",xparity);
  1954.     debug(F101,"ttbin entry xflow","",xflow);
  1955.     debug(F101,"ttbin entry flow","",flow);
  1956.  
  1957.     if (xparity > -1) {
  1958.         ttprty  = xparity;
  1959.         ttpflg  = 0;                    /* Parity not sensed yet */
  1960. #ifdef COMMENT
  1961. /*
  1962.   No.  We want the mask applied for file transfer, but not for CONNECT or
  1963.   scripts, because then we lose Telnet negotiations.
  1964. */
  1965.         ttpmsk  = ttprty ? 0177 : 0377; /* Parity stripping mask */
  1966. #endif /* COMMENT */
  1967.         debug(F101,"ttbin ttprty","",ttprty);
  1968.     }
  1969.  
  1970. #ifdef NETCONN
  1971.     if (network) return(0);             /* Nothing to do on net connections */
  1972. #endif /* NETCONN */
  1973.  
  1974.     if (!ttychn) return(-1);            /* Not open. */
  1975.  
  1976. /* The following applies only to serial ports - causes errors on network */
  1977.  
  1978.     ttdialing = 0;                      /* Not dialing */
  1979.     if (xflow != FLO_DIAL && ttflow != FLO_DIAX) {
  1980.         ttflow = xflow;                 /* Save for other CKVTIO routines. */
  1981.     } else if (xflow == FLO_DIAL) {     /* We're dialing */
  1982.         ttdialing = 1;                  /* Remember */
  1983.     }
  1984.     debug(F101,"ttbin ttdialing","",ttdialing);
  1985.     ttspeed = speed;                    /* Keep local copies of arguments */
  1986.     if ((s = ttsspd(speed/10)) < 0)     /* Get internal speed code */
  1987.       s = 0;
  1988.  
  1989. /* Log original terminal settings for debugging purposes */
  1990.  
  1991.     ttraw = ttold;                      /* Get a fresh copy of this */
  1992.     debug(F101, "ttbin ttraw.basic 1", "", ttraw.basic);
  1993.     debug(F101, "ttbin ttraw.extended 1", "", ttraw.extended);
  1994. /*
  1995.   Settings based on call parameters flow-control and parity...
  1996.   NOTE: we are using the GLOBAL copy of flow, not our parameter here.
  1997.   This is because the parameter might be FLO_DIAL or FLO_DIALX, which
  1998.   is not flow control at all.
  1999. */
  2000.     if (flow == FLO_XONX) {                             /* FLOW = XON/XOFF */
  2001.         debug(F100,"ttbin FLO_XONX","",0);
  2002.         ttraw.basic |=  (TT$M_HOSTSYNC|TT$M_TTSYNC);
  2003.     } else if (flow == FLO_NONE) {                      /* FLOW = NONE */
  2004.         debug(F100,"ttbin FLO_NONE","",0);
  2005.         ttraw.basic &= ~(TT$M_HOSTSYNC|TT$M_TTSYNC);
  2006.     } else if (flow == FLO_KEEP) {                      /* FLOW = KEEP */
  2007. /*
  2008.  * Put flow-control parameters back the way we found them when
  2009.  * the device was first opened.
  2010.  */
  2011.         if (ttold.basic & TT$M_HOSTSYNC) {
  2012.             ttraw.basic |= TT$M_HOSTSYNC;
  2013.             debug(F100,"ttbin FLO_KEEP HOSTSYNC","",0);
  2014.         } else {
  2015.             ttraw.basic &= ~TT$M_HOSTSYNC;
  2016.             debug(F100,"ttbin FLO_KEEP no HOSTSYNC","",0);
  2017.         }
  2018.         if (ttold.basic & TT$M_TTSYNC) {
  2019.             ttraw.basic |= TT$M_TTSYNC;
  2020.             debug(F100,"ttbin FLO_KEEP TTSYNC","",0);
  2021.         } else {
  2022.             ttraw.basic &= ~TT$M_TTSYNC;
  2023.             debug(F100,"ttbin FLO_KEEP no TTSYNC","",0);
  2024.         }
  2025. /*
  2026.   NOTE: VMS 7.0 supports RTS/CTS.  But how can we include that here
  2027.   portably -- distinction between compile time & run time, etc...
  2028. */
  2029.     }
  2030.     if (parity == 0)
  2031.       ttraw.basic  |= TT$M_EIGHTBIT;    /* Allow 8-bit data if no parity */
  2032.     else                                /* Otherwise */
  2033.       ttraw.basic  &= ~TT$M_EIGHTBIT;   /* 7-bit data. */
  2034.     ttraw.basic |= TT$M_NOBRDCST;       /* Turn on no-broadcasts */
  2035.     ttraw.basic |= TT$M_NOECHO;         /* Turn on no-echo */
  2036.     ttraw.basic &= ~TT$M_NOTYPEAHD;     /* Turn off no-type-ahead */
  2037.     ttraw.basic &= ~TT$M_ESCAPE;        /* Turn off escape-seq processing */
  2038.     ttraw.extended &= ~TT2$M_LOCALECHO; /* Turn off local-echo */
  2039.     ttraw.extended |= TT2$M_PASTHRU;    /* Turn on pass-through mode */
  2040.     ttraw.extended |= TT2$M_ALTYPEAHD;  /* Turn on big type-ahead buffers */
  2041.  
  2042. /* Report what we did so we can check for problems */
  2043.  
  2044.     debug(F101, "ttbin ttraw.basic 2", "", ttraw.basic);
  2045.     debug(F101, "ttbin ttraw.extended 2", "", ttraw.extended);
  2046.  
  2047.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2048.                          &ttraw, sizeof(ttraw), s, 0, 0, 0);
  2049.     if (!(vms_status & 1))
  2050.       vms_lasterr = vms_status;
  2051. /*
  2052.   On some VMS systems, during remote-mode file transfer, C-Kermit still seems
  2053.   sensitive to Ctrl-C, Ctrl-X, Ctrl-Y, Ctrl-N, and Ctrl-O.  It has been
  2054.   suggested that maybe the following will get rid of at least the ^C and ^Y
  2055.   sensitivity (although it is not clear why the code above did not already
  2056.   do this):
  2057.  
  2058.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE+IO$M_CTRLCAST,
  2059.                           0, 0, 0, <handler:what-goes-here?>, 0, 0, 0, 0, 0);
  2060.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE+IO$M_CTRLYAST,
  2061.                           0, 0, 0, <handler:what-goes-here?>, 0, 0, 0, 0, 0);
  2062.  
  2063.   Actually, no -- this just sets up Ctrl-C and Ctrl-Y handlers; it doesn't
  2064.   prevent VMS from trapping them...  Anyway, it's not a problem most places;
  2065.   observed locally only when coming into VMS thru the UCX 2.0 Telnet server.
  2066. */
  2067.     debug(F101,"ttbin sy$qiow","",vms_status);
  2068.     if (vms_status != SS$_NORMAL) {     /* Error queuing request */
  2069.         print_msg("ttbin: sys$qiow");
  2070.         return(-1);
  2071.     }
  2072.     debug(F101,"ttbin iosb status","",wrk_iosb.status);
  2073.     if (wrk_iosb.status != SS$_NORMAL) { /* Error executing request */
  2074.         vms_status = wrk_iosb.status;
  2075.         print_msg("ttbin: sys$qiow(iosb)");
  2076.         return(-1);
  2077.     }
  2078.     debug(F100,"ttbin ok","",0);
  2079.     return(0);                          /* All OK */
  2080. }
  2081.  
  2082. /*  T T P K T  --  Condition the communication device for packets. */
  2083.  
  2084. /*  Returns 0 on success, -1 on failure.  */
  2085.  
  2086. int
  2087. ttpkt(speed,flow,parity) long speed; int flow, parity; {
  2088.     int x;
  2089.     debug(F101,"ttpkt flow","",flow);
  2090.     x = ttbin(speed,flow,parity);       /* Put device in binary mode */
  2091.     debug(F101,"ttpkt ttbin","",x);
  2092.     ttpmsk = (ttprty) ? 0x7f : 0xff;    /* Parity stripping mask. */
  2093.     return(x);
  2094. }
  2095.  
  2096. /*  T T V T  --  Condition communication device terminal connection. */
  2097.  
  2098. int
  2099. ttvt(speed,flow) long speed; int flow; {
  2100.     int x;
  2101.     debug(F101,"ttvt flow","",flow);
  2102.     if ((x = ttbin(speed,flow,-1)) > -1) /* Put device in binary mode */
  2103.       tvtflg = 1;
  2104.     debug(F101,"ttvt ttbin","",x);
  2105.     ttpmsk = 0xff;                      /* Let CONNECT module handle it */
  2106.     return(x);
  2107. }
  2108.  
  2109. /* T T I S P D  -- Return binary baud rate for internal coded speed */
  2110.  
  2111. int
  2112. ttispd(ispeed) unsigned char ispeed; {
  2113.     int s;
  2114.     long x;
  2115.  
  2116. #ifdef NETCONN
  2117.     if (network) return(-1);
  2118. #endif /* NETCONN */
  2119.  
  2120. /* When the line is set, grab the line speed  and save it */
  2121.  
  2122.     for (s = 0;  ttspeeds[s].dec &&
  2123.         (ttspeeds[s].dec != ispeed);  s++)
  2124.                 ;
  2125.  
  2126. /* If speed is zero, then no match.  Set speed to -1 so it is undefined */
  2127.  
  2128.     x = ttspeeds[s].line ? (int) ttspeeds[s].line * 10 : -1;
  2129.     debug(F101,"ttispd","",x);
  2130.     return(x);
  2131. }
  2132.  
  2133. #define NSPDLIST 64
  2134. static long spdlist[NSPDLIST];
  2135.  
  2136. long *
  2137. ttspdlist() {
  2138.     int i; long n;
  2139.  
  2140.     for (i = 0; ttspeeds[i].dec; i++) {
  2141.         n  = ttspeeds[i].line * 10;
  2142.         if (n == 70L)
  2143.           n = 75L;
  2144.         else if (n == 130L)
  2145.           n = 134L;
  2146.         spdlist[i+1] = n;
  2147.     }
  2148.     spdlist[0] = i;
  2149.     return((long *)spdlist);
  2150. }
  2151.  
  2152. /*  T T S S P D  --  Set speed for serial device */
  2153. /*
  2154.   In VMS this routine doesn't actually change the speed; it just checks its
  2155.   argument and then if OK sets a global variable that is used by ttgspd() to
  2156.   say what the current speed is.  The speed is actually changed only by
  2157.   ttbin(), which has its own speed argument.  Note that in VMS there is no
  2158.   way to read the device's current speed (see ttgspd()).
  2159. */
  2160. int
  2161. ttsspd(cps) int cps; {
  2162.     int s;
  2163.     char msg[50];
  2164.  
  2165. #ifdef  NETCONN
  2166.     if (network) {
  2167. #ifdef TN_COMPORT
  2168.         if (istncomport())
  2169.           return(tnc_set_baud(cps * 10));
  2170.         else
  2171. #endif /* TN_COMPORT */
  2172.           return(0);
  2173.     }
  2174. #endif  /* NETCONN */
  2175.  
  2176.     if (cps <= 0)                       /* 026 Unknown cps fails */
  2177.       return (-1);
  2178.     for (s = 0;  ttspeeds[s].line && (ttspeeds[s].line != cps);  s++) ;
  2179.     if (ttspeeds[s].line) {
  2180.         ttspeed = cps * 10L;            /* Make a copy global to this module */
  2181.         if (ttspeed == 70L)             /* ... in bits per second, not cps, */
  2182.           ttspeed = 75L;                /* because ttgspd() uses it! */
  2183.         debug(F101,"ttsspd","",ttspeed);
  2184.         return(ttspeeds[s].dec);
  2185.     } else {
  2186.         sprintf(msg,"Unsupported line speed - %d\n",cps*10);
  2187.         debug(F101,"ttsspd fails","",cps*10);
  2188.         ermsg(msg);
  2189.         ermsg("Current speed not changed\n");
  2190.         return(-1);
  2191.     }
  2192. }
  2193.  
  2194. /* Interrupt Functions */
  2195.  
  2196. /*  C O N I N T  --  Console Interrupt setter  */
  2197.  
  2198. static SIGTYP (*cctrap)();
  2199.  
  2200. VOID
  2201. #ifdef CK_ANSIC
  2202. conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
  2203. #else
  2204. conint(f,s) int (*f)(int), (*s)(int);
  2205. #endif /* CK_ANSIC */
  2206. /* conint */ {                          /* Set an interrupt trap. */
  2207.     /* debug(F101,"conint batch","",batch); */
  2208.  
  2209.     cctrap = f;                         /* Make a global copy of handler. */
  2210.     if (!itsatty)                       /* Ignore signals in batch */
  2211.       return;                           /* or if COMMAND INTERRUPT OFF. */
  2212.     signal(SIGINT,f);                   /* Not batch - function to trap to. */
  2213.     conif = 1;                          /* Flag console interrupts on. */
  2214. }
  2215.  
  2216. /*  C O N N O I  --  Reset console terminal interrupts */
  2217.  
  2218. VOID
  2219. connoi() {                              /* Console-no-interrupts */
  2220.     signal(SIGINT,SIG_IGN);
  2221.     conif = 0;
  2222. }
  2223.  
  2224. /*  T T O L  --  Write string s, length n, to communication device.  */
  2225.  
  2226. #ifndef IO$M_BREAKTHRU
  2227. #define IO$M_BREAKTHRU  0x0200
  2228. #endif /* IO$M_BREAKTHRU */
  2229.  
  2230. #ifndef SS$_EXQUOTA
  2231. #define SS$_EXQUOTA 28
  2232. #endif /* SS$_EXQUOTA */
  2233.  
  2234. int
  2235. ttol(s,n) int n; CHAR *s; {
  2236.     int
  2237.       remaining,                        /* Amount left to write */
  2238.       size;                             /* How much to write this time */
  2239.     static int max = 0;                 /* Chunk size for writing */
  2240.  
  2241. #ifdef NETCONN
  2242.     debug(F101,"ttol network","",network);
  2243.     if (network)                        /* If SET HOST connection, */
  2244.         return(nettol(s,n));            /* call network package. */
  2245. #endif /* NETCONN */
  2246.  
  2247. /* It's not a SET HOST connection. */
  2248.  
  2249.     debug(F101,"ttol ttychn","",ttychn);
  2250.     if (!ttychn) return(-1);            /* Not open. */
  2251.     debug(F101,"ttol length","",n);
  2252.     debug(F101,"ttol max","",max);
  2253.  
  2254. /* Have we already calculated a chunk size? */
  2255.  
  2256.     if (max == 0) {                     /* No, try to send whole packet. */
  2257.         vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2258.                               &wrk_iosb, 0, 0, s, n, 0, 0, 0, 0);
  2259.         if (!(vms_status & 1)) vms_lasterr = vms_status;
  2260.         if (vms_status == SS$_NORMAL) {
  2261.             debug(F101,"ttol 1 ok","",n);
  2262.             return(n);
  2263.         }
  2264. #ifdef DEBUG
  2265.         if (deblog) {                   /* Failed. */
  2266.             debug(F101,"ttol 1 error, vms_status","",vms_status);
  2267.             debug(F101,"ttol 1 iosb size","",wrk_iosb.size);
  2268.             debug(F101,"ttol 1 iosb status","",wrk_iosb.status);
  2269.         }
  2270. #endif /* DEBUG */
  2271.         if (vms_status != SS$_EXQUOTA)  /* "Quota exceeded"? */
  2272.           return(-3);                   /* No, something else, give up. */
  2273. /*
  2274.   Here we should find out what MAXBUF is (not to mention BYTLM, BIOLM, and
  2275.   friends), and chop up the packet into pieces accordingly.  But reportedly
  2276.   this information, and how to use it (percent overhead, etc), is highly
  2277.   VMS-version-dependent.  So instead we just try different numbers.  Our first
  2278.   attempt keeps dividing it in half until it works, down to about 70.
  2279. */
  2280.         do {
  2281.             max = (max == 0) ? n / 2 : max / 2;
  2282.             debug(F101,"ttol 2 max","",max);
  2283.             vms_status = sys$qiow(QIOW_EFN, ttychn,
  2284.                                   IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2285.                                   &wrk_iosb, 0, 0, s, max, 0, 0, 0, 0);
  2286.             if (!(vms_status & 1)) vms_lasterr = vms_status;
  2287.             debug(F101,"ttol 2 vms_status","",vms_status);
  2288.             if (vms_status == SS$_NORMAL)
  2289.               break;
  2290.         } while (max > 70);             /* 70 is the minimum. */
  2291.  
  2292.         if (vms_status != SS$_NORMAL)   /* Loop exhausted, fail. */
  2293.           return(-3);
  2294.  
  2295.     } else {                            /* We already calculated max. */
  2296.  
  2297.         size = (max > n) ? n : max;     /* Write 1st chunk, but not too much */
  2298.         vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2299.                               &wrk_iosb, 0, 0, s, size, 0, 0, 0, 0);
  2300.         if (!(vms_status & 1)) vms_lasterr = vms_status;
  2301.         debug(F101,"ttol 3 vms_status","",vms_status);
  2302.         if (vms_status != SS$_NORMAL)
  2303.           return(-3);
  2304.         if (size == n) {                /* (Not strictly necessary) */
  2305.             debug(F101,"ttol 3 done","",n);
  2306.             return(n);
  2307.         }
  2308.     }
  2309. /*
  2310.   We have written the first chunk successfully, now write the remaining
  2311.   max-sized chunks, plus the (usually) less-than-max-sized last chunk.
  2312. */
  2313.     remaining = n;
  2314.     while (1) {
  2315.         s += max;                       /* Where to start */
  2316.         remaining -= max;               /* How much left to write */
  2317.         size = (remaining < max) ?      /* How much to write this time */
  2318.           remaining : max;
  2319.         if (size < 1)                   /* Done? */
  2320.           break;
  2321.  
  2322.         debug(F101,"ttol 4 size","",size);
  2323.         vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2324.                               &wrk_iosb, 0, 0, s, size, 0, 0, 0, 0);
  2325.         if (!(vms_status & 1)) vms_lasterr = vms_status;
  2326.         debug(F101,"ttol 4 vms_status","",vms_status);
  2327.         if (vms_status != SS$_NORMAL)
  2328.           return(-3);
  2329.     }
  2330.     debug(F101,"ttol 5 done","",n);
  2331.     return(n);
  2332. }
  2333.  
  2334. /*  T T O C  --  Output a character to the communication line  */
  2335.  
  2336. int
  2337. #ifdef CK_ANSIC
  2338. ttoc(char c)
  2339. #else
  2340. ttoc(c) char c;
  2341. #endif  /* CK_ANSIC */
  2342. /* ttoc */ {
  2343. #ifdef NETCONN
  2344.     if (network) {
  2345.         return(nettoc(c));
  2346.     } else {
  2347. #endif /* NETCONN */
  2348.         debug(F101,"ttoc char","",c);
  2349.         if (!ttychn) {
  2350.             debug(F100,"ttoc ttychn not open","",0);
  2351.             return(-1);                 /* Not open. */
  2352.         }
  2353.         if (CHECK_ERR("ttoc: sys$qiow",
  2354.                       sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2355.                                &wrk_iosb, 0, 0, &c, 1, 0, 0, 0, 0)))
  2356.           return(0);
  2357. #ifdef NETCONN
  2358.     }
  2359. #endif /* NETCONN */
  2360.     return(-1);
  2361. }
  2362.  
  2363. /*  T T _ C A N C E L  --  Cancel i/o on tty channel if not complete  */
  2364.  
  2365. VOID
  2366. tt_cancel() {
  2367.     int mask;
  2368. #ifdef NETCONN
  2369.     if (network) return;
  2370. #endif /* NETCONN */
  2371.     CHECK_ERR("tt_cancel: sys$cancel",sys$cancel(ttychn));
  2372.     tt_queued = 0;
  2373. }
  2374.  
  2375. /*  C O N _ C A N C E L  --  Cancel i/o on console channel if not complete  */
  2376.  
  2377. VOID
  2378. con_cancel() {
  2379.     int mask;
  2380.  
  2381.     CHECK_ERR("con_cancel: sys$cancel",sys$cancel(conchn));
  2382.     con_queued = 0;
  2383. }
  2384.  
  2385. /*  S N D B R K  --  Send a BREAK signal of the given length.  */
  2386.  
  2387. int
  2388. sndbrk(msec) int msec; {
  2389.     int long x = 0;
  2390.     int brklen;
  2391.     struct iosb_struct  tmp_ttiosb;
  2392.     struct tt_mode ttchr;
  2393. #ifndef TT$M_BREAK                      /* For old VMS with no BREAK... */
  2394. /*
  2395.   Note: 110 is used instead of 50, because 50 is not supported by all
  2396.   VAX serial port controllers.
  2397. */
  2398. #define BRKSPD = 110                    /* Speed for simulating BREAK */
  2399. #define BRKSYM = TT$C_BAUD_110;         /* VMS symbol for this speed */
  2400. #endif /* TT$M_BREAK */
  2401.  
  2402. #ifdef NETCONN
  2403.     if (network) {                      /* Send network BREAK */
  2404. #ifdef TN_COMPORT
  2405.         if (istncomport())
  2406.           return((tnsndb((long)msec) >= 0) ? 0 : -1);
  2407.         else
  2408. #endif /* TN_COMPORT */
  2409.         return(netbreak());             /* Length doesn't matter */
  2410.     }
  2411. #endif /* NETCONN */
  2412.  
  2413.     if (!ttychn) return(-1);            /* SET LINE not done. */
  2414.     debug(F101,"sndbrk msec","",msec);
  2415.  
  2416.     tt_cancel();                        /* Cancel I/O */
  2417.  
  2418. #ifndef TT$M_BREAK                      /* VMS doesn't have BREAK function */
  2419.  
  2420. /* Send the right number of NULs at BREAK-simulation speed... */
  2421.  
  2422.     brklen = ( BRKSPD * 1000 ) / ( msec * 10 ); /* Calculate number of chars */
  2423.     if (brklen > sizeof(brkarray)) brklen = sizeof(brkarray);
  2424.     debug(F101,"sndbrk speed","",BRKSPD);
  2425.     debug(F101,"sndbrk brklen","",brklen);
  2426.     /* Get current modes */
  2427.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  2428.         sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  2429.                 &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  2430.     /* Set speed */
  2431.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  2432.         sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  2433.                 &ttchr, sizeof(ttchr), BRKSYM, 0, 0, 0))) return(-1);
  2434.     /* Send NULs */
  2435.     if (!CHECK_ERR("ttsndb: writing nulls",
  2436.         sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &tmp_ttiosb,
  2437.                  0, 0, (char *) brkarray, brklen, 0, 0, 0, 0))) return(-1);
  2438.     /* Restore modes */
  2439.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  2440.         sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  2441.                 &ttchr, sizeof(ttchr), wrk_iosb.size, 0, 0, 0))) return(-1);
  2442. #else
  2443.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  2444.         sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  2445.                 &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  2446.     x = TT$M_BREAK;                     /* Break signal on */
  2447.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  2448.         sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2449.                 &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  2450.     msleep(msec);                       /* Sleep requested amount of time */
  2451.     x = 0;                              /* Break signal off */
  2452.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  2453.         sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2454.                 &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  2455. #endif /* TT$M_BREAK */
  2456.     return(0);
  2457. }
  2458.  
  2459. /*  T T S N D B  --  Send a BREAK signal  */
  2460.  
  2461. int
  2462. ttsndb() {
  2463.     return(sndbrk(275));
  2464. }
  2465.  
  2466. /*  T T S N D L B  --  Send a Long BREAK signal  */
  2467.  
  2468. int
  2469. ttsndlb() {
  2470.     return(sndbrk(1500));
  2471. }
  2472.  
  2473. /*  T T H A N G  --  Hang up the communications line  */
  2474. /*
  2475.   Warning: As written, this function DOES NOT WORK on terminal server
  2476.   ports.  This is a shortcoming of VMS, confirmed by the Digital Diagnostic
  2477.   Center (or whatever DDC stands for).  Someone should add code here to test
  2478.   if the ttychn device is not a real terminal, and if so to handle it some
  2479.   other way, like set the speed to zero for a sec, or close and reopen the
  2480.   device.
  2481. */
  2482. int
  2483. tthang() {
  2484.     if (!xlocal) return(0);             /* Only on local connections. */
  2485.  
  2486.     debug(F101,"tthang network","",network);
  2487. #ifdef NETCONN
  2488.     if (network) {                      /* Network connection. */
  2489.         int x;
  2490.         debug(F101,"tthang istncomport","",istncomport());
  2491. #ifdef TN_COMPORT
  2492.         if (istncomport()) {
  2493.             int rc = tnc_set_dtr_state(0);
  2494.             if (rc >= 0) {
  2495.                 msleep(500);
  2496.                 rc = tnc_set_dtr_state(1);
  2497.             }
  2498.             return(rc >= 0 ? 0 : -1);
  2499.         } else {
  2500. #endif /* TN_COMPORT */
  2501.             x = netclos();
  2502.             debug(F101,"tthang netclos","",x);
  2503.             return((x < 0) ? -1 : 1); /* Just close it. */
  2504. #ifdef TN_COMPORT
  2505.         }
  2506. #endif /* TN_COMPORT */
  2507.     }
  2508. #endif /* NETCONN */
  2509.  
  2510.     if (!ttychn) return(0);             /* Not open. */
  2511.  
  2512.     tt_cancel();                        /* Cancel pending i/o. */
  2513. /*
  2514.   This is NOT listed in the VMS Terminal Driver as one of the functions
  2515.   that does NOT work with LAT devices.
  2516. */
  2517.     debug(F101,"tthang 1","",gtimer());
  2518.     if (!CHECK_ERR("tthang: sys$qiow",
  2519.         sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE|IO$M_HANGUP, &wrk_iosb, 0, 0,
  2520.                 0, 0, 0, 0, 0, 0))) return(-1);
  2521. /*
  2522.   The following 3-second sleep is required because the sys$qiow() returns
  2523.   immediately, about 2.5 seconds before VMS brings DTR back up.  Without this
  2524.   sleep(), DIAL does not work at all if DIAL HANGUP is ON, and, worse,
  2525.   subsequent operations on the device can hang the Kermit process
  2526.   uninterruptibly.
  2527. */
  2528.     sleep(3);
  2529.     debug(F101,"tthang 2","",gtimer());
  2530.     return(1);
  2531. }
  2532.  
  2533. /*  M S L E E P  --  Millisecond version of sleep().  */
  2534.  
  2535. /*
  2536.  Handles intervals up to about 7 minutes (2**32 / 10**7 seconds)
  2537. */
  2538. int
  2539. msleep(m) int m; {
  2540.  
  2541.     struct time_struct {
  2542.         long int hi, lo;
  2543.     } t;
  2544.  
  2545.     if (m <= 0) return(0);
  2546.     t.hi = -10000 * m;  /*  Time in 100-nanosecond units  */
  2547.     t.lo = -1;
  2548.     if (!CHECK_ERR("msleep: sys$schdwk",
  2549.         sys$schdwk(0, 0, &t, 0))) return(-1);
  2550.     sys$hiber();
  2551.     debug(F101,"msleep ok","",m);
  2552.     return(0);
  2553. }
  2554.  
  2555. /*  R T I M E R --  Reset elapsed time counter  */
  2556.  
  2557. VOID
  2558. rtimer() {
  2559.     tcount = time( (TIME_T *) 0);
  2560. }
  2561.  
  2562. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  2563.  
  2564. int
  2565. gtimer() {
  2566.     int x;
  2567.     x = (int) (time( (TIME_T *) 0 ) - tcount);
  2568.     return( (x < 0) ? 0 : x );
  2569. }
  2570.  
  2571. #ifdef GFTIMER
  2572. #ifdef VMSI64
  2573. /* The native VMS code is broken in VMS/IA64 8.1. */
  2574. /* Luckily, in VMS 8.1 we can use the Unix code. */
  2575.  
  2576. static struct timeval tzero;
  2577.  
  2578. VOID
  2579. rftimer() {
  2580.     (VOID) gettimeofday(&tzero, (struct timezone *)0);
  2581. }
  2582.  
  2583. CKFLOAT
  2584. gftimer() {
  2585.     struct timeval tnow, tdelta;
  2586.     CKFLOAT s;
  2587. #ifdef DEBUG
  2588.     char fpbuf[64];
  2589. #endif /* DEBUG */
  2590.     (VOID) gettimeofday(&tnow, (struct timezone *)0);
  2591.  
  2592.     tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
  2593.     tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
  2594.  
  2595.     if (tdelta.tv_usec < 0) {
  2596.     tdelta.tv_sec--;
  2597.     tdelta.tv_usec += 1000000;
  2598.     }
  2599.     s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
  2600.     if (s < GFMINTIME)
  2601.       s = GFMINTIME;
  2602. #ifdef DEBUG
  2603.     if (deblog) {
  2604.     sprintf(fpbuf,"%f",s);
  2605.     debug(F110,"gftimer",fpbuf,0);
  2606.     }
  2607. #endif /* DEBUG */
  2608.     return(s);
  2609. }
  2610.  
  2611.  
  2612. #else
  2613.  
  2614. static QUAD tzero;
  2615.  
  2616. VOID
  2617. rftimer() {
  2618.     int status;
  2619.     status = sys$gettim(&tzero);
  2620.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  2621.     debug(F101,"rftimer status","",status);
  2622. }
  2623.  
  2624. /* Floating-point (fractional) timer -- granularity in VMS is ~0.00098 sec. */
  2625.  
  2626. CKFLOAT
  2627. gftimer() {
  2628.     float s;                            /* gcc gawks at CKFLOAT */
  2629.     QUAD tnow, diff;                    /* 64-bit times */
  2630.     int status;
  2631.     unsigned long lkd = LIB$K_DELTA_SECONDS_F;
  2632. #ifdef DEBUG
  2633.     char fpbuf[64];
  2634. #endif /* DEBUG */
  2635.     status = sys$gettim(&tnow);
  2636.     if (!(status & 1)) vms_lasterr = status;
  2637.     debug(F101,"gftimer status 1","",status);
  2638.     status = lib$sub_times(&tnow, &tzero, &diff );
  2639.     if (!(status & 1)) vms_lasterr = status;
  2640.     debug(F101,"gftimer status 2","",status);
  2641.     status = lib$cvtf_from_internal_time(&lkd,&s,&diff);
  2642.     if (!(status & 1)) vms_lasterr = status;
  2643.     debug(F101,"gftimer status 3","",status);
  2644. #ifdef DEBUG
  2645.     if (deblog) {
  2646.         sprintf(fpbuf,"%f",s);
  2647.         debug(F110,"gftimer s",fpbuf,0);
  2648.     }
  2649. #endif /* DEBUG */
  2650.     return(s > 0.0 ? (CKFLOAT) s : (CKFLOAT) 0.000001);
  2651. }
  2652. #endif    /* VMSI64 */
  2653. #endif /* GFTIMER */
  2654.  
  2655. /*  Z T I M E  --  Return date/time string  */
  2656.  
  2657. VOID
  2658. ztime(s) char **s; {
  2659.     static TIME_T clock;
  2660. #ifdef COMMENT
  2661. #ifdef bogus
  2662.     static char time_string[24];
  2663.     struct dsc$descriptor_s t =
  2664.         {sizeof(time_string)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&time_string};
  2665.  
  2666.     if (!CHECK_ERR("ztime: sys$asctim",
  2667.         sys$asctim(0, &t, 0, 0))) return(-1);
  2668.     time_string[t.dsc$w_length] = '\0';
  2669.     if (*s)
  2670.       *s = &time_string;
  2671. #else
  2672.     char *asctime();
  2673.     struct tm *tp;
  2674.  
  2675.     time(&clock);
  2676.     tp = localtime(&clock);
  2677.     if (*s)
  2678.       *s = asctime(tp);
  2679. #endif /* bogus */
  2680. #else /* not COMMENT */
  2681. /*
  2682.  Apparently ctime() is available in old C libraries, even though asctime()
  2683.  is not.  Let's use the same method for all versions.
  2684. */
  2685.     time(&clock);
  2686.     if (s)
  2687.       *s = ctime(&clock);
  2688. #endif /* COMMENT */
  2689. }
  2690.  
  2691. /*  C O N G M  --  Get console terminal modes.  */
  2692.  
  2693. /*
  2694.  Saves current console mode, and establishes variables for switching between
  2695.  current (presumably normal) mode and other modes.
  2696. */
  2697. int
  2698. congm() {
  2699.     char s[] = CONDEV_COLON;
  2700.     extern int bgset;
  2701.     struct itmlst dviitm[] = { {4,DVI$_DEVCLASS,NULL,0}, {0,0,0,0}};
  2702. #ifdef COMMENT /* old */
  2703.     struct dsc$descriptor_s
  2704.         r = {sizeof(s),DSC$K_DTYPE_T,DSC$K_CLASS_S,(char *)&s};
  2705. #else /* from ttj */
  2706.     struct dsc$descriptor_s
  2707.         devnam = {sizeof(s)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL};
  2708.     devnam.dsc$a_pointer = s;
  2709. #endif /* COMMENT */
  2710.  
  2711.     debug(F101,"congm bgset","",bgset); /* Background forced */
  2712.     if (bgset > 0)
  2713.       {
  2714.       batch = 1;
  2715.       backgrd = 1;
  2716.       itsatty = 0;
  2717.       return(-1);               /* e.g. by -B on command line */
  2718.       }
  2719.  
  2720.     debug(F101,"congm cgmf","",cgmf);
  2721.     if (cgmf) return(-1);               /* If called already, then nop */
  2722.  
  2723.     debug(F101,"congm batch","",batch);
  2724.  
  2725.     dviitm[0].adr = (char *)&dviitm[0].adr;
  2726.  
  2727. #ifndef CK_USEGETJPI
  2728. #ifdef JPI$_MODE                        /* I don't know how far back */
  2729. #ifdef JPI$K_BATCH                      /* these go... */
  2730. /* #define CK_USEGETJPI */
  2731. #endif /* JPI$K_BATCH */
  2732. #endif /* JPI$_MODE */
  2733. #endif /* CK_USEGETJPI */
  2734.  
  2735. #ifdef CK_USEGETJPI                     /* New way works better I think */
  2736.     {                                   /* (fdc, Jan 98) */
  2737.         struct itmlstdef {              /* Update by Hunter Goatley Jul 2001 */
  2738.             short int buflen;
  2739.             short int itmcod;
  2740.             char *bufaddr;
  2741.             long int *retlen;
  2742.         };
  2743.         short int terminal_name_size;   /* lh 31 Dec 2001 */
  2744.         char *terminal_name[32];
  2745.         struct itmlstdef gjiitm[] = { 32, JPI$_TERMINAL, NULL, 0, 0, 0, 0, 0 };
  2746.  
  2747.         /* Get the terminal name for the process */
  2748.  
  2749.         gjiitm[0].bufaddr = (char *)&terminal_name;
  2750.         gjiitm[0].retlen = (long *)&terminal_name_size;
  2751.         vms_status = sys$getjpiw(0, 0, 0, &gjiitm, 0, 0, 0);
  2752.         if (!(vms_status & 1)) vms_lasterr = vms_status;
  2753.         if (vms_status != SS$_NORMAL) {
  2754.             debug(F101,"congm sys$getjpiw error","",vms_status);
  2755.         } else {
  2756.             debug(F101, "congm sys$getdviw: terminal_name_size", "",
  2757.                   (unsigned long int) terminal_name_size);
  2758.  
  2759.             /* If the process has a terminal, make sure the device really */
  2760.             /* is a terminal class device. */
  2761.  
  2762.             if (terminal_name_size != 0) {
  2763.                 devnam.dsc$a_pointer = (char *)&terminal_name;
  2764.                 devnam.dsc$w_length = terminal_name_size;
  2765.                 if (!CHECK_ERR("congm: sys$getdviw",
  2766.                              sys$getdviw(0,0,&devnam,&dviitm,&wrk_iosb,0,0,0))
  2767.                     )
  2768.                   return(-1);
  2769.                 debug(F101, "congm sys$getdviw: devclass", "",
  2770.                       (unsigned long int) dviitm[0].adr);
  2771.                 if ((unsigned long int) dviitm[0].adr != DC$_TERM) {
  2772.                     if (bgset < 0) {    /* No "-z" on command line */
  2773.                         batch = 1;
  2774.                         backgrd = 1;
  2775.                         itsatty = 0;
  2776.                         debug(F111,"congm batch","devclass",batch);
  2777.                     }
  2778.                 }
  2779.             } else {
  2780.                 if (bgset < 0) {        /* Only if "-z" not given. */
  2781.                     batch = 1;
  2782.                     backgrd = 1;
  2783.                     itsatty = 0;
  2784.                     debug(F111,"congm batch","terminal_name_size",batch);
  2785.                 }
  2786.  
  2787.             }
  2788.             debug(F101,"congm sys$getjpiw batch","",batch);
  2789.         }
  2790.     }
  2791. #else /* Old way */
  2792.     if (!CHECK_ERR("congm: sys$getdviw",
  2793.         sys$getdviw(0, 0, &devnam, &dviitm, &wrk_iosb, 0, 0, 0))) return(-1);
  2794.     debug(F101, "congm sys$getdviw: devclass", "",
  2795.           (unsigned long int) dviitm[0].adr);
  2796.     if ((unsigned long int) dviitm[0].adr != DC$_TERM)
  2797.       {
  2798.       batch = 1;
  2799.       backgrd = 1;
  2800.       itsatty = 0;
  2801.       }
  2802.     else
  2803.       {
  2804.       batch = 0;
  2805.       backgrd = 0;
  2806.       itsatty = 1;
  2807.       }
  2808.     debug(F101,"congm sys$getdviw batch","",batch);
  2809. #endif /* COMMENT */
  2810.  
  2811. #ifdef COMMENT                          /* Let's try it anyway... */
  2812.       else {
  2813. #endif /* COMMENT */
  2814.         /*
  2815.            NOTE: Reportedly, when C-Kermit is run from a .COM file
  2816.            it complains "Sorry, terminal type not supported: vt300-80".
  2817.            Reportedly, the cure is to execute the following code always,
  2818.            not just when the if condition above is false; i.e. just get
  2819.            rid of {, } else {, and }.  But some of the following system
  2820.            calls look like they might be dangerous on non-terminals,
  2821.            so widespread testing would be needed.  Better safe than sorry.
  2822.         */
  2823.         debug(F101, "congm: conchn", "", conchn);
  2824.         if (!conchn) {                  /* Get console channel */
  2825.             $DESCRIPTOR(sys_input, CONDEV_COLON);
  2826.             conchn = vms_assign_channel(&devnam);
  2827.         }
  2828.         if (!conchn)
  2829.           return(-1);
  2830.         if (itsatty) {                  /* lh 31 Dec 2001 */
  2831.             if (!CHECK_ERR("congm: sys$qiow",
  2832.                            sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE, &wrk_iosb,
  2833.                                     0, 0, &ccold, sizeof(ccold), 0, 0, 0, 0)))
  2834.               return(-1);
  2835.         }
  2836.         ccraw = cccbrk = ccold;
  2837. #ifdef COMMENT
  2838.     }
  2839. #endif /* COMMENT */
  2840.     cgmf = 1;                           /* Flag that we got them. */
  2841.     return(0);
  2842. }
  2843.  
  2844. /*  C O N C B --  Put console in cbreak mode.  */
  2845.  
  2846. /*  Returns 0 if ok, -1 if not  */
  2847.  
  2848. int
  2849. #ifdef CK_ANSIC
  2850. concb(char esc)
  2851. #else
  2852. concb(esc) char esc;
  2853. #endif /* CK_ANSIC */
  2854. /* concb */ {
  2855.     int x;
  2856.  
  2857.     debug(F101,"concb batch","",batch);
  2858.     if (!itsatty) {                     /* If we're running in batch */
  2859.         extern int bgset;               /* but */
  2860.         if (bgset == 0)                 /* the user said SET BACKROUND OFF */
  2861.           ckxech = 1;                   /* allow echoing to batch log */
  2862.         debug(F101,"concb 1 ckxech","",ckxech);
  2863.         return(0);
  2864.     }
  2865.     if (!cgmf) congm();                 /* Get modes if necessary. */
  2866.     escchr = esc;                       /* Make this available to other fns */
  2867.     ckxech = 1;                         /* Program can echo characters */
  2868.     debug(F101,"concb 2 ckxech","",ckxech);
  2869. /*
  2870.   Note: PASTHRU / PASSALL is what is preventing the Ctrl-C trap in the
  2871.   main program from working.  This business can be removed without any effect
  2872.   at all on the command parser -- everything still works: completion, ?-help,
  2873.   editing, etc.  The only problem is that Ctrl-Y is not trapped, so the
  2874.   program dies and leaves the terminal in no-echo mode.
  2875. */
  2876.     cccbrk.extended |= TT2$M_PASTHRU | TT2$M_ALTYPEAHD;
  2877.     if (parity)
  2878.       cccbrk.basic |= TT$M_NOECHO;
  2879.     else
  2880.       cccbrk.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  2881.     cccbrk.basic &= ~TT$M_ESCAPE;       /* Disable escape-seq processing */
  2882.     cccbrk.extended &= ~TT2$M_LOCALECHO; /* and local echoing */
  2883.     if (!CHECK_ERR("concb: sys$qiow",
  2884.         sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2885.                  &cccbrk, sizeof(cccbrk), 0, 0, 0, 0))) return(-1);
  2886.     debug(F100,"concb ok","",0);
  2887.     return(0);
  2888. }
  2889.  
  2890. /*  C O N B I N  --  Put console in binary mode  */
  2891.  
  2892. /*  Returns 0 if ok, -1 if not  */
  2893.  
  2894. int
  2895. #ifdef CK_ANSIC
  2896. conbin(char esc)
  2897. #else
  2898. conbin(esc) char esc;
  2899. #endif /* CK_ANSIC */
  2900. /* conbin */ {
  2901.  
  2902.     debug(F101,"conbin batch","",batch);
  2903.     if (!itsatty) return(0);
  2904.     if (!cgmf) congm();                 /* Get modes if necessary. */
  2905.     escchr = esc;                       /* Make this available to other fns */
  2906.     ckxech = 1;                         /* Program can echo characters */
  2907.     debug(F101,"conbin ckxech","",ckxech);
  2908.     ccraw.extended |= TT2$M_PASTHRU | TT2$M_ALTYPEAHD;
  2909.     ccraw.basic &= ~TT$M_ESCAPE;        /* Disable escape-seq processing */
  2910.     ccraw.extended &= ~TT2$M_LOCALECHO; /* and local echoing */
  2911.     ccraw.basic |= TT$M_NOBRDCST;       /* Turn on no-broadcasts */
  2912.     if (parity)
  2913.       ccraw.basic |= TT$M_NOECHO;
  2914.     else
  2915.       ccraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  2916. #ifdef COMMENT
  2917.     ccraw.basic &= ~(TT$M_HOSTSYNC | TT$M_TTSYNC);
  2918. #endif /* COMMENT */
  2919.     if (!CHECK_ERR("conbin: sys$qiow",
  2920.         sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2921.                  &ccraw, sizeof(ccraw), 0, 0, 0, 0))) return(-1);
  2922.     return(0);
  2923. }
  2924.  
  2925. /*  C O N R E S  --  Restore the console terminal  */
  2926.  
  2927. int
  2928. conres() {
  2929.     debug(F101,"conres cgmf","",cgmf);
  2930.     if (!cgmf) return(0);               /* Do nothing if modes unknown */
  2931.     if (!itsatty) return(0);
  2932.  
  2933.     msleep(250);
  2934.     ckxech = 0;                         /* System should echo chars */
  2935.     debug(F101,"conres ckxech","",ckxech);
  2936.     debug(F101,"conres calling sys$qiow","",0);
  2937.     vms_status = sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2938.         &ccold, sizeof(ccold), 0, 0, 0, 0);
  2939.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  2940.     debug(F101,"conres sys$qiow status","",vms_status);
  2941.     if (vms_status == SS$_NORMAL) {
  2942.         debug(F100,"conres ok","",0);
  2943.         return(0);
  2944.     } else if (vms_status == SS$_DEVOFFLINE) {
  2945.         debug(F100,"conres DEVOFFLINE","",0);
  2946.         exit(SS$_ABORT);
  2947.     } else
  2948.       return(-1);
  2949. }
  2950.  
  2951. /*  C O N R E S N E --  Restore the console terminal with No Echo */
  2952.  
  2953. int
  2954. conresne() {
  2955.     debug(F101,"conresne cgmf","",cgmf);
  2956.     if (!cgmf) return(0);               /* Don't do anything if modes unk */
  2957.     if (!itsatty) return(0);
  2958.  
  2959.     msleep(250);
  2960.     ckxech = 1;                         /* Program should echo chars */
  2961.     debug(F101,"conresne ckxech","",ckxech);
  2962.     cctmp = ccold;
  2963.     cctmp.basic |= TT$M_NOECHO;
  2964.     if (!CHECK_ERR("conres: sys$qiow",
  2965.         sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2966.         &cctmp, sizeof(cctmp), 0, 0, 0, 0))) return(-1);
  2967.     debug(F100,"conresne ok","",0);
  2968.     return(0);
  2969. }
  2970.  
  2971. /*  C O N O C  --  Output a character to the console terminal  */
  2972.  
  2973. int
  2974. #ifdef CK_ANSIC
  2975. conoc(char c)
  2976. #else
  2977. conoc(c) char c;
  2978. #endif /* CK_ANSIC */
  2979. /* conoc */ {
  2980.     if (!itsatty || !initflg)
  2981.       putchar(c);
  2982.     else if (!CHECK_ERR("conoc: sys$qiow",
  2983.                 sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2984.                      &wrk_iosb, 0, 0, &c, 1, 0, 0, 0, 0)))
  2985.       return(-1);
  2986.     return(1);
  2987. }
  2988.  
  2989. /*  C O N X O  --  Write x characters to the console terminal  */
  2990.  
  2991. int
  2992. conxo(x,s) char *s; int x; {
  2993.     if (!itsatty || !initflg) fprintf(stdout, "%.*s", x, s);
  2994.     else if (!CHECK_ERR("conxo: sys$qiow",
  2995.         sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2996.                  &wrk_iosb, 0, 0, s, x, 0, 0, 0, 0))) return(-1);
  2997.     return(0);
  2998. }
  2999.  
  3000. /*  C O N O L  --  Write a line to the console terminal  */
  3001.  
  3002. int
  3003. conol(s) char *s; {
  3004.     int len;
  3005.  
  3006.     if (!itsatty || !initflg)
  3007.       fputs(s, stdout);
  3008.     else {
  3009.         len = strlen(s);
  3010.         if (!CHECK_ERR("conol: sys$qiow",
  3011.             sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb,
  3012.                      0, 0, s, len, 0, 0, 0, 0))) return(-1);
  3013.     }
  3014.     return(1);
  3015. }
  3016.  
  3017. /*  C O N O L A  --  Write an array of lines to console, with CRLFs added */
  3018.  
  3019. int
  3020. conola(s) char *s[]; {
  3021.     int i;
  3022.     char t[100], *cp;
  3023.  
  3024.     for (i = 0; *s[i] ; i++) {
  3025.         ckstrncpy(t,s[i],100);
  3026.         for (cp = t + strlen(t); --cp >= t;) {
  3027.             if (*cp != '\n' && *cp != '\r') {
  3028.                 cp++;
  3029.                 *cp++ = '\r'; *cp++ = '\n'; *cp++ = '\0';
  3030.                 break;
  3031.             }
  3032.         }
  3033.         if (conol(t) < 0) return(-1);
  3034.     }
  3035.     return(0);
  3036. }
  3037.  
  3038. /*  C O N O L L  --  Output a string followed by CRLF  */
  3039.  
  3040. int
  3041. conoll(s) char *s; {
  3042.     int x;
  3043.     x = conol(s);
  3044.     if (x > -1)
  3045.       x = conol("\r\n");
  3046.     return(x);
  3047. }
  3048.  
  3049. /*  C O N C H K  --  Check if characters available at console  */
  3050.  
  3051. int
  3052. conchk() {
  3053.     struct {
  3054.         unsigned short count;
  3055.         unsigned char first;
  3056.         unsigned char reserved1;
  3057.         long reserved2;
  3058.         } t;
  3059.  
  3060.     if (!itsatty || !initflg)
  3061.       return(0);
  3062.     return(CHECK_ERR("conchk: sys$qiow",
  3063.         sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, &wrk_iosb,
  3064.                  0, 0, &t, sizeof(t), 0, 0, 0, 0)) ? t.count : 0);
  3065. }
  3066.  
  3067. /*  C O N I N C  --  Get a character from the console  */
  3068.  
  3069. int
  3070. coninc(timo) int timo; {                /* Timo > 0 = timeout in seconds. */
  3071.     int n = 0;
  3072.     unsigned char ch;
  3073.     int func, mask;
  3074.  
  3075.     debug(F101,"coninc timo","",timo);
  3076.     debug(F101,"coninc con_queued","",con_queued);
  3077.  
  3078.     if (!itsatty || !initflg)           /* (was "if (batch || !initflg)" */
  3079.       return(getchar());
  3080.  
  3081.     mask = 1 << CON_EFN;
  3082.  
  3083.     if (con_queued) {           /* If a console read was already posted... */
  3084.                                 /* e.g. by contti() ... */
  3085.         if (timo > 0) {                     /* If a timeout was specified... */
  3086.             struct { int hi, lo; } qtime;   /* Set a timer... */
  3087.             qtime.hi = -10*1000*1000*timo;  /* in VMS "delta-time" notation. */
  3088. /*
  3089.   If the timo value is big enough to make the delta-time overflow an integer,
  3090.   substitute something useful.
  3091. */
  3092.             if (qtime.hi > 0)           /* Did it go positive? */
  3093.               qtime.hi = -0x7fffffff;   /* Yes, so fudge it. */
  3094.             qtime.lo = -1;
  3095.             sys$setimr(TIM_EFN, &qtime, 0, 0, 0); /* Specify event flag. */
  3096.             mask |= TIM_EFN;            /* And add it to read mask. */
  3097.         }
  3098.         sys$wflor(CON_EFN, mask);       /* Wait for SETIMR to complete. */
  3099.         sys$readef(CON_EFN, &mask);     /* Read event flags. */
  3100.         if (mask & (1 << CON_EFN)) {    /* We got a console event? */
  3101.             ch = (unsigned char) conch; /* (see contti() about this...) */
  3102.             CHECK_ERR("coninc: coniosb.status", coniosb.status);
  3103.             con_queued = 0;
  3104.         } else {                        /* We didn't */
  3105.             ch = -1;                    /* So indicate that coninc() ... */
  3106.             vms_status = SS$_TIMEOUT;   /*  timed out. */
  3107.         }
  3108.     } else {                            /* Console read not already posted */
  3109.         func = IO$_READVBLK | IO$M_NOFILTR;
  3110.         if (timo > 0) func |= IO$M_TIMED;
  3111.         CHECK_ERR("coninc: sys$qiow",
  3112.           sys$qiow(QIOW_EFN, conchn, func, &wrk_iosb,0,0,&ch,1,timo,0,0,0));
  3113.     }
  3114.     if (vms_status & 1) {
  3115.         if (wrk_iosb.status == SS$_TIMEOUT)
  3116.           return(-1);
  3117.         else return((ch == '\r') ? '\n' : (unsigned)ch);
  3118.     } else return(-1);
  3119. }
  3120.  
  3121. /*  V M S _ G E T C H A R -- get a character from the console (no echo).
  3122.  *      Since we use raw reads, we must check for ctrl/c, ctrl/y and
  3123.  *      ctrl/z ourselves.  We probably should post a "mailbox" for
  3124.  *      ctrl/c and ctrl/y so the poor user can abort a runaway Kermit.
  3125.  *      Note: this routine intends for ctrl/z (eof) to be "permanent".
  3126.  *      Currently, no kermit routine calls "clearerror".  If this
  3127.  *      changes, the following code must be rewritten.
  3128.  */
  3129.  
  3130. int
  3131. vms_getchar() {
  3132.     register unsigned int ch;
  3133.     static int ateof = 0;
  3134.  
  3135.     if (ateof)
  3136.       return (EOF);
  3137.     ch = coninc(0);
  3138.     switch (ch) {
  3139.       case ('Y' - 64):
  3140.       case ('C' - 64):
  3141. #ifndef COMMENT
  3142. /*
  3143.   Just call the same handler that signal(SIGINT,xxx) would have invoked
  3144.   if Ctrl-C had been trapped.  The pointer to the handler was saved in
  3145.   cctrap by conint().
  3146. */
  3147.         if (cctrap)
  3148.           (*cctrap)(SIGINT,0);
  3149. #else
  3150.         ttclos(ttyfd);                  /* Close down other terminal    */
  3151.         conres();                       /* And cleanup console modes    */
  3152.         exit(SS$_ABORT);                /* Fatal exit.                  */
  3153. #endif /* COMMENT */
  3154.       case ('Z' - 64):
  3155.         ateof = 1;
  3156.         return (EOF);
  3157.  
  3158.       default:
  3159.         return (ch);
  3160.     }
  3161. }
  3162.  
  3163. /*  C O N T T I  --  Get character from console then from tty  */
  3164. /*
  3165.   This is used in conect() when NO_FORK is defined.
  3166.   src is returned with 1 if the character came from the comm. line,
  3167.   0 if it was from the console, and with -1 if there was any error.
  3168. */
  3169. #ifdef TCPIPLIB
  3170. /*
  3171.  * Network/console read posted?
  3172.  */
  3173. static int      nettty_queued   = 0;
  3174. static int      netcon_queued   = 0;
  3175. #endif /* TCPIPLIB */
  3176.  
  3177. #ifdef CK_SSL
  3178. #ifdef TCPIPLIB
  3179. int
  3180. ssl_contti(c, src) int *c, *src; {
  3181.  
  3182. #ifdef CMU_TCPIP
  3183.     int s;                                      /* select status */
  3184.     fd_set exceptfds;                           /* select exceptions */
  3185.     fd_set readfds;                             /* select read */
  3186.     static struct timeval timeout;              /* for non-blocking select */
  3187. #endif /* CMU_TCPIP */
  3188.  
  3189. #define NET_EFN 7                               /* Network event flag */
  3190.  
  3191.     int                         mask;           /* Event flag mask */
  3192.  
  3193.     static CHAR                 concc;          /* Console and network data */
  3194.     static CHAR                 netcc;
  3195.  
  3196.     static struct iosb_struct   net_iosb;
  3197.     static struct iosb_struct   con_iosb;       /* IO status blocks */
  3198.  
  3199. /* Buffered network data, count, next character.  Declared in CKCNET.C ... */
  3200.  
  3201.     extern CHAR                 ttibuf[];
  3202.     extern int                  ttibn;
  3203.     extern int                  ttibp;
  3204. #ifdef NETLEBUF
  3205.     /* See NETLEBUF in ckcnet.h and ckcnet.c */
  3206.     extern int                  ttpush, le_data;
  3207. #endif /* NETLEBUF */
  3208.     int                         avail;
  3209.  
  3210. #ifdef DEBUG
  3211.     if (deblog) {
  3212.         debug(F101,"ssl_contti: network","",network);
  3213.         debug(F101,"ssl_contti: ttyfd","",ttyfd);
  3214.         debug(F101,"ssl_contti: ttychn","",ttychn);
  3215.     }
  3216. #endif /* DEBUG */
  3217.  
  3218.     *src = -1;                          /* Assume there was an error */
  3219.  
  3220.     if (network && ttyfd < 0)           /* Make sure we're not called */
  3221.       return(-1);                       /* out of context... */
  3222.     if (!network && !ttychn)
  3223.       return(-1);
  3224.     if (!(ssl_active_flag || tls_active_flag))
  3225.       return(-1);
  3226.  
  3227.     debug(F100,"ssl_contti: network","",0);
  3228.     debug(F101,"ssl_contti: ttibn","",ttibn);
  3229.     debug(F101,"ssl_contti: ttpush","",ttpush);
  3230.     debug(F101,"ssl_contti: le_data","",le_data);
  3231.  
  3232.     /*
  3233.      * Handle the case where data remains in our "internal" buffer.
  3234.      * We need to:
  3235.      *
  3236.      *      -- Handle the console keyboard (is a character ready?)
  3237.      *      -- Return one character from the network buffer if not
  3238.      *
  3239.      * Post a new console read if necessary
  3240.      */
  3241.     if (!netcon_queued) {
  3242. #ifdef CMU_TCPIP
  3243.     cmu_stdin_read(IO$_READVBLK, &concc, 1, 0, 0);
  3244. #else
  3245.     debug(F100,"ssl_contti: sys$qio conchn 1","",0);
  3246.     if (!CHECK_ERR("ssl_contti: console sys$qio",
  3247.             sys$qio(CON_EFN, conchn, IO$_READVBLK,
  3248.                  &con_iosb, 0, 0, &concc,
  3249.                  1, 0, 0, 0, 0))) {
  3250.         debug(F100,"ssl_contti: sys$qio conchn 1 fails","",0);
  3251.         return(*c = -1);
  3252.     }
  3253.     debug(F100,"ssl_contti: sys$qio conchn 2","",0);
  3254. #endif /* CMU_TCPIP */
  3255.     netcon_queued = 1;
  3256.     }
  3257.  
  3258.     /* Console char ready? */
  3259. #ifdef CMU_TCPIP
  3260.     FD_ZERO(&exceptfds);
  3261.     FD_SET(0,&exceptfds);
  3262.     FD_ZERO(&readfds);
  3263.     FD_SET(0,&readfds);
  3264. #ifdef CMU_TCPIP_BOGUS_SELECT
  3265.     if (select(1, &readfds, 0, &exceptfds, &timeout) == 1)
  3266.     if (FD_ISSET(0,&exceptfds))
  3267.         return(*c = -1);
  3268.     netcon_queued = 0;
  3269.     *c   = (unsigned)(concc & 0xff);
  3270.     *src = 0;
  3271.     return(1);
  3272. #else   /* CMU_TCPIP_BOGUS_SELECT (wjm 02-feb-1997) */
  3273.     /* non-blocking select() - zero timeout */
  3274.     switch(select(1, &readfds, 0, &exceptfds, &timeout)) {
  3275.     case 1:       /* console ready */
  3276.     netcon_queued = 0;                  /* QIO completed */
  3277.     *src = 0;
  3278.     if (!(FD_ISSET(0,&exceptfds))) {    /* o.k. */
  3279.         *c = (unsigned)(concc & 0xff);
  3280.         return(1);
  3281.     } else                              /* I/O error */
  3282.         return(*c = -1);
  3283.  
  3284.     case 0:       /* timeout (no console input) */
  3285.     break;
  3286.  
  3287.     default:      /* select() error */
  3288.     return(*c = -1);            /* shouldn't get here */
  3289.     }
  3290. #endif /* CMU_TCPIP_BOGUS_SELECT (wjm 02-feb-1997) */
  3291. #else /* CMU_TCPIP */
  3292.     (void) sys$readef(CON_EFN, &mask);
  3293.     if (mask & (1 << CON_EFN)) {
  3294.     netcon_queued = 0;
  3295.     if (!CHECK_ERR("ssl_contti: con_iosb.status",
  3296.             con_iosb.status)) {
  3297.         debug(F100,"ssl_contti: con_iosb.status fails","",0);
  3298.         return(*c = -1);
  3299.     }
  3300.     *c = (unsigned)(concc & 0xff);
  3301.     *src = 0;
  3302.     return(1);
  3303.     }
  3304. #endif /* CMU_TCPIP */
  3305.     /*
  3306.      * No console data; return buffered network character
  3307.      */
  3308.  
  3309.     avail = nettchk();
  3310.     debug(F101,"ssl_contti: nettchk","",avail);
  3311.     if (avail > 0) {
  3312.     *c = netinc(0);              /* See ttbufr() in ckcnet.c */
  3313.     return(*src = (*c > -1) ? 1 : 0);
  3314.     } else if (avail < 0) {
  3315.     return(*src = -1);
  3316.     }
  3317.     /* all clear up to here - jaltman */
  3318.  
  3319.     /*
  3320.      * No buffered data; post network and console reads
  3321.      */
  3322.     debug(F101,"ssl_contti: nettty_queued","",nettty_queued);
  3323.     if (!nettty_queued) {
  3324. #ifdef CMU_TCPIP
  3325.  
  3326. /* Network read is always posted */
  3327.  
  3328. #else /* CMU_TCPIP */
  3329.  
  3330. /*     -lt.  1992-09-14  begin */
  3331. /* All the event flag numbers should be obtained using lib$get_ef().
  3332.  * Using hard coded numbers, especially < 31 is tres dangereuse!!!
  3333.  * Be careful, one must also change the event flag cluster used by
  3334.  * sys$readef. It is *not* just a simple matter of changing a few #defines.
  3335.  *
  3336.  * At least for DEC TCP/IP Services, socket calls return a proper file
  3337.  * descriptor (fd).  OpenVMS system services require a channel
  3338.  * (from sys$assign).  The two are *not* the same.  The call vaxc$get_sdc()
  3339.  * maps from a DEC TCP/IP fd to a channel.
  3340.  *
  3341.  * This is "gag me with a spoon" code, but it gets thing up and running.
  3342.  *
  3343.  */
  3344. #ifdef DEC_TCPIP
  3345.     {
  3346.         static int last_ttyfd = -1;
  3347.         static short int net_chan = -1;
  3348.  
  3349.         if (ttyfd != last_ttyfd) {
  3350.         last_ttyfd = ttyfd;
  3351.         net_chan = GET_SDC(last_ttyfd);
  3352.         }
  3353.         if (!CHECK_ERR("ssl_contti: network sys$qio",
  3354.                 sys$qio(NET_EFN, net_chan, IO$_READVBLK,
  3355.                      &net_iosb, 0, 0,
  3356.                      &netcc, 1, 0, INET$C_MSG_PEEK, 0, 0))) {
  3357.         debug(F100,"ssl_contti: network sys$qio net_chan fails","",0);
  3358.         return(*c = -1);
  3359.         }
  3360.     }
  3361. #else /* Not DEC_TCPIP */
  3362.     if (!CHECK_ERR("ssl_contti: network sys$qio",
  3363.             sys$qio(NET_EFN, ttyfd, IO$_READVBLK, &net_iosb,
  3364.                  0, 0, &netcc, 0, 0, INET$C_MSG_PEEK, 0, 0))) {
  3365.         debug(F100,"ssl_contti: network sys$qio ttyfd fails","",0);
  3366.         return(*c = -1);
  3367.     }
  3368. #endif /* DEC_TCPIP */
  3369. #endif /* CMU_TCPIP */
  3370.     nettty_queued = 1;
  3371.     }
  3372.  
  3373.     debug(F101,"ssl_contti: netcon_queued","",netcon_queued);
  3374.     if (!netcon_queued) {
  3375. #ifdef CMU_TCPIP
  3376.     cmu_stdin_read(IO$_READVBLK, &concc, 1, 0, 0);
  3377. #else
  3378.     if (!CHECK_ERR("ssl_contti: console sys$qio",
  3379.             sys$qio(CON_EFN, conchn, IO$_READVBLK, &con_iosb,
  3380.                  0, 0, &concc, 1, 0, 0, 0, 0))) {
  3381.         debug(F100,"ssl_contti: console sys$qio fails","",0);
  3382.         return(*c = -1);
  3383.     }
  3384. #endif /* CMU_TCPIP */
  3385.     netcon_queued = 1;
  3386.     }
  3387.     /*
  3388.      * Wait for a character
  3389.      */
  3390. #ifdef CMU_TCPIP
  3391.     debug(F100,"CMU_TCPIP","",0);
  3392.     FD_ZERO(&exceptfds);
  3393.     FD_SET(0,&exceptfds);
  3394.     FD_SET(ttyfd,&exceptfds);
  3395.     FD_ZERO(&readfds);
  3396.     FD_SET(0,&readfds);
  3397.     FD_SET(ttyfd,&readfds);
  3398.     s = select(ttyfd+1, &readfds, 0, &exceptfds, 0); /*a blocking select*/
  3399.     if (s <= 0)
  3400.     return(-1);
  3401.  
  3402.     if (FD_ISSET(0,&exceptfds))
  3403.     return(-1);
  3404.  
  3405.     if (FD_ISSET(ttyfd,&exceptfds))
  3406.     return(-1);
  3407.  
  3408.     if (FD_ISSET(0,&readfds)) {
  3409.     *c            = (unsigned)(concc & 0xff);
  3410.     *src          = 0;
  3411.     netcon_queued = 0;
  3412.     } else {
  3413.     if (FD_ISSET(ttyfd,&readfds)) {
  3414.         *c = netinc(0);
  3415.         if (*c < 0)
  3416.         return(-1);
  3417.         *src      = 1;
  3418.         nettty_queued = 0;
  3419.         return(1);
  3420.     }
  3421.     }
  3422. #else /* CMU_TCPIP */
  3423.     debug(F100,"not CMU_TCPIP","",0);
  3424.     mask = (1 << CON_EFN) | (1 << NET_EFN);
  3425.  
  3426.     if (!CHECK_ERR("ssl_contti: sys$wflor", sys$wflor(CON_EFN, mask))) {
  3427.     debug(F100,"ssl_contti: sys$wflor fails", "", 0);
  3428.     return(*c = -1);
  3429.     }
  3430.     if (!CHECK_ERR("ssl_contti: sys$readef",sys$readef(CON_EFN, &mask))) {
  3431.     debug(F100,"ssl_contti: sys$readef fails", "", 0);
  3432.     return(*c = -1);
  3433.     }
  3434.     if (mask & (1 << CON_EFN)) {    /* Console */
  3435.     if (!CHECK_ERR("ssl_contti: con_iosb.status", con_iosb.status)) {
  3436.         debug(F100,"ssl_contti: con_iosb.status fails","",0);
  3437.         return(-1);
  3438.     }
  3439.     *c = (unsigned)(concc & 0xff);
  3440.     *src = 0;
  3441.     netcon_queued = 0;
  3442.     }
  3443.     else if (mask & (1 << NET_EFN)) { /* Network */
  3444.     if (!(net_iosb.status & 1)) { /* Read error */
  3445. #ifdef WINTCP
  3446. #ifdef OLD_TWG
  3447.         perror("ssl_contti: net_iosb.status");
  3448. #else
  3449.         _$set_vaxc_error(SS$_NORMAL, net_iosb.status);
  3450.         win$perror("ssl_contti: net_iosb.status");
  3451. #endif /* OLD_TWG */
  3452. #endif /* WINTCP */
  3453.         debug(F100,"ssl_contti: network read error", "", 0);
  3454.         return(*c = -1);
  3455.     }
  3456.     debug(F101,"ssl_contti: net_iosb.size","",net_iosb.size);
  3457.     if (net_iosb.size == 0) {   /* Handle reset from remote */
  3458.         debug(F100,"ssl_contti: network reset from remote", "", 0);
  3459.         return(*c = -1);
  3460.     }
  3461.     /* We ignore the character we peeked at and call the net code */
  3462.     debug(F100,"ssl_contti: calling netinc(0)","",0);
  3463.     *c = netinc(0);
  3464.     *src = 1;
  3465.     nettty_queued = 0;
  3466.     }
  3467. #endif /* CMU_TCPIP */
  3468.  
  3469.     debug(F101,"ssl_contti *src","",*src);
  3470.     return((*src > -1) ? 1 : 0);
  3471. }
  3472. #endif /* TCPIPLIB */
  3473. #endif /* CK_SSL */
  3474.  
  3475. int
  3476. contti(c, src) int *c, *src; {
  3477.  
  3478. #ifndef TCPIPLIB
  3479.     int mask = 1<<CON_EFN | 1<<TTY_EFN;
  3480.     int x; unsigned char cc;
  3481.  
  3482. #else /* TCPIPLIB */
  3483.  
  3484. #ifdef CMU_TCPIP
  3485.     int s;                                      /* select status */
  3486.     fd_set exceptfds;                           /* select exceptions */
  3487.     fd_set readfds;                             /* select read */
  3488.     static struct timeval timeout;              /* for non-blocking select */
  3489. #endif /* CMU_TCPIP */
  3490.  
  3491. #define NET_EFN 7                               /* Network event flag */
  3492.  
  3493.     int                         mask;           /* Event flag mask */
  3494.  
  3495.     static CHAR                 concc;          /* Console and network data */
  3496.     static CHAR                 netcc;
  3497.  
  3498.     static struct iosb_struct   net_iosb;
  3499.     static struct iosb_struct   con_iosb;       /* IO status blocks */
  3500.  
  3501. /* Buffered network data, count, next character.  Declared in CKCNET.C ... */
  3502.  
  3503.     extern CHAR                 ttibuf[];
  3504.     extern int                  ttibn;
  3505.     extern int                  ttibp;
  3506. #ifdef NETLEBUF
  3507.     /* See NETLEBUF in ckcnet.h and ckcnet.c */
  3508.     extern int                  ttpush, le_data;
  3509. #endif /* NETLEBUF */
  3510. #endif /* TCPIPLIB */
  3511.  
  3512. #ifdef DEBUG
  3513.     if (deblog) {
  3514.         debug(F101,"contti: network","",network);
  3515.         debug(F101,"contti: ttyfd","",ttyfd);
  3516.         debug(F101,"contti: ttychn","",ttychn);
  3517.     }
  3518. #endif /* DEBUG */
  3519.  
  3520.     *src = -1;                          /* Assume there was an error */
  3521.  
  3522.     if (network && ttyfd < 0)           /* Make sure we're not called */
  3523.       return(-1);                       /* out of context... */
  3524.     if (!network && !ttychn)
  3525.       return(-1);
  3526.  
  3527. #ifdef TCPIPLIB
  3528.     if (network) {                      /* For active network connections */
  3529.         debug(F100,"contti: network","",0);
  3530.         debug(F101,"contti: ttibn","",ttibn);
  3531.  
  3532.         if (ttibn > 0 || ttpush > 0 || le_data > 0) {
  3533.                 /*
  3534.                  * Handle the case where data remains in our "internal" buffer.
  3535.                  * We need to:
  3536.                  *
  3537.                  *      -- Handle the console keyboard (is a character ready?)
  3538.                  *      -- Return one character from the network buffer if not
  3539.                  *
  3540.                  * Post a new console read if necessary
  3541.                  */
  3542.                 if (!netcon_queued) {
  3543. #ifdef CMU_TCPIP
  3544.                         cmu_stdin_read(IO$_READVBLK, &concc, 1, 0, 0);
  3545. #else
  3546.                         debug(F100,"contti: sys$qio conchn 1","",0);
  3547.                         if (!CHECK_ERR("contti: console sys$qio",
  3548.                                        sys$qio(CON_EFN, conchn, IO$_READVBLK,
  3549.                                                &con_iosb, 0, 0, &concc,
  3550.                                                1, 0, 0, 0, 0))) {
  3551.                             debug(F100,"contti: sys$qio conchn 1 fails","",0);
  3552.                             return(*c = -1);
  3553.                         }
  3554.                         debug(F100,"contti: sys$qio conchn 2","",0);
  3555. #endif /* CMU_TCPIP */
  3556.                         netcon_queued = 1;
  3557.                 }
  3558.                 /* Console char ready? */
  3559. #ifdef CMU_TCPIP
  3560.                 FD_ZERO(&exceptfds);
  3561.                 FD_SET(0,&exceptfds);
  3562.                 FD_ZERO(&readfds);
  3563.                 FD_SET(0,&readfds);
  3564. #ifdef CMU_TCPIP_BOGUS_SELECT
  3565.                 if (select(1, &readfds, 0, &exceptfds, &timeout) == 1)
  3566.                   if (FD_ISSET(0,&exceptfds))
  3567.                     return(*c = -1);
  3568.                 netcon_queued = 0;
  3569.                 *c   = (unsigned)(concc & 0xff);
  3570.                 *src = 0;
  3571.                 return(1);
  3572. #else   /* CMU_TCPIP_BOGUS_SELECT (wjm 02-feb-1997) */
  3573.                 /* non-blocking select() - zero timeout */
  3574.                 switch(select(1, &readfds, 0, &exceptfds, &timeout)) {
  3575.                   case 1:       /* console ready */
  3576.                     netcon_queued = 0;                  /* QIO completed */
  3577.                     *src = 0;
  3578.                     if (!(FD_ISSET(0,&exceptfds))) {    /* o.k. */
  3579.                         *c = (unsigned)(concc & 0xff);
  3580.                         return(1);
  3581.                     } else                              /* I/O error */
  3582.                         return(*c = -1);
  3583.  
  3584.                   case 0:       /* timeout (no console input) */
  3585.                     break;
  3586.  
  3587.                   default:      /* select() error */
  3588.                     return(*c = -1);            /* shouldn't get here */
  3589.                 }
  3590. #endif /* CMU_TCPIP_BOGUS_SELECT (wjm 02-feb-1997) */
  3591. #else
  3592.                 (void) sys$readef(CON_EFN, &mask);
  3593.                 if (mask & (1 << CON_EFN)) {
  3594.                     netcon_queued = 0;
  3595.                     if (!CHECK_ERR("contti: con_iosb.status",
  3596.                                    con_iosb.status)) {
  3597.                         debug(F100,"contti: con_iosb.status fails","",0);
  3598.                         return(*c = -1);
  3599.                     }
  3600.                     *c = (unsigned)(concc & 0xff);
  3601.                     *src = 0;
  3602.                     return(1);
  3603.                 }
  3604. #endif /* CMU_TCPIP */
  3605.                 /*
  3606.                  * No console data; return buffered network character
  3607.                  */
  3608. #ifdef NETLEBUF
  3609.                 if (ttpush > 0 || le_data > 0) { /* See NETLEBUF in ckcnet.c */
  3610.                     *c = netinc(0);     /* See ttbufr() in ckcnet.c */
  3611.                 } else {
  3612. #endif /* NETLEBUF */
  3613.                     ttibn--;
  3614.                     *c   = (unsigned)(ttibuf[ttibp++]);
  3615. #ifdef NETLEBUF
  3616.                 }
  3617. #endif /* NETLEBUF */
  3618.                 *src = 1;
  3619.                 return(1);
  3620.         }
  3621.         /*
  3622.          * No buffered data; post network and console reads
  3623.          */
  3624.         debug(F101,"contti: nettty_queued","",nettty_queued);
  3625.         if (!nettty_queued) {
  3626.  
  3627. /* Another attempt by fdc to catch a broken connection. */
  3628.  
  3629.             int x;
  3630.             x = nettchk();
  3631.             debug(F101,"contti: nettchk","",x);
  3632.             if (x < 0) {
  3633.                 return(*src = x);
  3634.             }
  3635. #ifdef CMU_TCPIP
  3636.  
  3637. /* Network read is always posted */
  3638.  
  3639. #else
  3640.  
  3641. /*     -lt.  1992-09-14  begin */
  3642. /* All the event flag numbers should be obtained using lib$get_ef().
  3643.  * Using hard coded numbers, especially < 31 is tres dangereuse!!!
  3644.  * Be careful, one must also change the event flag cluster used by
  3645.  * sys$readef. It is *not* just a simple matter of changing a few #defines.
  3646.  *
  3647.  * At least for DEC TCP/IP Services, socket calls return a proper file
  3648.  * descriptor (fd).  OpenVMS system services require a channel
  3649.  * (from sys$assign).  The two are *not* the same.  The call vaxc$get_sdc()
  3650.  * maps from a DEC TCP/IP fd to a channel.
  3651.  *
  3652.  * This is "gag me with a spoon" code, but it gets thing up and running.
  3653.  *
  3654.  */
  3655. #ifdef DEC_TCPIP
  3656.             {
  3657.                 static int last_ttyfd = -1;
  3658.                 static short int net_chan = -1;
  3659.  
  3660.                 if (ttyfd != last_ttyfd) {
  3661.                     last_ttyfd = ttyfd;
  3662. #ifdef COMMENT
  3663. #ifdef __DECC
  3664.                     net_chan = (short) decc$get_sdc(last_ttyfd);
  3665. #else
  3666. #ifdef VAXC
  3667.                     net_chan = vaxc$get_sdc(last_ttyfd);
  3668. #else
  3669. # error CALL TO GET_SDC requires DECC or VAXC compiler!
  3670. #endif  /* VAXC */
  3671. #endif  /* DECC */
  3672. #else /* COMMENT */
  3673.                     net_chan = GET_SDC(last_ttyfd);
  3674. #endif /* COMMENT */
  3675.                 }
  3676.                 if (!CHECK_ERR("contti: network sys$qio",
  3677.                                sys$qio(NET_EFN, net_chan, IO$_READVBLK,
  3678.                                        &net_iosb, 0, 0,
  3679.                                        &netcc, 1, 0, 0, 0, 0))) {
  3680.                     debug(F100,"contti: network sys$qio net_chan fails","",0);
  3681.                     return(*c = -1);
  3682.                 }
  3683.             }
  3684.  
  3685. #else /* Not DEC_TCPIP */
  3686.             if (!CHECK_ERR("contti: network sys$qio",
  3687.                            sys$qio(NET_EFN, ttyfd, IO$_READVBLK, &net_iosb,
  3688.                                    0, 0, &netcc, 1, 0, 0, 0, 0))) {
  3689.                 debug(F100,"contti: network sys$qio ttyfd fails","",0);
  3690.                 return(*c = -1);
  3691.             }
  3692. #endif /* DEC_TCPIP */
  3693. #endif /* CMU_TCPIP */
  3694.             nettty_queued = 1;
  3695.         }
  3696.         if (!netcon_queued) {
  3697. #ifdef CMU_TCPIP
  3698.             cmu_stdin_read(IO$_READVBLK, &concc, 1, 0, 0);
  3699. #else
  3700.             if (!CHECK_ERR("contti: console sys$qio",
  3701.                            sys$qio(CON_EFN, conchn, IO$_READVBLK, &con_iosb,
  3702.                                    0, 0, &concc, 1, 0, 0, 0, 0))) {
  3703.                 debug(F100,"contti: console sys$qio fails","",0);
  3704.                 return(*c = -1);
  3705.             }
  3706. #endif /* CMU_TCPIP */
  3707.             netcon_queued = 1;
  3708.         }
  3709.         /*
  3710.          * Wait for a character
  3711.          */
  3712. #ifdef CMU_TCPIP
  3713.         FD_ZERO(&exceptfds);
  3714.         FD_SET(0,&exceptfds);
  3715.         FD_SET(ttyfd,&exceptfds);
  3716.         FD_ZERO(&readfds);
  3717.         FD_SET(0,&readfds);
  3718.         FD_SET(ttyfd,&readfds);
  3719.         s = select(ttyfd, &readfds, 0, &exceptfds, 0); /*a blocking select*/
  3720.  
  3721.         if (FD_ISSET(0,&exceptfds))
  3722.             return(-1);
  3723.  
  3724.         if (FD_ISSET(ttyfd,&exceptfds))
  3725.             return(-1);
  3726.  
  3727.         if (FD_ISSET(0,&readfds)) {
  3728.             *c            = (unsigned)(concc & 0xff);
  3729.             *src          = 0;
  3730.             netcon_queued = 0;
  3731.         } else {
  3732.             if (FD_ISSET(ttyfd,&readfds)) {
  3733.                 s = cmu_read(ttyfd, &netcc, 1);
  3734.                 if (s <= 0)
  3735.                     return(-1);
  3736.                 *c        = (unsigned)(netcc & 0xff);
  3737.                 *src      = 1;
  3738.                 nettty_queued = 0;
  3739.             }
  3740.         }
  3741. #else
  3742.         mask = (1 << CON_EFN) | (1 << NET_EFN);
  3743.  
  3744.         if (!CHECK_ERR("contti: sys$wflor", sys$wflor(CON_EFN, mask))) {
  3745.             debug(F100,"contti: sys$wflor fails", "", 0);
  3746.             return(*c = -1);
  3747.         }
  3748.         if (!CHECK_ERR("contti: sys$readef",sys$readef(CON_EFN, &mask))) {
  3749.             debug(F100,"contti: sys$readef fails", "", 0);
  3750.             return(*c = -1);
  3751.         }
  3752.         if (mask & (1 << CON_EFN)) {    /* Console */
  3753.             if (!CHECK_ERR("contti: con_iosb.status", con_iosb.status)) {
  3754.                 debug(F100,"contti: con_iosb.status fails","",0);
  3755.                 return(-1);
  3756.             }
  3757.             *c = (unsigned)(concc & 0xff);
  3758.             *src = 0;
  3759.             netcon_queued = 0;
  3760.  
  3761.         } else if (mask & (1 << NET_EFN)) { /* Network */
  3762.             if (!(net_iosb.status & 1)) { /* Read error */
  3763. #ifdef WINTCP
  3764. #ifdef OLD_TWG
  3765.                 perror("contti: net_iosb.status");
  3766. #else
  3767.                 _$set_vaxc_error(SS$_NORMAL, net_iosb.status);
  3768.                 win$perror("contti: net_iosb.status");
  3769. #endif /* OLD_TWG */
  3770. #else
  3771. #ifdef MULTINET
  3772. #ifdef COMMENT
  3773. /*
  3774.   When user hangs up, this prints an unnecessary scary message,
  3775.   like "Operation would block."
  3776. */
  3777.                 socket_perror("contti: net_iosb.status");
  3778. #endif /* COMMENT */
  3779. #endif /* MULTINET */
  3780. #endif /* WINTCP */
  3781.                 debug(F100,"contti: network read error", "", 0);
  3782.                 return(*c = -1);
  3783.             }
  3784.             debug(F101,"contti: net_iosb.size","",net_iosb.size);
  3785.             if (net_iosb.size == 0) {   /* Handle reset from remote */
  3786.                 debug(F100,"contti: network reset from remote", "", 0);
  3787.                 return(*c = -1);
  3788.             }
  3789.             *c = (unsigned)(netcc & 0xff);
  3790.             *src = 1;
  3791.             nettty_queued = 0;
  3792.         }
  3793. #endif /* CMU_TCPIP */
  3794.     } else                              /* Not network */
  3795. #endif /* TCPIPLIB */
  3796.  
  3797. /*
  3798.   Should we worry about a network connection that's running under batch ?
  3799. */
  3800.     if (!itsatty) {                     /* Batch? */
  3801.         debug(F100,"contti batch","",0);
  3802.         if ((*c = getchar()) != EOF) {
  3803.             *src = 0;
  3804.         } else {
  3805.             *src = 1;
  3806.             *c = ttinc(0);
  3807.         }
  3808.     } else {                            /* Interactive but not network */
  3809.  
  3810. #ifdef TTXBUF
  3811.         if (ttxbn > 0) {                /* Buffered port chars available */
  3812.  
  3813. /* Post a read on the console if one is not posted already */
  3814.  
  3815.             if (!con_queued) {
  3816.                 if (!CHECK_ERR("contti: console sys$qio",
  3817.                              sys$qio(CON_EFN, conchn, IO$_READVBLK,
  3818.                                      &coniosb, 0, 0,
  3819.                                      &conch, 1, 0, 0, 0, 0)))
  3820.                   return(-1);
  3821.                 con_queued = 1;
  3822.             }
  3823.  
  3824. /* See if a console character has been read and if so, return it.  */
  3825.  
  3826.             (void) sys$readef(CON_EFN, &mask);
  3827.             if (mask & (1 << CON_EFN)) {
  3828.                 con_queued = 0;
  3829.                 if (!CHECK_ERR("contti: coniosb.status",
  3830.                                coniosb.status))
  3831.                   return(-1);
  3832.                 *c   = (unsigned)(conch & 0xff);
  3833.                 *src = 0;
  3834.                 return(1);
  3835.             }
  3836.  
  3837. /* No console character, so return buffered port character */
  3838.  
  3839.             *c = ttinc(0);
  3840.             *src = 1;
  3841.             return(1);
  3842.         }
  3843.  
  3844. /* No buffered port data; post both network and console reads... */
  3845.  
  3846. #endif /* TTXBUF */
  3847.  
  3848.         mask = 1<<CON_EFN | 1<<TTY_EFN; /* Event mask */
  3849.  
  3850.         debug(F101,"contti interactive mask","",mask);
  3851.  
  3852.         if (!con_queued) {              /* Console read not queued... */
  3853.             if (!CHECK_ERR("contti: console sys$qio",
  3854.                     sys$qio(CON_EFN, conchn, IO$_READVBLK, &coniosb, 0, 0,
  3855.                     &conch, 1, 0, 0, 0, 0))) return(-1);
  3856.             con_queued = 1;
  3857.             debug(F100,"contti con_queued","",0);
  3858.         }
  3859.         if (!tt_queued) {               /* Port read not queued */
  3860.             ttch = -9;                  /* Impossible value */
  3861.             if (!CHECK_ERR("contti: tty sys$qio",
  3862.                            sys$qio(TTY_EFN, ttychn, IO$_READVBLK,
  3863.                                    &ttiosb, 0, 0, &ttch, 1, 0, 0, 0, 0)))
  3864.               return(-1);
  3865.             tt_queued = 1;
  3866.             debug(F100,"contti tt_queued","",0);
  3867.         }
  3868.  
  3869. /* Wait for one of the queued reads to complete */
  3870.  
  3871.         if (!CHECK_ERR("contti: sys$wflor",
  3872.             sys$wflor(CON_EFN, mask))) return(-1);
  3873.         debug(F100,"contti sys$wflor ok","",0);
  3874.  
  3875. /* Read the event flags to see which read was completed */
  3876.  
  3877.         if (!CHECK_ERR("contti: sys$readef",
  3878.             sys$readef(CON_EFN, &mask))) return(-1);
  3879.         debug(F100,"contti sys$readef ok","",0);
  3880.  
  3881. /* Return the character with the appropriate source (src) indicator */
  3882.  
  3883.         if (!(*src = ((mask & 1<<CON_EFN) ? 0 : 1))) {
  3884.             *c = (unsigned)(conch);
  3885.             CHECK_ERR("contti: coniosb.status", coniosb.status);
  3886.             con_queued = 0;
  3887.         } else {
  3888.             *c = (ttprty ? (unsigned)(ttch & 0177) : (unsigned)ttch);
  3889.             if (ttiosb.status == SS$_HANGUP) {
  3890.                 debug(F101,"contti hangup ttch","",ttch);
  3891.                 if (ttcarr != CAR_OFF) {
  3892.                     xhangup = 1;
  3893.                     fprintf(stderr,"\n%%CKERMIT-F-HANGUP, data set hang-up");
  3894.                     *src = -1;
  3895.                     return(1);
  3896.                 } else if (ttch == -9) {
  3897.                     tt_queued = 0;
  3898.                     *src = -2;
  3899.                     return(1);
  3900.                 }
  3901.             } else if (ttiosb.status != SS$_HANGUP) {
  3902.                 CHECK_ERR("contti: ttiosb.status", ttiosb.status);
  3903.             }
  3904.             tt_queued = 0;
  3905.         }
  3906.         if (!(vms_status & 1)) *src = -1;
  3907.     }
  3908.     debug(F101,"contti *src","",*src);
  3909.     return((*src > -1) ? 1 : 0);
  3910. }
  3911.  
  3912. /*
  3913.   C A N C I O
  3914.   Cancel pending I/O requests on console and communication device.
  3915. */
  3916.  
  3917. int
  3918. ck_cancio() {
  3919.  
  3920.     debug(F101,"ck_cancio: ttyfd","",ttyfd);
  3921.     if (network && ttyfd < 0)
  3922.       return(0);
  3923.     debug(F101,"ck_cancio: ttychn","",ttychn);
  3924.     if (!network && !ttychn)
  3925.       return(0);
  3926. #ifdef NETCONN
  3927.     if (network) {
  3928. #ifdef TCPIPLIB
  3929. #ifdef DEC_TCPIP
  3930.         short int net_chan = -1;
  3931.  
  3932.         net_chan = GET_SDC(ttyfd);
  3933.         if (nettty_queued) (void) sys$cancel(net_chan);
  3934.         nettty_queued = 0;              /*+wjm*/
  3935. #else  /* DEC_TCPIP */
  3936. #ifdef CMU_TCPIP
  3937.     /* not going to do this when CMU is the network transport.
  3938.      * the sys$cancel will cause the channel to shutdown
  3939.      *
  3940.      * if (nettty_queued) (void) sys$cancel(cmu_get_sdc(ttyfd));
  3941.      */
  3942. #else  /* !CMU_TCPIP */
  3943.        if (nettty_queued) (void) sys$cancel(ttyfd);
  3944.         nettty_queued = 0;              /*+wjm*/
  3945. #endif /* CMU_TCPIP */
  3946. #endif /* DEC_TCPIP */
  3947.         if (netcon_queued) (void) sys$cancel(conchn);
  3948.         netcon_queued = 0;
  3949.         return(0);
  3950. #else /* Not TCPIPLIB */
  3951.         return(0);
  3952. #endif /* TCPIPLIB */
  3953.     }
  3954. #endif /* NETCONN */
  3955.  
  3956.     if (itsatty) {
  3957.         CHECK_ERR("ck_cancio: console sys$cancel",
  3958.             sys$cancel(conchn));
  3959.         CHECK_ERR("ck_cancio: tty sys$cancel",
  3960.             sys$cancel(ttychn));
  3961.         con_queued = 0;
  3962.         tt_queued = 0;
  3963.     }
  3964.     return(0);
  3965. }
  3966.  
  3967. /* get_qio_maxbuf_size()
  3968.  *
  3969.  * Get maximum size of QIO that can occur without getting the dreaded
  3970.  * exceeded quota status.
  3971.  */
  3972.  
  3973. #ifndef SYI$_MAXBUF
  3974. #define SYI$_MAXBUF 4175
  3975. #endif /* SYI$_MAXBUF */
  3976.  
  3977. int
  3978. get_qio_maxbuf_size(ttychn) unsigned long int ttychn; {
  3979.     unsigned char *tmpbuf;
  3980.     int unsigned long max=0;
  3981.     struct itmlst syiitm[] = { {2,SYI$_MAXBUF,NULL,0},
  3982.                 {0,0,0,0}};
  3983.  
  3984.     syiitm[0].adr = (char *)&max;
  3985.  
  3986.     if (!ttychn) return(-1);
  3987.  
  3988.     if (!CHECK_ERR("get_qio_maxbuf_size: sys$getsyiw",
  3989.         sys$getsyiw(     0      /* efn */
  3990.                         ,0      /* csidadr */
  3991.                         ,0      /* nodename */
  3992.                         ,&syiitm /* itmlst */
  3993.                         ,&wrk_iosb /* iosb */
  3994.                         ,0      /* astadr */
  3995.                         ,0)))   /* astprm */
  3996.                 exit(SS$_ABORT);                /* Fatal exit */
  3997.  
  3998.     if (!(tmpbuf = malloc(max)))
  3999.         return(0);
  4000.  
  4001.     for (; max > 0; max -= 16) {
  4002.         if (!test_qio(ttychn,max,tmpbuf)) /* (was &tmpbuf, caused crash) */
  4003.         {
  4004.             free(tmpbuf);
  4005.             return(max);
  4006.         }
  4007.     }
  4008.  
  4009.     free(tmpbuf);
  4010.     printf("\n%%CKERMIT-F-get_qio_maxbuf_size, Could not get maxbuf size\n");
  4011.     exit(SS$_ABORT);            /* Fatal exit */
  4012. }
  4013.  
  4014. int
  4015. test_qio(ttychn,max,dest)
  4016. unsigned long int ttychn;
  4017. long int max;
  4018. unsigned char *dest;
  4019. {
  4020.     static int trmmsk[2] = {0,0};
  4021.  
  4022. /*    trmmsk[1] = 1 << eol; */
  4023.  
  4024.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED,
  4025.                           &wrk_iosb, 0, 0, dest, max, 0, &trmmsk, 0, 0);
  4026.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  4027.     return( !(vms_status & 1) ||
  4028.         (!(wrk_iosb.status & 1)) && wrk_iosb.status != SS$_TIMEOUT);
  4029. }
  4030.  
  4031.  
  4032. /* Flush communications device output buffer */
  4033.  
  4034. int
  4035. ttfluo() {
  4036.  
  4037.     long n=0;
  4038.  
  4039. #ifdef NETCONN
  4040.     if (network) return(0);
  4041. #endif /* NETCONN */
  4042.  
  4043.     if (!ttychn) return(-1);            /* Not open. */
  4044.  
  4045.     if (!CHECK_ERR("ttfluo: sys$qiow",
  4046.         sys$qiow(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED|IO$M_PURGE,
  4047.                  &wrk_iosb, 0, 0, &n, 0, 0, 0, 0, 0))) {
  4048.         perror("flush failed");
  4049.         return(-1);
  4050.         }
  4051.     return(0);
  4052. }
  4053.  
  4054. /*  T T G M D M  --  Get modem signals  */
  4055. /*
  4056.  Looks for the modem signals CTS, DSR, and CTS, and returns those that are
  4057.  on in as its return value, in a bit mask as described for ttwmdm.  Returns:
  4058.  -3 Not implemented
  4059.  -2 if the line does not have modem control
  4060.  -1 on error.
  4061.  >= 0 on success, with a bit mask containing the modem signals that are on.
  4062. */
  4063. int
  4064. ttgmdm() {
  4065.     struct {
  4066.         unsigned char type;
  4067.         unsigned char spare1;
  4068.         unsigned char modem;
  4069.         unsigned char spare2;
  4070.         unsigned long filler;
  4071.     } mdminfo;
  4072.     int retval;
  4073.  
  4074. #ifdef NETCONN
  4075.     if (network) {
  4076. #ifdef TN_COMPORT
  4077.         if (istncomport())
  4078.           return(tngmdm());
  4079.         else
  4080. #endif /* TN_COMPORT */
  4081.           return(-2);
  4082.     }
  4083. #endif /* NETCONN */
  4084. /*
  4085.   According to the VMS I/O manual, devices that do not have the TT$M_MODEM
  4086.   characteristics can have their modem signals read using IO$M_MAINT.
  4087. */
  4088.     /* This does not work on inbound ports or on LAT devices */
  4089.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE|IO$M_RD_MODEM,
  4090.                           &wrk_iosb, 0, 0, &mdminfo, 0, 0, 0, 0, 0);
  4091.     if (!(vms_status & 1)) vms_lasterr = vms_status;
  4092.     if (vms_status != SS$_NORMAL) {
  4093.         debug(F101,"ttgmdm serious error, status","",vms_status);
  4094.         debug(F101,"ttgmdm ttychn","",ttychn);
  4095.         return(-1);
  4096.     }
  4097.     debug(F101,"ttgmdm iosb","",wrk_iosb.status);
  4098.     debug(F101,"ttgmdm type","",mdminfo.type);
  4099.     debug(F101,"ttgmdm modem","",mdminfo.modem);
  4100.  
  4101.     if (wrk_iosb.status != SS$_NORMAL) {
  4102.         debug(F101,"ttgmdm iosb error, status","",wrk_iosb.status);
  4103.         return(-1);
  4104.     }
  4105.  
  4106. #ifdef DT$_LAT
  4107.     if (mdminfo.type == DT$_LAT) {
  4108.         debug(F101,"ttgmdm LAT port, no modem control","",0);
  4109.         return(-2);
  4110.     }
  4111. #endif /* DT$_LAT */
  4112.  
  4113. #ifndef VMS64BIT            /* This works only on VAX */
  4114. /*
  4115.   It was suggested that we test for TT$M_MODEM here, but if it failed
  4116.   that does not necessarily mean we can't read modem signals.  As of
  4117.   now (12/1997) no reliable test is known that tells whether we can believe
  4118.   the mdminfo.modem bits.  But hopefully we won't get this far in that case.
  4119. */
  4120.     if (mdminfo.type == 0) {
  4121.         debug(F101,"ttgmdm unknown driver, modem","",mdminfo.modem);
  4122.         return(-2);
  4123.     }
  4124. #endif /* VMS64BIT */
  4125.  
  4126.     retval = BM_DTR | BM_RTS;           /* Not visible, set by TTDRIVER */
  4127.     if (mdminfo.modem & TT$M_DS_CTS)
  4128.         retval |= BM_CTS;
  4129.     if (mdminfo.modem & TT$M_DS_DSR)
  4130.         retval |= BM_DSR;
  4131.     if (mdminfo.modem & TT$M_DS_CARRIER)
  4132.         retval |= BM_DCD;
  4133.     if (mdminfo.modem & TT$M_DS_RING)
  4134.         retval |= BM_RNG;
  4135.     return(retval);
  4136. }
  4137.  
  4138. long
  4139. congspd() {
  4140.     return(conspd);
  4141. }
  4142.  
  4143. /*
  4144.   Return serial communication device speed.  The speed returned is simply
  4145.   the last one set.  Why?  Because VMS apparently provides no method to
  4146.   query the speed.
  4147. */
  4148. long
  4149. ttgspd() {
  4150.     int i;
  4151.     extern int speed;
  4152.     unsigned int vms_speed, s1, s2;
  4153.     long x;
  4154.  
  4155. #ifdef COMMENT
  4156.     struct tt_mode ttmodes;
  4157. #endif /* COMMENT */
  4158.  
  4159.     debug(F101,"ttgspd ttspeed","",ttspeed);
  4160.     debug(F101,"ttgspd network","",network);
  4161.  
  4162. #ifdef NETCONN
  4163.     if (network) {
  4164. #ifdef TN_COMPORT
  4165.         if (istncomport())
  4166.           return(tnc_get_baud());
  4167.         else
  4168. #endif /* TN_COMPORT */
  4169.           return(-1);                   /* -1 if network connection */
  4170.     }
  4171. #endif /* NETCONN */
  4172.  
  4173. #ifdef COMMENT
  4174. /*
  4175.   This looks like it should work and in fact it does -- but it returns
  4176.   the NOMINAL (permanent) speed of the device, not the current speed.
  4177.   So it's useless.  If there is a way to get the actual current speed,
  4178.   I'd like to know what it is.
  4179. */
  4180.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  4181.                           &ttmodes, sizeof(ttmodes), 0, 0, 0, 0);
  4182.     if (vms_status != SS$_NORMAL) {
  4183.         debug(F101,"ttgspd: sys$qiow error","",vms_status);
  4184.         return(-1);
  4185.     }
  4186.     if (wrk_iosb.status != SS$_NORMAL) { /* Error executing request */
  4187.         vms_status = wrk_iosb.status;
  4188.         debug(F101,"ttgspd: sys$qiow iosb error","",wrk_iosb.status);
  4189.         return(-1);
  4190.     }
  4191.     x = ttispd((unsigned char)wrk_iosb.size);
  4192.     if (x > 0)
  4193.       ttspeed = x;
  4194.     else
  4195. #endif /* COMMENT */
  4196.       x = ttspeed;
  4197.     debug(F101,"ttgspd returns","",x);
  4198.     return(x);
  4199. }
  4200.  
  4201. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  4202.  *
  4203.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  4204.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  4205.  *  2 = Auto: For "modem direct": The same as "Off".
  4206.  *            For real modem types: Heed carrier during connect, but ignore
  4207.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  4208.  *
  4209.  * As you can see, this setting does not affect dialing, which always ignores
  4210.  * carrier (unless there is some special exception for some modem type).  It
  4211.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  4212.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  4213.  * (or should be) always called before any communications is tried, which
  4214.  * means that, practically speaking, the effect is immediate.
  4215.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  4216.  */
  4217. int
  4218. ttscarr(carrier) int carrier; {
  4219.     ttcarr = carrier;
  4220.     debug(F101, "ttscarr","",ttcarr);
  4221.     return(ttcarr);
  4222. }
  4223.  
  4224. int
  4225. psuspend(x) int x; {
  4226.  
  4227.     return(-1);
  4228. }
  4229.  
  4230. int
  4231. vmsttyfd() {
  4232.     return(network ? ttyfd : ttychn);
  4233. }
  4234.  
  4235. #ifdef CK_CURSES
  4236. /*
  4237.   tgetent() support for VMS curses emulation.
  4238.   Used by all three VMS fullscreen methods.
  4239.   Called from "SET FILE DISPLAY FULLSCREEN" in ckuus7.c.
  4240. */
  4241. int isvt52 = 0;                         /* VT52/VT1xx flag */
  4242.  
  4243. int
  4244. tgetent(lp, term) char *lp, *term; {
  4245.     debug(F101,"tgetent terminal type","",ccold.type);
  4246.     debug(F101,"tgetent terminal extended","",ccold.extended);
  4247.  
  4248.     if ((ccold.type == DT$_VT5X) || (ccold.type == DT$_VT55)) {
  4249.         debug(F100,"tgetent VT5x","",0);
  4250.         isvt52 = 1;
  4251.         return(1);
  4252.     }
  4253.     if ((ccold.extended & TT2$M_ANSICRT) == TT2$M_ANSICRT) {
  4254.         debug(F100,"tgetent ANSICRT","",0);
  4255.         isvt52 = 0;
  4256.         return(1);
  4257.     }
  4258.     if ((ccold.extended & TT2$M_DECCRT) == TT2$M_DECCRT) {
  4259.         debug(F100,"tgetent DECCRT","",0);
  4260.         isvt52 = 0;
  4261.         return(1);
  4262.     }
  4263.     return(0);                          /* Not a supported terminal type */
  4264. }
  4265. #endif /* CK_CURSES */
  4266.  
  4267. #ifdef CMDATE2TM
  4268. struct tm *
  4269. #ifdef CK_ANSIC
  4270. cmdate2tm(char * date, int gmt)         /* date as "yyyymmdd hh:mm:ss" */
  4271. #else
  4272. cmdate2tm(date,gmt) char * date; int gmt;
  4273. #endif
  4274. {
  4275.     /* date as "yyyymmdd hh:mm:ss" */
  4276.     static struct tm _tm;
  4277.     time_t now;
  4278.  
  4279.     if (strlen(date) != 17 ||
  4280.     date[8] != ' ' ||
  4281.     date[11] != ':' ||
  4282.     date[14] != ':')
  4283.       return(NULL);
  4284.  
  4285.     time(&now);
  4286.     if (gmt)
  4287.       _tm = *gmtime(&now); /* Only returns non-NULL for VMS > 6.x ! */
  4288.     else
  4289.       _tm = *localtime(&now);
  4290.     _tm.tm_year = (date[0]-'0')*1000 + (date[1]-'0')*100 +
  4291.                   (date[2]-'0')*10   + (date[3]-'0')-1900;
  4292.     _tm.tm_mon  = (date[4]-'0')*10   + (date[5]-'0')-1;
  4293.     _tm.tm_mday = (date[6]-'0')*10   + (date[7]-'0');
  4294.     _tm.tm_hour = (date[9]-'0')*10   + (date[10]-'0');
  4295.     _tm.tm_min  = (date[12]-'0')*10  + (date[13]-'0');
  4296.     _tm.tm_sec  = (date[15]-'0')*10  + (date[16]-'0');
  4297.  
  4298.     /* Should we set _tm.tm_isdst to -1 here? */
  4299.  
  4300.     _tm.tm_wday = 0;
  4301.     _tm.tm_yday = 0;
  4302.  
  4303.     return(&_tm);
  4304. }
  4305. #endif /* CMDATE2TM */
  4306.