home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckvtio.c < prev    next >
C/C++ Source or Header  |  1994-10-03  |  98KB  |  3,047 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. #ifdef __ALPHA
  6. # define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) AXP(tm)";
  7. #else
  8. # ifdef VAX
  9. #  module ckvtio "2.0-077"
  10. #  define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) VAX(tm)";
  11. # else
  12. #  ifdef __GNUC__
  13. #   define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) VAX(tm) (GCC)";
  14. #  else
  15. #   error -- CKVTIO.C unknown architecture, neither VAX(tm) nor AXP(tm)
  16. #  endif /* __GNUC__ */
  17. # endif /* VAX */
  18. #endif /* __ALPHA */
  19. /*
  20.   Module version number and date.
  21.   Also update the module number above accordingly.
  22. */
  23. char *ckxv = "Communications I/O 2.0(077), 22 Sep 94";
  24. /*
  25.   This is the default architecture and operating system herald string.
  26.   It is redetermined dynamically in sysinit() below.  
  27. */
  28. char *ckxsys = CKVTIO_OS_ARCH_STRING;
  29.  
  30. /*  C K V T I O  --  Terminal and Interrupt Functions for VAX/VMS  */
  31.  
  32. /* C-Kermit interrupt, terminal control & i/o functions for VMS systems */
  33.  
  34. /*
  35.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  36.   Columbia University Academic Information Systems, New York City.
  37.  
  38.   Copyright (C) 1985, 1994, Trustees of Columbia University in the City of New
  39.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  40.   sold for profit as a software product itself, nor may it be included in or
  41.   distributed with commercial products or otherwise distributed by commercial
  42.   concerns to their clients or customers without written permission of the
  43.   Office of Kermit Development and Distribution, Columbia University.  This
  44.   copyright notice must not be removed, altered, or obscured.
  45. */
  46.  
  47. /* Edit History
  48.  *
  49.  * Originally adapted to VMS by:
  50.  * Stew Rubenstein, Harvard University Chemical Labs, 1985.
  51.  *
  52.  * Cast of characters:
  53.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  54.  * wb  William Bader     Lehigh University
  55.  * mab Mark Buda         Digital (DEC)
  56.  * fdc Frank da Cruz     Columbia U
  57.  * HG  Hunter Goatley    Western Kentucky University
  58.  * jh  James Harvey      Indiana / Purdue University
  59.  * ttj Tarjei T. Jensen  Norwegian Hydrographic Service
  60.  * tmk Terry Kennedy     Saint Peters College
  61.  * MM  Martin Minow      Digital
  62.  * mlo Mike O'Malley     Digital
  63.  * DS  Dan Schullman     Digital
  64.  * js  James Sturdevant
  65.  * LT  Lee Tibbert       Digital
  66.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  67.  * 006  8-May-85 MM   Got rid of "typeahead buffer" code as it didn't
  68.  *              solve the problem of data overruns at 4800 Baud.
  69.  *              Added vms "read a char" routine that checks for
  70.  *              CTRL/C, CTRL/Z, etc.
  71.  * 007 16-May-85 fdc  Changed calling convention of ttopen(), make it
  72.  *                    set value of its argument "lcl", to tell whether
  73.  *                    C-Kermit is in local or remote mode.
  74.  * 008 11 Jun 85 MM   Fix definition of CTTNAM
  75.  * 009 18 Jun 85 fdc  Move def of CTTNAM to ckcdeb.h so it can be shared.
  76.  * 010 25 Jun 85 MM   Added sysinit() to open console.
  77.  * 011  5 Jul 85 DS   Treat hangup of closed line as success.
  78.  * 012 11 Jul 85 fdc  Add gtimer(), rtimer() for timing statistics.
  79.  * 013 14 Sep 87 fdc  Add parity strip to ttinl(), add syscleanup().
  80.  * 014 14 Feb 89 mab  Make break REALLY work.  Add IOSB's to all QIO's.
  81.  * 015 26 Feb 89 mab  Add dcl exit handler and minor cleanup
  82.  * 016 23-Mar-89 mab  Add IO$M_BREAKTHRU to IO$_WRITEVBLK.
  83.  *              Add zchkspd() function to check for valid speed.
  84.  * 017 04-Apr-89 mab  Fix some minor bugs to local/remote code
  85.  * 018 23-Apr-89 mab  Add some of Valerie Mates' parity changes.
  86.  * 019 25-Apr-89 mab  Change baud to 110 for V4.x break routine as
  87.  *               50 baud is not supported on most Muxes by VMS.
  88.  * 020 13-Jun-89 mab  Fix on exquota problem on qiow(readvblk)
  89.  * 021 08-Jul-89 mab  Add ^C/^Y abort server mode code.
  90.  * 022 11-May-90 mab  Add V5A code 
  91.  * 023 20-Jul-90 wb   Add support for old VAX C and VMS versions
  92.  * 024 22-Sep-90 wb   Fixes to cps/bps confusion
  93.  * 025 26-Sep-90 tmk  Fix the ztime() function
  94.  * 026 29-Sep-90 tmk  Edit 024 cause a server command to give some blither-
  95.  *              ings about unsupported line speeds.  Added a simple hack
  96.  *              to exit quietly if the passed speed is 0.  Adventurous
  97.  *              maintainers may want to look in ttpkt(), where ttsspd()
  98.  *              is being called with a value of -1/10.
  99.  * 027 11-Oct-90 fdc  Made ttol return number of chars successfully written.
  100.  *                    Made ztime() use ctime() in all cases.
  101.  *                    Another fix (from tmk) for bps/cps confusion.
  102.  *                    Wrapped source lines longer than 80 characters.
  103.  * 028 18-Oct-90 fdc  Added comments to concb() and vms_getchar() to show
  104.  *                    how to make Ctrl-C trap work.  Didn't actually do it,
  105.  *                    though, because Ctrl-Y apparently still can't be caught.
  106.  *                    Also, more minor reformatting.  Adjust time() declare.
  107.  *                    Added support for automatic parity sense in ttinl(),
  108.  *                    within #ifdef PARSENSE conditionals.  Built with PARSENSE
  109.  *                    defined, works ok.
  110.  * 029  5-Apr-91 fdc  Extensive reworking of many routines to allow for
  111.  *              network connections, addition of TGV MultiNet support.
  112.  * 030 31-Aug-91 tmk  Fix problem with INPUT statements not timing out due to
  113.  *              extraneous rtimer() inside gtimer().
  114.  * 032  6-Nov-91 fdc  Correct parity problem.
  115.  * 032  6-Nov-91 fdc  Cosmetic cleanup in sysinit().
  116.  * 033 14-Jan-91 fdc  Fix to get_qio_maxbuf_size to prevent crashes:
  117.  *                    remove "&" from "!test_qio(ttychn,max,&tmpbuf)",
  118.  *                    from John Schultz at 3M.
  119.  * 034  8-Feb-92 fdc  Don't change EIGHTBIT setting in ttvt, concb, or conbin.
  120.  *                    Set EIGHTBIT in ttpkt only if parity is not NONE.  From
  121.  *                    Alan Robiette, Oxford U, UK.
  122.  * 035 10-Jun-92 fdc  Added code from Ray Hunter of The Wollongong Group to
  123.  *                    support both WIN/TCP and TGV Multinet.  Network section
  124.  *                    of contti() redone to eliminate polling loop.  It's
  125.  *                    infinitely faster.
  126.  * 036 11-Jun-92 tmk  Fixed up edit 034 so 8-bit characters could be passed
  127.  *                    in connect mode.
  128.  * 037 19-Jun-92 fdc  Totally rewrote all the serial input and mode-setting 
  129.  *                    routines in this module to use nonblocking, fully
  130.  *                    buffered input and to share a common buffer.  All
  131.  *                    serial-line input is localized to a single routine,
  132.  *                    txbufr(), which, in turn is known only to ttinc().  The
  133.  *                    other input routines, ttxin() and ttinl(), simply call
  134.  *                    ttinc().  ttchk() and ttflui() are totally cognizant of
  135.  *                    the buffer.  ttinl() now recognizes packets with
  136.  *                    printable start characters and/or lacking terminators,
  137.  *                    so VMS C-Kermit can now engage in "Doomsday Kermit"
  138.  *                    protocol.  ttvt() and ttpkt() were merged into a single
  139.  *                    new (static) routine, ttbin(), which no longer puts the
  140.  *                    device into PASALL mode (which defeats flow control).
  141.  *                    Added ttsndlb() to send a Long BREAK.  Much fine-tuning,
  142.  *                    testing, and filling-in remains to be done, including
  143.  *                    (a) make ttopen() and ttclos() aware of LAT devices; (b)
  144.  *                    check remaining BYTLM quota before issuing a read, (c)
  145.  *                    integrate network and serial buffers, and much more.
  146.  *                    Anyway, this code seems to run faster than ever before,
  147.  *                    and for the first time I can actually use sliding
  148.  *                    windows AND long packets on my 8-year old MicroVAX-II.
  149.  * 038 28-Jun-92 tmk  Additional work on edit 37, general cleanup of old defs.
  150.  * 039  1-Jul-92 wb   Changes for VMS 4.4.
  151.  * 040  4-Jul-92 tmk  Add modem signal support (ttgmdm routine).
  152.  * 041  4-Jul-92 tmk  Add tgetent(), worker routine for el-cheapo curses.
  153.  * 042  4-Jul-92 jh   Enable typeahead in ttbin().
  154.  * 043 21-Aug-92 fdc  Make default flow control be KEEP instead of Xon/Xoff.
  155.  * 044  6-Sep-92 fdc  Put default flow back to Xon/Xoff, but allow KEEP to be
  156.  *                    used to restore device's original flow-control setting.
  157.  * 045 23-Sep-92 fdc  Add sleep(1) to tthang().  Seems to fix HANGUP command.
  158.  *                    Suggested by Lee Tibbert.  Change ttbin() to use global
  159.  *                    flow variable rather than its flow parameter for setting
  160.  *                    flow control, to ensure the desired type of flow control
  161.  *                    is used during DIAL operations.
  162.  * 046 26-Sep-92 fdc  Change sleep(1) in tthang() to sleep(3).  Annoying but
  163.  *                    necessary.  IO$M_HANGUP takes about 3 seconds, but the
  164.  *                    sys$qiow() function returns immediately instead of
  165.  *                    waiting for the action to complete.
  166.  * 047 08-Oct-92 HG   Add call to sys$alloc in ttopen() to prevent user with
  167.  *              SHARE from getting port in use.  Some add'l cleanup.
  168.  * 048 12-Oct-92 LT   Minor changes to support DEC TCP/IP (nee UCX).
  169.  * 049 25-Oct-92 fdc  Adapt cancio() to DEC TCP/IP.
  170.  *                    Remove superfluous ttflui() call from ttpkt().
  171.  *                    Add code from Lee Tibbert to sysinit() to figure out OS
  172.  *                    and architecture name at runtime.
  173.  * 050 18-Nov-92 fdc  Read from comm device in 1024-byte chunks, rather than
  174.  *                    trusting the qio_maxbuf_size.  This should reduce BYTLM
  175.  *                    quota-exceeded errors.  Suggested by tmk as a temporary
  176.  *                    workaround.
  177.  * 051 10-May-93 fdc  Add support for SET TRANSFER CANCELLATION.
  178.  * 052 16-May-93 fdc  Change VMSTCPIP to TCPIPLIB to agree with new CKCNET.H.
  179.  * 053 16-May-93 fdc  ANSIfication for GNU CC, from James Sturdevant.
  180.  * 054 08-Jun-83 fdc  Add TT$M_LOCALECHO and TT$M_ESCAPE to the terminal modes
  181.  *                    we handle, to prevent "getty babble" with modems, VAX
  182.  *                    PSI, etc.
  183.  * 055 16-Jun-93 fdc  Edit 054 only affected ttbin().  This edit does the same
  184.  *                    for conbin() and concb().  Fixes double echoing in
  185.  *                    command mode when coming in via VAX PSI.
  186.  * 056  8-Aug-93 fdc  Add types to all function declarations.
  187.  * 057 17-Aug-93 fdc  Add GET_SDC macro as in CKVIOC.C, accounting for GCC.
  188.  *                    From Tarjei T. Jensen <tarjeij@extern.uio.no>.
  189.  * 058 27-Sep-93 HG   Fix for real the SHARE issue when allocating terminal
  190.  *              by dropping SHARE before trying to assign the channel.
  191.  * 059  7-Oct-93 mlo  Added support for CMU-OpenVMS/IP ("CMU/Tek").  Requires
  192.  *                    CMU-OpenVMS/IP sockets library, also by mlo.
  193.  * 060  9-Oct-93 HG   Fix improper call to vms_assign_channel in edit 058,
  194.  *                    noticed by Fritz@GEMS.VCU.EDU.
  195.  * 061  9-Oct-93 fdc  For some reason, conbin() was turning off flow control.
  196.  *                    This caused massive data loss during CONNECT mode when
  197.  *                    running C-Kermit from a low-speed connection through
  198.  *                    a DECserver.  Now conbin() leaves the console flow
  199.  *                    control setting alone.
  200.  * 062 10-Oct-93 ttj  Change parameters to time() and ctime() from long to
  201.  *                    time_t (pointers).  Made prototype for vms_assign_channel
  202.  *                    and caught an erroneous function call.
  203.  * 063  9-Nov-93 fdc  In sysinit(), don't run sys$getdviw() on the "console"
  204.  *                    if the console is not a terminal (from tcwkw@sf.msc.edu).
  205.  *                    And (blame this one on me) _never_ set the backgrd flag.
  206.  * 064 25-Nov-93 fdc  Fixed coninc(n) to return -1 on timeout.
  207.  * 065  9-Dec-93 fdc  Fix transfer cancellation to account for parity, and
  208.  *                    allow it only in remote mode.
  209.  * 066 13-Dec-93 fdc  Make debug logging in ttol() show why packet writes fail.
  210.  * 067 15-Dec-93 fdc  New, MAXBUF-proof ttol() recovers from failures by
  211.  *                    writing the packet in chunks, whose size is computed
  212.  *                    dynamically.  This seems to cause no noticable slowdown
  213.  *                    in the transfer rate.
  214.  * 068 31-Dec-93 fdc  Fix bug in parity-detection code in ttinl().
  215.  * 069 14-Dec-93 fdc  Add ttgwsiz() routine, code from John Berryman.
  216.  * 070 14-MAR-94 mlo  CMU_TCPIP modifications: contti - return error (-1)
  217.  *                    if number of characters read is zero; cancio - pass
  218.  *                    correct i/o channel for ttyfd to sys$cancel.
  219.  * 071 15-MAR-94 mlo  ttol() - add #ifdef DEBUG for compiles with NODEBUG
  220.  * 072 27-Mar-94 fdc  Straighten out some ttsspd()/ttgspd() confusion.
  221.  * 073 11-AUG-94 fdc  Make conoll() return a proper return code.
  222.  * 074 12-AUG-94 fdc  Make syscleanup() handle conres() error.  Make 
  223.  * 075 20-AUG-94 js   Make congm() get terminal type, etc, to remove annoying
  224.  *                    "Sorry, terminal type not supported" messages when
  225.  *                    running from a .COM file, etc.
  226.  * 076 02-Sep-94 fdc  Call con_cancel() in syscleanup() to cancel any pending
  227.  *                    console i/o, hopefully eliminating zombies after
  228.  *                    after disconnection, etc.
  229.  * 077 22-Sep-94 mlo  Don't call sys$cancel() in cancio() on CMU/Tek network
  230.  *                    connections - it breaks the connection.
  231.  */
  232.  
  233. /*
  234.  Variables available to outside world:
  235.  
  236.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  237.    dfloc  -- 0 if dftty is console(remote), 1 if external line(local).
  238.    dfprty -- Default parity
  239.    dfflow -- Default flow control
  240.    ckxech -- Flag for who echoes console typein:
  241.      1 - The program (system echo is turned off)
  242.      0 - The system (or front end, or terminal).
  243.    functions that want to do their own echoing should check this flag
  244.    before doing so.
  245.  
  246.    backgrd
  247.      Flag indicating program not executing interactively.
  248.      Used to ignore INT and QUIT signals, suppress messages, etc.
  249.    vms_status
  250.      Status returned by most recent VMS system service,
  251.      can be used for error reporting.
  252.  
  253.  Functions for assigned communication line (either external or console tty):
  254.  
  255.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  256.    ttclos()                -- Close & reset the tty, releasing any access lock.
  257.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  258.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  259.                 or in DIALING or CONNECTED modem control state.
  260.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  261.    ttinc(timo)             -- Timed read character from tty.
  262.    ttchk()                 -- See how many characters in tty input buffer.
  263.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  264.    ttol(string,length)     -- Write a string to the tty.
  265.    ttoc(c)                 -- Write a character to the tty.
  266.    ttflui()                -- Flush tty input buffer.
  267.    tt_cancel()           -- Cancel any asynch I/O to tty
  268. */
  269.  
  270. /*
  271. Functions for console terminal:
  272.    congm()   -- Get console terminal modes.
  273.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  274.    conbin(esc) -- Put the console in binary (raw) mode.
  275.    conres()  -- Restore the console to mode obtained by congm().
  276.    conoc(c)  -- Unbuffered output, one character to console.
  277.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  278.    conola(s) -- Unbuffered output, array of lines to the console, CRLFs added.
  279.    conxo(n,s) -- Unbuffered output, n characters to the console.
  280.    conchk()  -- Check if characters available at console (bsd 4.2).
  281.         Check if escape char (^\) typed at console (System III/V).
  282.    coninc(timo)  -- Timed get a character from the console.
  283.    conint()  -- Enable terminal interrupts on the console if not background.
  284.    connoi()  -- Disable terminal interrupts on the console if not background.
  285.    contti()  -- Get a character from either console or tty, whichever is first.
  286.  
  287. Time functions
  288.  
  289.    msleep(m) -- Millisecond sleep
  290.    ztime(&s) -- Return pointer to date/time string
  291.    rtimer()  -- Reset elapsed time counter
  292.    gtimer()  -- Get elapsed time
  293. */
  294.  
  295. /* Includes */
  296. #include "ckcdeb.h"            /* Formats for debug() */
  297. #include "ckcasc.h"
  298. #include "ckcker.h"
  299.  
  300. #include "ckvvms.h"
  301.  
  302. #include <stdio.h>            /* Unix Standard i/o */
  303. #include <signal.h>            /* Interrupts */
  304. #include <setjmp.h>            /* Longjumps */
  305. #include <iodef.h>
  306. #include <ttdef.h>
  307. #include <tt2def.h>
  308. #include <ssdef.h>
  309. #include <descrip.h>
  310. #include <dvidef.h>
  311. #include <dcdef.h>
  312. #include <devdef.h>
  313. #include <time.h>
  314. #include <syidef.h>
  315. #include <prvdef.h>
  316.  
  317. /* lt 1992-10-08 Begin
  318.  */
  319. #ifndef __ALPHA
  320. # ifndef __GNUC__
  321. #  define void int
  322. # endif /* __GNUC__ */
  323. #endif /* __ALPHA */
  324. /* lt 1992-10-08 End
  325.  */
  326.  
  327. #if defined(VMS_V40) || defined(VMS_V42) || defined(VMS_V44) /* No starlet */
  328. #define IO$_TTY_PORT 41
  329. #else
  330. #include <starlet.h>
  331. #endif /* (Old VMS) */
  332.  
  333. /* Macros */
  334.  
  335. #define xx_inc(timo) (--ttxbn>=0?ttxbuf[ttxbp++]:txbufr(timo))
  336.  
  337. /* Declarations */
  338.  
  339. #ifndef __ALPHA
  340. #ifndef MULTINET
  341.     time_t time();
  342. #endif
  343. #endif
  344.     char *ctime();            /* Convert to asctime() string */
  345.  
  346.     void dcl_exit_h();            /* Exit handler */
  347.     unsigned short vms_assign_channel(struct dsc$descriptor_s *ttname);
  348.     VOID tt_cancel();
  349.  
  350. /*
  351.   This is the device name for the console.
  352.   When we use SYS$INPUT, it prevents CONNECT from working in DCL
  353.   procedures that do not "$ DEFINE SYS$INPUT SYS$COMMAND".
  354.   When we use SYS$COMMAND, it allows CONNECT to work in DCL procedures,
  355.   but it forces the command parser to read from the terminal, and therefore
  356.   prevents inclusion of Kermit commands as "image data" in DCL procedures.
  357. */
  358. #define CONDEVICE    "SYS$INPUT"
  359. #define CONDEV_COLON "SYS$INPUT:"
  360.  
  361. /* dftty is the device name of the default device for file transfer */
  362. /* dfloc is 1 if dftty is the user's console terminal, 0 if an external line */
  363.  
  364.     char *dftty = CTTNAM;
  365.     int dfloc = 0;            /* Default location is local */
  366.     int dfprty = 0;            /* Parity (0 = none) */
  367.     int ttprty = 0;            /* Parity in use */
  368.     int ttpflg = 0;            /* Parity not sensed yet. */
  369.     int backgrd = 0;            /* Running in "background" (no tty) */
  370.     static int ttpmsk = 0377;        /* Communication device parity mask */
  371.     int ttmdm = 0;                      /* Modem in use. */
  372.     int dfflow = FLO_XONX;        /* Default flow control is Xon/Xoff */
  373.     int batch = 0;            /* Assume interactive */
  374.     int ttcarr = CAR_AUT;        /* Carrier Handling Mode */
  375.     int tvtflg = 0;            /* Flag that ttvt has been called */
  376.     long ttspeed = -1;            /* For saving speed */
  377.     int ttflow = -9;            /* For saving flow */
  378.  
  379. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  380.  
  381. unsigned int vms_status;        /* Used for system service return status */
  382.  
  383. /* Structures used within this module */
  384.  
  385. #ifndef TT$C_BAUD_38400
  386. #define TT$C_BAUD_38400    0x11
  387. #endif /* TT$C_BAUD_38400 */
  388.  
  389. static struct {
  390.     unsigned char dec;
  391.     unsigned short int line;
  392.     } ttspeeds[] = {
  393.     {TT$C_BAUD_50,       5},
  394.     {TT$C_BAUD_75,       7},
  395.     {TT$C_BAUD_110,     11},
  396.     {TT$C_BAUD_134,     13},
  397.         {TT$C_BAUD_150,     15},
  398.     {TT$C_BAUD_300,     30},
  399.     {TT$C_BAUD_600,     60},
  400.     {TT$C_BAUD_1200,   120},
  401.     {TT$C_BAUD_1800,   180},
  402.     {TT$C_BAUD_2000,   200},
  403.     {TT$C_BAUD_2400,   240},
  404.     {TT$C_BAUD_3600,   360},
  405.     {TT$C_BAUD_4800,   480},
  406.     {TT$C_BAUD_7200,   720},
  407.     {TT$C_BAUD_9600,   960},
  408.     {TT$C_BAUD_19200, 1920},
  409.     {TT$C_BAUD_38400, 3840},
  410.     {0,                   0} };
  411.  
  412. /* Declarations of variables global within this module */
  413.  
  414. /* was long... */
  415. #define TIME_T time_t
  416. #ifdef __ALPHA
  417. #ifdef WINTCP
  418. #undef TIME_T
  419. #define TIME_T long
  420. #endif /* WINTCP */
  421. #endif /* __ALPHA */
  422.  
  423. static TIME_T tcount = 0;        /* For timing statistics */
  424.  
  425. static char brkarray[] = {        /* For simulating BREAK */
  426.  
  427.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  428.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  429.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  430.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
  431. };
  432.  
  433. int ttyfd = -1;                /* TTY file descriptor */
  434.  
  435. #ifdef COMMENT /* old */
  436. static int conif = 0,            /* Console interrupts on/off flag */
  437.     conclass = 0,            /* Console device type */
  438.     cgmf = 0,                /* Flag that console modes saved */
  439.     xlocal = 0,                         /* Flag for tty local or remote */
  440.     ttychn = 0,                /* TTY i/o channe; */
  441.     conchn = 0,                /* Console i/o channel */
  442.     con_queued = 0,            /* console i/o queued in contti() */
  443.     tt_queued = 0,            /* tty i/o queued in contti() */
  444.     conch,                /* console input character buffer  */
  445.     curcarr = 0,            /* Carrier mode: require/ignore */
  446.     ttch;                /* tty input character buffer */
  447. #else /* new */
  448. static unsigned short
  449.     ttychn = 0,                /* TTY i/o channe; */
  450.     conchn = 0,                /* Console i/o channel */
  451.     con_queued = 0,            /* console i/o queued in contti() */
  452.     tt_queued = 0;            /* tty i/o queued in contti() */
  453.  
  454. static int conif = 0,            /* Console interrupts on/off flag */
  455.     conclass = 0,            /* Console device type */
  456.     cgmf = 0,                /* Flag that console modes saved */
  457.     xlocal = 0,                         /* Flag for tty local or remote */
  458.     conch,                /* console input character buffer  */
  459.     curcarr = 0,            /* Carrier mode: require/ignore */
  460.     ttch;                /* tty input character buffer */
  461. #endif /* COMMENT */
  462.  
  463. static unsigned char escchr;        /* Escape or attn character */
  464. static char ttnmsv[80];              /* copy of open path for tthang */
  465. static char lclnam[80];            /* Local device name */
  466.  
  467. static char tt_fulldevnam[65];
  468. static struct dsc$descriptor_s tt_fulldevnam_d;    /* Descriptor for line name */
  469.  
  470. static long int qio_maxbuf_size;    /* Maximum size of QIO to succeed */
  471. static unsigned long dclexh_status;    /* Exit status for DCL exit handler */
  472. static struct iosb_struct coniosb, ttiosb, wrk_iosb;
  473. static struct tt_mode
  474.     ttold, ttraw, tttvt,        /* for communication line */
  475.     ccold, ccraw, cccbrk,        /* and for console */
  476.     cctmp;
  477.  
  478. /* Network support */
  479.  
  480. #include "ckcnet.h"            /* Network type symbols */
  481. extern int ttnet;            /* Network type */
  482. static int network = 0;            /* 1 if network connection */
  483. extern int xfrcan, xfrchr, xfrnum;    /* Transfer cancellation */
  484.  
  485. /*
  486.   Select proper library function for getting socket device channel.
  487. */
  488. #ifdef TCPIPLIB
  489. #if defined (__DECC)
  490. # define GET_SDC (short)decc$get_sdc
  491. #elif (defined (VAXC) || defined (__VAXC) || defined (__GNUC__))
  492. # define GET_SDC vaxc$get_sdc
  493. #else
  494. # error unknown compiler, not DECC and not VAXC
  495. #endif /* __DECC */
  496. #endif /* TCPIPLIB */
  497.  
  498. /* Needed for parity fixes in edit 036 */
  499. extern int parity;            /* current parity setting */
  500.  
  501. /*
  502.   New buffered input scheme.
  503. */
  504. #define TTXBUF
  505.  
  506. #ifdef TTXBUF
  507. #define TTXBUFL RBSIZ            /* Internal buffer size */
  508.  
  509. CHAR     ttxbuf[TTXBUFL+1];        /* The buffer */
  510. int     ttxbp = 0, ttxbn = 0;        /* Buffer pointer and count */
  511.  
  512. /*
  513.   T X B U F R
  514.  
  515.   Read bytes from communication device into internal buffer ttxbuf[].
  516.   To be called only when input buffer is empty, i.e. when ttxbn == 0.
  517.  
  518.   Other comm-device reading routines, like ttinc, ttinl, ttxin, should check
  519.   the internal buffer first, and call this routine for a refill if necessary.
  520.  
  521.   When data is read successfully, the first character is returned and
  522.   the global buffer count, ttxbn, is set to the number of characters remaining
  523.   in ttxbuf after it, and the global buffer offset, ttxbp, is set to 1.
  524.  
  525.   When data is not read successfully, -1 is returned indicating a timeout,
  526.   or -2 indicating disconnection.
  527. */
  528. int
  529. txbufr(timo) int timo; {        /* TT Buffer Read */
  530.     int count;
  531.     int func;                /* Read function code */
  532.     int mask;                /* Event mask */
  533.     int vms_status;            /* Read QIO return code */
  534.     static int trmmsk[2] = {0,0};    /* Terminal read break mask */
  535.     static int trmlong[8] = {0,0,0,0,0,0,0,0}; /* Break on nothing */
  536.  
  537.     debug(F101,"txbufr entry, ttxbn","",ttxbn);
  538.     if (ttxbn > 0) {            /* Should not be called */
  539.     debug(F101,"txbufr called with ttxbn","",ttxbn); /* if ttxbn > 0! */
  540.     ttxbn--;
  541.     return(ttxbuf[ttxbp++] & 0xff);
  542.     }
  543.     ttxbp = ttxbn = 0;            /* Reset buffer pointer and count */
  544.     ttxbuf[0] = NUL;
  545.  
  546.     if (timo < 0)            /* Be safe */
  547.       timo = 0;
  548.     debug(F101,"txbufr timo","",timo);
  549.  
  550.     func = IO$_READVBLK | IO$M_NOFILTR;    /* Read virtual block, no filtering */
  551.     trmmsk[0] = sizeof(trmlong);    /* No terminators */
  552.     trmmsk[1] = (int)&trmlong;        /* Keep all characters */
  553.  
  554. /*
  555.   We try to scoop up as many as we can in a nonblocking read (timed, but with
  556.   timeout value of 0).  This is supposed to return immediately with up to
  557.   "count" characters placed in our buffer.
  558. */
  559.     count = TTXBUFL;            /* Maximum characters to read */
  560.  
  561. #ifdef COMMENT
  562. /*
  563.   This causes problems because we are not adjusting according to the CURRENT
  564.   BYTLM quota, but rather to the one that was obtained when Kermit started.
  565.   Since the quota is dynamic, it might have been reduced since then.
  566. */
  567.     if (count > qio_maxbuf_size)
  568.     count = qio_maxbuf_size;
  569. #else
  570. /*
  571.   So for now we use 1024, which tends to be smaller than the value obtained
  572.   above.  Later, this should be changed to find out the remaining BYTLM quota
  573.   and use that instead.  This size can be overridden at compile time by
  574.   defining the symbol...
  575. */
  576. #ifndef CKV_IO_SIZE
  577. #define CKV_IO_SIZE 1024
  578. #endif /* CKV_IO_SIZE */
  579.  
  580.     if (count > CKV_IO_SIZE)
  581.     count = CKV_IO_SIZE;
  582. #endif /* COMMENT */
  583.  
  584.     debug(F101,"txbufr 1 read","",count);
  585.     vms_status = sys$qiow(QIOW_EFN, ttychn, func|IO$M_TIMED, &wrk_iosb, 0, 0,
  586.               ttxbuf, count, 0, &trmmsk, 0, 0);
  587. /*
  588.  * Did something _really_ bad happen?
  589.  */
  590.     if (vms_status != SS$_NORMAL) {
  591.     debug(F101,"txbufr 1 serious error, status","",vms_status);
  592.     return(-2);
  593.     }
  594.     debug(F101,"txbufr 1 size","",wrk_iosb.size);
  595.     debug(F101,"txbufr 1 iosb","",wrk_iosb.status);
  596.     debug(F110,"txbufr 1 ttxbuf",ttxbuf,0);
  597. /*
  598.  * How about a hangup?
  599.  */
  600.     if (wrk_iosb.status == SS$_HANGUP) { /* Check for disconnection */
  601.     debug(F100,"txbufr 1 hangup","",0);
  602.     return(-2);
  603.     }
  604. /*
  605.  * Did anything useful happen?
  606.  */
  607.     if (wrk_iosb.size > 0) {
  608.     ttxbn = wrk_iosb.size;        /* Set buffer count. */
  609.     ttxbn--;            /* Less one for the one we return */
  610.     return(ttxbuf[ttxbp++] & 0xff);    /* Return it, bump offset */
  611.     }
  612. /*
  613.  * An unexpected status?
  614.  */
  615.     if (wrk_iosb.status != SS$_TIMEOUT) {
  616.     debug(F101, "txbufr 1 unexpected iosb status", "", wrk_iosb.status);
  617.     return(-2);            /* Call it a hangup */
  618.     }
  619. /*
  620.  * If we didn't get any characters, then try a blocking, possibly timed,
  621.  * read for a single character.  Since this routine will be called again very
  622.  * soon, the first read with a zero timeout will have the rest of the user
  623.  * data in it.  Thus, this isn't as inefficient as it first appears.
  624.  */
  625.     if (timo > 0)
  626.       func |= IO$M_TIMED;
  627.     debug(F101,"txbufr 2 read","",count);
  628.     vms_status = sys$qiow(QIOW_EFN, ttychn, func, &wrk_iosb, 0, 0,
  629.               ttxbuf, 1, timo, &trmmsk, 0, 0);
  630.     debug(F101,"txbufr 2 vms_status", "",vms_status);
  631.     debug(F101,"txbufr 2 iosb status","",wrk_iosb.status);
  632. /*
  633.  * Did something _really_ bad happen?
  634.  */
  635.     if (vms_status != SS$_NORMAL) {
  636.     debug(F101,"txbufr fails","",-2);
  637.     return(-2);
  638.     }
  639.     debug(F101,"txbufr 2 size","",wrk_iosb.size);
  640.     debug(F101,"txbufr 2 iosb","",wrk_iosb.status);
  641.     debug(F110,"txbufr 2 ttxbuf",ttxbuf,0);
  642.  
  643. /*
  644.  * How about a hangup?
  645.  */
  646.     if (wrk_iosb.status == SS$_HANGUP) { /* Check for disconnection */
  647.     debug(F100,"txbufr 2 hangup","",0);
  648.     return(-2);
  649.     }
  650.  
  651. /*
  652.  * Did anything useful happen?
  653.  */
  654.     if(wrk_iosb.size > 0) {
  655.     ttxbn = wrk_iosb.size;        /* Set buffer count. */
  656.     ttxbn--;            /* Less one for the one we return */
  657.     return(ttxbuf[ttxbp++] & 0xff);    /* Return it, bump offset */
  658.     }
  659.  
  660. /*
  661.  * An unexpected status?
  662.  */
  663.     if (wrk_iosb.status != SS$_TIMEOUT) {
  664.     debug(F101, "txbufr 2 unexpected iosb status", "", wrk_iosb.status);
  665.     return(-2);            /* Call it a hangup */
  666.     }
  667.  
  668. /*
  669.  * Otherwise it's a timeout
  670.  */
  671.     debug(F100, "txbufr 2 returning timeout", "", 0);
  672.     return(-1);
  673. }
  674.  
  675. /*  T T I N C  --  Read a character from the communication device  */
  676. /*
  677.   ttinc() maintains an internal buffer to minimize system calls.
  678.   Returns the next character, or -1 if there is a timeout, or -2
  679.   on communications disconnect.  Calls txbufr() to refill its buffer
  680.   when necessary.
  681. */
  682. int
  683. ttinc(timo) int timo; {
  684.     int x; unsigned char c;
  685.  
  686. #ifdef NETCONN
  687.     if (network)
  688.       return(netinc(timo));
  689. #endif /* NETCONN */
  690.  
  691.     debug(F101,"ttinc ttxbn","",ttxbn);
  692.     if (--ttxbn >= 0) {            /* Something in internal buffer? */
  693.     c = ttxbuf[ttxbp++];        /* Yes, return next character. */
  694.     debug(F101,"ttinc returns c","",c);
  695.     return(c & 0xff);
  696.     } else if ((x = txbufr(timo)) < 0) { /* No, fill buffer */
  697.     debug(F101,"ttinc timed out","",x); /* Pass along failure. */
  698.     return(x);
  699.     } else {                /* Success. */
  700.     debug(F101,"ttinc returns x","",x);
  701.     return(x & 0xff);        /* Return the character */
  702.     }
  703. }
  704.  
  705. /*  T T X I N  --  Get n bytes from tty input buffer  */
  706. /*
  707.   Call with n = number of bytes to get, buf = where to put them.
  708.  
  709.   This routine assumes that the given number of bytes is available
  710.   and will not return until they are gotten.  You should only call this
  711.   routine after calling ttchk to find out how many bytes are waiting to
  712.   to be read.
  713.  
  714.   Returns:
  715.   -1 on error, number of chars gotten on success.
  716. */
  717. int
  718. ttxin(n,buf) int n; CHAR *buf; {
  719.     int i, x;
  720.  
  721.     debug(F101,"ttxin","",n);
  722.  
  723. #ifdef NETCONN
  724.     if (network) {
  725.     for (i = 0; i < n; i++) {
  726.         if ((x = ttinc(0)) < 0) return(-1);
  727.         buf[i] = (char) x;
  728.     }
  729.     } else {
  730. #endif /* NETCONN */
  731. /* xx_inc() is a macro */
  732.     for (i = 0; i < n; i++) {
  733.         if ((x = xx_inc(0)) < 0) return(-1);
  734.         buf[i] = (char) x;
  735.     }
  736. #ifdef NETCONN
  737.     }
  738. #endif /* NETCONN */
  739.     buf[i] = NUL;
  740.     return(i);
  741. }
  742.  
  743. /*  T T F L U I  --  Flush communication device input buffer  */
  744.  
  745. int
  746. ttflui() {
  747.     int n;
  748.     debug(F100,"ttflui","",0);
  749. #ifdef NETCONN
  750.     if (network)
  751.       return(netflui());
  752. #endif /* NETCONN */
  753.  
  754.     ttxbn = ttxbp = 0;            /* Flush internal buffer *FIRST* */
  755.     if ((n = ttchk()) > 0) {
  756.     debug(F101,"ttflui count","",n);
  757. #ifdef NETCONN
  758.     if (network)
  759.       while ((n--) && ttinc(2) > -1) ; /* Don't worry, it's buffered. */
  760.     else
  761. #endif /* NETCONN */
  762.       while ((n--) && xx_inc(2) > -1) ; /* Don't worry, it's buffered. */
  763.     }
  764.     return(0);
  765. }
  766.  
  767. /*  T T C H K  --  Check how many bytes are waiting to be read */
  768. /*
  769.   Returns number of bytes waiting, or -1 if connection has been dropped.
  770.   The number of bytes waiting includes those in our internal buffer plus
  771.   those in VMS's internal input buffer.
  772. */
  773. int                    /* Check how many bytes are ready */
  774. ttchk() {                /* for reading from network */
  775.     static struct {
  776.     unsigned short count;
  777.     unsigned char first;
  778.     unsigned char reserved1;
  779.     long reserved2; } ttchk_struct;
  780.  
  781. #ifdef NETCONN
  782.     if (network)            /* If network connection active... */
  783.       return(nettchk());        /* Check real network. */
  784. #endif /* NETCONN */
  785.  
  786.     CHECK_ERR("ttchk: sys$qiow",
  787.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, &wrk_iosb,
  788.          0, 0, &ttchk_struct, sizeof(ttchk_struct), 0, 0, 0, 0));
  789. #ifdef DEBUG
  790.     debug(F101,"ttchk count","",(int)ttchk_struct.count);
  791.     if (ttchk_struct.count)
  792.       debug(F101,"ttchk first","",(int)ttchk_struct.first);
  793. #endif /* DEBUG */
  794.     return(vms_status & 1 ? ttchk_struct.count + ttxbn : ttxbn);
  795. }
  796.  
  797. #ifdef CTRLC
  798. #undef CTRLC
  799. #endif /* CTRLC */
  800. #define CTRLC '\03'
  801.  
  802. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  803. /*
  804.   Reads up to "max" characters from the communication line, terminating on:
  805.  
  806.     (a) the packet length field if the "turn" argument is zero, or
  807.     (b) on the packet-end character (eol) if the "turn" argument is nonzero
  808.     (c) two Ctrl-C's in a row
  809.  
  810.   and returns the number of characters read upon success, or if "max" was
  811.   exceeded or the timeout interval expired before (a) or (b), returns -1.
  812.  
  813.   The characters that were input are copied into "dest" with their parity bits
  814.   stripped if parity was selected.  Returns the number of characters read.
  815.   Characters after the eol are available upon the next call to this function.
  816.  
  817.   Since this function has grown to have its fingers so deeply into the
  818.   protocol, it is slated for removal: rpack() will take care of everything.
  819. */
  820.  
  821. int
  822. #ifdef CK_ANSIC
  823. ttinl(CHAR *dest, int max, int timo, CHAR eol, CHAR start, int turn)
  824. #else
  825. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest,eol,start;
  826. #endif /* CK_ANSIC */
  827. /* ttinl */ {
  828.     int x, y, c, i, j;
  829.     int ccn = 0;        /* Control C counter */
  830.     int flag;
  831.     int cc;
  832.     unsigned char *cp;
  833.     int pktlen = -1;
  834.     int lplen = 0;
  835.     int havelen = 0;
  836.  
  837.     debug(F101,"ttinl start","",start);
  838.     debug(F101,"ttinl turn","",turn);
  839.     i = j = flag = 0;
  840.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask. */
  841.     while (i < max) {
  842.     cc = network ? ttinc(timo) : xx_inc(timo); /* Read a byte */
  843.     if (cc < 0)            /* Check for error */
  844.       return(-1);
  845.     /* Check for cancellation */
  846.     if (!xlocal && xfrcan && ((cc & ttpmsk) == xfrchr)) {
  847.         if (++ccn >= xfrnum) {    /* If xfrnum in a row, bail out. */
  848.         fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
  849.         return(-2);
  850.         }
  851.     } else ccn = 0;            /* No cancel, so reset counter, */
  852.  
  853.     if ((flag == 0) && ((cc & 0x7f) == start)) {
  854.         debug(F100,"ttinl got start","",0);
  855.         flag = 1;            /* Got packet start. */
  856.     }
  857.     if (flag) {            /* If we're in a packet... */
  858.         dest[i++] = cc & ttpmsk;
  859.         if ((cc & 0x7f) == eol) { /* Stop at eol. */
  860.         debug(F101,"ttinl got eol, i","",i);
  861.         break;
  862.         }
  863.     }
  864. /*
  865.   If we have not been instructed to wait for a turnaround character, we
  866.   can go by the packet length field.  If turn != 0, we must wait for the
  867.   end of line (eol) character before returning.
  868. */
  869. #ifndef xunchar
  870. #define xunchar(ch) (((ch) - 32 ) & 0xFF )    /* Character to number */
  871. #endif /* xunchar */
  872.  
  873.     if (i == 2) {
  874.         pktlen = xunchar(dest[1] & 0x7f);
  875.         havelen = (pktlen > 1);
  876.         debug(F101,"ttinl length","",pktlen);
  877.     } else if (i == 5 && pktlen == 0) {
  878.         lplen = xunchar(dest[4] & 0x7f);
  879.     } else if (i == 6 && pktlen == 0) {
  880.         pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
  881.         havelen = 1;
  882.         debug(F101,"ttinl length","",pktlen);
  883.     }
  884.     if (havelen && !turn && (i > pktlen+1)) { /* Use length field */
  885.         debug(F101,"ttinl break on length","",i);
  886.         break;
  887.     }
  888.     }
  889.     dest[i] = '\0';            /* Terminate the string */
  890.     debug(F101,"ttinl loop done, i","",i);
  891.     debug(F101,"ttinl max","",max);
  892.     debug(F101,"ttinl dest[i-1]","",dest[i-1]);
  893.     debug(F101,"ttinl eol","",eol);
  894.  
  895.     if (i >= max) {
  896.     debug(F100,"ttinl buffer overflow","",0);
  897.     return(-1);    /* Overflowed dest buffer without getting eol */
  898.     }
  899.     x = i;                /* Size. */
  900.     debug(F111,"ttinl got packet",dest,x);
  901.  
  902.     debug(F101,"ttinl size","",x);    /* Log the size */
  903.     dest[x] = '\0';            /* Terminate with null */
  904.  
  905.     if (ttpflg++ == 0 && ttprty == 0) {    /* Check and adjust the parity. */
  906.         if ((ttprty = parchk(dest,start,x)) > 0) {
  907.         debug(F000,"ttinl parchk senses parity","",ttprty);
  908.         ttpmsk = 0x7f;
  909.         for (i = 0; i < x; i++)    /* Strip parity from this packet */
  910.           dest[i] &= 0x7f;
  911.     }
  912.     if (ttprty < 0) ttprty = 0;    /* Restore if parchk error */
  913.     }
  914.     return(x);                /* Return length */
  915. }
  916.  
  917. #endif /* TTXBUF */
  918.  
  919. SIGTYP (*saval)() = NULL;        /* For saving alarm handler */
  920.  
  921. VOID
  922. ttimoff() {                /* Turn off any timer interrupts */
  923.     alarm(0);
  924.     if (saval) {
  925.     signal(SIGALRM,saval);
  926.     saval = NULL;
  927.     } else {
  928.     signal(SIGALRM,SIG_IGN);    /* (was SIG_DFL) */
  929.     }
  930. }
  931.  
  932. /*  P R I N T _ M S G  --  Log an error message from VMS  */
  933.  
  934. int
  935. print_msg(s) char *s; {
  936.     long int blen = 0;
  937.     char buf[PMSG_BUF_SIZE], msg[PMSG_MSG_SIZE];
  938.     struct dsc$descriptor_s b = {
  939.     PMSG_BUF_SIZE-1,
  940.     DSC$K_DTYPE_T,
  941.     DSC$K_CLASS_S,(char *)&buf
  942.     };
  943.  
  944.     if (!((vms_status = sys$getmsg(vms_status, &blen, &b, 0, 0)) & 1)) {
  945.     fprintf(stderr,"print_msg; sys$getmsg\n");
  946.     return(-1);
  947.     }
  948.     buf[blen] = '\0';
  949.     sprintf(msg, "%s: %s\n", s, buf);
  950.     debug(F100,s,"",0);
  951.     ermsg(msg);
  952.     return(0);
  953. }
  954.  
  955. /*  S Y S I N I T  --  System-dependent program initialization.  */
  956.  
  957. #ifndef DVI$_FULLDEVNAM
  958. #define DVI$_FULLDEVNAM 232
  959. #endif /* DVI$_FULLDEVNAM */
  960.  
  961. #ifndef DVI$_STS
  962. #define DVI$_STS 226
  963. #endif /* DVI$_STS */
  964.  
  965. int
  966. ttgwsiz() {                /* Get console window (screen) size */
  967.     int x = -1;
  968.     extern int tt_rows, tt_cols;
  969.     typedef struct {            /* define an item list struct */
  970.     short length;            /* length of buffer */
  971.     short code;            /* item code */
  972.     void *ptr;            /* ptr to buffer */
  973.     void *retlen;            /* ptr to return length */
  974.     } item_list;
  975.     int status, iosb[2];
  976.     item_list tt_dvi[] = {        /* Item list for GETDVI */
  977.     {4,DVI$_DEVBUFSIZ,&tt_cols,0},
  978.     {4,DVI$_TT_PAGE,&tt_rows,0},
  979.     {0,0,0,0}
  980.     };
  981.     $DESCRIPTOR(sysin,CONDEVICE);
  982.     status = sys$getdviw(0,0,&sysin,&tt_dvi,&iosb,0,0,0);
  983.     if ((status & 1) == 0)
  984.       return(-1);
  985.     if (tt_rows < 1 || tt_cols < 1) return(0);
  986.     return(1);
  987. }
  988.  
  989. int
  990. sysinit() {
  991.     extern int speed;
  992.     extern char ttname[];
  993.     extern char *ckzsys;
  994.     struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,(char *)&lclnam,0},
  995.             {sizeof(conclass),DVI$_DEVCLASS,(char *)&conclass,0},
  996.                 {0,0,0,0}};
  997.  
  998.     static struct desblk {
  999.     long int *fl;            /* Forward link.  Used by VMS only */
  1000.     void (*fncpnt)();        /* Function to call */
  1001.     unsigned char argcnt;        /* Only one arg allowed */
  1002.     unsigned char filler[3];    /* Filler.  Must be zero */
  1003.     long int *sts;            /* Address of sts (written by VMS) */
  1004.     } dclexh_ = {0,dcl_exit_h,1,{0,0,0},&dclexh_status};
  1005.  
  1006. #define GETCKXSYS
  1007. /*
  1008.   Get architecture and operating system name.
  1009. */
  1010. #ifdef GETCKXSYS
  1011.  
  1012. #if defined(__ALPHA)
  1013.  
  1014.     ckxsys = " OpenVMS AXP";
  1015.  
  1016. #elif !(defined(__VAX) || defined (VAX) || defined (__GNUC__))
  1017. # error Unknown Hardware type, not VAX(tm) and not AXP (TM)
  1018. #else /* VAX */
  1019.  
  1020. /* OK, we have a VAX so what is the name of the OS? */
  1021.  
  1022. #ifndef SYI$_ARCH_NAME    /* Should be in syidef.h but is not there yet */
  1023. # define SYI$_ARCH_NAME 4454
  1024. #endif /* SYI$_ARCH_NAME */
  1025.  
  1026.     struct iosb_t {
  1027.     short int status;        /* System service status */
  1028.     short int unused[3];
  1029.     } iosb;
  1030.  
  1031.     struct itmlst_t {
  1032.     short unsigned int buffer_len;    /* Buffer length */
  1033.     short unsigned int item_code;    /* Item code */
  1034.     char*buffer;            /* Where to write SYI info */
  1035.     long unsigned int *ret_len;    /* Pointer to returned length */
  1036.     long unsigned int mbz;        /* Must Be Zero */
  1037.  
  1038.     } itmlst;
  1039.  
  1040.     char arch_name[sizeof ("Alpha") - 1]; /* Architecture name */
  1041.     long unsigned int ret_len;        /* Returned length */
  1042. /*
  1043.   $getsyi of "hw_arch" will fail prior to VMS 5.5.  This failure indicates that
  1044.   the OS name is "VAX/VMS" (sic).  Use success or failure or $getsyi "hw_arch"
  1045.   rather than the more straight forward $getsyi "node_swvers" because latter
  1046.   is defined as four (4) characters and will get strange representing VMS
  1047.   10.0.
  1048. */
  1049.  
  1050. /*  Default -- Not strictly correct but traditional & familiar... */
  1051.     ckxsys = " VAX/VMS";
  1052.  
  1053.     itmlst.buffer_len = sizeof (arch_name);
  1054.     itmlst.item_code = SYI$_ARCH_NAME;
  1055.     itmlst.buffer = arch_name;
  1056.     itmlst.ret_len = &ret_len;
  1057.     itmlst.mbz = 0;
  1058.  
  1059.     if ((sys$getsyiw (0, 0, 0,
  1060.             &itmlst,
  1061.             &iosb,
  1062.             0, 0) & 1) == 1)
  1063.     if ((iosb.status & 1) == 1)
  1064.         ckxsys = " OpenVMS VAX";
  1065.  
  1066.     ckzsys = ckxsys;            /* Same deal for file module */
  1067.  
  1068. #endif /* OS Type */
  1069. #endif /* GETCKXSYS */
  1070.  
  1071. /*
  1072.  * Set up DCL Exit handler.  This allows us to reset terminal
  1073.  * and any other modifications we have done.
  1074.  */
  1075.     debug(F101,"sysinit ttychn","",ttychn);
  1076.     debug(F101,"sysinit conchn","",conchn);
  1077.     if (!CHECK_ERR("sysinit: sys$dclexh",
  1078.            sys$dclexh(&dclexh_))) {
  1079.         debug(F100,"sysinit failed to declare exit handler","",0);
  1080. #ifdef COMMENT
  1081.     return(0);
  1082. #endif /* COMMENT */
  1083.     }
  1084.     if (ttychn)                         /* if comms line already opened */
  1085.       return(0);            /* (how could it be???) */
  1086.  
  1087.     if (!conchn) {            /* Get console channel */
  1088. #ifdef CMU_TCPIP
  1089.       /* need to open console using libcmu routine to enable `select' call on
  1090.        * file descriptor zero.
  1091.        */
  1092.       cmu_stdin_open(dftty);
  1093.       conchn = cmu_get_sdc(0);
  1094. #else
  1095.       struct dsc$descriptor_s devnam =
  1096.         {sizeof(dftty)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,dftty};
  1097.       conchn = vms_assign_channel(&devnam);
  1098. #endif /* CMU_TCPIP */
  1099.     }
  1100.     congm();                /* Get and save its modes */
  1101. /*
  1102.  * Parse console terminal device name.
  1103.  */
  1104.     if (isatty(0)) {             /* So following won't fail under batch */
  1105.     CHECK_ERR("sysinit: sys$getdviw",
  1106.           sys$getdviw(0, conchn, 0, &dviitm, &wrk_iosb, 0, 0, 0));
  1107.     debug(F111,"sysinit","lclnam",lclnam);
  1108.  
  1109.     if (!CHECK_ERR("sysinit: sys$qiow",
  1110.                sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE,
  1111.                 &wrk_iosb, 0, 0,
  1112.                 &ccold, sizeof(ccold), 0, 0, 0, 0)))
  1113.       return(-1);
  1114.     ttspeed = speed = ttispd((unsigned char) wrk_iosb.size);
  1115.     debug(F111,"sysinit speed",lclnam,speed);
  1116.     strncpy(ttname,lclnam,80);
  1117.     }
  1118.  
  1119.     /* Initialize descriptor */
  1120.     tt_fulldevnam_d.dsc$b_dtype = DSC$K_DTYPE_T;
  1121.     tt_fulldevnam_d.dsc$b_class = DSC$K_CLASS_S;
  1122.  
  1123.     debug(F100,"sysinit done","",0);
  1124.     return(0);
  1125. }
  1126.  
  1127. /*
  1128.  * DCL Exit handler.  This is the cleanup handler for program.
  1129.  * Any final cleanup (closing channels etc) should be done at this
  1130.  * point.
  1131.  */
  1132. VOID
  1133. dcl_exit_h(sts) unsigned long int *sts; {
  1134.     syscleanup();
  1135.     return;
  1136. }
  1137.  
  1138. /*  S Y S C L E A N U P -- System-dependent program epilog.  */
  1139.  
  1140.  
  1141. int
  1142. syscleanup() {
  1143.     int x;
  1144.     extern zclosf();
  1145.     void con_cancel();
  1146.     debug(F101,"syscleanup entry","",ttyfd);
  1147.     con_cancel();        /* Cancel pending console i/o. */
  1148.     ttclos(ttyfd);        /* Do the cleanup no matter what... */
  1149.     zclosf(ZSYSFN);        /* Close various files and kill child procs */
  1150. #ifdef COMMENT
  1151.     /* This is a bit extreme... */
  1152.     if ((x = conres()) < 0) exit(SS$_ABORT);
  1153. #else
  1154.     conres();
  1155. #endif /* COMMENT */
  1156.     debug(F101,"syscleanup conres","",x);
  1157.     printf("\r");
  1158.     return(0);
  1159. }
  1160.  
  1161. /*  T T O P E N  --  Open a tty for exclusive access.  */
  1162.  
  1163. /*  Returns 0 on success, -1 on failure.  */
  1164. /*
  1165.   If called with lcl < 0, sets value of lcl as follows:
  1166.   0: the terminal named by ttname is the job's controlling terminal.
  1167.   1: the terminal named by ttname is not the job's controlling terminal.
  1168.   But watch out: if a line is already open, or if requested line can't
  1169.   be opened, then lcl remains (and is returned as) -1.
  1170. */
  1171. int
  1172. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
  1173.     extern int speed;
  1174.     int s, x;
  1175.     unsigned long int no_share_priv[2], prev_privs[2];
  1176.     unsigned long int devchar, devclass, devsts;
  1177. /*    char dvibuf[65]; */
  1178.     struct dsc$descriptor_s devnam = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1179.     struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,(char *)&tt_fulldevnam,0},
  1180.             {sizeof(devchar),DVI$_DEVCHAR,(char *)&devchar,0},
  1181.             {sizeof(devclass),DVI$_DEVCLASS,(char *)&devclass,0},
  1182.             {sizeof(devsts),DVI$_STS,(char *)&devsts,0},
  1183.             {0,0,0,0}};
  1184.  
  1185. #ifdef NETCONN
  1186.     if (network && ttyfd > -1) {    /* if device already opened */
  1187.         if (strncmp(ttname,ttnmsv,80))    /* are new & old names equal? */
  1188.           ttclos(ttyfd);        /* no, close old ttname, open new */
  1189.         else                 /* else same, ignore this call, */
  1190.       return(0);            /* and return. */
  1191.     }
  1192.     if (modem < 0) {            /* modem < 0 = special code for net */
  1193.     int x;
  1194.     ttmdm = modem;
  1195.     modem = -modem;            /* Positive network type number */
  1196.     debug(F111,"ttopen net",ttname,modem);
  1197.     x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
  1198.     if (x > -1) {
  1199.         strncpy(ttnmsv,ttname,DEVNAMLEN);
  1200.         network = 1;
  1201. #ifdef COMMENT
  1202. /* Let netopen() handle this. */
  1203.         x = tn_ini();        /* Initialize telnet protocol. */
  1204. #endif /* COMMENT */
  1205.         ttnet = modem;
  1206.     } else network = 0;
  1207.         return(x);
  1208.     }
  1209. #endif /* NETCONN */
  1210.  
  1211.     if (ttychn) return(0);        /* Close channel if open */
  1212.  
  1213.     devnam.dsc$w_length  = strlen(ttname);
  1214.     devnam.dsc$a_pointer = ttname;
  1215.     sys$getdviw(0, 0, &devnam, &dviitm, &wrk_iosb, 0, 0, 0);
  1216.     tt_fulldevnam[65] = '\0';        /* Make sure it has an end.... */
  1217.  
  1218.     if (devclass != DC$_TERM) {        /* Is it a terminal? */
  1219.     fprintf(stderr,
  1220.         "%%CKERMIT-W-NOTTERM, %s is not a terminal\n",ttname);
  1221.     return(-1);
  1222.     }
  1223.     if (!(devchar & DEV$M_AVL)) {    /* Is it available? */
  1224.     fprintf(stderr,
  1225.         "%%CKERMIT-W-NOTAVAL, %s is not available\n",tt_fulldevnam);
  1226.     return(-5);
  1227.     }
  1228.     if (!(devsts & UCB$M_ONLINE)) {    /* Is it online? */
  1229.     fprintf(stderr,
  1230.         "%%CKERMIT-W-OFFLINE, %s is not online\n",tt_fulldevnam);
  1231.     return(-5);
  1232.     }
  1233.     ttmdm = modem;            /* Make this available to other fns */
  1234.     xlocal = *lcl;            /* Make this available to other fns */
  1235.  
  1236. /*
  1237.  *  Set up the tt_fulldevnam_d descriptor for use by ttclos() later.
  1238.  */
  1239.     tt_fulldevnam_d.dsc$w_length  = strlen(tt_fulldevnam);
  1240.     tt_fulldevnam_d.dsc$a_pointer = tt_fulldevnam;
  1241.  
  1242. /*
  1243.  *  Assume the user has SHARE privilege enabled and turn it off.  This is
  1244.  *  necessary to prevent a privileged user from assigning a channel to
  1245.  *  a device already in use by another process.
  1246.  */
  1247.     no_share_priv[0] = PRV$M_SHARE;
  1248.     sys$setprv (0, &no_share_priv, 0, &prev_privs);
  1249.  
  1250.     ttychn = vms_assign_channel(&devnam); /* Get a channel for it. */
  1251.  
  1252.     sys$setprv (1, &prev_privs, 0, 0);    /* Re-enable the old privs */
  1253.  
  1254.     debug(F111,"ttopen","modem",modem);
  1255.     debug(F101," ttychn","",ttychn);
  1256.  
  1257.     if (!ttychn) return(-1);        /* If couldn't open, fail. */
  1258. /*
  1259.  * Check for maximum size of QIO, so as to not get the dreaded quota exceeded
  1260.  * status returned.  When doing a QIO that has a larger buffer than
  1261.  * MAXBUF, exceeded quota wil be returned.
  1262.  *
  1263.  * Example: MAXBUF = 2048, QIO = 1936, overhead is 112 will succeed.
  1264.  *        QIO of 1937 will fail.
  1265.  *
  1266.  * This can change for different versions of VMS.
  1267.  */
  1268.     qio_maxbuf_size = get_qio_maxbuf_size(ttychn);
  1269.  
  1270.     strncpy(ttname,tt_fulldevnam,80);    /* Copy true name back to main pgm  */
  1271.  
  1272.     strcpy(ttnmsv,ttname);        /* Open, keep copy of name locally. */
  1273.     ttxbn = ttxbp = 0;            /* Initialize input buffer */
  1274.  
  1275. /* Caller wants us to figure out if line is controlling tty */
  1276.  
  1277.     debug(F111,"ttopen ok",ttname,*lcl);
  1278.     if (*lcl < 0) {
  1279.     if (conclass == DC$_TERM)
  1280.       xlocal = (strncmp(ttname,lclnam,80) == 0) ? 0 : 1;
  1281.     else
  1282.       xlocal = 1;             /* If not a term, then we must be local */
  1283.     debug(F111,"ttyname",lclnam,xlocal);
  1284.     }
  1285.     if (!CHECK_ERR("ttopen: sys$qiow",
  1286.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1287.          &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  1288.  
  1289.     ttspeed = speed = ttispd((unsigned char) wrk_iosb.size);
  1290.  
  1291. /* Got the line, now set the desired value for local. */
  1292.  
  1293.     if (*lcl) *lcl = xlocal;
  1294.  
  1295.     tttvt = ttold;
  1296.     ttraw = ttold;
  1297.     debug(F101," lcl","",*lcl);
  1298.     return(0);
  1299. }
  1300.  
  1301. #ifdef COMMENT
  1302. /*
  1303.   Old version.
  1304. */
  1305. unsigned long int
  1306. vms_assign_channel(ttname) char *ttname;  {
  1307.     unsigned int channel = 0;
  1308.     struct dsc$descriptor_s d = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1309.  
  1310.     d.dsc$w_length  = strlen(ttname);
  1311.     d.dsc$a_pointer = ttname;
  1312.     if (!CHECK_ERR("vms_assign_channel: sys$assign",
  1313.     sys$assign(&d, &channel, 0, 0))) return(0);
  1314.     return(channel);
  1315. }
  1316. #else
  1317. /*
  1318.   New version from Hunter Goatley.
  1319. */
  1320. unsigned short int
  1321. vms_assign_channel(ttname) struct dsc$descriptor_s *ttname; {
  1322.     unsigned short channel = 0;
  1323.  
  1324. #ifdef COMMENT
  1325. /* what's all this then ... */
  1326.     struct dsc$descriptor_s d = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1327.     d.dsc$w_length  = strlen(ttname);
  1328.     d.dsc$a_pointer = ttname;
  1329. #endif /* COMMENT */
  1330.  
  1331.     if (!CHECK_ERR("vms_assign_channel: sys$assign",
  1332.     sys$assign(ttname, &channel, 0, 0))) return(0);
  1333.  
  1334. #ifdef NEW_STUFF_FROM_BRUCE_DAY
  1335. /*
  1336.   Which is not presently defined...
  1337.   This is supposed to allow C-Kermit to go into protocol mode on an LTA 
  1338.   device without a prior CONNECT command.
  1339. */
  1340. #ifdef IO$M_LT_CONNECT
  1341.     vms_status = sys$qiow(QIOW_EFN, channel, IO$_TTY_PORT|IO$M_LT_CONNECT,
  1342.                           &wrk_iosb, 0, 0, 0, 0, 0, 0, 0, 0);
  1343.     debug(F101, "vms_assign_channel LAT connect status","",vms_status);
  1344.     debug(F101, "vms_assign_channel LAT connect iosb","",wrk_iosb.status);
  1345. #endif /* IO$M_LT_CONNECT */
  1346. #endif /* NEW_STUFF_FROM_BRUCE_DAY */
  1347.  
  1348.     return(channel);
  1349. }
  1350. #endif /* COMMENT */
  1351.  
  1352. /*  T T C L O S  --  Close the communication device.  */
  1353.  
  1354. int
  1355. ttclos(ttyfd) int ttyfd; {
  1356. #ifdef NETCONN
  1357.     if (network) {            /* Network connection. */
  1358.     debug(F100,"ttclos closing net","",0);
  1359.     netclos();            /* Close it. */
  1360.     network = 0;
  1361.     return(0);
  1362.     }
  1363. #endif /* NETCONN */
  1364.     if (!ttychn) return(0);        /* Wasn't open. */
  1365. /*
  1366.   Observations indicate that it can take 20-30 seconds for DTR to drop
  1367.   after closing the device.  Perhaps a call to tthang() should go here.
  1368. */
  1369.     ttres();                /* Reset modes. */
  1370.  
  1371. /*
  1372.   Assume it's a LAT device and try to do a LAT disconnect on it.
  1373.   If it fails, then it's not a LAT device and no harm is done.
  1374. */
  1375. #ifdef IO$M_LT_DISCON
  1376.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_TTY_PORT|IO$M_LT_DISCON,
  1377.               &wrk_iosb, 0, 0, 0, 0, 0, 0, 0, 0);
  1378.     debug(F101, "ttclos LAT disconnect, status", "", vms_status);
  1379.     debug(F101, "ttclos LAT disconnect, iosb", "", wrk_iosb.status);
  1380. #else
  1381.     debug(F100, "ttclos LAT disconnect not supported", "", 0);
  1382. #endif /* IO$M_LT_DISCON */
  1383.     if (!CHECK_ERR("ttclos: sys$dassgn",
  1384.     sys$dassgn(ttychn))) return(-1);
  1385.     ttychn = 0;                /* Mark it as closed. */
  1386.     return(0);
  1387. }
  1388.  
  1389.  
  1390. /*  T T R E S  --  Restore terminal to its original modes.  */
  1391.  
  1392. int
  1393. ttres() {                /* Restore the tty to normal. */
  1394. #ifdef NETCONN
  1395.     if (network) return (0);        /* Network connection, do nothing */
  1396. #endif /* NETCONN */
  1397.  
  1398.     if (!ttychn) return(-1);        /* Not open. */
  1399.  
  1400.     tt_cancel();            /* Cancel outstanding I/O */
  1401.     msleep(250);            /* Wait for pending i/o to finish. */
  1402.     debug(F101,"ttres, ttychn","",ttychn);
  1403.     if (!CHECK_ERR("ttres: sys$qiow",
  1404.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1405.              &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  1406.     return(0);
  1407. }
  1408.  
  1409. /*  T T B I N  --  Code shared by ttpkt() and ttvt()  */
  1410. /*
  1411.   Puts communication device in "binary" mode.  In VMS there's no distinction
  1412.   between device modes for terminal connection, packet operation, and dialing.
  1413. */
  1414. static int
  1415. ttbin(speed, xflow, xparity) int speed, xflow, xparity; {
  1416.     int s;
  1417.     extern int flow;            /* Global flow control variable */
  1418.  
  1419. #ifdef NETCONN
  1420.     if (network) return(0);        /* Nothing to do on net connections */
  1421. #endif /* NETCONN */
  1422.     if (!ttychn) return(-1);        /* Not open. */
  1423.  
  1424.     ttspeed = speed;            /* Keep local copies of arguments */
  1425.     if (xflow != FLO_DIAL && ttflow != FLO_DIAX)
  1426.       ttflow = xflow;            /* for other CKVTIO routines. */
  1427.     if (xparity > -1) {
  1428.     ttprty  = xparity;
  1429.     ttpflg  = 0;            /* Parity not sensed yet */
  1430.     ttpmsk  = ttprty ? 0177 : 0377;    /* Parity stripping mask */
  1431.     debug(F101,"ttbin ttprty","",ttprty);
  1432.     }
  1433.     ttraw = ttold;            /* Get a fresh copy of this */
  1434.  
  1435.     if ((s = ttsspd(speed/10)) < 0)    /* Get internal speed code */
  1436.       s = 0;
  1437.  
  1438. /*
  1439.  * Log original terminal settings for debugging purposes
  1440.  */
  1441.     debug(F101, "original ttraw.basic", "", ttraw.basic);
  1442.     debug(F101, "original ttraw.extended", "", ttraw.extended);
  1443.  
  1444. /*
  1445.  * Settings based on call parameters flow-control and parity...
  1446.  * NOTE: we are using the GLOBAL copy of flow, not our parameter here.
  1447.  * This is because the parameter might be FLO_DIAL or FLO_DIALX, which
  1448.  * is not flow control at all.
  1449.  */
  1450.     if (flow == FLO_XONX) {                /* FLOW = XON/XOFF */
  1451.     ttraw.basic |=  (TT$M_HOSTSYNC|TT$M_TTSYNC);
  1452.     } else if (flow == FLO_NONE) {            /* FLOW = NONE */
  1453.     ttraw.basic &= ~(TT$M_HOSTSYNC|TT$M_TTSYNC);
  1454.     } else if (flow == FLO_KEEP) {            /* FLOW = KEEP */
  1455. /*
  1456.  * Put flow-control paramaters back the way we found them when
  1457.  * the device was first opened.
  1458.  */
  1459.     if (ttold.basic & TT$M_HOSTSYNC)
  1460.       ttraw.basic |= TT$M_HOSTSYNC;
  1461.     else
  1462.       ttraw.basic &= ~TT$M_HOSTSYNC;
  1463.     if (ttold.basic & TT$M_TTSYNC)
  1464.       ttraw.basic |= TT$M_TTSYNC;
  1465.     else
  1466.       ttraw.basic &= ~TT$M_TTSYNC;
  1467. /*
  1468.   NOTE: any other FLOW-related parameters should also be handled here.
  1469.   READSYNC?  And especially if DEC ever implements RTS/CTS or other
  1470.   hardware flow control for (Open)VMS.
  1471. */
  1472.     }
  1473.  
  1474. /*
  1475.   EIGHTBIT setting depends on GLOBAL copy of parity variable, not our
  1476.   parameter.
  1477. */
  1478.     if (parity == 0)
  1479.       ttraw.basic  |= TT$M_EIGHTBIT;    /* Allow 8-bit data if no parity */
  1480.     else                /* Otherwise */
  1481.       ttraw.basic  &= ~TT$M_EIGHTBIT;    /* 7-bit data. */
  1482.  
  1483.     ttraw.basic |= TT$M_NOECHO;        /* Turn off echo */
  1484.     ttraw.basic |= TT$M_NOBRDCST;    /* Turn off broadcasts */
  1485.     ttraw.basic &= ~TT$M_NOTYPEAHD;    /* Enable type-ahead */
  1486.     ttraw.basic &= ~TT$M_ESCAPE;    /* Disable escape-seq processing */
  1487.     ttraw.extended &= ~TT2$M_LOCALECHO;    /* Disable local echo */
  1488.     ttraw.extended |= TT2$M_PASTHRU;    /* Enable pass-through mode */
  1489.     ttraw.extended |= TT2$M_ALTYPEAHD;    /* Use big type-ahead buffers */
  1490.  
  1491. /*
  1492.  * Report what we did so we can check for problems
  1493.  */
  1494.     debug(F101, "ttraw.basic", "", ttraw.basic);
  1495.     debug(F101, "ttraw.extended", "", ttraw.extended);
  1496.  
  1497.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1498.              &ttraw, sizeof(ttraw), s, 0, 0, 0);
  1499.  
  1500.     if (vms_status != SS$_NORMAL) {    /* Error queuing request */
  1501.     print_msg("ttbin: sys$qiow");
  1502.     return(-1);
  1503.     }
  1504.     if (wrk_iosb.status != SS$_NORMAL) { /* Error executing request */
  1505.     vms_status = wrk_iosb.status;
  1506.     print_msg("ttbin: sys$qiow(iosb)");
  1507.     return(-1);
  1508.     }
  1509.     debug(F100,"ttbin ok","",0);
  1510.     return(0);                /* All OK */
  1511. }
  1512.  
  1513. /*  T T P K T  --  Condition the communication device for packets. */
  1514.  
  1515. #ifdef COMMENT
  1516. #define DIALING    4        /* Flags (via flow) for modem handling */
  1517. #define CONNECT 5        /* NOT YET IMPLEMENTED IN VMS! */
  1518. #endif /* COMMENT */
  1519.  
  1520. /*  Returns 0 on success, -1 on failure.  */
  1521.  
  1522. int
  1523. ttpkt(speed,flow,parity) long speed; int flow, parity; {
  1524.     int x;
  1525.     debug(F101,"ttpkt flow","",flow);
  1526.     x = ttbin(speed,flow,parity);    /* Put device in binary mode */
  1527.     debug(F101,"ttpkt ttbin","",x);
  1528.     return(x);
  1529. }
  1530.  
  1531. /*  T T V T  --  Condition communication device terminal connection. */
  1532.  
  1533. int
  1534. ttvt(speed,flow) long speed; int flow; {
  1535.     int x;
  1536.     debug(F101,"ttvt flow","",flow);
  1537.     if ((x = ttbin(speed,flow,-1)) > -1) /* Put device in binary mode */
  1538.       tvtflg = 1;
  1539.     debug(F101,"ttvt ttbin","",x);
  1540.     return(x);
  1541. }
  1542.  
  1543. /* T T I S P D  -- Return binary baud rate for internal coded speed */
  1544.  
  1545. int
  1546. ttispd(ispeed) unsigned char ispeed; {
  1547.     int s;
  1548.  
  1549. #ifdef NETCONN
  1550.     if (network) return(-1);
  1551. #endif /* NETCONN */
  1552.  
  1553. /* When the line is set, grab the line speed  and save it */
  1554.  
  1555.     for (s = 0;  ttspeeds[s].dec &&
  1556.     (ttspeeds[s].dec != ispeed);  s++)
  1557.         ;
  1558.  
  1559. /* If speed is zero, then no match.  Set speed to -1 so it is undefined */
  1560.  
  1561.     return(ttspeeds[s].line ? (int) ttspeeds[s].line * 10 : -1);
  1562. }
  1563.  
  1564.  
  1565. /*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
  1566.  
  1567. int
  1568. ttsspd(cps) int cps; {
  1569.     int s;
  1570.     char msg[50];
  1571.  
  1572. #ifdef    NETCONN
  1573.     if (network) return(0);
  1574. #endif    /* NETCONN */
  1575.  
  1576.     if (cps <= 0)            /* 026 Unknown cps fails */
  1577.       return (-1);
  1578.     for (s = 0;  ttspeeds[s].line && (ttspeeds[s].line != cps);  s++) ;
  1579.     if (ttspeeds[s].line) {
  1580.         ttspeed = cps * 10L;        /* Make a copy global to this module */
  1581.     if (ttspeed == 70L)        /* ... in bits per second, not cps, */
  1582.       ttspeed = 75L;        /* because ttgspd() uses it! */
  1583.     return(ttspeeds[s].dec);
  1584.     } else {
  1585.     sprintf(msg,"Unsupported line speed - %d\n",cps*10);
  1586.     ermsg(msg);
  1587.     ermsg("Current speed not changed\n");
  1588.     return(-1);
  1589.     }
  1590. }
  1591.  
  1592.  
  1593. /* Interrupt Functions */
  1594.  
  1595.  
  1596. /*  C O N I N T  --  Console Interrupt setter  */
  1597.  
  1598. static int (*cctrap)();
  1599.  
  1600. VOID
  1601. #ifdef CK_ANSIC
  1602. conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
  1603. #else
  1604. conint(f,s) int (*f)(int), (*s)(int);
  1605. #endif /* CK_ANSIC */
  1606. /* conint */ {                /* Set an interrupt trap. */
  1607.  
  1608.     cctrap = f;                /* Make a global copy */
  1609.     debug(F101,"conint batch","",batch);
  1610.     if (batch) return;            /* Ignore signals in background. */
  1611.  
  1612. #ifdef COMMENT
  1613. /*
  1614.    Forget this whole thing. 
  1615.    The batch flag should be set in only one place: congm().
  1616. */
  1617.  
  1618. /*
  1619.   Check if invoked in background -- if so signals set to be ignored.
  1620.   But VMS has no notion of background, so no worries, right?
  1621. */
  1622.     if (!isatty(0)) {
  1623.     debug(F100,"conint isatty diagnoses batch","",0);
  1624. #ifdef COMMENT
  1625.     batch = backgrd = 1;
  1626. #else
  1627. /*
  1628.   But we still might need to know whether we are running under batch.
  1629.   In which case, the test above is probably inadequate.  According to Carl
  1630.   Friedberg <friedberg@esb.com>, "I believe this can be done unambiguously by
  1631.   checking that (1) SYS$GETJPI returns a null string as the terminal; and
  1632.   (2) the current process is NOT a subprocess (a subprocess ALWAYS has a null
  1633.   string as its terminal ID). The real test is if PCB$L_STS has the
  1634.   PCB$M_BATCH bit set.  If the current process is a subprocess, then the test
  1635.   must be repeated for the MASTER (root) process in the job tree.  It is legal
  1636.   to run Kermit in a subprocess from within a batch job... and in that case,
  1637.   it should still behave like a batch job (no terminal input; must execute a
  1638.   SET LINE command).
  1639. */
  1640.     batch = 1;
  1641.     backgrd = 0;
  1642. #endif /* COMMENT */
  1643.     return;
  1644.     }
  1645. #endif /* COMMENT */
  1646.     signal(SIGINT,f);            /* Function to trap to. */
  1647.     conif = 1;                /* Flag console interrupts on. */
  1648. }
  1649.  
  1650. /*  C O N N O I  --  Reset console terminal interrupts */
  1651.  
  1652. VOID
  1653. connoi() {                /* Console-no-interrupts */
  1654.  
  1655.     if (batch) return;            /* must ignore signals in bkgrd */
  1656.  
  1657. #ifdef COMMENT
  1658. /* wrong... */
  1659.     signal(SIGINT,SIG_DFL);
  1660. #else
  1661. /* right?.. */
  1662.     signal(SIGINT,SIG_IGN);
  1663. #endif /* COMMENT */
  1664.     conif = 0;
  1665. }
  1666.  
  1667. /*  T T O L  --  Write string s, length n, to communication device.  */
  1668.  
  1669. #ifndef IO$M_BREAKTHRU
  1670. #define IO$M_BREAKTHRU    0x0200
  1671. #endif /* IO$M_BREAKTHRU */
  1672.  
  1673. #ifndef SS$_EXQUOTA  
  1674. #define SS$_EXQUOTA 28
  1675. #endif /* SS$_EXQUOTA */
  1676.  
  1677. int
  1678. ttol(s,n) int n; CHAR *s; {
  1679.     int
  1680.       remaining,            /* Amount left to write */
  1681.       size;                /* How much to write this time */
  1682.     static int max = 0;            /* Chunk size for writing */
  1683.  
  1684. #ifdef NETCONN
  1685.     debug(F101,"ttol network","",network);
  1686.     if (network)            /* If SET HOST connection, */
  1687.     return(nettol(s,n));        /* call network package. */
  1688. #endif /* NETCONN */
  1689.  
  1690. /* It's not a SET HOST connection. */
  1691.  
  1692.     debug(F101,"ttol ttychn","",ttychn);
  1693.     if (!ttychn) return(-1);        /* Not open. */
  1694.     debug(F101,"ttol length","",n);
  1695.     debug(F101,"ttol max","",max);
  1696.    
  1697. /* Have we already calculated a chunk size? */   
  1698.    
  1699.     if (max == 0) {            /* No, try to send whole packet. */
  1700.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1701.                   &wrk_iosb, 0, 0, s, n, 0, 0, 0, 0);
  1702.     if (vms_status == SS$_NORMAL) {
  1703.         debug(F101,"ttol 1 ok","",n);
  1704.         return(n);
  1705.     }
  1706. #ifdef DEBUG
  1707.     if (deblog) {            /* Failed. */
  1708.         debug(F101,"ttol 1 error, vms_status","",vms_status);    
  1709.         debug(F101,"ttol 1 iosb size","",wrk_iosb.size);
  1710.         debug(F101,"ttol 1 iosb status","",wrk_iosb.status);
  1711.     }
  1712. #endif
  1713.     if (vms_status != SS$_EXQUOTA)    /* "Quota exceeded"? */
  1714.       return(-3);            /* No, something else, give up. */
  1715. /*
  1716.   Here we should find out what MAXBUF is (not to mention BYTLM, BIOLM, and
  1717.   friends), and chop up the packet into pieces accordingly.  But reportedly
  1718.   this information, and how to use it (percent overhead, etc), is highly
  1719.   VMS-version-dependent.  So instead we just try different numbers.  Our first
  1720.   attempt keeps dividing it in half until it works, down to about 70.
  1721. */
  1722.     do {
  1723.         max = (max == 0) ? n / 2 : max / 2;
  1724.         debug(F101,"ttol 2 max","",max);
  1725.         vms_status = sys$qiow(QIOW_EFN, ttychn,
  1726.                   IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1727.                   &wrk_iosb, 0, 0, s, max, 0, 0, 0, 0);
  1728.           debug(F101,"ttol 2 vms_status","",vms_status); 
  1729.         if (vms_status == SS$_NORMAL)
  1730.           break;
  1731.     } while (max > 70);        /* 70 is the minimum. */
  1732.     
  1733.     if (vms_status != SS$_NORMAL)    /* Loop exhausted, fail. */
  1734.       return(-3);
  1735.    
  1736.     } else {                /* We already calculated max. */
  1737.  
  1738.     size = (max > n) ? n : max;      /* Write 1st chunk, but not too much */
  1739.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1740.                   &wrk_iosb, 0, 0, s, size, 0, 0, 0, 0);
  1741.     debug(F101,"ttol 3 vms_status","",vms_status); 
  1742.     if (vms_status != SS$_NORMAL)
  1743.       return(-3);
  1744.     if (size == n) {        /* (Not strictly necessary) */
  1745.         debug(F101,"ttol 3 done","",n);
  1746.           return(n);
  1747.     }  
  1748.     }    
  1749. /*   
  1750.   We have written the first chunk successfully, now write the remaining
  1751.   max-sized chunks, plus the (usually) less-than-max-sized last chunk.
  1752. */    
  1753.     remaining = n;
  1754.     while (1) {
  1755.     s += max;            /* Where to start */
  1756.     remaining -= max;        /* How much left to write */
  1757.     size = (remaining < max) ?    /* How much to write this time */
  1758.       remaining : max;
  1759.     if (size < 1)            /* Done? */
  1760.       break;
  1761.   
  1762.       debug(F101,"ttol 4 size","",size);
  1763.       vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1764.                   &wrk_iosb, 0, 0, s, size, 0, 0, 0, 0);
  1765.     debug(F101,"ttol 4 vms_status","",vms_status); 
  1766.     if (vms_status != SS$_NORMAL)
  1767.       return(-3);
  1768.     }
  1769.     debug(F101,"ttol 5 done","",n);
  1770.     return(n);
  1771. }
  1772.  
  1773. /*  T T O C  --  Output a character to the communication line  */
  1774.  
  1775. int
  1776. #ifdef CK_ANSIC
  1777. ttoc(char c)
  1778. #else
  1779. ttoc(c) char c;
  1780. #endif    /* CK_ANSIC */
  1781. /* ttoc */ {
  1782. #ifdef NETCONN
  1783.     if (network) {
  1784.     return(nettoc(c));
  1785.     } else {
  1786. #endif /* NETCONN */
  1787.     debug(F101,"ttoc char","",c);
  1788.     if (!ttychn) {
  1789.         debug(F100,"ttoc ttychn not open","",0);
  1790.         return(-1);            /* Not open. */
  1791.     }    
  1792.     if (CHECK_ERR("ttoc: sys$qiow",
  1793.               sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1794.                    &wrk_iosb, 0, 0, &c, 1, 0, 0, 0, 0)))
  1795.       return(0);
  1796. #ifdef NETCONN
  1797.     }
  1798. #endif /* NETCONN */
  1799.     return(-1);
  1800. }
  1801.  
  1802. /*  T T _ C A N C E L  --  Cancel i/o on tty channel if not complete  */
  1803.  
  1804. VOID
  1805. tt_cancel() {
  1806.     int mask;
  1807. #ifdef NETCONN
  1808.     if (network) return;
  1809. #endif /* NETCONN */
  1810.     CHECK_ERR("tt_cancel: sys$cancel",sys$cancel(ttychn));
  1811.     tt_queued = 0;
  1812. }
  1813.  
  1814. /*  C O N _ C A N C E L  --  Cancel i/o on console channel if not complete  */
  1815.  
  1816. VOID
  1817. con_cancel() {
  1818.     int mask;
  1819.  
  1820.     CHECK_ERR("con_cancel: sys$cancel",sys$cancel(conchn));
  1821.     con_queued = 0;
  1822. }
  1823.  
  1824. /*  S N D B R K  --  Send a BREAK signal of the given length.  */
  1825.  
  1826. int
  1827. sndbrk(msec) int msec; {
  1828.     int long x = 0;
  1829.     int brklen;
  1830.     struct iosb_struct  tmp_ttiosb;
  1831.     struct tt_mode ttchr;
  1832. #ifndef TT$M_BREAK            /* For old VMS with no BREAK... */
  1833. /*
  1834.   Note: 110 is used instead of 50, because 50 is not supported by all
  1835.   VAX serial port controllers.
  1836. */
  1837. #define BRKSPD = 110            /* Speed for simulating BREAK */
  1838. #define BRKSYM = TT$C_BAUD_110;        /* VMS symbol for this speed */
  1839. #endif /* TT$M_BREAK */
  1840.  
  1841. #ifdef NETCONN
  1842.     if (network)             /* Send network BREAK */
  1843.       return(netbreak());        /* Length doesn't matter */
  1844. #endif /* NETCONN */
  1845.  
  1846.     if (!ttychn) return(-1);        /* SET LINE not done. */
  1847.     debug(F101,"sndbrk msec","",msec);
  1848.  
  1849.     tt_cancel();            /* Cancel I/O */
  1850.  
  1851. #ifndef TT$M_BREAK            /* VMS doesn't have BREAK function */
  1852.  
  1853. /* Send the right number of NULs at BREAK-simulation speed... */
  1854.  
  1855.     brklen = ( BRKSPD * 1000 ) / ( msec * 10 ); /* Calculate number of chars */
  1856.     if (brklen > sizeof(brkarray)) brklen = sizeof(brkarray);
  1857.     debug(F101,"sndbrk speed","",BRKSPD);
  1858.     debug(F101,"sndbrk brklen","",brklen);
  1859.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  1860.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1861.         &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  1862.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  1863.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  1864.         &ttchr, sizeof(ttchr), BRKSYM, 0, 0, 0))) return(-1);
  1865.     if (!CHECK_ERR("ttsndb: writing nulls",
  1866.     sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &tmp_ttiosb,
  1867.          0, 0, (char *) brkarray, brklen, 0, 0, 0, 0))) return(-1);
  1868.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  1869.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  1870.         &ttchr, sizeof(ttchr), wrk_iosb.size, 0, 0, 0))) return(-1);
  1871. #else
  1872.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  1873.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1874.         &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  1875.     x = TT$M_BREAK;            /* Break signal on */
  1876.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  1877.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1878.         &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  1879.     msleep(msec);            /* Sleep requested amount of time */
  1880.     x = 0;                /* Break signal off */
  1881.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  1882.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1883.         &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  1884. #endif /* TT$M_BREAK */
  1885.     return(0);
  1886. }
  1887.  
  1888. /*  T T S N D B  --  Send a BREAK signal  */
  1889.  
  1890. int
  1891. ttsndb() {
  1892.     return(sndbrk(275));
  1893. }
  1894.  
  1895. /*  T T S N D L B  --  Send a Long BREAK signal  */
  1896.  
  1897. int
  1898. ttsndlb() {
  1899.     return(sndbrk(1500));
  1900. }
  1901.  
  1902. /*  T T H A N G  --  Hang up the communications line  */
  1903. /*
  1904.   Warning: As written, this function DOES NOT WORK on terminal server
  1905.   ports.  This is a shortcoming of VMS, confirmed by the Digital Diagnostic
  1906.   Center (or whatever DDC stands for).  Someone should add code here to test
  1907.   if the ttychn device is not a real terminal, and if so to handle it some
  1908.   other way, like set the speed to zero for a sec, or close and reopen the
  1909.   device.
  1910. */
  1911. int
  1912. tthang() {
  1913.     if (!xlocal) return(0);        /* Only on local connections. */
  1914.  
  1915. #ifdef NETCONN
  1916.     if (network) {            /* Network connection. */
  1917.     int x;
  1918.     if (netclos() < 0) return(-1);    /* Close it */
  1919.         tvtflg = 0;
  1920.         x = 1;
  1921.     netopen(ttnmsv, &x, ttmdm);    /* Open it again */
  1922.         return(1);
  1923.     }
  1924. #endif /* NETCONN */
  1925.  
  1926.     if (!ttychn) return(0);        /* Not open. */
  1927.  
  1928.     tt_cancel();            /* Cancel pending i/o. */
  1929. /*
  1930.   This is NOT listed in the VMS Terminal Driver as one of the functions
  1931.   that does NOT work with LAT devices.
  1932. */
  1933.     debug(F101,"tthang 1","",gtimer());
  1934.     if (!CHECK_ERR("tthang: sys$qiow",
  1935.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE|IO$M_HANGUP, &wrk_iosb, 0, 0,
  1936.         0, 0, 0, 0, 0, 0))) return(-1);
  1937. /*
  1938.   The following 3-second sleep is required because the sys$qiow() returns
  1939.   immediately, about 2.5 seconds before VMS brings DTR back up.  Without this
  1940.   sleep(), DIAL does not work at all if DIAL HANGUP is ON, and, worse,
  1941.   subsequent operations on the device can hang the Kermit process
  1942.   uninterruptibly.
  1943. */
  1944.     sleep(3);
  1945.     debug(F101,"tthang 2","",gtimer());
  1946.     return(1);
  1947. }
  1948.  
  1949. /*  M S L E E P  --  Millisecond version of sleep().  */
  1950.  
  1951. /*
  1952.  Handles intervals up to about 7 minutes (2**32 / 10**7 seconds)
  1953. */
  1954. int
  1955. msleep(m) int m; {
  1956.  
  1957.     struct time_struct {
  1958.     long int hi, lo;
  1959.     } t;
  1960.  
  1961.     if (m <= 0) return(0);
  1962.     t.hi = -10000 * m;  /*  Time in 100-nanosecond units  */
  1963.     t.lo = -1;
  1964.     if (!CHECK_ERR("msleep: sys$schdwk",
  1965.     sys$schdwk(0, 0, &t, 0))) return(-1);
  1966.     sys$hiber();
  1967.     debug(F101,"msleep ok","",m);
  1968.     return(0);
  1969. }
  1970.  
  1971. /*  R T I M E R --  Reset elapsed time counter  */
  1972.  
  1973. VOID
  1974. rtimer() {
  1975.     tcount = time( (TIME_T *) 0);
  1976. }
  1977.  
  1978.  
  1979. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  1980.  
  1981. int
  1982. gtimer() {
  1983.     int x;
  1984.     x = (int) (time( (TIME_T *) 0 ) - tcount);
  1985.     return( (x < 0) ? 0 : x );
  1986. }
  1987.  
  1988. /*  Z T I M E  --  Return date/time string  */
  1989.  
  1990. VOID
  1991. ztime(s) char **s; {
  1992.     static TIME_T clock;
  1993. #ifdef COMMENT
  1994. #ifdef bogus
  1995.     static char time_string[24];
  1996.     struct dsc$descriptor_s t =
  1997.     {sizeof(time_string)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&time_string};
  1998.  
  1999.     if (!CHECK_ERR("ztime: sys$asctim",
  2000.     sys$asctim(0, &t, 0, 0))) return(-1);
  2001.     time_string[t.dsc$w_length] = '\0';
  2002.     *s = &time_string;
  2003. #else
  2004.     char *asctime();
  2005.     struct tm *tp;
  2006.  
  2007.     time(&clock);
  2008.     tp = localtime(&clock);
  2009.     *s = asctime(tp);
  2010. #endif /* bogus */
  2011. #else /* not COMMENT */
  2012. /*
  2013.  Apparently ctime() is available in old C libraries, even though asctime()
  2014.  is not.  Let's use the same method for all versions.
  2015. */
  2016.     time(&clock);
  2017.     *s = ctime(&clock);
  2018. #endif /* COMMENT */
  2019. }
  2020.  
  2021. /*  C O N G M  --  Get console terminal modes.  */
  2022.  
  2023. /*
  2024.  Saves current console mode, and establishes variables for switching between
  2025.  current (presumably normal) mode and other modes.
  2026. */
  2027. int
  2028. congm() {
  2029.     char s[] = CONDEV_COLON;
  2030.     struct itmlst dviitm[] = { {4,DVI$_DEVCLASS,(char *)&dviitm[0].adr,0},
  2031.             {0,0,0,0}};
  2032. #ifdef COMMENT /* old */
  2033.     struct dsc$descriptor_s
  2034.       r = {sizeof(s),DSC$K_DTYPE_T,DSC$K_CLASS_S,(char *)&s};
  2035. #else /* from ttj */
  2036.     struct dsc$descriptor_s
  2037.       devnam = {sizeof(s)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,s};
  2038. #endif /* COMMENT */
  2039.  
  2040.     debug(F101,"congm cgmf","",cgmf);
  2041.     if (cgmf) return(-1);        /* If called already, then nop */
  2042.  
  2043.     if (!CHECK_ERR("congm: sys$getdviw",
  2044.     sys$getdviw(0, 0, &devnam, &dviitm, &wrk_iosb, 0, 0, 0))) return(-1);
  2045.     debug(F101, "congm: devclass", "", (unsigned long int) dviitm[0].adr);
  2046.     if ((unsigned long int) dviitm[0].adr != DC$_TERM) {
  2047.     batch = 1;
  2048.     }
  2049. #ifdef COMMENT                /* Let's try it anyway... */
  2050.       else {
  2051. #endif /* COMMENT */
  2052.     /*
  2053.        NOTE: Reportedly, when C-Kermit is run from a .COM file
  2054.            it complains "Sorry, terminal type not supported: vt300-80".
  2055.            Reportedly, the cure is to execute the following code always,
  2056.            not just when the if condition above is false; i.e. just get
  2057.            rid of {, } else {, and }.  But some of the following system
  2058.            calls look like they might be dangerous on non-terminals,
  2059.            so widespread testing would be needed.  Better safe than sorry.
  2060.         */
  2061.         debug(F101, "congm: conchn", "", conchn);
  2062.     if (!conchn) {            /* Get console channel */
  2063.         $DESCRIPTOR(sys_input, CONDEV_COLON);
  2064.         conchn = vms_assign_channel(&devnam);
  2065.     }
  2066.     if (!conchn)
  2067.       return(-1);
  2068.         if (!CHECK_ERR("congm: sys$qiow",
  2069.         sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  2070.                  &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  2071.         ccraw = cccbrk = ccold;
  2072. #ifdef COMMENT
  2073.     }
  2074. #endif /* COMMENT */
  2075.     cgmf = 1;                /* Flag that we got them. */
  2076.     return(0);
  2077. }
  2078.  
  2079. /*  C O N C B --  Put console in cbreak mode.  */
  2080.  
  2081. /*  Returns 0 if ok, -1 if not  */
  2082.  
  2083. int
  2084. #ifdef CK_ANSIC
  2085. concb(char esc)
  2086. #else
  2087. concb(esc) char esc;
  2088. #endif /* CK_ANSIC */
  2089. /* concb */ {
  2090.     int x;
  2091.  
  2092.     debug(F101,"concb batch","",batch);
  2093.     if (batch) return(0);
  2094.     if (!cgmf) congm();            /* Get modes if necessary. */
  2095.     escchr = esc;            /* Make this available to other fns */
  2096.     ckxech = 1;                /* Program can echo characters */
  2097. /*
  2098.   Note: PASTHRU / PASSALL is what is preventing the Ctrl-C trap in the
  2099.   main program from working.  This business can be removed without any effect
  2100.   at all on the command parser -- everything still works: completion, ?-help,
  2101.   editing, etc.  The only problem is that Ctrl-Y is not trapped, so the
  2102.   program dies and leaves the terminal in no-echo mode.
  2103. */
  2104.     cccbrk.extended |= TT2$M_PASTHRU | TT2$M_ALTYPEAHD;
  2105.     if (parity)
  2106.       cccbrk.basic |= TT$M_NOECHO;
  2107.     else
  2108.       cccbrk.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  2109.     cccbrk.basic &= ~TT$M_ESCAPE;    /* Disable escape-seq processing */
  2110.     cccbrk.extended &= ~TT2$M_LOCALECHO; /* and local echoing */
  2111.     if (!CHECK_ERR("concb: sys$qiow",
  2112.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2113.                  &cccbrk, sizeof(cccbrk), 0, 0, 0, 0))) return(-1);
  2114.     debug(F100,"concb ok","",0);
  2115.     return(0);
  2116. }
  2117.  
  2118. /*  C O N B I N  --  Put console in binary mode  */
  2119.  
  2120. /*  Returns 0 if ok, -1 if not  */
  2121.  
  2122. int
  2123. #ifdef CK_ANSIC
  2124. conbin(char esc)
  2125. #else
  2126. conbin(esc) char esc;
  2127. #endif /* CK_ANSIC */
  2128. /* conbin */ {
  2129.  
  2130.     debug(F101,"conbin batch","",batch);
  2131.     if (batch) return(0);
  2132.     if (!cgmf) congm();            /* Get modes if necessary. */
  2133.     escchr = esc;            /* Make this available to other fns */
  2134.     ckxech = 1;                /* Program can echo characters */
  2135.     ccraw.extended |= TT2$M_PASTHRU | TT2$M_ALTYPEAHD;
  2136.     ccraw.basic &= ~TT$M_ESCAPE;    /* Disable escape-seq processing */
  2137.     ccraw.extended &= ~TT2$M_LOCALECHO;    /* and local echoing */
  2138.     if (parity)
  2139.       ccraw.basic |= TT$M_NOECHO;
  2140.     else
  2141.       ccraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  2142. #ifdef COMMENT
  2143.     ccraw.basic &= ~(TT$M_HOSTSYNC | TT$M_TTSYNC);
  2144. #endif /* COMMENT */
  2145.     if (!CHECK_ERR("conbin: sys$qiow",
  2146.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2147.                  &ccraw, sizeof(ccraw), 0, 0, 0, 0))) return(-1);
  2148.     return(0);
  2149. }
  2150.  
  2151.  
  2152. /*  C O N R E S  --  Restore the console terminal  */
  2153.  
  2154. int
  2155. conres() {
  2156.     debug(F101,"conres cgmf","",cgmf);
  2157.     if (!cgmf) return(0);        /* Do nothing if modes unknown */
  2158.     if (batch) return(0);
  2159.  
  2160.     msleep(250);
  2161.     ckxech = 0;                /* System should echo chars */
  2162.     if (!CHECK_ERR("conres: sys$qiow",
  2163.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2164.     &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  2165.     debug(F100,"conres ok","",0);
  2166.     return(0);
  2167. }
  2168.  
  2169.  
  2170. /*  C O N R E S N E --  Restore the console terminal with No Echo */
  2171.  
  2172. int
  2173. conresne() {
  2174.     debug(F101,"conresne cgmf","",cgmf);
  2175.     if (!cgmf) return(0);        /* Don't do anything if modes unk */
  2176.     if (batch) return(0);
  2177.  
  2178.     msleep(250);
  2179.     ckxech = 1;                /* Program should echo chars */
  2180.  
  2181.     cctmp = ccold;
  2182.     cctmp.basic |= TT$M_NOECHO;
  2183.     if (!CHECK_ERR("conres: sys$qiow",
  2184.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  2185.     &cctmp, sizeof(cctmp), 0, 0, 0, 0))) return(-1);
  2186.     debug(F100,"conresne ok","",0);
  2187.     return(0);
  2188. }
  2189.  
  2190. /*  C O N O C  --  Output a character to the console terminal  */
  2191.  
  2192. int
  2193. #ifdef CK_ANSIC
  2194. conoc(char c)
  2195. #else
  2196. conoc(c) char c;
  2197. #endif /* CK_ANSIC */
  2198. /* conoc */ {
  2199.     if (batch) putchar(c);
  2200.     else
  2201.     if (!CHECK_ERR("conoc: sys$qiow",
  2202.         sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2203.              &wrk_iosb, 0, 0, &c, 1, 0, 0, 0, 0))) return(-1);
  2204.     return(1);
  2205. }
  2206.  
  2207. /*  C O N X O  --  Write x characters to the console terminal  */
  2208.  
  2209. int
  2210. conxo(x,s) char *s; int x; {
  2211.     if (batch) fprintf(stdout, "%.*s", x, s);
  2212.     else if (!CHECK_ERR("conxo: sys$qiow",
  2213.     sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  2214.          &wrk_iosb, 0, 0, s, x, 0, 0, 0, 0))) return(-1);
  2215.     return(0);
  2216. }
  2217.  
  2218. /*  C O N O L  --  Write a line to the console terminal  */
  2219.  
  2220. int
  2221. conol(s) char *s; {
  2222.     int len;
  2223.  
  2224.     if (batch) fputs(s, stdout);
  2225.     else {
  2226.     len = strlen(s);
  2227.     if (!CHECK_ERR("conol: sys$qiow",
  2228.         sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb,
  2229.              0, 0, s, len, 0, 0, 0, 0))) return(-1);
  2230.     }
  2231.     return(1);
  2232. }
  2233.  
  2234. /*  C O N O L A  --  Write an array of lines to console, with CRLFs added */
  2235.  
  2236. int
  2237. conola(s) char *s[]; {
  2238.     int i;
  2239.     char t[100], *cp;
  2240.  
  2241.     for (i=0 ; *s[i] ; i++) {
  2242.     strncpy(t,s[i],100);
  2243.     for (cp = t + strlen(t); --cp >= t;) {
  2244.         if (*cp != '\n' && *cp != '\r') {
  2245.         cp++;
  2246.         *cp++ = '\r'; *cp++ = '\n'; *cp++ = '\0';
  2247.         break;
  2248.         }
  2249.     }
  2250.     if (conol(t) < 0) return(-1);
  2251.     }
  2252.     return(0);
  2253. }
  2254.  
  2255. /*  C O N O L L  --  Output a string followed by CRLF  */
  2256.  
  2257. int
  2258. conoll(s) char *s; {
  2259.     int x;
  2260.     x = conol(s);
  2261.     if (x > -1)
  2262.       x = conol("\r\n");
  2263.     return(x);
  2264. }
  2265.  
  2266.  
  2267. /*  C O N C H K  --  Check if characters available at console  */
  2268.  
  2269. int
  2270. conchk() {
  2271.     struct {
  2272.     unsigned short count;
  2273.     unsigned char first;
  2274.     unsigned char reserved1;
  2275.     long reserved2;
  2276.     } t;
  2277.  
  2278.     if (batch) return(0);
  2279.     return(CHECK_ERR("conchk: sys$qiow",
  2280.     sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, &wrk_iosb,
  2281.          0, 0, &t, sizeof(t), 0, 0, 0, 0)) ? t.count : 0);
  2282. }
  2283.  
  2284. /*  C O N I N C  --  Get a character from the console  */
  2285.  
  2286. int
  2287. coninc(timo) int timo; {        /* Timo > 0 = timeout in seconds. */
  2288.     int n = 0;
  2289.     unsigned char ch;
  2290.     int func, mask;
  2291.  
  2292.     debug(F101,"coninc timo","",timo);
  2293.     debug(F101,"coninc con_queued","",con_queued);
  2294.  
  2295.     if (batch)
  2296.       return(getchar());
  2297.  
  2298.     mask = 1 << CON_EFN;
  2299.  
  2300.     if (con_queued) {        /* If a console read was already posted... */
  2301.                 /* e.g. by contti() ... */
  2302.     if (timo > 0) {                /* If a timeout was specified... */
  2303.         struct { int hi, lo; } qtime;   /* Set a timer... */
  2304.         qtime.hi = -10*1000*1000*timo;  /* in VMS "delta-time" notation. */
  2305. /*
  2306.   If the timo value is big enough to make the delta-time overflow an integer,
  2307.   substitute something useful.
  2308. */  
  2309.         if (qtime.hi > 0)        /* Did it go positive? */
  2310.           qtime.hi = -0x7fffffff;    /* Yes, so fudge it. */
  2311.         qtime.lo = -1;
  2312.         sys$setimr(TIM_EFN, &qtime, 0, 0, 0); /* Specify event flag. */
  2313.         mask |= TIM_EFN;        /* And add it to read mask. */
  2314.     }
  2315.     sys$wflor(CON_EFN, mask);    /* Wait for SETIMR to complete. */
  2316.     sys$readef(CON_EFN, &mask);    /* Read event flags. */
  2317.     if (mask & (1 << CON_EFN)) {    /* We got a console event? */
  2318.         ch = (unsigned char) conch;    /* (see contti() about this...) */
  2319.         CHECK_ERR("coninc: coniosb.status", coniosb.status);
  2320.         con_queued = 0;
  2321.     } else {            /* We didn't */
  2322.         ch = -1;            /* So indicate that coninc() ... */
  2323.         vms_status = SS$_TIMEOUT;    /*  timed out. */
  2324.     }
  2325.     } else {                /* Console read not already posted */
  2326.     func = IO$_READVBLK | IO$M_NOFILTR;
  2327.     if (timo > 0) func |= IO$M_TIMED;
  2328.     CHECK_ERR("coninc: sys$qiow",
  2329.       sys$qiow(QIOW_EFN, conchn, func, &wrk_iosb,0,0,&ch,1,timo,0,0,0));
  2330.     }
  2331.     if (vms_status & 1) {
  2332.     if (wrk_iosb.status == SS$_TIMEOUT)
  2333.       return(-1);
  2334.     else return( (ch == '\r') ? '\n' : ch );
  2335.     } else return(-1);
  2336. }
  2337.  
  2338.  
  2339. /*  V M S _ G E T C H A R -- get a character from the console (no echo).
  2340.  *    Since we use raw reads, we must check for ctrl/c, ctrl/y and
  2341.  *    ctrl/z ourselves.  We probably should post a "mailbox" for
  2342.  *    ctrl/c and ctrl/y so the poor user can abort a runaway Kermit.
  2343.  *    Note: this routine intends for ctrl/z (eof) to be "permanent".
  2344.  *    Currently, no kermit routine calls "clearerror".  If this
  2345.  *    changes, the following code must be rewritten.
  2346.  */
  2347.  
  2348. int
  2349. vms_getchar() {
  2350.     register unsigned int ch;
  2351.     static int ateof = 0;
  2352.  
  2353.     if (ateof)
  2354.       return (EOF);
  2355.     ch = coninc(0);
  2356.     switch (ch) {
  2357.       case ('Y' - 64):
  2358.       case ('C' - 64):
  2359. #ifndef COMMENT
  2360. /*
  2361.   Just call the same handler that signal(SIGINT,xxx) would have invoked
  2362.   if Ctrl-C had been trapped.  The pointer to the handler was saved in
  2363.   cctrap by conint().
  2364. */
  2365.     if (cctrap)
  2366.       (*cctrap)(SIGINT,0);
  2367. #else
  2368.     ttclos(ttyfd);            /* Close down other terminal    */
  2369.     conres();            /* And cleanup console modes    */
  2370.     exit(SS$_ABORT);        /* Fatal exit.            */
  2371. #endif /* COMMENT */
  2372.       case ('Z' - 64):
  2373.     ateof = 1;
  2374.     return (EOF);
  2375.  
  2376.       default:
  2377.     return (ch);
  2378.     }
  2379. }
  2380.  
  2381. /*  C O N T T I  --  Get character from console then from tty  */
  2382. /*
  2383.   This is used in conect() when NO_FORK is defined.
  2384.   src is returned with 1 if the character came from the comm. line,
  2385.   0 if it was from the console, and with -1 if there was any error.
  2386. */
  2387. #ifdef TCPIPLIB
  2388. /*
  2389.  * Network/console read posted?
  2390.  */
  2391. static int    nettty_queued    = 0;
  2392. static int    netcon_queued    = 0;
  2393. #endif /* TCPIPLIB */
  2394.  
  2395. int
  2396. contti(c, src) int *c, *src; {
  2397.  
  2398. #ifndef TCPIPLIB
  2399.     int mask = 1<<CON_EFN | 1<<TTY_EFN;
  2400.     int x; unsigned char cc;
  2401.  
  2402. #else /* TCPIPLIB */
  2403.  
  2404. #ifdef CMU_TCPIP
  2405.     int s;                    /* select status */
  2406.     fd_set exceptfds;                /* select exceptions */
  2407.     static struct timeval timeout;        /* for non-blocking select */
  2408. #endif /* CMU_TCPIP */
  2409.  
  2410. #define NET_EFN 7                /* Network event flag */
  2411.  
  2412.     int                mask;        /* Event flag mask */
  2413.  
  2414.     static CHAR            concc;        /* Console and network data */
  2415.     static CHAR            netcc;
  2416.  
  2417.     static struct iosb_struct    net_iosb;
  2418.     static struct iosb_struct    con_iosb;    /* IO status blocks */
  2419.  
  2420. /*
  2421.   Buffered network data, count, next character.  Declared in CKCNET.C ...
  2422. */
  2423.     extern CHAR            ttibuf[];
  2424.     extern int            ttibn;    
  2425.     extern int            ttibp;
  2426. #endif /* TCPIPLIB */
  2427.  
  2428.     *src = -1;                /* Assume there was an error */
  2429.  
  2430. #ifdef TCPIPLIB
  2431.     if (network) {            /* For active network connections */
  2432.     debug(F100,"contti network","",0);
  2433.  
  2434.     if (ttibn > 0) {
  2435.         /*
  2436.          * Handle the case where data remains in our "internal" buffer.
  2437.          * We need to:
  2438.          *
  2439.          *    -- Handle the console keyboard (is a character ready?)
  2440.          *    -- Return one character from the network buffer if not
  2441.          *
  2442.          * Post a new console read if necessary
  2443.          */
  2444.             if (!netcon_queued) {
  2445. #ifdef CMU_TCPIP
  2446.             cmu_stdin_read(IO$_READVBLK, &concc, 1, 0, 0);
  2447. #else
  2448.                 if (!CHECK_ERR("contti: console sys$qio",
  2449.                             sys$qio(CON_EFN, conchn, IO$_READVBLK,
  2450.                     &con_iosb, 0, 0, &concc, 1,
  2451.                     0, 0, 0, 0))) return(-1);
  2452. #endif /* CMU_TCPIP */
  2453.                     netcon_queued = 1;
  2454.         }
  2455.         /*
  2456.          * Console character ready?
  2457.          */
  2458. #ifdef CMU_TCPIP
  2459.         exceptfds = mask = 1;
  2460.         if (select(1, &mask, 0, &exceptfds, &timeout) == 1) {
  2461.             /*
  2462.              * check for error
  2463.              */
  2464.             if (FD_ISSET(0,&exceptfds)) {
  2465.                 return(-1);
  2466.             }
  2467. #else
  2468.                (void) sys$readef(CON_EFN, &mask);
  2469.  
  2470.             if (mask & (1 << CON_EFN)) {
  2471. #endif /* CMU_TCPIP */
  2472.             /*
  2473.              * Yes, return it
  2474.              */
  2475.             netcon_queued = 0;
  2476. #ifndef CMU_TCPIP
  2477.              if (!CHECK_ERR("contti: con_iosb.status",
  2478.                     con_iosb.status)) return(-1);
  2479. #endif /* CMU_TCPIP */
  2480.             *c   = concc & 0xff;
  2481.                 *src = 0;
  2482.                 return(1);
  2483.         }
  2484.         /*
  2485.          * No console data; return buffered network character
  2486.          */
  2487.         ttibn--;
  2488.         *c   = ttibuf[ttibp++];
  2489.         *src = 1;
  2490.         return(1);
  2491.     }
  2492.     /*
  2493.      * No buffered data; post network and console reads
  2494.      */
  2495.         if (!nettty_queued) {
  2496. #ifdef CMU_TCPIP
  2497.         /*
  2498.          * network read is always posted
  2499.          */
  2500. #else
  2501. /*     -lt.  1992-09-14  begin */
  2502. /* All the event flag numbers should be obtained using lib$get_ef().
  2503.  * Using hard coded numbers, especially < 31 is tres dangereuse!!!
  2504.  * Be careful, one must also change the event flag cluster used by
  2505.  * sys$readef. It is *not* just a simple matter of changing a few #defines.
  2506.  *
  2507.  * At least for DEC TCP/IP Services, socket calls return a proper file
  2508.  * descriptor (fd).  OpenVMS system services require a channel
  2509.  * (from sys$assign).  The two are *not* the same.  The call vaxc$get_sdc()
  2510.  * maps from a DEC TCP/IP fd to a channel.
  2511.  *
  2512.  * This is "gag me with a spoon" code, but it gets thing up and running.
  2513.  *
  2514.  */
  2515. #ifdef DEC_TCPIP
  2516.  
  2517.     {
  2518.        static int last_ttyfd = -1;
  2519.        static short int net_chan = -1;
  2520.  
  2521.     if (ttyfd != last_ttyfd){
  2522.         last_ttyfd = ttyfd;
  2523. #ifdef COMMENT
  2524. #ifdef __DECC
  2525.         net_chan = (short) decc$get_sdc(last_ttyfd);
  2526. #else
  2527. #ifdef VAXC
  2528.         net_chan = vaxc$get_sdc(last_ttyfd);
  2529. #else
  2530. #        error CALL TO GET_SDC requires DECC or VAXC compiler!
  2531. #endif    /* VAXC */
  2532. # endif    /* DECC */
  2533. #else /* COMMENT */
  2534.         net_chan = GET_SDC(last_ttyfd);
  2535. #endif /* COMMENT */
  2536.             }
  2537.  
  2538.             if (!CHECK_ERR("contti: network sys$qio",
  2539.                     sys$qio(NET_EFN, net_chan, IO$_READVBLK, &net_iosb, 0, 0,
  2540.                             &netcc, 1, 0, 0, 0, 0))) return(-1);
  2541.         }
  2542.  
  2543. #else /* Not DEC_TCPIP */
  2544.  
  2545.             if (!CHECK_ERR("contti: network sys$qio",
  2546.                     sys$qio(NET_EFN, ttyfd, IO$_READVBLK, &net_iosb, 0, 0,
  2547.                             &netcc, 1, 0, 0, 0, 0))) return(-1);
  2548. #endif /* DEC_TCPIP */
  2549. #endif /* CMU_TCPIP */
  2550.         nettty_queued = 1;
  2551.     }
  2552.  
  2553.         if (!netcon_queued) {
  2554. #ifdef CMU_TCPIP
  2555.         cmu_stdin_read(IO$_READVBLK, &concc, 1, 0, 0);
  2556. #else
  2557.             if (!CHECK_ERR("contti: console sys$qio",
  2558.                     sys$qio(CON_EFN, conchn, IO$_READVBLK, &con_iosb,
  2559.                 0, 0, &concc, 1, 0, 0, 0, 0))) return(-1);
  2560. #endif /* CMU_TCPIP */
  2561.             netcon_queued = 1;
  2562.     }
  2563.     /*
  2564.      * Wait for a character
  2565.      */
  2566. #ifdef CMU_TCPIP
  2567.     exceptfds = mask = (1 | (1<<ttyfd));
  2568.     s = select(ttyfd, &mask, 0, &exceptfds, 0); /*a blocking select*/
  2569.  
  2570.     if (FD_ISSET(0,&exceptfds))
  2571.         return(-1);
  2572.  
  2573.     if (FD_ISSET(ttyfd,&exceptfds))
  2574.         return(-1);
  2575.  
  2576.     if (FD_ISSET(0,&mask)) {
  2577.         *c         = concc & 0xff;
  2578.         *src       = 0;
  2579.         netcon_queued = 0;
  2580.     }
  2581.     else {
  2582.         if (FD_ISSET(ttyfd,&mask)) {
  2583.         s = cmu_read(ttyfd, &netcc, 1);
  2584.         if (s <= 0)
  2585.             return(-1);
  2586.         *c         = netcc & 0xff;
  2587.         *src       = 1;
  2588.         nettty_queued = 0;
  2589.             }
  2590.     }
  2591. #else
  2592.         mask = (1 << CON_EFN) | (1 << NET_EFN);
  2593.  
  2594.         if (!CHECK_ERR("contti: sys$wflor",
  2595.                     sys$wflor(CON_EFN, mask))) return(-1);
  2596.  
  2597.         if (!CHECK_ERR("contti: sys$readef",
  2598.                     sys$readef(CON_EFN, &mask))) return(-1);
  2599.  
  2600.         if (mask & (1 << CON_EFN)) {
  2601.         /*
  2602.          * Console
  2603.          */
  2604.             if (!CHECK_ERR("contti: con_iosb.status",
  2605.                 con_iosb.status)) return(-1);
  2606.  
  2607.             *c         = concc & 0xff;
  2608.         *src       = 0;
  2609.             netcon_queued = 0;
  2610.  
  2611.         } else if (mask & (1 << NET_EFN)) {
  2612.         /*
  2613.          * Network
  2614.          */
  2615.         if (!(net_iosb.status & 1)) {
  2616.         /*
  2617.          * Network read error
  2618.          */
  2619. #ifdef WINTCP
  2620.         _$set_vaxc_error(SS$_NORMAL, net_iosb.status);
  2621.         win$perror("contti: net_iosb.status");
  2622. #else
  2623. #ifdef MULTINET
  2624. #ifdef COMMENT
  2625. /*
  2626.   When user hangs up, this prints an unnecessary scary message,
  2627.   like "Operation would block."
  2628. */
  2629.         socket_perror("contti: net_iosb.status");
  2630. #endif /* COMMENT */
  2631. #endif /* MULTINET */
  2632. #endif /* WINTCP */
  2633.         return(-1);
  2634.         }
  2635.  
  2636.         if (net_iosb.size == 0) {
  2637.         /*
  2638.          * Handle reset from remote
  2639.          */
  2640.         return(-1);
  2641.         }
  2642.         *c         = netcc & 0xff;
  2643.         *src       = 1;
  2644.             nettty_queued = 0;
  2645.         }
  2646. #endif /* CMU_TCPIP */
  2647.     } else                /* Not network */
  2648. #endif /* TCPIPLIB */
  2649.  
  2650. /*
  2651.   Should we worry about a network connection that's running under BATCH ?
  2652. */
  2653.     if (batch) {            /* Batch? */
  2654.     debug(F100,"contti batch","",0);
  2655.     if ((*c = getchar()) != EOF) {
  2656.         *src = 0;
  2657.     } else {
  2658.         *src = 1;
  2659.         *c = ttinc(0);
  2660.     }
  2661.     } else {                /* Interactive but not network */
  2662.  
  2663. #ifdef TTXBUF
  2664.     if (ttxbn > 0) {        /* Buffered port chars available */
  2665.  
  2666. /* Post a read on the console if one is not posted already */
  2667.  
  2668.         if (!con_queued) {
  2669.         if (!CHECK_ERR("contti: console sys$qio",
  2670.                  sys$qio(CON_EFN, conchn, IO$_READVBLK,
  2671.                      &coniosb, 0, 0,
  2672.                      &conch, 1, 0, 0, 0, 0)))
  2673.           return(-1);
  2674.         con_queued = 1;
  2675.         }
  2676.  
  2677. /* See if a console character has been read and if so, return it.  */
  2678.  
  2679.         (void) sys$readef(CON_EFN, &mask);
  2680.         if (mask & (1 << CON_EFN)) {
  2681.         con_queued = 0;
  2682.         if (!CHECK_ERR("contti: coniosb.status",
  2683.                    coniosb.status))
  2684.           return(-1);
  2685.         *c   = conch & 0xff;
  2686.         *src = 0;
  2687.         return(1);
  2688.         }
  2689.  
  2690. /* No console character, so return buffered port character */
  2691.  
  2692.         *c = ttinc(0);
  2693.         *src = 1;
  2694.         return(1);
  2695.     }
  2696.  
  2697. /* No buffered port data; post both network and console reads... */
  2698.  
  2699. #endif /* TTXBUF */
  2700.  
  2701.         mask = 1<<CON_EFN | 1<<TTY_EFN;    /* Event mask */
  2702.  
  2703.     debug(F101,"contti interactive mask","",mask);
  2704.  
  2705.         if (!con_queued) {        /* Console read not queued... */
  2706.             if (!CHECK_ERR("contti: console sys$qio",
  2707.             sys$qio(CON_EFN, conchn, IO$_READVBLK, &coniosb, 0, 0,
  2708.                     &conch, 1, 0, 0, 0, 0))) return(-1);
  2709.         con_queued = 1;
  2710.         debug(F100,"contti con_queued","",0);
  2711.     }
  2712.         if (!tt_queued) {        /* Port read not queued */
  2713.             if (!CHECK_ERR("contti: tty sys$qio",
  2714.             sys$qio(TTY_EFN, ttychn, IO$_READVBLK, &ttiosb, 0, 0,
  2715.                     &ttch, 1, 0, 0, 0, 0))) return(-1);
  2716.         tt_queued = 1;
  2717.         debug(F100,"contti tt_queued","",0);
  2718.     }
  2719.  
  2720. /* Wait for one of the queued reads to complete */
  2721.  
  2722.         if (!CHECK_ERR("contti: sys$wflor",
  2723.             sys$wflor(CON_EFN, mask))) return(-1);
  2724.     debug(F100,"contti sys$wflor ok","",0);
  2725.  
  2726. /* Read the event flags to see which read was completed */
  2727.  
  2728.         if (!CHECK_ERR("contti: sys$readef",
  2729.             sys$readef(CON_EFN, &mask))) return(-1);        
  2730.     debug(F100,"contti sys$readef ok","",0);
  2731.  
  2732.  
  2733. /* Return the character with the appropriate source (src) indicator */
  2734.  
  2735.         if (!(*src = ((mask & 1<<CON_EFN) ? 0 : 1))) {
  2736.             *c = conch;
  2737.             CHECK_ERR("contti: coniosb.status", coniosb.status);
  2738.             con_queued = 0;
  2739.         } else {
  2740.             *c = (ttprty ? ttch & 0177 : ttch);
  2741.         if (ttiosb.status == SS$_HANGUP) {
  2742.         fprintf(stderr,"\n%%CKERMIT-F-HANGUP, data set hang-up");
  2743.         *src = -1;
  2744.         return(1);
  2745.         }
  2746.             CHECK_ERR("contti: ttiosb.status", ttiosb.status);
  2747.             tt_queued = 0;
  2748.         }
  2749.         if (!(vms_status & 1)) *src = -1;
  2750.     }
  2751.     debug(F101,"contti *src","",*src);
  2752.     return((*src > -1) ? 1 : 0);
  2753. }
  2754.  
  2755. /*
  2756.   C A N C I O
  2757.   Cancel pending I/O requests on console and communication device.
  2758. */
  2759. VOID
  2760. cancio()  {
  2761. #ifdef NETCONN
  2762.     if (network) {
  2763. #ifdef TCPIPLIB
  2764. #ifdef DEC_TCPIP
  2765.     short int net_chan = -1;
  2766. #ifdef COMMENT
  2767. #ifdef __DECC
  2768.     net_chan = (short) decc$get_sdc(ttyfd);
  2769. #else  /* !__DECC */
  2770. #ifdef VAXC
  2771.     net_chan = vaxc$get_sdc(ttyfd);
  2772. #else  /* !VAXC */
  2773. # error CALL TO GET_SDC requires DECC or VAXC compiler!
  2774. #endif /* VAXC */
  2775. #endif /* __DECC */
  2776. #else  /* COMMENT */
  2777.     net_chan = GET_SDC(ttyfd);
  2778. #endif /* COMMENT */
  2779.         if (nettty_queued) (void) sys$cancel(net_chan);
  2780. #else  /* DEC_TCPIP */
  2781. #ifdef CMU_TCPIP
  2782.     /* not going to do this when CMU is the network transport.
  2783.      * the sys$cancel will cause the channel to shutdown
  2784.      *
  2785.      * if (nettty_queued) (void) sys$cancel(cmu_get_sdc(ttyfd));
  2786.      */
  2787. #else  /* !CMU_TCPIP */
  2788.        if (nettty_queued) (void) sys$cancel(ttyfd);
  2789. #endif /* CMU_TCPIP */
  2790. #endif /* DEC_TCPIP */
  2791.         if (netcon_queued) (void) sys$cancel(conchn);
  2792.  
  2793.         netcon_queued = 0;
  2794.         nettty_queued = 0;
  2795.     return;
  2796. #else /* Not TCPIPLIB */
  2797.     return;
  2798. #endif /* TCPIPLIB */
  2799.     }
  2800. #endif /* NETCONN */
  2801.  
  2802.     if (!batch) {
  2803.         CHECK_ERR("cancio: console sys$cancel",
  2804.             sys$cancel(conchn));
  2805.         CHECK_ERR("cancio: tty sys$cancel",
  2806.             sys$cancel(ttychn));
  2807.         con_queued = 0;
  2808.         tt_queued = 0;
  2809.     }
  2810. }
  2811.  
  2812. /* get_qio_maxbuf_size()
  2813.  *
  2814.  * Get maximum size of QIO that can occur without getting the dreaded
  2815.  * exceeded quota status.
  2816.  */
  2817.  
  2818. #ifndef SYI$_MAXBUF
  2819. #define SYI$_MAXBUF 4175
  2820. #endif /* SYI$_MAXBUF */
  2821.  
  2822. int
  2823. get_qio_maxbuf_size(ttychn) unsigned long int ttychn; {
  2824.     unsigned char *tmpbuf;
  2825.     int unsigned long max=0;
  2826.     struct itmlst syiitm[] = { {2,SYI$_MAXBUF,(char *)&max,0},
  2827.             {0,0,0,0}};
  2828.  
  2829.     if (!ttychn) return(-1);
  2830.  
  2831.     if (!CHECK_ERR("get_qio_maxbuf_size: sys$getsyiw",
  2832.     sys$getsyiw(     0    /* efn */
  2833.             ,0    /* csidadr */
  2834.             ,0    /* nodename */
  2835.             ,&syiitm /* itmlst */
  2836.             ,&wrk_iosb /* iosb */
  2837.             ,0    /* astadr */
  2838.             ,0)))    /* astprm */
  2839.         exit(SS$_ABORT);        /* Fatal exit */
  2840.  
  2841.     if (!(tmpbuf = malloc(max)))
  2842.     return(0);
  2843.  
  2844.     for (; max > 0; max -= 16) {
  2845.     if (!test_qio(ttychn,max,tmpbuf)) /* (was &tmpbuf, caused crash) */
  2846.     {
  2847.         free(tmpbuf);
  2848.         return(max);
  2849.     }
  2850.     }
  2851.  
  2852.     free(tmpbuf);
  2853.     printf("\n%%CKERMIT-F-get_qio_maxbuf_size, Could not get maxbuf size\n");
  2854.     exit(SS$_ABORT);        /* Fatal exit */
  2855. }
  2856.  
  2857. int
  2858. test_qio(ttychn,max,dest)
  2859. unsigned long int ttychn;
  2860. long int max;
  2861. unsigned char *dest;
  2862. {
  2863.     static int trmmsk[2] = {0,0};
  2864.  
  2865. /*    trmmsk[1] = 1 << eol; */
  2866.  
  2867.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED,
  2868.               &wrk_iosb, 0, 0, dest, max, 0, &trmmsk, 0, 0);
  2869.     return( !(vms_status & 1) ||
  2870.     (!(wrk_iosb.status & 1)) && wrk_iosb.status != SS$_TIMEOUT);
  2871. }
  2872.  
  2873.  
  2874. /*
  2875.  * Flush tt output buffer
  2876.  */
  2877.  
  2878. int
  2879. ttfluo() {
  2880.  
  2881.     long n=0;
  2882.  
  2883. #ifdef NETCONN
  2884.     if (network) return(0);
  2885. #endif /* NETCONN */
  2886.  
  2887.     if (!ttychn) return(-1);        /* Not open. */
  2888.  
  2889.     if (!CHECK_ERR("ttfluo: sys$qiow",
  2890.     sys$qiow(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED|IO$M_PURGE,
  2891.          &wrk_iosb, 0, 0, &n, 0, 0, 0, 0, 0))) {
  2892.     perror("flush failed");
  2893.     return(-1);
  2894.     }
  2895.     return(0);
  2896. }
  2897.  
  2898. /*  T T G M D M  --  Get modem signals  */
  2899. /*
  2900.  Looks for the modem signals CTS, DSR, and CTS, and returns those that are
  2901.  on in as its return value, in a bit mask as described for ttwmdm.  Returns:
  2902.  -3 Not implemented
  2903.  -2 if the line does not have modem control
  2904.  -1 on error.
  2905.  >= 0 on success, with a bit mask containing the modem signals that are on.
  2906. */
  2907. int
  2908. ttgmdm() {
  2909.     struct {
  2910.     unsigned char type;
  2911.     unsigned char spare1;
  2912.     unsigned char modem;
  2913.     unsigned char spare2;
  2914.     unsigned long filler;
  2915.     } mdminfo;
  2916.     int retval;
  2917.  
  2918. #ifdef NETCONN
  2919.     if (network) return(-2);
  2920. #endif /* NETCONN */
  2921.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE|IO$M_RD_MODEM,
  2922.               &wrk_iosb, 0, 0, &mdminfo, 0, 0, 0, 0, 0);
  2923.  
  2924.     if (vms_status != SS$_NORMAL) {
  2925.     debug(F101,"ttgmdm serious error, status","",vms_status);
  2926.     return(-1);
  2927.     }
  2928.  
  2929.     debug(F101,"ttgmdm iosb","",wrk_iosb.status);
  2930.     debug(F101,"ttgmdm type","",mdminfo.type);
  2931.     debug(F101,"ttgmdm modem","",mdminfo.modem);
  2932.  
  2933.     if (wrk_iosb.status != SS$_NORMAL) {
  2934.     debug(F101,"ttgmdm iosb error, status","",wrk_iosb.status);
  2935.     return(-1);
  2936.     }
  2937.  
  2938. #ifdef DT$_LAT
  2939.     if (mdminfo.type == DT$_LAT) {
  2940.     debug(F101,"ttgmdm LAT port, no modem control","",0);
  2941.     return(-2);
  2942.     }
  2943. #endif /* DT$_LAT */
  2944.  
  2945.     if (mdminfo.type == 0) {
  2946.     debug(F101,"ttgmdm unknown driver, modem","",mdminfo.modem);
  2947.     return(-2);
  2948.     }
  2949.  
  2950.     retval = BM_DTR | BM_RTS;        /* Not visible, set by TTDRIVER */
  2951.     if (mdminfo.modem & TT$M_DS_CTS)
  2952.     retval |= BM_CTS;
  2953.     if (mdminfo.modem & TT$M_DS_DSR)
  2954.     retval |= BM_DSR;
  2955.     if (mdminfo.modem & TT$M_DS_CARRIER)
  2956.     retval |= BM_DCD;
  2957.     if (mdminfo.modem & TT$M_DS_RING)
  2958.     retval |= BM_RNG;
  2959.     return(retval);
  2960. }
  2961.  
  2962. /*
  2963.   Return serial communication device speed.  Speed is retreived from a qiow
  2964.   initially.  It is then changed only at user request.  (Yes, but it would
  2965.   still be better to do another qiow here to actually read the speed from the
  2966.   device so we know it is what we think it should be!)
  2967. */
  2968. long
  2969. ttgspd() {
  2970.     extern int speed;
  2971. #ifdef NETCONN
  2972.     if (network) return(-1);        /* -1 if network connection */
  2973. #endif /* NETCONN */
  2974.     return(ttspeed);
  2975. }
  2976.  
  2977.  
  2978. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  2979.  *
  2980.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  2981.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  2982.  *  2 = Auto: For "modem direct": The same as "Off".
  2983.  *            For real modem types: Heed carrier during connect, but ignore
  2984.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  2985.  *
  2986.  * As you can see, this setting does not affect dialing, which always ignores
  2987.  * carrier (unless there is some special exception for some modem type).  It
  2988.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  2989.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  2990.  * (or should be) always called before any communications is tried, which
  2991.  * means that, practically speaking, the effect is immediate.
  2992.  *
  2993.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  2994.  *
  2995.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  2996.  * environment (or any non-termio using environment).  Until that time, this
  2997.  * will simply be a no-op for BSD.
  2998.  *
  2999.  * Note that in previous versions, the carrier was most often left unchanged
  3000.  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
  3001.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  3002.  * modes.
  3003.  */
  3004. int
  3005. ttscarr(carrier) int carrier; {
  3006.  
  3007.     return(-1);
  3008. }
  3009.  
  3010. int
  3011. psuspend(x) int x; {
  3012.  
  3013.     return(-1);
  3014. }
  3015.  
  3016. #ifdef CK_CURSES
  3017. /*
  3018.   tgetent() support for VMS curses emulation.
  3019.   Used by all three VMS fullscreen methods.
  3020.   Called from "SET FILE DISPLAY FULLSCREEN" in ckuus7.c.
  3021. */
  3022. int isvt52 = 0;                /* VT52/VT1xx flag */
  3023.  
  3024. int
  3025. tgetent(lp, term) char *lp, *term; {
  3026.     debug(F101,"tgetent terminal type","",ccold.type);
  3027.     debug(F101,"tgetent terminal extended","",ccold.extended);
  3028.  
  3029.     if ((ccold.type == DT$_VT5X) || (ccold.type == DT$_VT55)) {
  3030.     debug(F100,"tgetent VT5x","",0);
  3031.     isvt52 = 1;
  3032.     return(1);
  3033.     }
  3034.     if ((ccold.extended & TT2$M_ANSICRT) == TT2$M_ANSICRT) {
  3035.     debug(F100,"tgetent ANSICRT","",0);
  3036.     isvt52 = 0;
  3037.     return(1);
  3038.     }
  3039.     if ((ccold.extended & TT2$M_DECCRT) == TT2$M_DECCRT) {
  3040.     debug(F100,"tgetent DECCRT","",0);
  3041.     isvt52 = 0;
  3042.     return(1);
  3043.     }
  3044.     return(0);                /* Not a supported terminal type */
  3045. }
  3046. #endif /* CK_CURSES */
  3047.