[mod.amiga.sources] VT100

doc@j.cc.purdue.edu (10/14/86)

This is the "official" release of V2.2

Major items of interest include:

	- You can now define an INIT file that chains to any number of SCRIPT
	  files and then exits (if desired). Great for having the program wake
	  up at 3am, dial your favorite BBS and download the world.

	- Hangup, Break, Null, Autowrap, Audible Beep, Function Key Scripts,
	  Every Parity type, all implemented.

	- Menus, Lattice compile, BOLD, Graphics "box", Double Shift, Title bar
	  all cleaned up (or fixed).

	- Script and init files now use the same control character sequences.

*** NOTICE ***

	- Any bug reports MUST specify the version of the software being used.

	- The ONLY bugs I will respond to are from this version (V2.2) as of
	  today (10/12/86).

	- Do not expect another major version for awhile (unless there is a 
	  MAJOR problem). I am starting a new project (3d graphics editor,
	  display system) and will be pretty well tied up.


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	readme
#	vt100.doc
#	makefile
#	window.c
#	xmodem.c
# This archive created: Tue Oct 14 12:57:23 1986
# By:	Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > readme
This archive contains a vt100 emulator with KERMIT and XMODEM file transfer
protocols by Dave Wecker (V2.2 DBW 861012).

Thanks:
-------
	To everyone who sent in code and suggestions!

Releases:
---------
	v2.2 861012 DBW - more of the same
 	v2.1 860915 DBW - new features (see README)
	v2.0 860823 DBW - Major rewrite
	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
	v1.0 860712 DBW	- First version released

Usage:
------
	Please read VT100.DOC for usage information and examples.

Release Notes:
--------------
v2.2 861012 DBW - more of the same:

	- The INIT file "exit" command can now take an optional argument
	  which is the name of a script to execute after initialization
	  is complete.

	- The SCRIPT command "exit" takes an optional paramater which may
	  be either the pathname of the next script to execute or the
	  string "VT100" (which causes the emulator to exit completely).

	- Hangup menu item now works.

	- Autowrap can now be set from VT100.H, VT100.INIT and the standard
	  escape sequence (<ESC>[?7h - set, <ESC>[?7l - reset)

	- Control-G is now handled with an audible beep (volume set with the
	  VOLUME parameter in VT100.H and VT100.INIT). If the volume is set
	  to 0, a visual beep (DisplayBeep) will be used instead.

	- Script now used "^chr" to send control characters instead of
	  "|" (which was screwing up U**X users). See VT100.DOC for details.

	- The graphics "box" character (a) was added so bar charts now work
	  in line drawing mode (e.g., monitor system on VMS).

	- Control-@ and Control-` now send the NULL character

	- Alternate color for BOLD has been re-instated by popular demand
	  (instead of using SetSoftStyle) when there is more than 1 bit-
	  plane. With one bit-plane, SetSoftStyle is used.

	- Menus have been cleaned up.

	- Lattice compilation cleaned up.

	- No more wordsize parameter since PARITY takes care of all cases
	  (NONE=8bit, MARK, SPACE, EVEN ODD).

	- Any function key definition that begins with a KEYSCRIPT
	  introducer will invoke a script from the function key: e.g.,
	  "~df1:foo/script.txt" (if KEYSCRIPT = 0x7E = "~")

	- Double shift keys are now handled correctly.

	- Version has been added to the title bar (for bug reports).

v2.1 860915 DBW - new features / bug fixes

	- Now identifies as a VT100 (including the response to <esc>Z)
	- Cursor color now gets read in as hex (instead of decimal)
	- REPORTMOUSE taken out of definitions (not needed)
	- XON/XOFF now being handled by the device driver instead of me
	- Literal escape characters have been replaced with \033
	- At init time the user can now specify the input BUFFER size
	  (typically between 512 and 2048 bytes) depending on baud rate
	- Script files are now case insensitive for commands
	- XMODEM now turns off the driver XON/XOFF during transfers
	- Graphic rendition now done by the OS instead of me.
	- Initialization files are now searched for in S: instead of C:
	- Forward GOTO bug fixed in the script package.
	- Keypad can now be used in both numeric and application mode
	- General purpose cleanup() routine added for all exits.
	- Utility menu added (sendbreak, hangup, change directory).
	  NOTE: hangup is not implemented yet.
	- Full wild card support in file transfers (see vt100.doc).
	- Kermit cleaned up with better filename handling (from host).
	- Script now has CD (changed directory) and SB (send break) commands
	- Added Parity and Wordsize choices in VT100.H, VT100.INIT, menu
	  and scripts. (Generates parity from a table).
	- Added 8th bit quoting in KERMIT when using 7 bit words (ODD or
	  EVEN parity).
	- Break time can be set from VT100.H, VT100.INIT or a script file.
	- Transfer mode (image or CRLF) can now be set from a script file.
	- Control characters in escape sequences now act like a true VT100.
	- F10 now works from init files.
	- Right (or Left) AMIGA with period (".") sends a BREAK to the host
	  from the keyboard.
	- XMODEM status kept down to one line for a file transfer.

v2.0 860823 DBW	- Major rewrite:

	- Emulator now compiles under either MANX or LATTICE by defining
	  the appropriate compiler type in VT100.H.
	- Sped up code to an effective baud rate of (about) 8k. This means
	  that clear text at 4800 baud should be no problem.
	- Added XON/XOFF generation so that characters should not get lost
	  any more at 9600 baud (when receiving clear text).
	- Got rid of all command line switches and environment variables.
	  Instead upon invocation the program searches first for any file
	  named on the command line, then looks for VT100.INIT in the
	  current directory and finally searches for C:VT100.INIT.
	  All parameters can be set in the init file, and a sample VT100.INIT
	  is provided in VT100.DOC that shows all possible options.
	- All parameters that are set by VT100.INIT are defined in VT100.H
	  (variables starting with "p_"). This allows you to compile your
	  own defaults into the code.
	- You can now set the number of lines (for all you EMACS freaks :-).
	  On an interlaced screen this gives you upto a 48 line terminal.
	- WORKBENCH colors are NEVER touched.
	- In an attempt to keep the size down, the color palette menu item
	  has been removed (current). Code is about 36K in size with a
	  run time image (using workbench screen) of about 88k.
	- Many bugs fixed including reverse scrolling with descenders,
	  reverse video at end of line, clearing with scrolling regions,
		... and 20 or more others.
	- File capture now no longer sends the filename to the host.
	- BOLD (<esc>[1m) has now been added by using an additional color
	  when you specify a depth of 2 (instead of 1) bitplane.
	- UNDERLINE (<esc>[4m) has now been added.
	- The handling of remote (host) escape sequences has been completly
	  re-written (thanks to Dawn Banks for all the work).
	- Function keys (and shifted function keys) can now be bound to
	  arbitrary strings (Jim Ravan gets his macros). See VT100.DOC
	  for details.
	- Cursor has no been reduced to the size of a normal character for
	  easier readability.
	- XMODEM has been improved (by Steve Drew) to use a timer device
	  (for timeouts) and to abort immediately if the user types <ESC>.
	- KERMIT has been completely re-written and appears to work fine,
	  thanks to the efforts of Steve Drew.
	- New menu item allows script file support. Module written by
	  Steve Drew. See VT100.DOC for details.

Known problems:
---------------

	- none reported yet.

Suggestions not implemented:
----------------------------

	- "ASCII capture uses synchronous I/O so capture of game playing
	  is jerky"

	  This change MAY be made if someone else wants to write the code.

	- "Beep should be in stereo"

	  I am trying to use as FEW system resources as possible, therefore
	  beep only ties up 1 of the 4 possible channels.

Installation:
-------------
	The files in this archive may be extracted by the bourne shell
	(/bin/sh) or the shar program using the "unshar switch (-u)",
	contact me if you need a copy of this version of shar.

	REMEMBER: Set the correct compiler definition in VT100.H

Files:
------
	README		- this file

	vt100.doc	- documentation for the terminal emulator

	makefile	- make file for the emulator (under MANX AZTEC-C)

	vt100.h		- include file used by all other modules

	window.c	- manager for window and keyboard

	vt100.c		- main module, handles menus

	remote.c	- handle remote characters (vt100 emulation)

	kermit.c	- kermit protocol (to transfer text files on VMS
			  select the CRLF option on the transfer mode menu,
			  otherwise use image mode).

	init.c		- startup code

	xmodem.c	- xmodem protocol that understands AMIGA binary and
			  text file formats (automatically).

	script.c	- script control package

	expand.c	- filename expansion (wildcards) and dir setting

Contact:
--------
Please send bugs/comments/suggestions to:

	Dave Wecker at	ENET:	COOKIE::WECKER
			ARPA:	wecker%cookie.dec.com@decwrl.dec.com
			USENET:	{decvax|decwrl}!cookie.dec.com!wecker
			SNAIL:	Dave Wecker
				115 Palm Springs Drive
				Colorado Springs, CO  80908
SHAR_EOF
cat << \SHAR_EOF > vt100.doc
This is the documentation file for the VT100 terminal emulator by Dave
Wecker (V2.2 DBW 861012). Comments/suggestions/bugs/problems/praise should
be sent to:

	Dave Wecker at	ENET:	COOKIE::WECKER
			ARPA:	wecker%cookie.dec.com@decwrl.dec.com
			USENET:	{decvax|decwrl}!cookie.dec.com!wecker
			SNAIL:	Dave Wecker
				115 Palm Springs Drive
				Colorado Springs, CO  80908

Multi-file transfer, the new version of KERMIT and script support were
contributed by Steve Drew (Aug 20 1986). If you wish to thank Steve
directly he can be contacted through:

    	Steve Drew at	ENET:    CGFSV1::DREW
    			ARPA:    drew%cfgsv1.dec.com@decwrl.dec.com
    			USENET:  decvax!decwrl!cgfsv1.dec.com!drew    

Many other pieces of code/suggestions have been sent in.. thanks to all!

Program startup:
----------------
	1> vt100 [initfile]

		- At startup, the program will search for an initialization
		  file to execute. It will first look for the specified
		  "initfile", then VT100.INIT (in the current directory)
		  and finally S:VT100.INIT. The format for the init file
		  is described later in this document.

		- The init file controls the setting of initial defaults
		  and screen and macro definitions.

		- If none of the files (listed above) are found, the
		  built-in defaults (defined in VT100.H as variables,
		  beginning with "p_") are used.

		- All commands are either menu or script based. Scripts
		  are described below.

Menus:
------
File 	  			- file transfers
	Ascii Capture		- Begin/end a script of the current session
	Ascii Send		- Type a file to the host
	Xmodem Receive		- Receive a file using XMODEM protocol
	Xmodem Send		- Send    a file using XMODEM protocol
	Kermit Get		- Receive files from a host KERMIT SERVER
	Kermit Receive		- Receive files from a host KERMIT
	Kermit Send		- Send    files to   a host KERMIT [SERVER]
	Kermit Bye		- Terminate a host KERMIT SERVER
Comm Setup			- Setup communications
	Baud Rate		- Set the terminal baud rate
		300, 1200, 2400,
		4800, 9600
	Parity
		NONE, MARK, SACE,
		EVEN, ODD	- Type of parity
	Xfer Mode
		image		- Send files verbatim (for UNIX hosts or
				  binary files)
		CR LF		- Send CR LF as line terminator and strip
				  CR on received files (VMS text).
Script 	  			- Script commands
	Execute file		- Start up an asynchronous script file
	Abort Execution		- Terminate a script file
Utility   			- Utility commands
	Send Break		- send a break to the host
	Hang Up			- close line (not implemented yet)
	Change Dir		- change the local directory (for transfers)

Keypad mapping (in application mode):
-------------------------------------

		AMIGA		VT100		comments
		-------		-------		---------------------------
		0-9	==	0-9
		.	==	.
		ENTER	==	ENTER		(basically, flip the bottom
		-	==	,		 2 keys up to get a VT100)
		HELP	==	-		(only free key around)
		f1-f4	==	PF1-PF4		(or any rebinding you do)
		arrows	==	arrows

Note:	Right (or Left) AMIGA key in conjunction with a period (".") will
	send a break to the host.

	CTRL in conjunction with either an at-sign ("@") or a backquote ("`")
	will send a NULL to the host.

Initialization file example:
----------------------------
Here is a (hopefully) self-explanatory VT100.INIT file with all options
used:

#######################################################################
#
#	VT100 sample initialization file
#	v2.2 861012 DBW	- Dave Wecker standard defaults
#
# Hash mark at the beginning of a line denotes a comment.
# White space (space(s) or tab(s)) delimit fields.
# Case ignored except for function key bindings.
#
# All items in this file overide variables of the same name in VT100.H
# (all variables in vt100.h have a "p_" prepended to them)
#
##########################################################################
#
BAUD		2400		# Anything after required fields is ignored
SCREEN		CUSTOM		# may be CUSTOM or WORKBENCH
INTERLACE	ON		# ON for CUSTOM or interlaced workbench
DEPTH		1		# number of bit planes to use (1 or 2)
FOREGROUND	950		# Colors are only used on the custom screen
BACKGROUND	000		# Colors are in hex RGB from 000 to FFF
BOLD		a00		# Color for bold highlighting (in custom)
CURSOR		00a		# Color for cursor (in custom screen)
LINES		48		# normal <= 24 interlaced <= 48
MODE		CRLF		# IMAGE or CRLF (for KERMIT transfers)
BUFFER		512		# 512 <= Input buffer size <= 2048
PARITY		NONE		# NONE (= 8 bit), MARK, SPACE, ODD or EVEN
BREAK		750000		# Length for break key in microseconds
VOLUME		64		# Beep Volume (0 = Visual Beep)
WRAP		OFF		# Auto wrap ON or OFF
KEYSCRIPT	7E		# Hex value for script introducer
#
# Function bindings (strings to type when any of F1 through F10 are pressed)
#	f<num>	= function key
#	F<num>	= shifted function key
#
# The string specified must be delimited and uses one special character:
#	^	= control next character
#	^^	= up arrow
#
# Sample control characters:
#	^[	= escape	^M	= carriage return
#	^J	= line feed	^L	= form feed
#
# If the first character of the string is a script introducer (KEYSCRIPT)
# then the string is interpreted as a script filename to be executed when
# the key is pressed.
#
# Examples of bindings:
#
f1	"^[OP"			# f1-f4 = PF1 - PF4 on a VT100
f2	"^[OQ"
f3	"^[OR"
f4	"^[OS"
#
# f5,6,7 = scripts to execute (assuming that KEYSCRIPT = '~' = 0x7E)
#
f5	"~df1:vt100_source/dialwork.script"
f6	"~df1:vt100_source/sendvt100.script"
f7	"~df1:vt100_source/getpics.script"
#
f8	"MAIL^M"		# Reads my mail (note embedded <CR>)
f9	"NOTE^M"		# Reads conferences
F1	"$2400!"		# dials the phone to work
F2	"$bbs1!"		# dials the phone to billboard 1
F3	"$bbs2!"		# dials the phone to billboard 2
F4	"$bbs3!"		# dials the phone to billboard 3
#
# all done with init, now execute script as startup sequence
#
exit df1:vt100_source/dialwork.script

Multi file Xfers:
-----------------
The VT100 emulator now supports multiple file transfers. This is specified
by using a comma (",") between file names when using XMODEM or KERMIT.
(NOTE: host XMODEM's normally CANNOT support multiple file transfers).

When specifying a file name to recieve by default the directory path is
stripped of the filename when sent to the host but is kept for the local
file spec. eg:

        receive file: ram:file.txt,df1:newfile.bin,$

will ask the server for file.txt and put it in ram:, and get newfile.bin
and put it on df1: (see explanation of "$" below). If you do a single file
transfer you will get another prompt for the remote name e.g.:

        receive file: ram:file.txt
        remote file name[file.txt] userdisk1:wantfile.txt

The same rules apply to sending multiple files therefore if you are
doing multi file transfers make sure the host server is connected to the
desired directory.

In addition KERMIT now supports wildcards (* = any number of characters,
? = any single character). Examples:

	send:	*.c,*.h,*.doc
	get:	*.c,*.h,$

KERMIT receive is now smart enough to use the host filename so no filename
needs to be specified on the AMIGA's side.

Script file operation:
----------------------
The script file can be invoked by selecting 'execute file' from the script 
menu. At any time you can abort the script file by selecting
'Abort Execution'.

During the time script file is running the terminal emulation is still
active and you may type simulataneous to the script file. This may be desired
if your script file is WAITing for a string or is DELAYing for a period of
time etc.

Script file Commands (case insensitive):
------------------------------------------------------------
#	Commented line
   Format:
	# comment		 may not be on same line as a command.
   Example:
	# this is a comment
------------------------------------------------------------
ASCII_SEND Send an ascii file to the host.
   Format:
	(same format as CAPTURE)
------------------------------------------------------------
BAUD 	Set baud rate
   Format:
	BAUD rate		Sets the baud rate for send/receive
   Example:
	BAUD 2400		Sets the baud rate at 2400 baud
------------------------------------------------------------
BT	Set the break time (for an SB command)
   Format:
	BT value		Value is in micro-seconds
   Example:
	BT 750000
------------------------------------------------------------
CAPTURE	To start/stop ascii file capture.
   Format:
	CAPTURE	file		Start ascii capturing
	CAPTURE			End ascii capturing
   Example:
	CAPTURE foo.bar		Starts capture of file foo.bar
	CAPTURE			Ends ascii capture of file foo.bar
------------------------------------------------------------
CD 	To change the local directory
   Format:
	CD	newdir		set a new directory for file transfers
   Example:
	CD	DF1:foo/bar	set the directory as specified
------------------------------------------------------------
DELAY 	Suspends script file for a specified time
   Format:        
        DELAY 	n		Suspends execution for n seconds
   Example:
	DELAY	2		Suspends for 2 seconds
------------------------------------------------------------
EXIT	Ends execution of the current script file.
   Format:
	EXIT			Exit the current script
	EXIT VT100		Exit vt100 program
	EXIT newscript		Exit this script and start up newscript
   Example:
	EXIT DF1:FOO.BAR	Exit the current script and start FOO.BAR
------------------------------------------------------------
GOTO	Jumps to a different part of the script file.
   Format:
	GOTO label		Jumps to a line beginning with label:
				Jumps may be forward or backward.
   Example:
	FOO:			Sets up a label
	GOTO FOO		Jumps to FOO
------------------------------------------------------------
KB  	Send a BYE packet to a host KERMIT server (shut down server).
   Format:
	KB
------------------------------------------------------------
KG  	Gets files from host. (which is running as a server).
   Format:
	(same format as KS)
------------------------------------------------------------
KR  	Receives a file from kermit host (not running as server)
   Format:
	(same format as KS)
------------------------------------------------------------
KS  	Sends files via kermit to the host.
   Format:
	KS file			Send one file
	KS file1,file2,...	Send multiple files
	KS file1,file2,...,$	Send multiple files and shut down server
   Example:
	KS foo.bar		sends foo.bar (note no quoting is used)
	KS foo1,foo2,foo3	sends three files
	KS foo1,foo2,foo3,$	sends three files and shuts down server
------------------------------------------------------------
ON	Peforms a command every time a string is received
   Format:
        ON      "string"  cmd	Execute cmd when string is received. Only
				one ON string may be installed at a time.

  				If cmd is a GOTO and we were previously
				WAITing for a string the WAIT is aborted and
				execution resumes at the new label.

              			If cmd is not SEND and we were previously
				DELAYing, then the DELAY is aborted and the
				cmd is executed, followed by the next command
				after the DELAY.

				If cmd is a SEND and we were previously
				DELAYing, then the DELAY is continued.
   Example:
        ON  "LOSS CARRIER" GOTO RESTART
				If modem drops carrier, try to redial
        ON  "--more--" SEND " "
				Send a space every time --more-- is received
------------------------------------------------------------
PARITY	Sets the parity
   Format:
	PARITY	type		Set the parity type
   Example:
	PARITY	NONE		no parity
	PARITY	MARK		mark parity
	PARITY	SPACE		space parity
	PARITY	ODD		odd parity
	PARITY	EVEN		even parity
------------------------------------------------------------
SEND 	Sends a string or character to the host.
   Format:
	SEND    "string"	Sends a string to the host. Beginning and
				ending double quotes (") are required. A
				carat (^) may be used to send control chars.
				Two carats transmits a carat character.
        SEND    chr           	Sends a single character.
        SEND    ^chr   	    	Sends a single control character. The chr
				is NOT case sensitve
   Example:
	SEND	"mail"		Send the string mail
	SEND    "dir^M"		Send the string dir followed by a <CR>
	SEND	a		Send the letter a
	SEND	^C		Send a control C
	SEND	"abc^^def"	Send the string abc^def
	SEND	^^		Send a control-uparrow
	SEND	"		Send the '"' character
------------------------------------------------------------
SB	Sends a break character to the host
   Format:
	SB			Note that any pending character to send
   Example:				is aborted by this call
	SB
------------------------------------------------------------
TM	Set a transfer mode for KERMIT to use
   Format:
	TM type			type of transfers to perform
   Example:
	TM IMAGE		image mode transfers
	TM CRLF			<CR><LF> text transfers (VMS Kermit).
------------------------------------------------------------
WAIT 	Suspends the script file until a certain string is received.
   Format:
	WAIT	"string"	Same rules for string as SEND
	WAIT			Enter an endless wait. Usually used after
				some "ON" commands have been set up. Can
				still aborted via the script menu.
   Example:
        WAIT    "User:"    	Waits for the string User:
        WAIT               	Waits forever
------------------------------------------------------------
XR  	Receives a file via XMODEM.
   Format:
	(same format as KS)
------------------------------------------------------------
XS  	Sends a file via XMODEM.
   Format:
	(same format as KS)
------------------------------------------------------------


Script file examples:
--------------------
#########################################################################
# Script to dial work (dialwork.script)
#	v2.2	861012	DBW
#########################################################################
#
# Make sure that we have all the parameters we want
#
	DELAY	2
	BAUD	2400
	PARITY	NONE
	TM	CRLF
	BT	750000
	SB
#
# First get the modem's attention:
#
Start:
	DELAY 1
	ON "Ready" GOTO Dial
	SEND ^B
	DELAY 2
	GOTO Start
#
# Now dial the 2400 baud line to work:
#
Dial:
	ON "Attached" GOTO Login
	SEND "$2400!"
	DELAY 30
	GOTO Start
#
# We got attached, so keep hitting return until the Gandalf terminal
# handler wakes up:
#
Login:
	ON "enter" GOTO Gandalf
	DELAY 1
	SEND ^M
	GOTO Login
#
# Now connect from the Gandalf to the terminal server (ts1):
# (when it asks for a password I need to type the password manually here)
#
Gandalf:
	DELAY 2
	SEND "ts1^M"
	WAIT "class start"
#
# Keep sending <CR>'s until the LAT prompts for a username:
#
WaitLat:
	DELAY 2
	ON "username>" GOTO Lat
	SEND ^M
	GOTO WaitLat
#
# Tell the LAT that it's me, and connect to the "cookie cluster" (my host
# systems). Tell the cluster my user name.
# (when it asks for a password I need to type the password manually here)
#
Lat:
	SEND "wecker^M"
	DELAY 1
	SEND "connect cookie^M"
	WAIT "Username:"
	SEND "WECKER^M"
	WAIT "at home"
	SEND "^M^M^M"
#
# Got through all the LOGIN garbage, so let's do some work.
#
	WAIT "$ "
#
# Now go back to the LAT and connect to my workstation
#
	SEND "^]connect child^M"
	WAIT "login:"
	SEND "wecker^M"
	WAIT "at home"
	SEND "^M^M^M"
#
# Leave us on VMS
#
	SEND ^^
	DELAY 2
#
# Go run the next script
#
	EXIT df1:vt100_source/sendvt100.script

#########################################################################
# Script to upload the terminal emulator sources (sendvt100.script)
#	v2.2	861012	DBW
#########################################################################
#
# Make sure that we have all the parameters we want
#
	DELAY	2
	PARITY	NONE
	TM	IMAGE
#
# Get into the right directory and upload to my U**X workstation
#
	CD df1:vt100_source
	SEND ^^
	SEND "cd ~/amiga/vt100^M"
	SEND "rm -f *^M"
	WAIT "% "
	DELAY 2
#
# Send the readme file for the terminal emulator via XMODEM:
#
	SEND "xmodem -r readme^M"
	DELAY 3
	XS readme
	WAIT "% "
#
# Send the other terminal emulator files via KERMIT:
#
	DELAY 1
	SEND "kermit -x^M"
	DELAY 3
	KS vt100.doc,makefile,vt100.h,*.c
	DELAY 2
	KB
	WAIT "% "
#
# We popped out of server mode, so send the compiled code
#
	DELAY 1
	SEND "kermit -i -x^M"
	DELAY 3
	KS vt100
	DELAY 2
	KB
	WAIT "% "
#
# Now build the target shar files
#
	SEND "shar -a readme vt100.doc makefile vt100.h vt100.c init.c "
	SEND "> vt100_22a.shar^M"
	SEND "shar -a script.c remote.c window.c expand.c kermit.c xmodem.c "
	SEND "> vt100_22b.shar^M"
#
# Time to pull copies over to VMS
#
	SEND ^^
	SEND "swi [wecker.amiga]^M"
	SEND "cop child::"
	SEND "
	SEND "/staff/wecker/amiga/vt100/vt100_22a.shar"
	SEND "
	SEND " []vt100_22a.shar^M"
	WAIT "$ "
	SEND "cop child::"
	SEND "
	SEND "/staff/wecker/amiga/vt100/vt100_22b.shar"
	SEND "
	SEND " []vt100_22b.shar^M"
	WAIT "$ "
	SEND "cop child::"
	SEND "
	SEND "/staff/wecker/amiga/vt100/vt100"
	SEND "
	SEND " []vt100_22.bin^M"
	WAIT "$ "
#
# Make them available to the world
#
	SEND "pub vt100_22*.*^M"
	WAIT "$ "
#
# All done so go to the next script
#
	EXIT df1:vt100_source/getpics.script

#########################################################################
# Script to download images (getpics.script)
#	v2.2	861012	DBW
#########################################################################
#
# Make sure that we have all the parameters we want
#
	DELAY	2
	PARITY	NONE
	TM	CRLF
#
# Get into the right directory and download
#
	CD RAY:
	SEND "swi [wecker.render]^M"
	SEND "kermit server^M"
	DELAY 3
	KG *.img
	DELAY 2
	KB
	WAIT "$ "
#
# Now get out of the emulator
#
	EXIT VT100

SHAR_EOF
cat << \SHAR_EOF > makefile
######################################################################
#
# Makefile to build vt100 terminal emulator
#
#	v2.2 861012 DBW	- more of the same
#	v2.1 860915 DBW - new features (see README)
#	     860823 DBW - Integrated and rewrote lots of code
#	v2.0 860809 DBW	- Major release.. LOTS of changes
# 	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
# 	v1.0 860712 DBW	- First version released
#
#
# Don't forget to define the right compiler (MANX or LATTICE) in VT100.H
#
######################################################################

OBJS	= vt100.o init.o window.o xmodem.o remote.o \
	  kermit.o script.o expand.o

INCL	= vt100.h
#INCL	= 

vt100	: $(OBJS)
	copy df0:lib/c.lib ram:
	ln -v -o vt100 $(OBJS) ram:c.lib
	delete ram:#?.lib

vt100.o	: vt100.c $(INCL)
	cc -b +Hvt100.syms vt100.c

init.o	: init.c $(INCL)
	cc -b +Ivt100.syms init.c

window.o : window.c $(INCL)
	cc -b +Ivt100.syms window.c

xmodem.o : xmodem.c $(INCL)
	cc -b +Ivt100.syms xmodem.c

remote.o : remote.c $(INCL)
	cc -b +Ivt100.syms remote.c

kermit.o : kermit.c $(INCL)
	cc -b +Ivt100.syms kermit.c

script.o : script.c $(INCL)
	cc -b +Ivt100.syms script.c

expand.o : expand.c $(INCL)
	cc -b +Ivt100.syms expand.c


SHAR_EOF
cat << \SHAR_EOF > window.c
/****************************************************
 * vt100 emulator - window/keyboard support
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 ****************************************************/

#define MODULE_WINDOW 1
#include "vt100.h"

/* keyboard definitions for toasc() */
static char keys[75] = {
    '`','1','2','3','4','5','6','7','8','9','0','-' ,
    '=','\\', 0, '0','q','w','e','r','t','y','u','i','o' ,
    'p','[',']', 0, '1','2','3','a','s','d','f','g','h' ,
    'j','k','l',';','\'', 0, 0, '4','5','6', 0, 'z','x','c','v',
    'b','n','m',44,'.','/', 0, '.','7','8','9',' ',8,
    '\t',13,13,27,127,0,0,0,'-' } ;

/* forward declarations for LATTICE */
void filename();
void emits();
void emit();
void emitbatch();
void cursoroff();
void cursoron();

/*************************************************
*  function to get file name
*************************************************/
void filename(name)
char name[];
    {
    char c;
    ULONG class;
    unsigned int code;
    int keepgoing,i;
    keepgoing = TRUE;
    i=0;
    while (keepgoing) {
	while( NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort) )
	    {
	    class = NewMessage->Class;
	    code = NewMessage->Code;
	    ReplyMsg( NewMessage );
	    if (class=RAWKEY)
		{
		c = toasc(code,1);
		name[i]=c;
		if (name[i] != 0)
		    {
		    if (name[i] == 13)
			{
			name[i]=0;
			keepgoing = FALSE;
			}
		    else
			{
			if (name[i] == 8 || name[i] == 127)
			    {
			    i -= 2;
			    if (i < -1)  i = -1;
			    else {
				if (x == MINX) { y -= 8; x = MAXX; }
				emit(8);
				emit(32);
				emit(8);
				}
			    }
			else
			emit(c);
			if (x == MAXX) emits("\n");
			}
		    i += 1;
		    }
		}
	    } /* end of new message loop */
	}   /* end of god knows what */
    emit(13);
    emit(10);
    } /* end of function */


/*************************************************
*  function to print a string
*************************************************/
void emits(string)
char string[];
    {
    int i;
    char c;

    i=0;
    while (string[i] != 0)
	{
	c=string[i];
	if (c == 10) emit(13);
	emit(c);
	i += 1;
	}
    }

/*************************************************
*  function to output ascii chars to window
*************************************************/
void emit(c)
char c;
    {
    static char wrap_flag = 0;	/* are we at column 80? */

    c &= 0x7F;
    switch( c )
	{
	case '\t':
	x += 64 - ((x-MINX) % 64);
	break;

	case 10:  /* lf */
	y += 8;
	break;

	case 13:  /* cr */
	x = MINX;
	break;

	case 8:   /* backspace */
	x -= 8;
	if (x < MINX) x = MINX;
	break;

	case 12:     /* page */
	x = MINX;
	y = MINY;
	SetAPen(mywindow->RPort,0L);
	RectFill(mywindow->RPort,(long)MINX,
	    (long)(MINY-7),(long)(MAXX+7),(long)(MAXY+1));
	SetAPen(mywindow->RPort,1L);
	break;

	case 7:     /* bell */
	if (p_volume == 0) DisplayBeep(NULL);
	else {
	    BeginIO(&Audio_Request);
	    WaitIO(&Audio_Request);
	    }
	break;

	default:
	if (c < ' ' || c > '~') break;
	if (p_wrap && wrap_flag) {
	    x = MINX;
	    y += 8;
	    if (y > MAXY) {
		y = MAXY;
		ScrollRaster(mywindow->RPort,0L,8L,(long)MINX,
		    (long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1));
		}
	    }
	Move(mywindow->RPort,(long)x,(long)y);

	if (curmode&FSF_BOLD) {
	    if (p_depth > 1) {
		SetAPen(mywindow->RPort,(long)(2+(1^p_screen)));
		SetSoftStyle(mywindow->RPort,(long)curmode,253L);
		}
	    else SetSoftStyle(mywindow->RPort,(long)curmode,255L);
	    }
	else SetSoftStyle(mywindow->RPort,(long)curmode,255L);

	if (curmode&FSF_REVERSE) {
	    SetDrMd(mywindow->RPort,(long)(JAM2+INVERSVID));
	    Text(mywindow->RPort,&c,1L);
	    SetDrMd(mywindow->RPort,(long)JAM2);
	    }
	else Text(mywindow->RPort,&c,1L);

	if (curmode&FSF_BOLD) SetAPen(mywindow->RPort,1L);
	x += 8;
	} /* end of switch */

    if (y > MAXY) {
	y = MAXY;
	x = MINX;
	ScrollRaster(mywindow->RPort,0L,8L,(long)MINX,
	    (long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1));
	}
    if (x > MAXX) {
	wrap_flag = 1;
	x = MAXX;
	}
    else wrap_flag = 0;
    }

/*************************************************
*  function to output ascii chars to window (batched)
*************************************************/
void emitbatch(la,lookahead)
int la;
char *lookahead;
    {
    int i;	

    Move(mywindow->RPort,(long)x,(long)y);
    i = x / 8;
    if (i+la >= maxcol) {
	if (p_wrap == 0) la = maxcol - i;
	else {
	    lookahead[la] = 0;
	    emits(lookahead);
	    return;
	    }
	}
    if (curmode&FSF_BOLD) {
	if (p_depth > 1) {
	    SetAPen(mywindow->RPort,(long)(2+(1^p_screen)));
	    SetSoftStyle(mywindow->RPort,(long)curmode,253L);
	    }
	else SetSoftStyle(mywindow->RPort,(long)curmode,255L);
	}
    else SetSoftStyle(mywindow->RPort,(long)curmode,255L);

    if (curmode&FSF_REVERSE) {
	SetDrMd(mywindow->RPort,(long)(JAM2+INVERSVID));
	Text(mywindow->RPort,lookahead,(long)la);
	SetDrMd(mywindow->RPort,(long)JAM2);
	}
    else Text(mywindow->RPort,lookahead,(long)la);
    if (curmode&FSF_BOLD) SetAPen(mywindow->RPort,1L);
    x += (8 * la);
    }

/******************************
* Manipulate cursor
******************************/
void cursoroff()
    {
    SetDrMd(mywindow->RPort,(long)COMPLEMENT);
    SetAPen(mywindow->RPort,3L);
    RectFill(mywindow->RPort,
	(long)(x-1),(long)(y-6),(long)(x+8),(long)(y+1));
    SetAPen(mywindow->RPort,1L);
    SetDrMd(mywindow->RPort,(long)JAM2);
    }

void cursoron()
    {
    SetDrMd(mywindow->RPort,(long)COMPLEMENT);
    SetAPen(mywindow->RPort,3L);
    RectFill(mywindow->RPort,
	(long)(x-1),(long)(y-6),(long)(x+8),(long)(y+1));
    SetAPen(mywindow->RPort,1L);
    SetDrMd(mywindow->RPort,(long)JAM2);
    }

/************************************************
*  function to take raw key data and convert it 
*  into ascii chars
**************************************************/
int toasc(code,local)
unsigned int code;
int local;
    {
    static int ctrl = 0;
    static int shift = 0;
    static int capsl = 0;
    static int amiga = 0;
    char c = 0, keypad = 0;
    char *ptr;

    switch ( code )
	{
	case 98:   capsl = 1; c = 0;break;
	case 226:  capsl = 0; c = 0;break;
	case 99:   ctrl  = 1; c = 0;break;
	case 227:  ctrl  = 0; c = 0;break;
	case 96:
	case 97:   if(++shift > 2) shift = 0; c = 0; break;
	case 224:
	case 225:  if (--shift < 0) shift = 0; c = 0;break;
	case 102:
	case 103:  if (++amiga > 2) amiga = 0; c = 0; break;
	case 230:
	case 231:  if (--amiga < 0) amiga = 0; c = 0; break;
	case 0x50: 
	case 0x51: 
	case 0x52: 
	case 0x53: 
	case 0x54: 
	case 0x55: 
	case 0x56: 
	case 0x57: 
	case 0x58: 
	case 0x59:  c = 0;
		    if (shift)	ptr = p_F[code - 0x50];
		    else	ptr = p_f[code - 0x50];
		    if (!script_on && *ptr == p_keyscript)
			    script_start(++ptr);
		    else    sendstring(ptr);
		    break;
	case 0x0f: c = (keyapp) ? 'p' : '0'; keypad = TRUE; break;
	case 0x1d: c = (keyapp) ? 'q' : '1'; keypad = TRUE; break;
	case 0x1e: c = (keyapp) ? 'r' : '2'; keypad = TRUE; break;
	case 0x1f: c = (keyapp) ? 's' : '3'; keypad = TRUE; break;
	case 0x2d: c = (keyapp) ? 't' : '4'; keypad = TRUE; break;
	case 0x2e: c = (keyapp) ? 'u' : '5'; keypad = TRUE; break;
	case 0x2f: c = (keyapp) ? 'v' : '6'; keypad = TRUE; break;
	case 0x3d: c = (keyapp) ? 'w' : '7'; keypad = TRUE; break;
	case 0x3e: c = (keyapp) ? 'x' : '8'; keypad = TRUE; break;
	case 0x3f: c = (keyapp) ? 'y' : '9'; keypad = TRUE; break;
	case 0x43: c = (keyapp) ? 'M' : 13 ; keypad = TRUE; break;
	case 0x4a: c = (keyapp) ? 'l' : '-'; keypad = TRUE; break;
	case 0x5f: sendstring("\033Om") ;break;
	case 0x3c: c = (keyapp) ? 'n' : '.'; keypad = TRUE; break;
	case 0x4c:
	case 0x4d: 
	case 0x4e: 
	case 0x4f: sendchar(27);            /* cursor keys */
		   if (keyapp) sendchar('O');
		   else sendchar('[');
		   sendchar(code - 11);
		   break;

	default:
	if (code < 75) c = keys[code];
	else c = 0;
	}

    if (keypad) {
        if (keyapp) sendstring("\033O");
        sendchar(c);
        return(0);
	}
        
    /* add modifiers to the keys */

    if (c != 0) {
	if (shift) {
	    if ((c <= 'z') && (c >= 'a')) c -= 32;
	    else
	    switch( c ) {
		case '[':  c = '{'; break;
		case ']':  c = '}'; break;
		case '\\': c = '|'; break;
		case '\'': c = '"'; break;
		case ';':  c = ':'; break;
		case '/':  c = '?'; break;
		case '.':  c = '>'; break;
		case ',':  c = '<'; break;
		case '`':  c = '~'; break;
		case '=':  c = '+'; break;
		case '-':  c = '_'; break;
		case '1':  c = '!'; break;
		case '2':  c = '@'; break;
		case '3':  c = '#'; break;
		case '4':  c = '$'; break;
		case '5':  c = '%'; break;
		case '6':  c = '^'; break;
		case '7':  c = '&'; break;
		case '8':  c = '*'; break;
		case '9':  c = '('; break;
		case '0':  c = ')'; break;
		default:            break;
		}
	    }
	else if (capsl && (c <= 'z') && (c >= 'a')) c -= 32;
	}
    if (ctrl) {
	if (c > '`' && c <= 127) c -= 96;
	else if (c > '@' && c <= '_') c -= 64;
	}
    if (amiga && c == '.') {
	if (!local) sendbreak();
	c = 0;
	}
    else if (ctrl && (c == '@' || c == '`')) {
	if (!local) sendchar(0);
	c = 0;
	}
    else if (c != 0 && (!local)) sendchar(c);
    return((int)c);
    }

SHAR_EOF
cat << \SHAR_EOF > xmodem.c
/*************************************************************
 * vt100 terminal emulator - XMODEM protocol support
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS - Added Parity and Word Length and support code
 *	     860823 DBW - Integrated and rewrote lots of code
 *	     860815 Steve Drew: readchar inproved with real timeouts
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *************************************************************/

#define MODULE_XMODEM 1
#include "vt100.h"

int enablexon = TRUE;

/* forward declarations for LATTICE */
void sendstring();
void sendchar();
void sendbreak();
void No_XON();
void Do_XON();

static unsigned long parity_settings[4] = {
    0x96696996,
    0x69969669,
    0x69969669,
    0x96696996 };

/************************************************************
* Send a string (using sendchar below)
************************************************************/

void sendstring(s)
char *s;
    {
    char c;

    while ((c = *s++) != '\000') sendchar(c);
    }

/**************************************************************/
/* send char and read char functions for the xmodem function */
/************************************************************/
void sendchar(ch)
int ch;
    {
    int doxon,i,j,k;

    doxon = enablexon;
    if (doxon) No_XON();
    switch (p_parity) {
	case 0:	/* no parity */
	rs_out[0] = ch & 0xFF;
	break;

	case 1: /* mark */
	rs_out[0] = (ch & 0x7F) | 0x80;
	break;

	case 2: /* space */
	rs_out[0] = ch & 0x7F;
	break;
	
	case 3:	/* even */
	case 4: /* odd  */
        i     = (ch >> 5) & 0x3;
	j     = ch & 0x1F;
	k     = ((parity_settings[i] >> j) & 0x1) << 7;
	if (p_parity == 3)			/* even parity */
	    rs_out[0] = (ch & 0x7F) | k;
	else					/* odd parity */
	    rs_out[0] = (ch & 0x7F) | (k ^ 0x80);
	}
    DoIO(Write_Request);
    if (doxon) Do_XON();
    }

/* send a break to the host */
void sendbreak() {
    AbortIO(Read_Request);
    Read_Request->IOSer.io_Command = SDCMD_BREAK;
    DoIO(Read_Request);
    Read_Request->IOSer.io_Command = CMD_READ;
    SendIO(Read_Request);
    }

int readchar()
    {
    int rd,ch;

    Timer.tr_time.tv_secs = ttime;
    Timer.tr_time.tv_micro = 0;
    SendIO((char *) &Timer.tr_node);
    
    rd = FALSE;
    while (rd == FALSE)  
        {	
	Wait((1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) |
            ( 1L << mywindow->UserPort->mp_SigBit) |
            ( 1L << Timer_Port->mp_SigBit));
	if (CheckIO(Read_Request))
            {
	    WaitIO(Read_Request);
	    ch=rs_in[0];
	    rd = TRUE;
	    SendIO(Read_Request);
	    }
	if (NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
	   if ((NewMessage->Class == RAWKEY) && (NewMessage->Code == 69))
	         {
                 AbortIO((char *) &Timer);
                 Wait (1L << Timer_Port->mp_SigBit);
	         if (want_message) 
	           emits("\nUser aborted transfer\n");
	         timeout = USERABORT;
                 return('\0');
	         }
            continue;
            }
        if (rd == FALSE && CheckIO(&Timer)) {
            if (want_message)
              emits("\nTimeout waiting for character\n");
            timeout = TIMEOUT;
            return('\0');
            }
	}     /* end while */
    AbortIO((char *) &Timer);
    Wait (1L << Timer_Port->mp_SigBit);
    timeout = GOODREAD;
    return(ch & 0xFF);
    }

void No_XON() {

    /* turn off XON/XOFF processing */
    enablexon = FALSE;
    Write_Request->io_SerFlags |= SERF_XDISABLED;
    Write_Request->IOSer.io_Command = SDCMD_SETPARAMS;
    DoIO(Write_Request);
    Write_Request->IOSer.io_Command = CMD_WRITE;
    }

void Do_XON() {
    /* turn on XON/XOFF processing */
    enablexon = TRUE;
    Write_Request->io_SerFlags &= ~SERF_XDISABLED;
    Write_Request->IOSer.io_Command = SDCMD_SETPARAMS;
    DoIO(Write_Request);
    Write_Request->IOSer.io_Command = CMD_WRITE;
    }

/**************************************/
/* xmodem send and recieve functions */
/************************************/

int XMODEM_Read_File(file)
char *file;
    {
    int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag;
    unsigned int checksum, j, bufptr;
    char numb[10];
    bytes_xferred = 0L;
    ttime = TTIME_SHORT;
    want_message = TRUE; /* tell readchar to print any error msgs */

    if ((fd = creat(file, 0)) < 0)
	{
	emits("Cannot Open File\n");
	return FALSE;
	}
    else
    emits("Receiving File\n\nType <ESC> to abort transfer\n");

    sectnum = errors = bufptr = 0;
    sendchar(NAK);
    firstchar = 0;
    No_XON();
    while (firstchar != EOT && errors != ERRORMAX)
	{
	errorflag = FALSE;

	do {                                    /* get sync char */
	    firstchar = readchar();
	    if (timeout != GOODREAD) {
		if (timeout == USERABORT || errors++ == ERRORMAX)
		    Do_XON();
		    return FALSE;
		}
	    } while (firstchar != SOH && firstchar != EOT);

	if  (firstchar == SOH)
	    {
	    emits(blanks);
	    emits("\rGetting Block ");
	    sprintf(numb, "%d", sectnum);
	    emits(numb);
	    emits("...");
	    sectcurr = readchar();
	    if (timeout != GOODREAD) { Do_XON(); return FALSE; }
	    sectcomp = readchar();
	    if (timeout != GOODREAD) { Do_XON(); return FALSE; }
	    if ((sectcurr + sectcomp) == 255)
		{
		if (sectcurr == ((sectnum + 1) & 0xff))
		    {
		    checksum = 0;
		    for (j = bufptr; j < (bufptr + SECSIZ); j++)
			{
			bufr[j] = readchar();
			if (timeout != GOODREAD) { Do_XON(); return FALSE; }
			checksum = (checksum + bufr[j]) & 0xff;
			}
		    if (checksum == readchar() && timeout == GOODREAD)
			{
			errors = 0;
			sectnum++;
			bufptr += SECSIZ;
			bytes_xferred += SECSIZ;
			emits("verified\r");
			if (bufptr == BufSize)
			    {
			    if (write(fd, bufr, BufSize-128) == EOF)
				{
				emits("\nError Writing File\n");
				Do_XON();
				return FALSE;
				}
			    bufptr = 128;
			    for (j = 0; j < 128; j++)
				bufr[j] = bufr[(BufSize-128)+j];
			    }
			sendchar(ACK);
			}
		    else
			{
			errorflag = TRUE;
			if (timeout == USERABORT) { Do_XON(); return FALSE; }
			}
		    }
		else
		    {
		    /* got a duplicate sector */	
		    if (sectcurr == (sectnum & 0xff))
			{
			/* wait until we time out for 5secs */
			do {
			    readchar();
			    } while (timeout == GOODREAD);
			if (timeout == USERABORT) {
			    Do_XON();
			    return FALSE;
			    }
			emits("\nReceived Duplicate Sector\n");
			sendchar(ACK);
			}
		    else errorflag = TRUE;
    		    }
		}
	    else errorflag = TRUE;
	    }
	if (errorflag == TRUE)
	    {
	    errors++;
	    emits("\nError\n");
	    sendchar(NAK);
	    }
	}        /* end while */
    if ((firstchar == EOT) && (errors < ERRORMAX))
	{
	sendchar(ACK);
	while (bufptr > 0 && (bufr[--bufptr] == 0x00 ||
			      bufr[bufptr]   == 0x1A)) ;
	write(fd, bufr, ++bufptr);
	close(fd);
	Do_XON();
	return TRUE;
	}
    Do_XON();
    return FALSE;
    }

int XMODEM_Send_File(file)
char *file;
    {
    int sectnum, bytes_to_send, size, attempts, c;
    unsigned checksum, j, bufptr;
    char numb[10];
    bytes_xferred = 0;
    ttime = TTIME_LONG;
    want_message = TRUE; /* tell readchar to print any error msgs */

    if ((fd = open(file, 0)) < 0) {
	emits("Cannot Open Send File\n");
	return FALSE;
	}
    else
    emits("Sending File\n\nType <ESC> to abort transfer\n");
    attempts = 0;
    sectnum = 1;
    No_XON();
    /* wait for sync char */
    j=1;
    while (((c = readchar()) != NAK) && (j++ < ERRORMAX))
	if (timeout == USERABORT) { Do_XON(); return(FALSE); }
    if (j >= (ERRORMAX))
	{
	emits("\nReceiver not sending NAKs\n");
	Do_XON();
	return FALSE;
	}

    while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX)
	{
	if (bytes_to_send == EOF)
	    {
	    emits("\nError Reading File\n");
	    Do_XON();
	    return FALSE;
	    }

	bufptr = 0;
	while (bytes_to_send > 0 && attempts != RETRYMAX)
	    {
	    attempts = 0;
	    emits(blanks);
	    emits("\rBlock ");
	    sprintf(numb, "%d ", sectnum);
	    emits(numb);
	    do {
		emits(".");    
		sendchar(SOH);
		sendchar(sectnum);
		sendchar(~sectnum);
		checksum = 0;
		size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send;
		bytes_to_send -= size;
		for (j = bufptr; j < (bufptr + SECSIZ); j++)
		if (j < (bufptr + size)) {
		    sendchar(bufr[j]);
		    checksum += bufr[j];
		    }
		else sendchar(0);
		sendchar(checksum);
		attempts++;
		c = readchar();
		if (timeout == USERABORT) {
		    emits("\n");
		    Do_XON();
		    return FALSE;
		    }
		} while ((c != ACK) && (attempts != RETRYMAX));
	    bufptr += size;
	    bytes_xferred += size;
	    emits(" sent\r");
	    sectnum++;
	    }
	}
    close(fd);
    if (attempts == RETRYMAX)
	{
	emits("\nNo Acknowledgment Of Sector, Aborting\n");
	Do_XON();
	return FALSE;
	}
    else
	{
	attempts = 0;
	do {
	    sendchar(EOT);
	    attempts++;
	    } while ((readchar() != ACK) &&
		     (attempts != RETRYMAX) &&
		     (timeout != USERABORT)) ;
	if (attempts == RETRYMAX)
	    emits("\nNo Acknowledgment Of End Of File\n");
	}
    Do_XON();
    return TRUE;
    }

SHAR_EOF
#	End of shell archive
exit 0

doc@j.cc.purdue.edu (10/14/86)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	expand.c
#	remote.c
#	script.c
#	vt100.c
#	vt100.h
# This archive created: Tue Oct 14 12:58:12 1986
# By:	Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > expand.c
/*************************************************************
 * vt100 terminal emulator - Wild card and Directory support
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW	- new features (see README)
 *           860830 Steve Drew Added Wild card support, features(expand.c)
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *      Much of the code from this module extracted from
 *      Matt Dillons Shell program. (Thanxs Matt.)
 *************************************************************/

#define MODULE_EXPAND 1
#include "vt100.h"

struct DPTR {                    /* Format of directory fetch pointer */
   struct FileLock *lock;        /* lock on directory   */
   struct FileInfoBlock *fib;    /* mod'd fib for entry */
};

/*
 * Disk directory routines
 *
 *
 * dopen() returns a struct DPTR, or NULL if the given file does not
 * exist.  stat will be set to 1 if the file is a directory.  If the
 * name is "", then the current directory is openned.
 *
 * dnext() returns 1 until there are no more entries.  The **name and
 * *stat are set.  *stat = 1 if the file is a directory.
 *
 * dclose() closes a directory channel.
 *
 */

struct DPTR *
dopen(name, stat)
char *name;
int *stat;
{
   struct DPTR *dp;
   int namelen, endslash = 0;
   struct FileLock *MyLock;
   
   MyLock = (struct FileLock *)( (ULONG) ((struct Process *)
                                 (FindTask(NULL)))->pr_CurrentDir);
   namelen = strlen(name);
   if (namelen && name[namelen - 1] == '/') {
      name[namelen - 1] = '\0';
      endslash = 1;
   }
   *stat = 0;
   dp = (struct DPTR *)malloc(sizeof(struct DPTR));
   if (*name == '\0') 
      dp->lock = (struct FileLock *)DupLock (MyLock);
   else
      dp->lock = (struct FileLock *)Lock (name, ACCESS_READ);
   if (endslash)
      name[namelen - 1] = '/';
   if (dp->lock == NULL) {
      free (dp);
      return (NULL);
   }
   dp->fib = (struct FileInfoBlock *)
         AllocMem((long)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
   if (!Examine (dp->lock, dp->fib)) {
      dclose (dp);
      return (NULL);
   }
   if (dp->fib->fib_DirEntryType >= 0)
      *stat = 1;
   return (dp);
}

dnext(dp, pname, stat)
struct DPTR *dp;
char **pname;
int *stat;
{
   if (dp == NULL)
      return (0);
   if (ExNext (dp->lock, dp->fib)) {
      *stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 1;
      *pname = dp->fib->fib_FileName;
      return (1);
   }
   return (0);
}


dclose(dp)
struct DPTR *dp;
{
   if (dp == NULL)
      return (1);
   if (dp->fib)
      FreeMem (dp->fib, (long)sizeof(*dp->fib));
   if (dp->lock)
      UnLock (dp->lock);
   free (dp);
   return (1);
}

free_expand(av)
char **av;
{
   char **base = av;

   if (av) {
      while (*av) {
         free (*av);
         ++av;
      }
      free (base);
   }
}

/*
 * EXPAND(wild_name, pac)
 *    wild_name      - char * (example: "df0:*.c")
 *    pac            - int  *  will be set to # of arguments.
 *
 */


char **
expand(base, pac)
char *base;
int *pac;
{
   char **eav = (char **)malloc (sizeof(char *));
   int  eleft, eac;

   char *ptr, *name;
   char *bname, *ename, *tail;
   int stat, scr;
   struct DPTR *dp;

   *pac = eleft = eac = 0;
   base = strcpy(malloc(strlen(base)+1), base);
   for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
   for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
   if (ptr < base) {
      bname = strcpy (malloc(1), "");
   } else {
      scr = ptr[1];
      ptr[1] = '\0';
      bname = strcpy (malloc(strlen(base)+1), base);
      ptr[1] = scr;
   }
   ename = ptr + 1;
   for (ptr = ename; *ptr && *ptr != '/'; ++ptr);
   scr = *ptr;
   *ptr = '\0';
   tail = (scr) ? ptr + 1 : NULL;

   if ((dp = dopen (bname, &stat)) == NULL  ||  stat == 0) {
      free (bname);
      free (base);
      free (eav);
      emits ("Could not open directory");
      return (NULL);
   }
   while (dnext (dp, &name, &stat)) {
      if (compare_ok(ename, name)) {
         if (tail) {
            int alt_ac;
            char *search, **alt_av, **scrav;
            struct FileLock *lock;

            if (!stat)           /* expect more dirs, but this not a dir */
               continue;
            lock = (struct FileLock *)CurrentDir (dp->lock);
            search = malloc(strlen(name)+strlen(tail)+2);
            strcpy (search, name);
            strcat (search, "/");
            strcat (search, tail);
            scrav = alt_av = expand (search, &alt_ac);
            CurrentDir (lock);
            if (scrav) {
               while (*scrav) {
                  if (eleft < 2) {
                     char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
                     movmem (eav, scrav, sizeof(char *) * (eac + 1));
                     free (eav);
                     eav = scrav;
                     eleft = 10;
                  }
                  eav[eac] = malloc(strlen(bname)+strlen(*scrav)+1);
                  strcpy(eav[eac], bname);
                  strcat(eav[eac], *scrav);
                  free (*scrav);
                  ++scrav;
                  --eleft, ++eac;
               }
               free (alt_av);
            }
         } else {
            if (eleft < 2) {
               char **scrav = (char **)malloc(sizeof(char *) * (eac + 10));
               movmem (eav, scrav, sizeof(char *) * (eac + 1));
               free (eav);
               eav = scrav;
               eleft = 10;
            }
            eav[eac] = malloc (strlen(bname)+strlen(name)+1);
            eav[eac] = strcpy(eav[eac], bname);
            strcat(eav[eac], name);
            --eleft, ++eac;
         }
      }
   }
   dclose (dp);
   *pac = eac;
   eav[eac] = NULL;
   free (bname);
   free (base);
   if (eac)
      return (eav);
   free (eav);
   return (NULL);
}

/*
 * Compare a wild card name with a normal name
 */

#define MAXB   8

compare_ok(wild, name)
char *wild, *name;
{
   char *w = wild;
   char *n = name;
   char *back[MAXB][2];
   int  bi = 0;

   while (*n || *w) {
      switch (*w) {
      case '*':
         if (bi == MAXB) {
            emits ("Too many levels of '*'");
            return (0);
         }
         back[bi][0] = w;
         back[bi][1] = n;
         ++bi;
         ++w;
         continue;
goback:
         --bi;
         while (bi >= 0 && *back[bi][1] == '\0')
            --bi;
         if (bi < 0)
            return (0);
         w = back[bi][0] + 1;
         n = ++back[bi][1];
         ++bi;
         continue;
      case '?':
         if (!*n) {
            if (bi)
               goto goback;
            return (0);
         }
         break;
      default:
         if (toupper(*n) != toupper(*w)) {
            if (bi)
               goto goback;
            return (0);
         }
         break;
      }
      if (*n)  ++n;
      if (*w)  ++w;
   }
   return (1);
}

set_dir(new)
char *new;
{
   register 	char 		*s;
   int   			i;
   struct 	FileLock 	*lock;
   char 			temp[60];
   struct       FileInfoBlock   fib;
  
   if (*new != '\000') {
      strcpy(temp, MyDir);
      s = new;
      if (*s == '/') {
         s++;
         for (i=strlen(MyDir);
              MyDir[i] != '/' && MyDir[i] != ':';
              i--);
         MyDir[i+1] = '\0';
           strcat(MyDir, s);
         }
      else if (exists(s, ':') == 0) {
         if (MyDir[strlen(MyDir)-1] != ':')
            strcat(MyDir, "/");
         strcat(MyDir, s);
         }
      else
         strcpy(MyDir, s);

      if ((lock = (struct FileLock *)Lock(MyDir)) == 0) {
         emits("Directory not found\n");
         strcpy(MyDir, temp);
         }
      else {
      	 if (Examine(lock, &fib)) {
      	    if (fib.fib_DirEntryType > 0) {
               if (lock = (struct FileLock *)CurrentDir(lock))
                  UnLock(lock);
               if (MyDir[strlen(MyDir)-1] == '/')
                  MyDir[strlen(MyDir)-1] = '\0';
               }
            else {
            	emits("Not a Directory\n");               
            	strcpy(MyDir,temp);
               }
            }
         }
      }
}

exists(s,c)
char *s,c;
    {
    while (*s != '\000')
	if (*s++ == c) return(1);
    return(0);
    }
SHAR_EOF
cat << \SHAR_EOF > remote.c
/****************************************************
 * vt100 emulator - remote character interpretation
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860803 DRB - Rewrote the control sequence parser
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 ****************************************************/

#define MODULE_REMOTE 1
#include "vt100.h"

static int    p[10];
static int    numpar;
static char   escseq[40];

void doctrl();
void doesc();				/* force correct denomination */
void doerase();
void doindex();

/************************************************
*  function to handle remote characters
*************************************************/
void doremote(c)
char c;
    {
    if (c == 24) { inesc = 0; inctrl = 0; return; }
    if (c == 27 || (inesc >= 0 && c >= ' ')) { doesc(c); return; }
    if (inctrl >= 0 && c >= ' ') { doctrl(c); return; }
    if (c == 10 || c == 11 || c == 12) {
	if (nlmode) doindex('E'); else doindex('D');
	return;
	}
    if (c == 13) {
	if (!nlmode) emit(c);
	return;
	}
    if (c == 15) { alt = 0; return; }
    if (c == 14) { alt = 1; return; }
    if (a[alt] && c > 94 && c < 127) { doalt(c); return; }
    emit(c);
    }

void doesc(c)
char c;
{
    if (inesc < 0) { inesc = 0; return; }
    if (c == 27 || c == 24) { inesc = -1; return; }
    if (c < ' ' || c == 127) return;		  /* Ignore control chars */
    if (c < '0') {escseq[inesc++] = c; return; }  /* Collect intermediates */

    /* by process of elimination, we have a final character.  Put it in
       the buffer, and dispatch on the first character in the buffer */

    escseq[inesc] = c;
    inesc = -1;				/* No longer collecting a sequence */
    switch (escseq[0])			/* Dispatch on the first received */
    {
      case '[':				/* Control sequence introducer */
	numpar = 0;			/* No parameters yet */
	private = 0;			/* Not a private sequence (yet?) */
	badseq = 0;			/* Good until proven bad */
	p[0] = p[1] = 0;		/* But default the first parameter */
	inctrl = 0;			/* We are in a control sequence */
	return;				/* All done for now ... */

      case 'D': case 'E': case 'M':	/* Some kind of index */
	doindex (c);			/* Do the index */
	return;				/* Return */

      case '7':				/* Save cursor position */
	savx = x; savy = y; savmode = curmode; savalt = alt;
	sa[0] = a[0]; sa[1] = a[1];
	return;

      case '8':				/* Restore cursor position */
	x = savx; y = savy; alt = savalt; curmode = savmode;
	a[0] = sa[0]; a[1] = sa[1];
	return;

      case 'c':				/* Reset */
	top = MINY; bot = MAXY; savx = MINX; savy = MINY;
	curmode = FS_NORMAL; keyapp = FALSE;
	inesc = -1;
	a[0] = 0; a[1] = 0; sa[0] = 0; sa[1] = 0;
	emit(12);
	return;

      case '(':				/* Change character set */
	if (c == '0' || c == '2') a[0] = 1; else a[0] = 0;
	return;

      case ')':				/* Change the other character set */
	if (c == '0' || c == '2') a[1] = 1; else a[1] = 0;
	return;

      case '=':				/* set keypad application mode */
        keyapp = TRUE;
        return;
        
      case '>':				/* reset application mode */
        keyapp = FALSE;
        return;
        
      case 'Z':
	sendchar(27); sendstring("[?1;7c"); return;

      /* If we didn't match anything, we can just return, happy in the
	 knowledge that we've at least eaten the whole sequence */

    }					/* End of switch */
    return;
}

void doctrl(c)
char c;
{
    int	    i;

    if (c == 27 || c == 24) { inctrl = -1; return; }
    if (c < ' ' || c == 127) return;		  /* Ignore control chars */

    /* First, look for some parameter characters.  If the very first
       parameter character isn't a digit, then we have a private sequence */

    if (c >= '0' && c < '@')
    {
	/* can't have parameters after intermediates */
	if (inctrl > 0) {badseq++ ; return; }
	switch (c)
	{
	  case '0': case '1': case '2': case '3': case '4':
	  case '5': case '6': case '7': case '8': case '9':
	    p[numpar] = p[numpar] * 10 + (c - '0');
	    return;

	  case ';':
	    p[++numpar] = 0;		/* Start a new parameter */
	    return;

	  case '<': case '=': case '>': case '?': /* Can only mean private */
	    if (inctrl == 0) private = c; /* Only allowed BEFORE parameters */
	    return;

	/* if we come here, it's a bad sequence */
	}
	badseq++;			/* Flag the bad sequence */
    }

    if (c < '0')			/* Intermediate character */
    {
	escseq[inctrl++] = c;		/* Save the intermediate character */
	return;
    }

    /* if we get here, we have the final character.  Put it in the 
       escape sequence buffer, then dispatch the control sequence */

    numpar++;				/* Reflect the real number of parameters */
    escseq[inctrl++] = c;		/* Store the final character */
    escseq[inctrl] = '\000';		/* Tie off the buffer */
    inctrl = -1;			/* End of the control sequence scan */

    /* Don't know how to do most private sequences right now, so just punt
       them */

    if ((private != 0 && private != '?') || badseq != 0) return;
    if (private == '?' && escseq[0] != 'h' && escseq[0] != 'l') return;

    switch (escseq[0])			/* Dispatch on first intermediate or final */
    {
      case 'A': if (p[0]<=0) p[0] = 1;
		y -= 8*p[0]; if (y<top)  y = top;  return;
      case 'B': if (p[0]<=0) p[0] = 1;
		y += 8*p[0]; if (y>bot)  y = bot;  return;
      case 'C': if (p[0]<=0) p[0] = 1;
		x += 8*p[0]; if (x>MAXX) x = MAXX; return;
      case 'D': if (p[0]<=0) p[0] = 1;  
		x -= 8*p[0]; if (x<MINX) x = MINX; return;

      case 'H': case 'f':		/* Cursor position */
	if (p[0] <= 0) p[0] = 1;
	if (p[1] <= 0) p[1] = 1;
	y = (--p[0]*8)+MINY; x = (--p[1]*8)+MINX;
	if (y > MAXY) y = MAXY;
	if (x > MAXX) x = MAXX;
	if (y < MINY) y = MINY;
	if (x < MINX) x = MINX;
	return;

      case 'r':				/* Set scroll region */
	if (p[0] <= 0) p[0] = 1;
	if (p[1] <= 0) p[1] = p_lines;
	top = (--p[0]*8)+MINY; bot = (--p[1]*8)+MINY;
	if (top < MINY) top = MINY;
	if (bot > MAXY) bot = MAXY;
	if (top > bot) { top = MINY; bot = MAXY; }
	x = MINX; y = MINY;
	return;

      case 'm':				/* Set graphic rendition */
	for (i=0;i<numpar;i++) {
	    if (p[i] < 0) p[i] = 0;
	    switch (p[i]) {
		case 0:
		curmode  = FS_NORMAL;
		break;

		case 1:
		curmode |= FSF_BOLD;
		break;

		case 4:
		curmode |= FSF_UNDERLINED;
		break;

		case 5:
		curmode |= FSF_ITALIC;
		break;

		default:
		curmode |= FSF_REVERSE;
		break;
		}
	    }
	return;

      case 'K':				/* Erase in line */
	doerase();
	return;

      case 'J':				/* Erase in display */
	if (p[0] < 0) p[0] = 0;
	SetAPen(mywindow->RPort,0L);
	if (p[0] == 0) {
	    if (y < MAXY) RectFill(mywindow->RPort,
		(long)MINX,(long)(y+2),(long)(MAXX+7),(long)(MAXY+1));
	    }
	else if (p[0] == 1) {
	    if (y > MINY) RectFill(mywindow->RPort,
		(long)MINX,(long)(MINY-6),(long)(MAXX+7),(long)(y-7));
	    }
	else RectFill(mywindow->RPort,
	    (long)MINX,(long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1));
	SetAPen(mywindow->RPort,1L);
	doerase(); return;

      case 'h':				/* Set parameter */
	if (private == 0 && p[0] == 20)		nlmode = 1;
	else if (private == '?' && p[0] == 7)	p_wrap = 1;
	return;

      case 'l':				/* Reset parameter */
	if (private == 0 && p[0] == 20)		nlmode = 0;
	else if (private == '?' && p[0] == 7)	p_wrap = 0;
	return;

      case 'x':
	sendchar(27); sendstring("[3;1;8;64;64;1;0x"); return;

      case 'n':
	if (p[0] == 6) {
	    sendchar(27);
	    sprintf(escseq,"[%d;%dR",((y-MINY)/8)+1,((x-MINX)/8)+1);
	    sendstring(escseq); return;
	    }
	sendchar(27); sendstring("[0n"); return;

      case 'c':
	sendchar(27); sendstring("[?1;7c"); return;
    }

    /* Don't know how to do this one, so punt it */
}

void doindex(c)
char c;
    {
    if (c != 'M') {
	if (c == 'E') x = MINX;
	if (y > bot) if (y < MAXY) y += 8;
	if (y == bot)
	    ScrollRaster(mywindow->RPort,0L,8L,(long)MINX,(long)(top-6),
		(long)(MAXX+7),(long)(bot+1));
	if (y < bot) y += 8;
	}
    else {
	if (y < top) if (y > MINY) y -= 8;
	if (y == top)
	    ScrollRaster(mywindow->RPort,0L,-8L,(long)MINX,(long)(top-6),
		(long)(MAXX+7),(long)(bot+1));
	if (y > top) y -= 8;
	}
    return;
    }

doalt(c)
char c;
    {
    int oldx,newx;
    inesc = -1;
    oldx = x; emit(' '); newx = x;
    x = oldx;
    SetAPen(mywindow->RPort,1L);
    switch (c) {
	case 'a':
	doline(0,-6,8,1);
	break;

	case 'j':
	case 'm':
	case 'v':   doline(4,-6,4,-2);
	if      (c=='j')  doline(0,-2,4,-2);
	else if (c=='m')  doline(4,-2,8,-2);
	else              doline(0,-2,8,-2);
	break;

	case 'k':
	case 'l':
	case 'w': doline(4,-2,4,1);
	if      (c=='k')  doline(0,-2,4,-2);
	else if (c=='l')  doline(4,-2,8,-2);
	else              doline(0,-2,8,-2);
	break;

	case 'n':
	case 'q': doline(0,-2,8,-2);
	if      (c=='n')  doline(4,-6,4,2);
	break;

	case 't':
	case 'u':
	case 'x':   doline(4,-6,4,1);
	if      (c=='t')  doline(4,-2,8,-2);
	else if (c=='u')  doline(0,-2,4,-2);
	break;
	}
    x = newx;
    }

doline(x1,y1,x2,y2) {
    RectFill(mywindow->RPort,(long)(x+x1),(long)(y+y1),
	(long)(x+x2),(long)(y+y2));
    }

void doerase()
    {
    if (p[0] < 0) p[0] = 0;
    SetAPen(mywindow->RPort,0L);
    if (p[0] == 0) RectFill(mywindow->RPort,(long)x,(long)(y-6),
	(long)(MAXX+7),(long)(y+1));
    else if (p[0] == 1) RectFill(mywindow->RPort,
	(long)MINX,(long)(y-6),(long)(x+7),(long)(y+1));
    else RectFill(mywindow->RPort,
	(long)MINX,(long)(y-6),(long)(MAXX+7),(long)(y+1));
    SetAPen(mywindow->RPort,1L);
    return;
    }

SHAR_EOF
cat << \SHAR_EOF > script.c
/*************************************************************
 * vt100 terminal emulator - Script file support
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS - Added BAUD, PARITY and WORD commands & handling
 *	     860823 DBW - Integrated and rewrote lots of code
 *	     860815 Steve Drew: Initial version written of SCRIPT.C
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *************************************************************/

#define MODULE_SCRIPT 1

#include "vt100.h"

struct COMMAND {
    void (*func)();
    char *cname;
    };

struct LABEL  {
    struct LABEL *next;
    char *name;
    long pos;
    };

extern long atol();

/****************  globals  needed  ******************/

char		on_string[20];       /* string to match on for on cmd    */
char 		wait_string[20];     /* string to match of for wait cmd  */
char 		golabel[20];         /* label we are looking for in goto */
char 		on_cmd[20];          /* command to execute when on matchs*/
int 		onsize;		     /* size of on_string                */
int 		waitsize;            /* size of wait_string              */
int 		onpos;               /* position in on string for search */
int 		waitpos;             /* pos in wait_string for search    */
int 		on_match;            /* flag set while doing on_cmd      */
FILE 		*sf;                 /* file pointer for script file     */
struct LABEL 	*lbase = NULL;       /* will point to first label        */
struct LABEL 	*labels;             /* current label pointer            */

void cmd_send(), cmd_wait(), cmd_on(), cmd_goto(), cmd_delay(), cmd_done(),
     cmd_ks(), cmd_kg(), cmd_kr(), cmd_xs(), cmd_xr(), cmd_cap(), cmd_as(),
     cmd_null(), cmd_kb(), cmd_cd(), cmd_sb(), cmd_baud(), cmd_word(),
     cmd_parity(), cmd_bt(), cmd_tm();

char *next_wrd(), *tostring();


/********************** command table **********************************/

static struct COMMAND commands[]= {
    cmd_send,   "send",         /* send string to host      */
    cmd_wait,   "wait",         /* wait for a string from host */
    cmd_on,     "on", 		/* on a 'string' do a cmd   */
    cmd_goto,   "goto",         /* goto label               */
    cmd_delay,  "delay",        /* delay amount of seconds  */
    cmd_done,   "exit",         /* exit script file         */
    cmd_ks,     "ks",           /* kermit send file         */
    cmd_kr,     "kr",           /* kermit receive file      */
    cmd_kg,     "kg",           /* kermit get file          */
    cmd_kb,	"kb",		/* kermit bye (for server)  */
    cmd_xs,     "xs",           /* xmodem send file         */
    cmd_xr,     "xr",           /* xmodem receive file      */
    cmd_cap,    "capture",      /* ascii capture on/off     */
    cmd_as,     "ascii_send",   /* ascii send               */
    cmd_cd,     "cd",		/* change directory	    */
    cmd_sb,     "sb",		/* Send a break		    */
    cmd_baud,   "baud",		/* Set Baud Rate            */
    cmd_parity, "parity",	/* Set Parity		    */
    cmd_bt,     "bt",		/* Set Break Time	    */
    cmd_tm,     "tm",		/* Set KERMIT transfer mode */
    cmd_null,   NULL		/* mark the end of the list */
    };

/********************************************************************/
/* checks char to see if match with on string or wait_string        */
/* if on string match oncmd gets executed imediately,               */
/* if wait_string match script_wait is set.                         */
/********************************************************************/

chk_script(c)
char c;
    {
    if (on_string[0] != '\0') {
        if (on_string[onpos] == c) {
            onpos++;
            if (onpos == onsize) {
                on_match = TRUE;
                do_script_cmd(ONCOMMAND); 
                on_match = FALSE;
                return(0);
		}
	    }
        else onpos = 0;
	}
    if (wait_string[0] != '\0') {
       if (wait_string[waitpos] != c) {
            waitpos = 0;
            return(0);
	    }
        waitpos++;
        if (waitpos != waitsize) return(0);
        wait_string[0] = '\0';
        script_wait = FALSE;
	}
    }

script_start(file)
char *file;
    {
    if ((sf = fopen(file, "r")) == NULL) {
        emits("Can't open script file\n");
        return(0);
	}
    script_on = TRUE;
    script_wait = FALSE;
    wait_string[0] = '\0';
    on_string[0] = '\0';
    on_match = FALSE;
    lbase = NULL;
    }

/* return pointer to next word. set l to size of the word */

char *next_wrd(s,l)
char *s;
int *l;
    {
    char *p;
    while(*s && (*s == ' ' || *s == 9)) s++;
    p = s;
    while(*s && (*s != ' ' && *s != 9)) s++;
    *l = s-p;
    return(p);
    }

exe_cmd(p,l)
char *p;
int l;
    {
    int i;

    /* downcase the command */
    for (i=0; i<l; i++) p[i] |= ' ';    

    /* now search for it */
    for (i=0; commands[i].func != cmd_null; ++i) 
        if (strncmp(p, commands[i].cname, l) == 0) {
            (*commands[i].func)(next_wrd(p+l, &l));
            return(TRUE);
	    }
    emits ("\nScript - unknown command: ");
    emits (p);
    emits ("\n"); 
    return(FALSE);
    }

struct LABEL *find_label(lname)
char *lname;
    {
    struct LABEL *label;
  
    label = lbase;
    while(label != NULL) {
	if (strcmp(label->name, lname) == 0) return (label);
	label = label->next;
	}
    return(NULL);
    }

do_script_cmd(stat)
int stat;
    {
    int len,l;
    char line[256];
    char *p;

    if (stat == ONCOMMAND) {    /* if ON command is matched and we were     */
        strcpy(line,on_cmd);    /* doing a DELAY then abort the delay timer,*/
        p = next_wrd(line,&l);  /* except if on_cmd was just a SEND.        */
	if (*p != 'S' && script_wait == WAIT_TIMER)  {
            AbortIO((char *) &Script_Timer);
            Wait (1L << Script_Timer_Port->mp_SigBit);
            script_wait = FALSE; /* script will proceed after on command    */
	    }
	exe_cmd(p,l);
        return(0);
	}
    script_wait = FALSE;
    while(fgets(line,256,sf) != NULL) {
       len = strlen(line);
       line[--len] = '\0';
       p = next_wrd(&line[0], &l);
       if (*(p + l - 1) == ':') {       	/* its a label */
           *(p + l - 1) = '\0';
           if (find_label(p) == NULL) {   	/* it's a new label */
		if (lbase == NULL)  {  		/* it's the first label */
		    labels = lbase = (struct LABEL *) malloc (sizeof (struct LABEL));
		    }
		else {
		    labels->next = 
                           (struct LABEL *) malloc (sizeof (struct LABEL));
		    labels = labels->next;
		    }
		labels->pos  = ftell(sf);
		labels->name = malloc(l);
		labels->next = NULL;
		strcpy(labels->name, p);
		if (stat == GOTOLABEL && strcmp(p, golabel) == 0) 
                      stat = NEXTCOMMAND;
		}
	    p = next_wrd(p+l+1, &l);
	    } 	/* end of it's a label */
	if (stat == GOTOLABEL || *p == '#') continue;
	if (*p) exe_cmd(p,l);
	return(0);
	} 		/* end of while */
    if (stat == GOTOLABEL) {
        emits("\nScript - label not found: ");
        emits(golabel);
        emits("\n");
	}         
    exit_script();
    }

exit_script()
    {
    if (script_wait == WAIT_TIMER)      /* timer not done yet */
       AbortIO((char *) &Script_Timer); /* so abort it */
    emits("\nScript - terminated\n");    
    script_on = FALSE;
    script_wait = TRUE;
    fclose(sf);
    }

/* remove quotes terminate string & return pointer to start */

char *tostring(ptr)
char *ptr;
    {
    char *s1,*s2;

    s1 = ptr;
    if (*ptr == '"') {
        while(*ptr++  && *ptr != '"') ;
        if (*ptr == '"') {
            *ptr = '\0';  
            ptr = s2 = ++s1;
            while(*s2) {
		if	(*s2 != '^')	 *s1++ = *s2;
		else if (*(s2+1) == '^') *s1++ = *s2++;
		else			 *s1++ = ((*++s2)|' ')-96;
		s2++;
		}
	    *s1 = '\0';
            return(ptr);
	    }
	}
    if (*s1 == '^') {
        *s1 = (*(s1+1)|' ')-96;
        *(s1+1) = '\0';
        return(s1);
        }
    *(s1+1) = '\0';
    return(s1);
    }   
        
/***************************** SCRIPT COMMANDS ***********************/

void cmd_goto(lname)
char *lname;
    {
    struct LABEL *label;
   	                    /* if on_cmd was a goto kill wait state */
    if (on_match) { wait_string[0] = '\0'; script_wait = FALSE; }
    if ((label = find_label(lname)) == NULL) {  /* is it forward */
        strcpy(golabel,lname);
        do_script_cmd(GOTOLABEL);
	}
    else {
        fseek(sf,(long)(label->pos),0);
	}
    }

void cmd_send(str)
char *str;
    {
    sendstring(tostring(str));
    }

void cmd_wait(str)
char *str;
    {
    str = tostring(str);
    *(str+20) = '\0';         /* 20 characters max */
    strcpy(wait_string, str);
    waitsize = strlen(str);
    script_wait = WAIT_STRING;
    }

void cmd_on(str)
char *str;
    {
   char *p;

    p = tostring(str);
    strcpy(on_string, p);
    onsize = strlen(p);
    *(p+onsize+2+20) = '\0';        /* 20 characters max */
    strcpy(on_cmd,p+onsize+2);
    }

void cmd_delay(seconds)
char *seconds;
    {
    script_wait = WAIT_TIMER;
    Script_Timer.tr_time.tv_secs = atoi(seconds);
    Script_Timer.tr_time.tv_micro = 0;
    SendIO((char *) &Script_Timer.tr_node);
    }

void cmd_done(option)
char *option;
    {
    char *p;
    int  l;

    if (*option) {
	p = next_wrd(option,&l);
	*(p+l) = '\000';
	if  (strcmp(p,"vt100") == 0 || strcmp(p,"VT100") == 0)
	    cleanup("Exit vt100 from script",0);
	exit_script();
	script_start(p);
	}
    }

void cmd_ks(file)
char *file;
    {
    multi_xfer(file, doksend, 1);
    }

void cmd_kr(file)
char *file;
    {
    multi_xfer(file, dokreceive, 0);
    }

void cmd_kg(file)
char *file;
    {
    server = TRUE;
    multi_xfer(file, dokreceive, 0);
    }

void cmd_kb()
    {
    saybye();
    }

void cmd_xs(file)
char *file;
    {
    multi_xfer(file, XMODEM_Send_File, 1);
    }

void cmd_xr(file)
char *file;
    {
    multi_xfer(file, XMODEM_Read_File, 1);
    }

void cmd_cap(file)
char *file;
    {
    do_capture(file);
    }

void cmd_as(file)
char *file;
    {
    do_send(file);
    }

void cmd_cd(name)
char *name;
    {
    set_dir(name);
    }

void cmd_sb(str)
char *str;
    {
    sendbreak();
    }

void cmd_baud(rate)
char *rate;
    {
    int i = atoi(rate);

    switch( i )
	{
	case  300:
	case 1200:
	case 2400:
	case 4800:
	case 9600:
	setserbaud(i, TRUE);
	break;

	default:
	emits("\nScript - invalid baud rate: ");
	emits(rate);
	emits("\n");
	break;
	}
    }

void cmd_parity(par)
char *par;
    {
    int i;

    switch( *par|' ' )
	{
	case 'n': i =  0; break;
	case 'm': i =  1; break;
	case 's': i =  2; break;
	case 'e': i =  3; break;
	case 'o': i =  4; break;

	default:
	emits("\nScript - invalid parity: ");
	emits(par);
	emits("\n");
	return;
	}
    p_parity = i;
    ClearMenuStrip( mywindow );         /* Remove old menu */
    InitCommItems();                    /* Re-do comm menu   */
    SetMenuStrip(mywindow,&menu[0]);    /* Re-display the menu */	
    }

void cmd_bt(breaklength)
char *breaklength;
    {
    long i = atol(breaklength);
    AbortIO(Read_Request);
    Read_Request->io_BrkTime = Write_Request->io_BrkTime = i;
    setparams();
    }

void cmd_tm(tmode)
char *tmode;
    {
    switch (*tmode|' ') {
	case 'i':
	p_mode = 0;
	break;

	case 'c':
	p_mode = 1;
	break;

	default:
	emits("\nScript - invalid transfer mode: ");
	emits(tmode);
	emits("\n");
	return;
	}

    ClearMenuStrip(mywindow);
    InitCommItems();                    /* Re-do comm menu   */
    SetMenuStrip(mywindow,&menu[0]);
    }

void cmd_null(file)
char *file;
    {
    }
SHAR_EOF
cat << \SHAR_EOF > vt100.c
/************************************************************************
 *  vt100 terminal emulator with xmodem transfer capability
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS - Added Parity and Word Length and support code
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *  use <esc> to abort xmodem or kermit transfers
 *
 *  written by Michael Mounier
 *  new version by Dave Wecker
 ************************************************************************/

/*  all includes defines and globals */
#define MODULE_MAIN 1
#include "vt100.h"

/******************************************************/
/*                   Main Program                     */
/*                                                    */
/*      This is the main body of the program.         */
/******************************************************/

char lookahead[80];
FILE *tranr = NULL;
FILE *trans = NULL;
int capture,send;
char name[80];
struct MsgPort *mySerPort;

main(argc,argv)
int	argc;
char	**argv;
    {
    ULONG class;
    unsigned int code;
    int KeepGoing,i,la,dola,actual;
    char c,*ptr;

    ptr = InitDefaults(argc,argv);
    InitDevs();
    InitFileItems();
    InitCommItems();
    InitScriptItems();
    InitUtilItems();
    InitMenu();
    SetMenuStrip(mywindow,&menu[0]);

    MyDir[0]  =	    '\000';
    KeepGoing =	    TRUE;
    capture   =	    FALSE;
    send      =	    FALSE;
    maxcol    =	    MAXX / 8;
    la	      =	    0;
    x	      =	    MINX ; 
    y	      =	    MINY; 
    curmode   =	    FS_NORMAL;
    keyapp    =	    0;
    script_on =     FALSE;
    script_wait=    TRUE;
    SetAPen(mywindow->RPort,1L);
    cursoron();
    cursoroff();    
    emit(12);
    mySerPort = Read_Request->IOSer.io_Message.mn_ReplyPort;
    SendIO(Read_Request);

    /* see if we had a startup script */
    if (ptr != NULL) script_start(ptr);

    while( KeepGoing )
	    {
	    /* wait for window message or serial port message */
	    cursoron();
	    if (script_wait)	/* if script ready dont wait here */
		Wait(
		 (1L << mySerPort->mp_SigBit) |
		 (1L << mywindow->UserPort->mp_SigBit) |
		 (1L << Script_Timer_Port->mp_SigBit));
	    cursoroff();
	    
	    /* do ascii file send */
	    if (send)
		{
		if ((c=getc(trans)) != EOF) {
		    if (c == '\n') c = '\r';
		    sendchar(c);
		    }
		else {
		    fclose(trans);
		    emits("\nFile Sent\n");
		    send=FALSE;
		    }
		}

	    /* see if there are any characters from the host */
	    if (CheckIO(Read_Request)) {
		WaitIO(Read_Request);
		c = rs_in[0] & 0x7F;
		doremote(c);
		if (script_on) chk_script(c);
	        if (capture && c != 10) {
	      	    if (c == 13) c = 10;
		    putc(c , tranr);
		    }
		Read_Request->IOSer.io_Command = SDCMD_QUERY;
		DoIO(Read_Request);
		Read_Request->IOSer.io_Command = CMD_READ;
		actual = (int)Read_Request->IOSer.io_Actual;
		if (actual > 0) {
		    if (inesc   <  0 &&
			inctrl  <  0 &&
			a[alt]  == 0 &&
			capture == FALSE) dola = 1;
		    else dola = 0;
		    Read_Request->IOSer.io_Length =
			Read_Request->IOSer.io_Actual;
		    DoIO(Read_Request);
		    Read_Request->IOSer.io_Length = 1;

		    for (i = 0; i < actual; i++) {
			c=rs_in[i] & 0x7f;
			if (script_on) chk_script(c);

			if (dola == 1) {
			    if (c >= ' ' && c <= '~' && la < 80)
				lookahead[la++] = c;
			    else {
				if (la > 0) {
				    emitbatch(la,lookahead);
				    la = 0;
				    }
				doremote(c);
				dola = 0;
				}
			    }
			else {
			    doremote(c);
			    if (inesc   <  0 &&
				inctrl  <  0 &&
				a[alt]  == 0 &&
				capture == FALSE) dola = 1;
			    if (capture && c != 10) {
				if (c == 13) c = 10;
				putc(c , tranr);
				}
			    }
			}

		    /* dump anything left in the lookahead buffer */
		    if (la > 0) {
			emitbatch(la,lookahead);
			la = 0;
			}
		    }
		SendIO(Read_Request);
		}

	    while((NewMessage = 
		    (struct IntuiMessage *)GetMsg(mywindow->UserPort))
			!= FALSE) {
		class = NewMessage->Class;
		code = NewMessage->Code;
		ReplyMsg( NewMessage );
		switch( class )
		    {
		    case CLOSEWINDOW:
		    KeepGoing = FALSE;
		    break;

		    case RAWKEY:
		    c = toasc(code,0);
		    break;

		    case NEWSIZE:
		    emit(12);
		    break;

		    case MENUPICK:
		    handle_menupick(class,code);
		    break;				    
		    }   /* end of switch (class) */
		}   /* end of while ( newmessage )*/

            if (!script_wait || 
                 (CheckIO(&Script_Timer) && script_wait == WAIT_TIMER))
		do_script_cmd(NEXTCOMMAND);
	    }  /* end while ( keepgoing ) */
		
    /*   It must be time to quit, so we have to clean
    *   up and exit.
    */

    cleanup("",0);

    } /* end of main */

/* cleanup code */

cleanup(reason, fault)
char *reason;
int fault;
    {
    switch(fault) {
	case 0:		/* quitting close everything */
	ClearMenuStrip( mywindow ); 
	CloseDevice(&Audio_Request);

	case 8:		/* error opening audio */
	DeletePort(Audio_Port);
	FreeMem(BeepWave,BEEPSIZE);
	CloseDevice(&Timer);

	case 7:		/* error opening timer */
	DeletePort(Timer_Port);  
	CloseDevice(&Script_Timer);
	DeletePort(Script_Timer_Port);

	case 6:		/* error opening write device */
	DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort);
	FreeMem(Write_Request,(long)sizeof(*Write_Request));
	CloseDevice(Read_Request);

	case 5:		/* error opening read device */
	DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
	FreeMem(Read_Request,(long)sizeof(*Read_Request));
	CloseWindow( mywindow );

	case 4:		/* error opening window */
	if (p_screen != 0) CloseScreen( myscreen );

	case 3:		/* error opening screen */
	case 2:		/* error opening graphics library */
	case 1:		/* error opening intuition */
	default:
	if (*reason) puts (reason);
	}
    exit(fault);
    } 

do_capture(file)
char *file;
    {
    if (capture == TRUE)
        {
        capture=FALSE;
        fclose(tranr);
        emits("\nEnd File Capture\n");
        }
    else
        {
        if (file == NULL) {
            emits("\nAscii Capture:");
            filename(name);
	    } 
	else strcpy(name, file);
        if ((tranr=fopen(name,"w")) == 0) {
	    capture=FALSE;
	    emits("\nError Opening File\n");
	    return(FALSE);
	    }
	capture=TRUE;
        }
    }

do_send(file)
char *file;
    {
    if (send == TRUE)
	{ 
        send=FALSE;
        fclose(trans);
        emits("\nFile Send Cancelled\n");
        }
    else
        {
        if (file == NULL) {
            emits("\nAscii Send:");
            filename(name);
            }
	else strcpy(name, file);
        if ((trans=fopen(name,"r")) == 0) {
   	    send=FALSE;
	    emits("\nError Opening File\n");
	    return(FALSE);
	    }
	send=TRUE;
	}
    }

void setparams()
    {
    Read_Request->IOSer.io_Command = 
	Write_Request->IOSer.io_Command = 
	    SDCMD_SETPARAMS;
    DoIO(Read_Request); DoIO(Write_Request);
    Read_Request->IOSer.io_Command = CMD_READ;
    SendIO(Read_Request);
    Write_Request->IOSer.io_Command = CMD_WRITE;
    }

void hangup ()
    {
    AbortIO(Read_Request);
    CloseDevice (Read_Request);
    Timer.tr_time.tv_secs=0L;
    Timer.tr_time.tv_micro=750000L;
    DoIO((char *) &Timer.tr_node);
    OpenDevice (SERIALNAME,NULL,Read_Request,NULL);
    setparams();
    }

void setserbaud(baud, redomenu)
int baud;
LONG redomenu;
    {
    AbortIO(Read_Request);
    Write_Request->io_Baud = Read_Request->io_Baud = baud;
    setparams();
    p_baud = baud;
    if (redomenu) {
	ClearMenuStrip( mywindow );         /* Remove old menu */
	InitCommItems();                    /* Re-do comm menu   */
	SetMenuStrip(mywindow,&menu[0]);    /* Re-display the menu */	
	}
    }

void handle_menupick(class, code)
ULONG class;
unsigned int code;
    {
    unsigned int menunum, itemnum, subnum;

    if (code == MENUNULL) return;

    menunum = MENUNUM( code );
    itemnum = ITEMNUM( code );
    subnum  = SUBNUM( code );
    switch( menunum ) {
	case 0:
	switch( itemnum ) {
	    case 0:
	    do_capture(NULL);
	    break;

	    case 1:
	    do_send(NULL);
	    break;

	    case 2:
	    if (p_parity > 0) {
		emits("\nParity setting prevents this\n");
		break;
		}
	    emits("\nXmodem Receive:");
	    filename(name);
	    multi_xfer(name,XMODEM_Read_File,0);
	    break;

	    case 3:
	    if (p_parity > 0) {
		emits("\nParity setting prevents this\n");
		break;
		}
	    emits("\nXmodem Send:");
	    filename(name);
	    multi_xfer(name,XMODEM_Send_File,1);
	    break;

	    case 4:
	    server = TRUE;
	    emits("\nKermit GET remote file(s):");
	    filename(name);
	    multi_xfer(name,dokreceive,0);
            break;

	    case 5:
	    multi_xfer("",dokreceive,0);
	    break;

	    case 6:
	    server = TRUE;
	    emits("\nKermit Send local name:");
	    filename(name);
	    multi_xfer(name,doksend,1);
	    break;

	    case 7:
	    saybye();
	    break;
	    }
	break;

	case 1:
	switch( itemnum ) {
	    case 0:
	    switch( subnum ) {
		case 0:
		setserbaud(300, FALSE);
		break;

		case 1:
		setserbaud(1200, FALSE);
		break;

		case 2:
		setserbaud(2400, FALSE);
		break;

		case 3:
		setserbaud(4800, FALSE);
		break;

		case 4:
		setserbaud(9600, FALSE);
		break;
		}
	    break;	    

	    case 1:
	    /* Set  Parity */
	    p_parity = subnum;
	    break;

	    case 2:
	    /* set transfer mode */
	    p_mode = subnum;
	    break;
	    }
	break;

	case 2:
	if (!itemnum && !script_on) {
	    emits("Script file name: ");
	    filename(name);
	    script_start(name);
	    }
	if (itemnum && script_on) exit_script();
	break;

	case 3:
	switch( itemnum ) {
	    case 0:
	    sendbreak();
	    break;

	    case 1:
	    hangup();
	    break;

	    case 2:
	    emits("\nDirectory [");
	    emits(MyDir);
	    emits("]: ");
	    filename(name);
	    set_dir(name);
	    break;
	    }

	break;
	} /* end of switch ( menunum ) */
    }

SHAR_EOF
cat << \SHAR_EOF > vt100.h
/*********************************************************************
 *  a terminal program that has ascii and xmodem transfer capability
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860809 DBW	- Major release.. LOTS of changes
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *  use esc to abort xmodem transfer
 *
 *  written by Michael Mounier
 *  new version by Dave Wecker 860621
 ************************************************************************/

/* ########  define the compiler type here ######## */
#define	LATTICE	0
#define MANX	1

/*  compiler diretives to fetch the necessary header files */
#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/text.h>
#include <graphics/regions.h>
#include <graphics/copper.h>
#include <graphics/gels.h>
#include <devices/serial.h>
#include <devices/keymap.h>
#include <devices/audio.h>
#include <hardware/blit.h>
#include <stdio.h>
#include <ctype.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <devices/timer.h>

#if MANX
#include <functions.h>
#undef NULL
#define   NULL   ((void *)0)
#endif

#define INTUITION_REV 1L
#define GRAPHICS_REV  1L

/* things for xmodem send and recieve */
#define GOODREAD    0
#define TIMEOUT	    1
#define USERABORT   2
#define SECSIZ   0x80
#define TTIME_SHORT 5        /* number of seconds for short timeout */
#define TTIME_LONG  50	     /* number of seconds for long  timeout */
#define TTIME_KERMIT 10	     /* number of seconds for KERMIT timeout */
#define BufSize  0x200       /* Text buffer for XMODEM */
#define ERRORMAX 10          /* Max errors before abort */
#define RETRYMAX 10          /* Maximum retrys before abort */
#define SOH      1           /* Start of sector char */
#define EOT      4           /* end of transmission char */
#define ACK      6           /* acknowledge sector transmission */
#define NAK      21          /* error in transmission detected */

#define FILEMAX 8    /* number of file menu items */
#define COMMAX 3     /* number of communication sub menus */
#define RSMAX 5      /* speed menu items */
#define PARMAX 5     /* parity items */
#define XFMAX 2      /* transfer mode items */
#define SCRIPTMAX 2  /* script menu items */
#define UTILMAX 3    /* utility menu */
#define MAXMENU 4    /* total number of menu entries */

#define FSF_REVERSE 256	/* fake font style to flag INVERSVID mode */

/* things for script support */

#define GOTOLABEL   1
#define	NEXTCOMMAND 0
#define ONCOMMAND   2

#define	WAIT_TIMER  2
#define WAIT_STRING 1

/* things for 'beep' support */
#define BEEPSIZE    10L
#define BEEPFREQ    1000L
#define COLORCLOCK  3579545L

extern struct MsgPort *CreatePort();
extern char *malloc(),*strcpy(),*fgets();
extern long ftell();

#ifdef MODULE_MAIN
char    bufr[BufSize];
int     fd, timeout = FALSE, ttime;
int	multi = FALSE, server;
long    bytes_xferred;
char	MyDir[60];
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

struct NewScreen NewScreen = {
   0L,197L,640L,205L,1L,       /* left, top, width, height, depth */
   0,1,HIRES,    /* DetailPen, BlockPen, ViewModes */
   CUSTOMSCREEN,NULL,   /* Type, Font */
   (UBYTE *)"VT100", /* Title */
   NULL,NULL };         /* Gadgets, Bitmap */

struct NewWindow NewWindow = {
   0,3L,640L,200L,     /* left, top, width, height */
   0,1,              /* detailpen, blockpen */
   MENUPICK | CLOSEWINDOW | RAWKEY | NEWSIZE,
   SMART_REFRESH | ACTIVATE | BORDERLESS |
   WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG, /* Flags */
   NULL,NULL,        /* FirstGadget, CheckMark */
   (UBYTE *)
   "VT100 (v2.2 861012 DBW) Terminal Window                                ",
   NULL,             /* set screen after open screen */
   NULL,             /* bitmap */
   640L, 200L, 640L, 200L,/* minw, minh, maxw, maxh */
   CUSTOMSCREEN      /* Type */
};

struct Screen *myscreen;            /* ptr to applications screen */
struct Window *mywindow;            /* ptr to applications window */
struct ViewPort *myviewport;
struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
struct Preferences  *Prefs;	    /* preferences from GetPrefs() */

struct MenuItem FileItem[FILEMAX];
struct IntuiText FileText[FILEMAX];
struct MenuItem CommItem[COMMAX];
struct IntuiText CommText[COMMAX];
struct MenuItem RSItem[RSMAX];
struct IntuiText RSText[RSMAX];
struct MenuItem ParItem[PARMAX];
struct IntuiText ParText[PARMAX];
struct MenuItem XFItem[XFMAX];
struct IntuiText XFText[XFMAX];
struct MenuItem ScriptItem[SCRIPTMAX];
struct IntuiText ScriptText[SCRIPTMAX];
struct MenuItem UtilItem[UTILMAX];
struct IntuiText UtilText[UTILMAX];
struct Menu menu[MAXMENU];
struct IOExtSer *Read_Request;
char *rs_in;
struct IOExtSer *Write_Request;
char rs_out[2];
struct timerequest Timer;
struct MsgPort *Timer_Port = NULL;
struct timerequest Script_Timer;
struct MsgPort *Script_Timer_Port = NULL;
struct IOAudio Audio_Request;
struct MsgPort *Audio_Port = NULL;
UBYTE  *BeepWave;
UBYTE  Audio_AllocMap[4] = { 1, 8, 2, 4 };
int want_message;
int x,y,curmode,keyapp;
int MINX	= 0;
int MAXX	= 632;
int MINY	= 14;
int MAXY	= 198;
int top		= 14;
int bot		= 198;
int savx	= 0;
int savy	= 14;
int savmode	= 0;
int nlmode	= 0;
int alt		= 0;
int savalt	= 0;
int a[2]	= { 0, 0 };
int sa[2]	= { 0, 0 };
int  inesc	= -1;
int  inctrl	= -1;
int  private	= 0;
int  badseq	= 0;
char *blanks	= "                                                      ";
int  maxcol	= 79;

/*************************** defaults ***********************************/
int	p_baud	     = 2400;	    /* baud rate */
int	p_screen     = 1;	    /* 0 = WORKBENCH,	    1 = CUSTOM */
int	p_interlace  = 1;	    /* 0 = no interlace,    1 = interlace */
int	p_depth	     = 1;	    /* number of bit planes (1 or 2) */
int	p_foreground = 0x950;	    /* default foreground RGB color */
int	p_background = 0x000;	    /* default background RGB color */
int	p_bold	     = 0xa00;	    /* default BOLD       RGB color */
int	p_cursor     = 0x00a;	    /* default Cursor	  RGB color */
int	p_lines	     = 48;	    /* number of lines on the screen */
int	p_mode	     = 1;	    /* 0 = image, 1 = CRLF (for kermit) */
int	p_buffer     = 512;	    /* read buffer size (>= 512 bytes) */
int     p_parity     = 0;	    /* 0=none,1=mark,2=space,3=even,4=odd */
long	p_break	     = 750000;	    /* break time (in micro seconds) */
int	p_volume     = 64;	    /* beep volume (0 = DisplayBeep) */
int	p_wrap	     = 0;	    /* 0 = truncate, 1 = wrap long lines */
char	p_keyscript  = 0x7E;	    /* function key script introducer = ~ */
char	*p_f[10]     = {	    /* function key defaults */
    "\033OP","\033OQ","\033OR","\033OS",
    "f5","f6","f7","f8","f9","f10" };

char	*p_F[10]     = {	    /* shifted function key defaults */
    "F1","F2","F3","F4","F5",
    "F6","F7","F8","F9","F10"};

/* for script file */
int script_on;
int script_wait;
void setserbaud(), setparams(), handle_menupick();

#else /* not MODULE_MAIN */

extern int     multi;		    /* flags multi file transfers */
extern int     server;
extern int     want_message;
extern char    bufr[BufSize];
extern int     fd, timeout, ttime;
extern long    bytes_xferred;
extern char    MyDir[60];

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;

extern struct NewScreen NewScreen;
extern struct NewWindow NewWindow;
extern struct Screen *myscreen;
extern struct Window *mywindow;
extern struct ViewPort *myviewport;
extern struct IntuiMessage *NewMessage;
extern struct Preferences  *Prefs;
extern struct MenuItem FileItem[FILEMAX];
extern struct IntuiText FileText[FILEMAX];
extern struct MenuItem CommItem[COMMAX];
extern struct IntuiText CommText[COMMAX];
extern struct MenuItem RSItem[RSMAX];
extern struct IntuiText RSText[RSMAX];
extern struct MenuItem ParItem[PARMAX];
extern struct IntuiText ParText[PARMAX];
extern struct MenuItem XFItem[XFMAX];
extern struct IntuiText XFText[XFMAX];
extern struct MenuItem ScriptItem[SCRIPTMAX];
extern struct IntuiText ScriptText[SCRIPTMAX];
extern struct MenuItem UtilItem[UTILMAX];
extern struct IntuiText UtilText[UTILMAX];
extern struct Menu menu[MAXMENU];
extern struct timerequest Timer, Script_Timer;
extern struct MsgPort *Timer_Port, *Script_Timer_Port;
extern struct IOExtSer *Read_Request;
extern char *rs_in;
extern struct IOExtSer *Write_Request;
extern char rs_out[2];
extern int x,y,curmode,keyapp;
extern int MINX,MAXX,MINY,MAXY,top,bot,savx,savy;
extern int savmode,nlmode,alt,savalt,a[2],sa[2];
extern int inesc,inctrl,private,badseq,maxcol;
extern char *blanks;
extern struct IOAudio Audio_Request;
extern struct MsgPort *Audio_Port;
extern UBYTE  *BeepWave;
extern UBYTE  Audio_AllocMap[];

extern int p_baud,p_screen,p_interlace,p_depth,p_buffer;
extern int p_foreground,p_background,p_bold,p_cursor,p_lines,p_mode;
extern int p_parity,p_volume,p_wrap,p_keyscript;
extern long p_break;
extern char *p_f[10],*p_F[10];
extern int script_on;
extern int script_wait;

extern int do_send(),do_capture(),cleanup();
extern void setserpar(), setserbaud(), setparams(),
	handle_menupick();

#endif /* not MODULE_MAIN */

#ifndef MODULE_INIT
extern void InitDevs(),InitFileItems(),InitCommItems(),
	 InitScriptItems(),InitUtilItems(),InitMenu();
extern char *InitDefaults();
#endif

#ifndef MODULE_WINDOW
extern	void filename(),emits(),emit(),emitbatch(),cursoroff(),cursoron();
extern	int  toasc();
#endif

#ifndef MODULE_XMODEM
extern	void sendchar(),sendstring(),sendbreak();
extern	int  readchar(),XMODEM_Read_File(),XMODEM_Send_File();
#endif

#ifndef MODULE_REMOTE
extern	void doremote(),doindex();
#endif

#ifndef MODULE_KERMIT
extern	int  doksend(),dokreceive(), multi_xfer(), saybye();
#endif

#ifndef MODULE_SCRIPT
extern int script_start(), chk_script(), exit_script(), do_script_cmd();
#endif

#ifndef MODULE_EXPAND
extern char **expand();
extern int  set_dir(), free_expand();
#endif

SHAR_EOF
#	End of shell archive
exit 0

doc@j.cc.purdue.edu (10/14/86)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	init.c
#	kermit.c
# This archive created: Tue Oct 14 12:58:51 1986
# By:	Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > init.c
/***************************************************************
 * vt100 - terminal emulator - initialization
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS	- Added Parity and Word Length and support code
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 ***************************************************************/

#define MODULE_INIT 1
#include "vt100.h"

char line[256];

char *InitDefaults(argc,argv)
int	argc;
char	**argv;
    {
    FILE    *fd;
    char    scr[32],delim,macro[256],c0,*ptr,*ptr2;
    int	    i,j,k;
    long    li;

    if (((argc > 1) && (fd=fopen(argv[1],"r")) != 0) ||
	(fd=fopen("vt100.init","r")) != 0 ||
	(fd=fopen("s:vt100.init","r")) != 0) {
	while (fgets(line,256,fd) != 0) {
	    if ((c0 = line[0]) == '#') continue;
	    if ((c0|' ') == 'e') break;
	    switch (c0|' ') {
		case 'b':
		if ((line[1]|' ') == 'o') {
		    /* bold color */
		    if (sscanf(line,"%s %x",scr,&i) == 2) p_bold = i;
		    break;
		    }
		if ((line[1]|' ') == 'u') {
		    /* buffer size */
		    if (sscanf(line,"%s %d",scr,&i) == 2) p_buffer = i;
		    if (p_buffer < 512) p_buffer = 512;
		    break;
		    }
		if ((line[1]|' ') == 'r') {
		    /* break time */
		    if (sscanf(line,"%s %ld",scr,&li) == 2) p_break = li;
		    break;
		    }
		if ((line[1]|' ') != 'a') break;
		switch(line[2]|' ') {
		    /* baud rate */
		    case 'u':
		    if (sscanf(line,"%s %d",scr,&i) == 2)
			switch (i) {
			    case  300:
			    case 1200:
			    case 2400:
			    case 4800:
			    case 9600:	p_baud = i; break;
			    }
		    break;

		    /* background */
		    case 'c':
		    if (sscanf(line,"%s %x",scr,&i) == 2) p_background = i;
		    break;
		    }
		break;

		/* screen type */
		case 's':
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[0]|' ') == 'w') p_screen = 0;
		    else		     p_screen = 1;
		    }
		break;

		/* number of lines */
		case 'l':
		if (sscanf(line,"%s %d",scr,&i) == 2) p_lines = i;
		break;

		/* screen depth */
		case 'd':
		if (sscanf(line,"%s %d",scr,&i) == 2) p_depth = i;
		break;

		/* cursor color */
		case 'c':
		if (sscanf(line,"%s %x",scr,&i) == 2) p_cursor = i;
		break;

		/* interlace type */
		case 'i':
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[1]|' ') == 'n') p_interlace = 1;
		    else		     p_interlace = 0;
		    }
		break;

		case 'f':
		switch (line[1]|' ') {

		    /* foreground color */
		    case 'o':
    		    if (sscanf(line,"%s %x",scr,&i) == 2) p_foreground = i;
		    break;

		    /* function key */
		    default:
		    if (sscanf(&line[1],"%d",&i) != 1) break;
		    if (i < 1 || i > 10) break;
		    delim = 0;
		    for (j=(i==10?3:2); line[j] != 0 &&
			      (line[j] == ' ' || line[j] == '\t'); j++) ;
		    if (line[j] == 0) {
			if (c0 == 'f') p_f[i-1] = NULL;
			else	       p_F[i-1] = NULL;
			break;
			}
		    delim = line[j];
		    k = 0;
		    macro[0] = 0;
		    while (line[++j] != delim) {
			if (line[j] == 0) {
			    if (fgets(line,256,fd) == 0) {
				line[0] = delim;
				line[1] = 0;
				}
			    j = -1;
			    continue;
			    }
			if (line[j] == '^' && line[++j] != '^')
			    macro[k++] = (line[j]|' ') - 0x60;
			else if (line[j] != '\n') macro[k++] = line[j];
			macro[k]   = 0;
			}
		    ptr = malloc(k+1);
		    if (c0 == 'f') p_f[i-1] = ptr;
		    else	   p_F[i-1] = ptr;
		    strcpy(ptr,macro);
		    break;
		    }
		break;

		case 'k':
		/*keyscript*/
		if (sscanf(line,"%s %x",scr,&i) == 2)
		    p_keyscript = i & 0x7F;
		break;

		case 'm':
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[0]|' ') == 'i')	p_mode = 0;
		    else			p_mode = 1;
		    }
		break;

		case 'p': /*parity*/
		if (sscanf(line,"%s %s",scr,scr) == 2)
		    switch(*scr|' ') {
			case 'n':   p_parity =  0; break;
			case 'm':   p_parity =	1; break;
			case 's':   p_parity =  2; break;
			case 'e':   p_parity =  3; break;
			case 'o':   p_parity =  4; break;
			}
		break;

		case 'v': /*volume*/
		if (sscanf(line,"%s %d",scr,&i) == 2)
		    if (i > 0) p_volume = i;
		break;

		case 'w':
		/*wrap*/
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[1]|' ') == 'n') p_wrap = 1;
		    else		     p_wrap = 0;
		    }
		break;
		}
	    }
	fclose(fd);
	}
    /* Now set up all the screen info as necessary */
    if (p_interlace == 0) {
	if (p_lines > 24) p_lines = 24;
	MINY = 14;
	NewWindow.Height    = (long)((p_lines*8)+8);
	}
    else {
	if (p_lines > 48) p_lines = 48;
	MINY = 16;
	NewScreen.ViewModes |= LACE;
	NewWindow.Height    = (long)((p_lines*8)+10);
	}
    NewWindow.MinHeight = NewWindow.Height;
    NewWindow.MaxHeight = NewWindow.Height;
    NewWindow.TopEdge   = 3L;
    MAXY = ((p_lines-1)*8) + MINY;
    top  = MINY;
    bot	 = MAXY;
    savx = MINX;
    savy = MINY;
    if (p_screen == 1) {
	if (p_depth > 2) p_depth = 2;
	if (p_depth < 1) p_depth = 1;
	NewScreen.Depth	    = (long)p_depth;
	NewScreen.Height    = (long)((p_lines*8)+15);
	if (p_interlace == 1)
	    NewScreen.TopEdge   = (long)(402 - NewScreen.Height);
	else
	    NewScreen.TopEdge   = 0L;
	}
    else {
	p_depth			= 2L;
	NewWindow.TopEdge	= 0L;
	NewWindow.Screen	= NULL;
	NewWindow.Type	= WBENCHSCREEN;
	}
    /* see if we exit with a startup script */
    if ((c0|' ') == 'e') {
	ptr = &line[0];
	while (*ptr != '\000' && *ptr != ' ' && *ptr != '\t') ptr++;
	if (*ptr == '\000') return(NULL);
	while (*ptr != '\000' && (*ptr == ' ' || *ptr == '\t')) ptr++;
	if (*ptr == '\000') return(NULL);
	ptr2 = ptr;	
	while (*ptr2 != '\000' && *ptr2 != ' ' &&
	       *ptr2 != '\t'   && *ptr2 != '\n') ptr2++;
	*ptr2 = '\000';
	return(ptr);
	}
    else return(NULL);
    }

void InitDevs()
{
USHORT	colors[4];
int	i;
BYTE	*b,*c;

IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", INTUITION_REV);
if( IntuitionBase == NULL )
   cleanup("can't open intuition",1);

GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",GRAPHICS_REV);
if( GfxBase == NULL )
   cleanup("can't open graphics library",2);

if (p_screen == 1) {
    if ((myscreen = (struct Screen *)OpenScreen(&NewScreen)) == NULL)
	cleanup("can't open screen",3);
    NewWindow.Screen = myscreen;
    }

if(( mywindow = (struct Window *)OpenWindow(&NewWindow) ) == NULL)
   cleanup("can't open window",4);

myviewport   = (struct ViewPort *)ViewPortAddress(mywindow);

if (p_screen != 0) {
    colors[0] = p_background;
    colors[1] = p_foreground;
    colors[2] = p_bold;
    colors[3] = p_cursor;
    if (p_depth == 1)
	LoadRGB4(myviewport,(struct ColorMap *)colors,2L);
    else
	LoadRGB4(myviewport,(struct ColorMap *)colors,4L);
    }

Read_Request = (struct IOExtSer *)
    AllocMem((long)sizeof(*Read_Request),MEMF_PUBLIC|MEMF_CLEAR);
Read_Request->io_SerFlags = 0L;
Read_Request->IOSer.io_Message.mn_ReplyPort = CreatePort(0,0);
if(OpenDevice(SERIALNAME,NULL,Read_Request,NULL))
   cleanup("Cant open Read device",5);
rs_in = malloc(p_buffer+1);
Read_Request->io_SerFlags = 0L;
Read_Request->io_Baud	  = p_baud;
Read_Request->io_ReadLen  = 8L;
Read_Request->io_WriteLen = 8L;
Read_Request->io_CtlChar  = 0x11130000L;
Read_Request->io_RBufLen  = p_buffer;
Read_Request->io_BrkTime  = p_break;
Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO(Read_Request);
Read_Request->IOSer.io_Command = CMD_READ;
Read_Request->IOSer.io_Length  = 1;
Read_Request->IOSer.io_Data    = (APTR) &rs_in[0];

Write_Request = (struct IOExtSer *)
    AllocMem((long)sizeof(*Write_Request),MEMF_PUBLIC|MEMF_CLEAR);
b = (BYTE *)Read_Request;
c = (BYTE *)Write_Request;
for (i=0;i<sizeof(struct IOExtSer);i++) *c++ = *b++;
Write_Request->IOSer.io_Message.mn_ReplyPort = CreatePort(0,0);
Write_Request->IOSer.io_Command = CMD_WRITE;
Write_Request->IOSer.io_Length  = 1;
Write_Request->IOSer.io_Data    = (APTR) &rs_out[0];

Timer_Port = CreatePort("Timer Port",0);
Script_Timer_Port = CreatePort("Timer Port",0);

if (OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &Timer, 0) ||
    OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &Script_Timer, 0)) 
	cleanup("can't open timer device",7);

Timer.tr_node.io_Message.mn_ReplyPort = Timer_Port;
Timer.tr_node.io_Command = TR_ADDREQUEST;
Timer.tr_node.io_Flags = 0;
Timer.tr_node.io_Error = 0;

Script_Timer.tr_node.io_Message.mn_ReplyPort = Script_Timer_Port;
Script_Timer.tr_node.io_Command = TR_ADDREQUEST;
Script_Timer.tr_node.io_Flags = 0;
Script_Timer.tr_node.io_Error = 0;

BeepWave   = (UBYTE *)AllocMem(BEEPSIZE,(long)(MEMF_CHIP|MEMF_CLEAR));
if (BeepWave != 0) BeepWave[0] = 100;

Audio_Port = CreatePort("Audio Port",0);

Audio_Request.ioa_Request.io_Message.mn_ReplyPort   = Audio_Port;
Audio_Request.ioa_Request.io_Message.mn_Node.ln_Pri = 85;
Audio_Request.ioa_Data		    = Audio_AllocMap;
Audio_Request.ioa_Length	    = (ULONG) sizeof(Audio_AllocMap);

if (OpenDevice(AUDIONAME, NULL, (char *) &Audio_Request, NULL))
	cleanup("can't open audio device",8);

Audio_Request.ioa_Request.io_Command	= CMD_WRITE;
Audio_Request.ioa_Request.io_Flags	= ADIOF_PERVOL;
Audio_Request.ioa_Data		= BeepWave;
Audio_Request.ioa_Length	= BEEPSIZE;
Audio_Request.ioa_Period	= COLORCLOCK / (BEEPSIZE * BEEPFREQ);
Audio_Request.ioa_Volume	= p_volume;
Audio_Request.ioa_Cycles	= 100;
}

/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the File menu topic.                      */
/*****************************************************************/
void InitFileItems()
{
int n;

/* initialize each menu item and IntuiText with loop */
for( n=0; n<FILEMAX; n++ )
   {
   FileItem[n].NextItem = &FileItem[n+1];
   FileItem[n].LeftEdge = 0;
   FileItem[n].TopEdge = 10 * n;
   FileItem[n].Width = 120;
   FileItem[n].Height = 10;
   FileItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP;
   FileItem[n].MutualExclude = 0;
   FileItem[n].ItemFill = (APTR)&FileText[n];
   FileItem[n].SelectFill = NULL;
   FileItem[n].Command = 0;
   FileItem[n].SubItem = NULL;
   FileItem[n].NextSelect = 0;

   FileText[n].FrontPen = 0;
   FileText[n].BackPen = 1;
   FileText[n].DrawMode = JAM2;     /* render in fore and background */
   FileText[n].LeftEdge = 0;
   FileText[n].TopEdge = 1;
   FileText[n].ITextFont = NULL;
   FileText[n].NextText = NULL;
   }
FileItem[FILEMAX-1].NextItem = NULL;

/* initialize text for specific menu items */

FileText[0].IText = (UBYTE *)"Ascii  Capture";
FileText[1].IText = (UBYTE *)"Ascii  Send";
FileText[2].IText = (UBYTE *)"Xmodem Receive";
FileText[3].IText = (UBYTE *)"Xmodem Send";
FileText[4].IText = (UBYTE *)"Kermit Get";
FileText[5].IText = (UBYTE *)"Kermit Receive";
FileText[6].IText = (UBYTE *)"Kermit Send";
FileText[7].IText = (UBYTE *)"Kermit BYE";
}

/*************************************************************************
/*			Main Comm menu
/*		set up for Baud & Parity submenus
/************************************************************************/
void InitCommItems()
{
int n;
                                
/* initialize each menu item and IntuiText with loop */
for( n=0; n<COMMAX; n++ )
   {
   CommItem[n].NextItem = &CommItem[n+1];
   CommItem[n].LeftEdge = 0;
   CommItem[n].TopEdge = 10 * n;
   CommItem[n].Width = 88;
   CommItem[n].Height = 10;
   CommItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP ;
   CommItem[n].MutualExclude = 0;
   CommItem[n].ItemFill = (APTR)&CommText[n];
   CommItem[n].SelectFill = NULL;
   CommItem[n].Command = 0;
   CommItem[n].NextSelect = 0;

   CommText[n].FrontPen = 0;
   CommText[n].BackPen = 1;
   CommText[n].DrawMode = JAM2;    
   CommText[n].LeftEdge = 0;
   CommText[n].TopEdge = 1;
   CommText[n].ITextFont = NULL;
   CommText[n].NextText = NULL;
   }
CommItem[COMMAX-1].NextItem = NULL;

CommText[0].IText = (UBYTE *)"Baud Rate";
CommText[1].IText = (UBYTE *)"Parity   ";
CommText[2].IText = (UBYTE *)"Xfer Mode";
CommItem[0].SubItem = RSItem;
CommItem[1].SubItem = ParItem;
CommItem[2].SubItem = XFItem;

/*****************************************************************/
/*    The following initializes the structure arrays		 */
/*   needed to provide the BaudRate Submenu topic.               */
/*****************************************************************/

for( n=0; n<RSMAX; n++ )
   {
   RSItem[n].NextItem = &RSItem[n+1];
   RSItem[n].LeftEdge = 75;
   RSItem[n].TopEdge = 10 * n;
   RSItem[n].Width = 56;
   RSItem[n].Height = 10;
   RSItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT;
   RSItem[n].MutualExclude = (~(1 << n));
   RSItem[n].ItemFill = (APTR)&RSText[n];
   RSItem[n].SelectFill = NULL;
   RSItem[n].Command = 0;
   RSItem[n].SubItem = NULL;
   RSItem[n].NextSelect = 0;

   RSText[n].FrontPen = 0;
   RSText[n].BackPen = 1;
   RSText[n].DrawMode = JAM2;     /* render in fore and background */
   RSText[n].LeftEdge = 0;
   RSText[n].TopEdge = 1;
   RSText[n].ITextFont = NULL;
   RSText[n].NextText = NULL;
   }
RSItem[RSMAX-1].NextItem = NULL;

/* select baud item chekced */
switch (p_baud) {
    case 300:	n = 0; break;
    case 1200:	n = 1; break;
    case 2400:	n = 2; break;
    case 4800:	n = 3; break;
    case 9600:	n = 4; break;
    default:	n = 2; p_baud = 2400;
    }
RSItem[n].Flags |= CHECKED;

/* initialize text for specific menu items */
RSText[0].IText = (UBYTE *)"   300";
RSText[1].IText = (UBYTE *)"  1200";
RSText[2].IText = (UBYTE *)"  2400";
RSText[3].IText = (UBYTE *)"  4800";
RSText[4].IText = (UBYTE *)"  9600";

/*****************************************************************/
/*    The following initializes the structure arrays		 */
/*   needed to provide the Parity   Submenu topic.               */
/*****************************************************************/

for( n=0; n<PARMAX; n++ )
   {
   ParItem[n].NextItem = &ParItem[n+1];
   ParItem[n].LeftEdge = 75;
   ParItem[n].TopEdge = 10 * n;
   ParItem[n].Width = 56;
   ParItem[n].Height = 10;
   ParItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT;
   ParItem[n].MutualExclude = (~(1 << n));
   ParItem[n].ItemFill = (APTR)&ParText[n];
   ParItem[n].SelectFill = NULL;
   ParItem[n].Command = 0;
   ParItem[n].SubItem = NULL;
   ParItem[n].NextSelect = 0;

   ParText[n].FrontPen = 0;
   ParText[n].BackPen = 1;
   ParText[n].DrawMode = JAM2;     /* render in fore and background */
   ParText[n].LeftEdge = 0;
   ParText[n].TopEdge = 1;
   ParText[n].ITextFont = NULL;
   ParText[n].NextText = NULL;
   }
ParItem[PARMAX-1].NextItem = NULL;

/* select parity item chekced */
ParItem[p_parity].Flags |= CHECKED;

/* initialize text for specific menu items */
ParText[0].IText = (UBYTE *)"  None ";
ParText[1].IText = (UBYTE *)"  Mark ";
ParText[2].IText = (UBYTE *)"  Space";
ParText[3].IText = (UBYTE *)"  Even ";
ParText[4].IText = (UBYTE *)"  Odd  ";

/*****************************************************************/
/*    The following initializes the structure arrays		 */
/*    needed to provide the Transfer Mode menu topic.            */
/*****************************************************************/

/* initialize each menu item and IntuiText with loop */
for( n=0; n<XFMAX; n++ )
   {
   XFItem[n].NextItem = &XFItem[n+1];
   XFItem[n].LeftEdge = 75;
   XFItem[n].TopEdge = 10 * n;
   XFItem[n].Width = 80;
   XFItem[n].Height = 10;
   XFItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT;
   XFItem[n].MutualExclude = (~(1 << n));
   XFItem[n].ItemFill = (APTR)&XFText[n];
   XFItem[n].SelectFill = NULL;
   XFItem[n].Command = 0;
   XFItem[n].SubItem = NULL;
   XFItem[n].NextSelect = 0;

   XFText[n].FrontPen = 0;
   XFText[n].BackPen = 1;
   XFText[n].DrawMode = JAM2;
   XFText[n].LeftEdge = 0;
   XFText[n].TopEdge = 1;
   XFText[n].ITextFont = NULL;
   XFText[n].NextText = NULL;
   }
XFItem[XFMAX-1].NextItem = NULL;
/* mode checked */
XFItem[p_mode].Flags |= CHECKED;

/* initialize text for specific menu items */
XFText[0].IText = (UBYTE *)"  image";
XFText[1].IText = (UBYTE *)"  CR LF";

} /* end of InitCommItems() */


/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the Script menu topic.                    */
/*****************************************************************/
void InitScriptItems()
{
int n;

/* initialize each menu item and IntuiText with loop */
for( n=0; n<SCRIPTMAX; n++ )
   {
   ScriptItem[n].NextItem = &ScriptItem[n+1];
   ScriptItem[n].LeftEdge = 0;
   ScriptItem[n].TopEdge = 10 * n;
   ScriptItem[n].Width = 128;
   ScriptItem[n].Height = 10;
   ScriptItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP;
   ScriptItem[n].MutualExclude = 0;
   ScriptItem[n].ItemFill = (APTR)&ScriptText[n];
   ScriptItem[n].SelectFill = NULL;
   ScriptItem[n].Command = 0;
   ScriptItem[n].SubItem = NULL;
   ScriptItem[n].NextSelect = 0;

   ScriptText[n].FrontPen = 0;
   ScriptText[n].BackPen = 1;
   ScriptText[n].DrawMode = JAM2;     /* render in fore and background */
   ScriptText[n].LeftEdge = 0;
   ScriptText[n].TopEdge = 1;
   ScriptText[n].ITextFont = NULL;
   ScriptText[n].NextText = NULL;
   }
ScriptItem[SCRIPTMAX-1].NextItem = NULL;

/* initialize text for specific menu items */
ScriptText[0].IText = (UBYTE *)"Execute file";
ScriptText[1].IText = (UBYTE *)"Abort Execution";
}

/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the Util menu topic.                    */
/*****************************************************************/
void InitUtilItems()
{
int n;

/* initialize each menu item and IntuiText with loop */
for( n=0; n<UTILMAX; n++ )
   {
    UtilItem[n].NextItem = &UtilItem[n+1];
    UtilItem[n].LeftEdge = 0;
    UtilItem[n].TopEdge = 10 * n;
    UtilItem[n].Width = 88;
    UtilItem[n].Height = 10;
    UtilItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP;
    UtilItem[n].MutualExclude = 0;
    UtilItem[n].ItemFill = (APTR)&UtilText[n];
    UtilItem[n].SelectFill = NULL;
    UtilItem[n].Command = 0;
    UtilItem[n].SubItem = NULL;
    UtilItem[n].NextSelect = 0;

    UtilText[n].FrontPen = 0;
    UtilText[n].BackPen = 1;
    UtilText[n].DrawMode = JAM2;     /* render in fore and background */
    UtilText[n].LeftEdge = 0;
    UtilText[n].TopEdge = 1;
    UtilText[n].ITextFont = NULL;
    UtilText[n].NextText = NULL;
    }

/*  until we know how to toggle DTR */
/* UtilItem[1].Flags ^= ITEMENABLED; */

UtilItem[UTILMAX-1].NextItem = NULL;

/* initialize text for specific menu items */
UtilText[0].IText = (UBYTE *)"Send Break";
UtilText[1].IText = (UBYTE *)"Hang Up";
UtilText[2].IText = (UBYTE *)"Change Dir";
}

/**********************************************************************/
/*   The following function initializes the Menu structure array with */
/*  appropriate values for our simple menu strip.  Review the manual  */
/*  if you need to know what each value means.                        */
/**********************************************************************/
void InitMenu()
{
menu[0].NextMenu = &menu[1];
menu[0].LeftEdge = 5;
menu[0].TopEdge = 0;
menu[0].Width = 40;
menu[0].Height = 10;
menu[0].Flags = MENUENABLED;
menu[0].MenuName = "File";           /* text for menu-bar display */
menu[0].FirstItem = &FileItem[0];    /* pointer to first item in list */

menu[1].NextMenu = &menu[2];
menu[1].LeftEdge = 55;
menu[1].TopEdge = 0;
menu[1].Width = 88;
menu[1].Height = 10;
menu[1].Flags = MENUENABLED;
menu[1].MenuName = "Comm Setup";        /* text for menu-bar display */
menu[1].FirstItem = &CommItem[0];    /* pointer to first item in list */

menu[2].NextMenu = &menu[3];
menu[2].LeftEdge = 153;
menu[2].TopEdge = 0;
menu[2].Width = 56;
menu[2].Height = 10;
menu[2].Flags = MENUENABLED;
menu[2].MenuName = "Script";        /* text for menu-bar display */
menu[2].FirstItem = &ScriptItem[0];    /* pointer to first item in list */

menu[3].NextMenu = NULL;
menu[3].LeftEdge = 225;
menu[3].TopEdge = 0;
menu[3].Width = 64;
menu[3].Height = 10;
menu[3].Flags = MENUENABLED;
menu[3].MenuName = "Utility";        /* text for menu-bar display */
menu[3].FirstItem = &UtilItem[0];    /* pointer to first item in list */
}

SHAR_EOF
cat << \SHAR_EOF > kermit.c
/*************************************************************
 * vt100 terminal emulator - KERMIT protocol support
 *
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS - Added eight bit quoting
 *           860830 Steve Drew Wild card support, error recovery, bugs.
 *	     860823 DBW - Integrated and rewrote lots of code
 *           860811 Steve Drew multi filexfer, bugs, status line ect..
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *************************************************************/

#define MODULE_KERMIT 1
#include "vt100.h"

#define CONVERTNAME TRUE    /* convert file name to lower case for receive */
#define MAXPACKSIZ 94       /* Maximum msgpkt size */
#define CR         13       /* ASCII Carriage Return */
#define LF         10       /* ASCII line feed */
#define SP         32       /* ASCII space */
#define DEL       127       /* Delete (rubout) */

#define MAXTRY    5        /* Times to retry a msgpkt */
#define MYQUOTE  '#'       /* Quote character I will use */
#define MYRPTQ   '~'       /* Repeat quote character */
#define MYEBQ	 '&'	   /* 8th bit prefix character */
#define MYPAD      0       /* Number of padding characters I will need */
#define MYPCHAR    0       /* Padding character I need (NULL) */
#define MYEOL    '\n'      /* End-Of-Line character I need */

#define tochar(ch)  ((ch) + ' ')
#define unchar(ch)  ((ch) - ' ')
#define ctl(ch)     ((ch) ^ 64 )

/* Global Variables */

int
   size,      /* Size of present data */
   osize,     /* Size of last data entry */
   rpsiz,     /* Maximum receive msgpkt size */
   spsiz,     /* Maximum send msgpkt size */
   timint,    /* Time interval to wait */
   pad,       /* How much padding to send */
   n,         /* Packet number */
   tp,        /* total packets */
   numtry,    /* Times this msgpkt retried */
   retry,     /* total retries */
   oldtry,    /* Times previous msgpkt retried */
   sendabort, /* flag for aborting send file  */
   rptflg,    /* are we doing repeat quoting */
   ebqflg,    /* are we doing 8th bit quoting */
   notfirst,  /* is this the first file received */
   first,     /* is this the first time in a file */
   rpt,       /* current repeat count */
   next,      /* what is the next character */
   t;         /* current character */
long
   totbytes;  /* total bytes xfered on this file */

char 
   state,     /* Present state of the automaton */
   padchar,   /* Padding character to send */
   eol,       /* End-Of-Line character to send */
   quote,     /* Quote character in incoming data */
   rptq,      /* Quote character for repeats */
   ebq,	      /* Quote character for 8th bit quoting */
   ackpkt[MAXPACKSIZ+20], /* ACK/NAK packet buffer */
   msgpkt[MAXPACKSIZ+20], /* Message Packet buffer */
   filnam[40];            /* remote file name */
   snum[10];

void encode(), decode(), rpar(), spar();
   
FILE *fp;     /* file for send/receive */

char *
getfname(name)   /* returns pointer to start of file name from file spec */
char *name;
    {
    int l;

    l = strlen(name);
    while(l && name[l] != '/' && name[l] != ':') l--;
    if (name[l] == '/' || name[l] == ':') l++;
    return(name += l);
    }
    
doksend(file,more)
char *file;
int more;
   {
   int amount, c, wild;
   char *p, **list = NULL;

   if (!strcmp(file,"$")) { saybye(); return(2); }
   want_message = FALSE;              /* tell readchar no error msgs */
   p = file;
   while(*p && *p != '*' && *p != '?') p++;
   if (*p) { 
       wild = TRUE;
       list = expand(file, &amount);
       if (list == NULL)  emits("No wild card match\n");
       }
   else {
       wild = FALSE;
       amount = 1;
       }
   for (c = 0; c < amount; c++) {
       if (wild == TRUE) p = list[c];
         else  p = file;
       strcpy(filnam,getfname(p));
       ttime = TTIME_KERMIT;
       tp = retry = n = numtry = 0; totbytes = 0L;
       statusline();
       if ((fp = fopen(p,"r")) == NULL) {
           emits("ERROR");
           emits("\nVT100 - Kermit - Cannot open send file: ");
           emits(p); 
           curmode = FS_NORMAL;
           continue;
           }
       emits("SEND");
       ClearBuffer();
       if (sendsw()) { x = 600; emits("DONE"); }
       fclose(fp);
       curmode = FS_NORMAL;
       } 
   free_expand(list);
   return TRUE;
   }
 
dokreceive(file,more)
char *file;
int more;
   {
   int retval;
   
   ttime = TTIME_KERMIT;
   if (!strcmp(file,"$")) { saybye(); return(2); }
   strcpy(filnam, file);   
   statusline();   
   if (server) emits("GET ");
   else emits("RECV");
   tp =  retry = n =  numtry = notfirst = 0; totbytes = 0L;
   want_message = FALSE; /* tell readchar no error msgs status bar instead */
   ClearBuffer();
   retval  = recsw();
   curmode = FS_NORMAL;
   return(retval);
   }

sendsw()
   {
   char sinit(), sfile(), sdata(), seof(), sbreak();
   sendabort = 0;
   state = 'S';
   while(TRUE) {
      switch(state) {
         case 'S':   state = sinit();  break;
         case 'F':   state = sfile();  break;
         case 'D':   state = sdata();  break;
         case 'Z':   state = seof();   break;
         case 'B':   state = sbreak(); break;
         case 'C':   if (sendabort) return FALSE;
                     else return TRUE;
         case 'E':   x = 600;            /* host sent us error packet    */
                     emits("ERROR");     /* so print the error and abort */
                     print_host_err(ackpkt);
                     return(FALSE);
         case 'A':   x = 600;
                     if (timeout == USERABORT) {
			 timeout = GOODREAD;
                         n = (n+1)%64;			 
                     	 sendabort = 1;
                     	 emits("ABORT");
                     	 strcpy(msgpkt, "D");
                     	 state = 'Z'; 
                     	 break;
                     	 }
                     if (timeout == TIMEOUT)  emits("TMOUT");
                     else { /* protocol error dectected by us */
			 emits("ERROR");
			 print_our_err();
			 }
                     return(FALSE);
         default:    return(FALSE);
         }
      }
   }

char sinit()
   {
   int num, len;
   
   retry++;
   if (numtry++ > MAXTRY) return('A');
   spar(msgpkt);

   spack('S',n,9,msgpkt);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':  return(state);
      case 'Y':  if (n != num) return(state);
                 rpar(ackpkt);
                 if (eol == 0) eol = '\n';
                 if (quote == 0) quote = MYQUOTE;
                 numtry = 0;
                 retry--;
                 n = (n+1)%64;
                 return('F');
      case 'E':  return('E');
      case FALSE:if (timeout == USERABORT) state = 'A';
                 return(state);
      default:   return('A');
      }
    }

char sfile()
   {
   int num, len;

   retry++;
   if (numtry++ > MAXTRY) return('A');

   spack('F',n,strlen(filnam),filnam);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':
         num = (--num<0 ? 63:num);
         if (n != num) return(state);
      case 'Y':
         if (n != num) return(state);
         numtry = 0;
         retry--;
         n = (n+1)%64;
         first = 1;
         size = getpkt();
         return('D');
      case 'E':
         return('E');
      case FALSE: if (timeout == USERABORT) state = 'A';
                  return(state);
      default:
         return('A');
      }
   }

char sdata()
   {
   int num, len;
   
   retry++;
   if (numtry++ > MAXTRY) return('A');

   spack('D',n,size,msgpkt);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':
         num = (--num<0 ? 63:num);
         if (n != num) return(state);
      case 'Y':
         if (n != num) return(state);
         numtry = 0;
         retry--;
         n = (n+1)%64;
         if ((size = getpkt()) == 0) return('Z');
         return('D');
      case 'E':
         return('E');
      case FALSE: if (timeout == USERABORT) state = 'A';
                  return(state);
      default:    
         return('A');
      }
   }

char seof()
   {
   int num, len;
   retry++;
   if (numtry++ > MAXTRY) return('A');

/*   if (timeout == USERABORT) { /* tell host to discard file */
/*      timeout = GOODREAD;
        spack('Z',n,1,"D"); 
        }   
   else    */ spack('Z',n,sendabort,msgpkt);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':
         num = (--num<0 ? 63:num);
         if (n != num) return(state);
      case 'Y':
         if (n != num) return(state);
         numtry = 0;
         retry--;
         n = (n+1)%64;
         return('B');
      case 'E':
         return('E');
      case FALSE: return(state);
      default:
         return('A');
      }
   }

char sbreak()
   {
   int num, len;
   retry++;
   if (numtry++ > MAXTRY) return('A');

   spack('B',n,0,msgpkt);
   switch (rpack(&len,&num,ackpkt)) {
      case 'N':
         num = (--num<0 ? 63:num);
         if (n != num) return(state);
      case 'Y':
         if (n != num) return(state);
         numtry = 0;
	 retry--;
         n = (n+1)%64;
         return('C');
      case 'E':
         return('E');
      case FALSE: return(state);
      default:    return ('A');
      }
   }

/* timeout equals USERABORT so lets end the file and quit  */
/* when host receives 'Z' packet with "D" in data field he */
/* should discard the file.                                */
/*
sabort()
   {
   emits("ABORT");
   n = (n+1)%64;
   retry--;
   state = 'Z';
   while (state == 'Z') state = seof();
   while (state == 'B') state = sbreak();
   return(FALSE);
   }
*/ 


recsw()
   {
   char rinit(), rfile(), rdata();

   state = 'R';
   
   while(TRUE) {
      switch(state) {
         case 'R':   state = rinit(); break;
         case 'Z':
         case 'F':   state = rfile(); break;
         case 'D':   state = rdata(); break;
         case 'C':   return(TRUE);
         case 'E':
         case 'A':   x = 600;
                     if (timeout == USERABORT){/* easy way to cleanly abort 
                                                  should really send and ACK
                                                  with "X" in data field and 
                                                  wait for host to abort but
                                                  not all kermits support
                                                  this feature.           */
                         emits("ABORT");   /* send an error packet back   */
                         spack('E',n,12,"User aborted"); 
                     }
                     else if (timeout == TIMEOUT) { /* we timed out waiting */
			   /* will we need to spack here ?*/
			 emits("TMOUT");
			 }
                     else emits("ERROR"); /* must be 'E' from host or we
					     detected a protocol error */

		     if (state == 'E') print_host_err(msgpkt);

		     else if (timeout == GOODREAD) /* tell host why */
			print_our_err();
			   /* will this kill all files ?*/
                     do  {
                         ttime = 2;        
                         readchar();
                         }  while (timeout == GOODREAD);
                     fclose(fp);
                     sendstring("\r");
                     return(FALSE);
	 default:    return(FALSE);	
         }
      }
   }



char rinit()
   {
   int len, num;
   retry++;
   if (numtry++ > MAXTRY) return('A');

   if (server) spack('R',n,strlen(filnam),filnam);
   else  spack('N',n,0,0);
   switch(rpack(&len,&num,msgpkt)) {
      case 'S':
         rpar(msgpkt);
         spar(msgpkt);
         spack('Y',n,9,msgpkt);
         oldtry = numtry;
         numtry = 0;
         retry--;
         n = (n+1)%64;
         return('F');
      case 'E':
         return('E');
      case FALSE:
         if (timeout == USERABORT) return('A');
         spack('N',n,0,0);
         return(state);
      default:
         return('A');
      }
   }

char rfile()
   {
   int num, len;
   retry++;
   if (numtry++ > MAXTRY) return('A');

   switch(rpack(&len,&num,msgpkt)) {
      case 'S':
         if (oldtry++ > MAXTRY) return('A');
         if (num == ((n==0) ? 63:n-1)) {
            spar(msgpkt);
            spack('Y',num,9,msgpkt);
            numtry = 0;
            return(state);
            }
         else return('A');
      case 'Z':
         if (oldtry++ > MAXTRY) return('A');
         if (num == ((n==0) ? 63:n-1)) {
            spack('Y',num,0,0);
            numtry = 0;
            return(state);
            }
         else return('A');
      case 'F':
         if (num != n) return('A');
	 strcpy(filnam,msgpkt);
         if (CONVERTNAME) {
             char *p;
	     p = &filnam[0];
             while (*p) { *p = tolower(*p); p++; }
             }
	 if (notfirst) { 
             curmode = FS_NORMAL;
             totbytes = 0L;
	     statusline();
             emits("RECV");
             }
         else {     /* is the first file so emit actual file name from host */
  	     x = 48; emits("                ");
	     x = 48; emits(filnam);
	     notfirst++;
	     }
         if ((fp = fopen(filnam,"w")) == NULL) {
	     strcpy(msgpkt,"VT100 - Kermit - Unable to create file: ");
	     strcat(msgpkt,filnam);
	     spack('E',n,strlen(msgpkt),msgpkt); /* let host know */
             x = 600; emits("ERROR");
             emits("\n");
             emits(msgpkt);       /* let user know */
             return ('\0');       /* abort everything */
             }
         spack('Y',n,0,0);
         oldtry = numtry;
         numtry = 0;
         retry--;
         n = (n+1)%64;
         return('D');
      case 'B':                     /* totaly done server sending no more */
         if (num != n) return ('A');
         spack('Y',n,0,0);
         retry--;
         return('C');
      case 'E':
         return('E');
      case FALSE:
         if (timeout == USERABORT) return('A');
         spack('N',n,0,0);
         return(state);
      default:
         return ('A');
      }
   }

char rdata()
   {
   int num, len;
   retry++;
   if (numtry++ > MAXTRY) return('A');

   switch(rpack(&len,&num,msgpkt)) {
      case 'D':
         if (num != n) {
            if (oldtry++ > MAXTRY) return('A');
            if (num == ((n==0) ? 63:n-1)) {
               spack('Y',num,6,msgpkt); 
               numtry = 0;
               return(state);
               }
            else return('A');
            }
         decode();
         spack('Y',n,0,0);
         oldtry = numtry;
         numtry = 0;
         retry--;
         n = (n+1)%64;
         return('D');
      case 'Z':
         if (num != n) return('A');
         spack('Y',n,0,0);
         n = (n+1)%64;
         retry--;
         x = 600;
         emits("DONE");
	 fclose(fp);
         return('Z');
      case 'F':
         if (oldtry++ > MAXTRY) return('A');
         if (num == ((n==0) ? 63:n-1)) {
	     spack('Y',num,0,0);
	     numtry = 0;
	     return(state);
             }
      case 'E':
         return('E');
      case FALSE:
         if (timeout == USERABORT) return('A');
         spack('N',n,0,0);
         return(state);
      default:
        return('A');
      }
   }


spack(type,num,len,data)
char type, *data;
int num, len;
   {
   int i;
   char chksum, buffer[100];
   register char *bufp;
   
   dostats(type);
   bufp = buffer;
   ClearBuffer();
   for (i=1; i<=pad; i++) sendchar(padchar);

   *bufp++ = SOH;
   *bufp++ = tochar(len+3);
   chksum  = tochar(len+3);
   *bufp++ = tochar(num);
   chksum += tochar(num);
   *bufp++ = type;
   chksum += type;

   for (i=0; i<len; i++) {
      *bufp++ = data[i];
      chksum += data[i];
      }
   chksum = (((chksum&0300) >> 6)+chksum)&077;
   *bufp++ = tochar(chksum);
   *bufp++ = '\r';
   *bufp++ = '\n';
   *bufp   = 0;
   sendstring(buffer);
   }

rpack(len,num,data)
int *len, *num;
char *data;
   {
   int i, done;
   char type, cchksum, rchksum;
   char t = '\0';

    do {
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       } while (t != SOH);

    done = FALSE;
    while (!done) {
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       cchksum = t;
       *len = unchar(t)-3;
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       cchksum = cchksum + t;
       *num = unchar(t);
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       cchksum = cchksum + t;
       type = t;
       for (i=0; i<*len; i++) {
          t = readchar();
          if (timeout != GOODREAD) return(FALSE);
          if (t == SOH) continue;
          cchksum = cchksum + t;
          data[i] = t;
          }
       data[*len] = 0;
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       rchksum = unchar(t);
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       done = TRUE;
       }
   dostats(type);
   cchksum = (((cchksum&0300) >> 6)+cchksum)&077;
   if (cchksum != rchksum) return(FALSE);
   return((int)type);
   }

getpkt() {
   int i,eof;

   static char leftover[10] = { '\0', '\0', '\0', '\0', '\0',
			        '\0', '\0', '\0', '\0', '\0' };

   if (first == 1) {
      first = 0;
      *leftover = '\0';
      t = getc(fp);
      if (t == EOF) {
         first = 1;
         return(size = 0);
         }
      totbytes++;
      }
   else if (first == -1) {
      first = 1;
      return(size = 0);
      }
   for (size = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ;
   *leftover = '\0';
   rpt = 0;
   eof = 0;
   while (!eof) {
      next = getc(fp);
      if (next == EOF) {
         first = -1;
         eof   =  1;
         }
      else totbytes++;
      osize = size;
      encode(t);
      t = next;
      if (size == spsiz-3) return(size);
      if (size > spsiz-3) {
         for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++) ;
         size = osize;
         msgpkt[size] = '\0';
         return(size);
         }
      }
   return(size);
   }

void encode(a)
char a;
   {
   int a7,b8;

   if (p_mode == 1 && a == '\n') {
      rpt = 0;
      msgpkt[size++] = quote;
      msgpkt[size++] = ctl('\r');
      if (size <= spsiz-3) osize = size;
      msgpkt[size++] = quote;
      msgpkt[size++] = ctl('\n');
      msgpkt[size]   = '\0';
      return;
      }
   if (rptflg) {
      if (a == next && (first == 0)) {
         if (++rpt < 94) return;
         else if (rpt == 94) {
            msgpkt[size++] = rptq;
            msgpkt[size++] = tochar(rpt);
            rpt = 0;
            }
         }
      else if (rpt == 1) {
         rpt = 0;
         encode(a);
         if (size <= spsiz-3) osize = size; 
         rpt = 0;
         encode(a);
         return;
         }
      else if (rpt > 1) {
         msgpkt[size++] = rptq;
         msgpkt[size++] = tochar(++rpt);
         rpt = 0;
         }
      }
   a7 = a & 0177;
   b8 = a & 0200;

   if (ebqflg && b8) {			/* Do 8th bit prefix if necessary. */
	msgpkt[size++] = ebq;
	a = a7;
	}
   
   if ((a7 < SP) || (a7==DEL)) {
      msgpkt[size++] = quote;
      a = ctl(a);
      }
   if (a7 == quote) msgpkt[size++] = quote;
   if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;

   if ((ebqflg) && (a7 == ebq))	/* Prefix the 8th bit prefix */
       msgpkt[size++] = quote;           /* if doing 8th-bit prefixes */

   msgpkt[size++] = a;
   msgpkt[size] = '\0';
   }

void decode()
   {
   USHORT  a, a7, b8;
   char *buf;

   buf = msgpkt;
   rpt = 0;
   
   while ((a = *buf++) != '\0') {
      if (rptflg) {
         if (a == rptq) {
            rpt = unchar(*buf++);
            a = *buf++;
            }
         }
      b8 = 0;
      if (ebqflg) {                  /* 8th-bit prefixing? */
	  if (a == ebq) {            /* Yes, got an 8th-bit prefix? */
	      b8 = 0200;             /* Yes, remember this, */
	      a = *buf++;            /* and get the prefixed character. */
	  }
      }
      if (a == quote) {
         a  = *buf++;
         a7 = a & 0177;
         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
         }
      a |= b8;
      if (rpt == 0) rpt = 1;
      if (p_mode == 1 && a == '\r') continue;
      totbytes += rpt;
      for (; rpt > 0; rpt--) putc(a, fp);
      }
   return;
   }

void spar(data)
char data[];
   {
   data[0] = tochar(MAXPACKSIZ);
   data[1] = tochar(TTIME_KERMIT);
   data[2] = tochar(MYPAD);
   data[3] = ctl(MYPCHAR);
   data[4] = tochar(MYEOL);
   data[5] = MYQUOTE;
   if ((p_parity >= 0) || ebqflg) {         /* 8-bit quoting... */
	data[6] = MYEBQ;                     /* If parity or flag on, send &. */
	if ((ebq > 0040 && ebq < 0100) ||   /* If flag off, then turn it on  */
	   (ebq > 0140 && ebq < 0177) ||   /* if other side has asked us to */
	   (ebq == 'Y')) ebqflg = 1;
	}
    else				    /* Normally, */
       data[6] = 'Y';			    /* just say we're willing. */
    data[7] = '1';
    data[8] = MYRPTQ;
    data[9] = '\0';
    }

void rpar(data)
char data[];
    {
    spsiz   = unchar(data[0]);
    ttime   = unchar(data[1]);
    pad     = unchar(data[2]);
    padchar = ctl(data[3]);
    eol     = unchar(data[4]);
    quote   = data[5];
    rptflg  = 0;
    ebqflg  = 0;
    if (data[6] == 0) return;
    ebq = data[6];
    if ((ebq > 040 && ebq < 0100) || (ebq > 0140 && ebq < 0177)) ebqflg = 1;
    else if (((p_parity >= 0) || ebqflg) && (ebq == 'Y')) {
	ebqflg = 1;
	ebq = '&';
	}
    else ebqflg = 0;
    if (data[7] == 0) return;
    if (data[8] == 0) return;
    rptq    = data[8];
    rptflg  = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177));
    }

saybye()
  {
  int len,num;
  spack('G',n,1,"F");  /* shut down server no more files */
  rpack(&len,&num,ackpkt);
  }

print_our_err()
  {
  if (retry > MAXTRY || oldtry > MAXTRY)
      strcpy(msgpkt,"VT100 - Kermit - Too many retries for packet");
  else
      strcpy(msgpkt,"VT100 - Kermit - Protocol Error");
  spack('E',n,strlen(msgpkt));
  emits("\n");
  emits(msgpkt);
  }

print_host_err(msg)
  char *msg;
  {
  curmode = FS_NORMAL;
  emits("\n");
  emits("Host Error: ");
  curmode = FSF_BOLD;
  emits(msg);
  }

statusline()
  {
  emits ("\nFile:                 Pckt:   Pckt No:      Retrn:    Bytes:         Stat:      ");
  x = 48;
  curmode = FSF_BOLD;  
  emits (filnam);
  x = 600;
  return(0);
  }

dostats(type)
char type;
  {
   if (type != 'Y' && type != 'N' && type != 'G') {
      x = 224;
      emit(type);
      x = 312;
      sprintf(snum,"%4d",n+(tp * 64));
      emits(snum);
      if (n==63) tp++;
      x = 408;
      sprintf(snum,"%2d",retry-1);
      emits(snum);
      x = 488;
      sprintf(snum,"%6ld",(long)totbytes);
      emits(snum);
      }
  }

/* allow for multi file xfers separated by commas under kermit and XMODEM */

multi_xfer(name,mode,do_send)
char *name;
int (*mode)();
int do_send;
    {
    int done = 0;
    int status;
    char *p;
    
    p = name;
    while(*p == ' ') p++;
    while(*p && *p != ',' && *p != ' ')   p++;
    if (*p == '\0')   done = TRUE;
     else multi = 1;
    *p = '\0';

    status = ((*mode)(name, multi));
    if (status == TRUE && want_message) {
        if (do_send) emits("Sent File: ");
          else emits("Received File: ");
    	emits(name);
    	emits("\n");
        }
    else if (status == FALSE && want_message)
        {
        close(fd);
        if (do_send) emits("Send Failed: ");
          else emits("Receive Failed: ");
        emits(name);
        emits("\n");	
        }    
    if (!done && timeout != USERABORT) multi_xfer(++p, mode, do_send);
    else emits("\n");
    server = 0;
    multi = 0;
    }

ClearBuffer()
   {
	AbortIO(Read_Request);
        Read_Request->IOSer.io_Command = CMD_CLEAR;
     	DoIO(Read_Request);
        Read_Request->IOSer.io_Command = CMD_READ;
        SendIO(Read_Request);
   }

SHAR_EOF
#	End of shell archive
exit 0