(a "remote"
line) than the one you are currently using for your interactive
session.  See the following example.  NOTE that UMODEM requires
that the remote line be set to EIGHT_BIT operation.  This is done
automatically when UMODEM is used on the local line, but must be
done manually when using UMODEM on a remote line.
3 Example
UNIX-VMS file transfer initiated from the VMS system using
VAXNET.
     $ set terminal/eight_bit remote    ! Needed for UMODEM, but
     $ vaxnet remote                    !   not VAXNET
     <you log on to the remote system>
     % umodem -rt vms.file              ! Start UMODEM on the
     ...                                !   remote UNIX system
     UMODEM:  Ready to RECEIVE File
     ^/ Q                               ! Get out of VAXNET
     $ define/user tt remote            ! Temporarily redefine
                                        !   logical name TT
     $ umodem -st vms.fil               ! Sends file from the
     ...                                !   VMS system
     UMODEM:  Ready to SEND File
     $ vaxnet remote                    ! Back to remote terminal
     %                                  !   operation.  Remember
                                        !   to log off!

2 Problems/Questions
     Contact Wally Reiher:  username REIHER, MB9-19, 495-1768.
He has a version of MODEM configured for the Heath/Zenith-89
microcomputer system which is in the public domain and free for
the asking.
/*
 *  VMODEM
 *  VMS support for UMODEM program
 *
 *	Defined herein are some utility routines to make the UNIX
 *	program UMODEM run under VAX/VMS C (Compiler newer than V 1.00)
 *
 *		ASSIGN_CHANNEL	Calls the VMS System Service $ASSIGN
 *				to assign a channel to a device.
 *				The routine currently has the device
 *				"TT" hardwired into it.
 *		GTTY		Gets terminal characteristics, almost
 *				like the UNIX GTTY system call.
 *		FILESTAT	P                                                rovide FILE STATistics under VMS:
 *				calls RMS to find out the length of
 *				the file specified in the argument.
 *		RAW_READ	Reads characters from the terminal
 *				without any echoing or interpretation
 *				and with an optional timeout period.
 *		RAW_WRITE	Writes a character to the terminal
 *				without any interpretation.
 *		STTY		Sets terminal characteristics, almost
 *				like the UNIX STTY system call.
 *
 *	Some of the ideas used here were obtained from code written
 *	by Max Benson and Robert Bruccoleri.
 *
 *  Walter Reiher
 *  Harvard University
 *  Department of Chemistry
 *  12 Oxford Street
 *  Cambridge, MA 02138
 *  March 11, 1983
 */
#include descrip
#include iodef
#include rms
#include ssdef
#include stdio
#include "vmodem.h"

#define  TRUE	1
#define  FALSE	0

static char	tt_name[]	= "TT";
static short	tt_chan		= -1;		/*  Terminal channel number  */

struct	tt_io_iosb				/*  Terminal I/O IOSB  */
		{
		short	status;
		short	byte_count;
		short	terminator;
		short	terminator_size;
		};

/*
 *	Terminator mask for PASSALL reads.
 *	Permits reads of all possible 8-bit characters.
 */
int	t_mask[32]	=  {	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
				 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
				 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
				 0,  0					};
struct	terminator_mask
		{
		short	size ;
		short	unused ;
		int	*mask ;
		}
		termin_mask	= { 32, 0, t_mask };
/*
 */
assign_channel()
	{
/*
 *	ASSIGN a channel to the logical name TT, which is usually
 *	the terminal.
 */
	int	status;
	$DESCRIPTOR(tt_descriptor, tt_name);

	if (tt_chan == -1)
		status	= sys$assign(&tt_descriptor, &tt_chan, 0, 0);
	else
		status	= SS$_NORMAL;

	if (status != SS$_NORMAL || tt_chan == -1)
		error("ASSIGN_CHANNEL:  error in SYS$ASSIGN\n", FALSE);

	return;
	}

gtty(tt_characteristics)
struct	tt_info	*tt_characteristics;
	{
/*
 *	Gets terminal information from VMS.
 */
	int				status;
                                                
	if (tt_chan == -1)
		assign_channel();

	status	= sys$qiow(0, tt_chan, IO$_SENSEMODE,
			&(tt_characteristics->dev_modes), NULL, 0,
			&(tt_characteristics->dev_characteristics), 12,
			0, 0, 0, 0);
	if (status != SS$_NORMAL ||
			tt_characteristics->dev_modes.status != SS$_NORMAL)
		error("GTTY:  sense mode QIO error return.\n", FALSE);

	return(status);
	}

/*
 *  FILESTAT
 *  Provide FILE STATistics under VMS
 *
 *	Calls RMS (ugh!) to find out something about the file whose
 *	name is pointed to in the argument FILENAME.
 *	Returns the number of bytes in the file, returns -1 on error.
 */
long	filestat(name)
char	*name;
	{
	short		lastbyte;
	long		blocks, bytes;
	int		status;
	struct	FAB	fab;
	struct	XABFHC	xabfhc;

	fab		= cc$rms_fab;
	xabfhc		= cc$rms_xabfhc;

	fab.fab$l_xab	= &xabfhc;
	fab.fab$l_fna	= name;
	fab.fab$b_fns	= strlen(name);

	status	= sys$open(&fab);
	if (status != RMS$_NORMAL && status != RMS$_KFF)
		{
		if (status == RMS$_FNF)
			printf("FILESTAT:  File %s not found.\n", name);
		else
			{
			printf("FILESTAT:  Error in $OPEN of ");
			printf("file %s, status = 0x%X\n", name, status);
			}
		return(-1);
		}

/*
 *	Pull out the end-of-file block and the first free byte in the
 *	end-of-file block from the XAB.
 */
	blocks		= fab.fab$l_xab->xab$l_ebk - 1;
	lastbyte	= fab.fab$l_xab->xab$w_ffb - 1;

	bytes	= blocks * 512 + lastbyte;

	status	= sys$close(&fab);
	if (status != RMS$_NORMAL)
		{
		printf("FILESTAT:  Error in $CLOSE of ");
		printf("file %s, status = 0x%X\n", name, status);
		return(-1);
		}

	return(bytes);
	}

int		raw_read(nchar, charbuf, seconds)
char		*charbuf;
int		nchar;
unsigned	seconds;
	{
/*
 *	Read NCHAR characters from the terminal without echoing or
 *	interpretation.
 *	If the argument SECONDS is non-zero, use that as the
 *	timeout period in seconds for the read.
 *
 *	NOTE THAT THIS FUNCTION RETURNS AN INT, NOT A CHAR!
 *	That is becaus                                                e of the possibility of a SS$_TIMEOUT return.
 */
	short			function;
	int			status;
	struct	tt_io_iosb	iosb;

	if (tt_chan == -1)
		assign_channel();

	function	= IO$_READVBLK | IO$M_NOECHO | IO$M_NOFILTR;

	if (seconds)
		status	= sys$qiow(0, tt_chan, function | IO$M_TIMED,
				&iosb, NULL, 0,
				charbuf, nchar, seconds,
				&termin_mask, NULL, 0);
	else
		status