; Kermit.m68 - a telecommunications & error free file transfer program
; Version 2.0 - supports wildcarding, 3 byte CRC
; Author:	Robert P. Rubendunst, Soft Machines,
;		P.O. box 3701, Champaign, IL 61821

; Copyright 1984, 1991  Robert P. Rubendunst. All rights reserved. In
; addition, anthology copyrights prohibited without written permission from
; the author.

; N O T E  - requires 1.3D AMOS/L//1.0D AMOS/32 or later to assemble.
; To assemble, M68 KERMIT.m68 produces KERMIT.LIT

; Edit History:
;[024] 16 March 1994 13:45	Edited by Bob Rubendunst
;	Added test & message when re-entering user tries to 
;	re-specify port name.
;[023] 31 January 1992 10:49	Edited by Bob Rubendunst
;	Corrected problems in RPAR which caused file transfers to fail.
;[022] 10 January 1992 09:37	Edited by Bob Rubendunst
;	Added logic to strip CONNECT to 7 bits if PARITY is not NONE.
;[021] 09 January 1992 09:37	Edited by Bob Rubendunst
;	Documentation changes in CONNECT message
;	Added TIMEOUT and ENDLINE parametes to SET parameters list in SHOW
;	Changed SHOCHR to always display 3 characters, show ^ as dim if ctl
;	fixed problem with outputting zero byte files
;	improved SPAR & RPAR logic to handle 7 bit cases better.
;[020] 31 December 1991 11:06	Edited by Bob Rubendunst
;	Added code to make CONNECT mode compatible with 8 bit terminals.
;	(Exit character must match all 8 bits if TDV presents TD$EXT)
;	Deleted BPT legerdemain and just used SUPVR instead in SETSTS!
;[019] 31 December 1991 10:41	Edited by Bob Rubendunst
;	AUTORECEIVE feature completed
;[018] 06 December 1991 13:08	Edited by Bob Rubendunst
;	Added random file bypass for batch SENDing.
;	Added code to eliminate possible bogus packet timeout at midnight.
;	Added command line help.
;	Added SET PARITY input checking
;[017] 02 December 1991 11:48	Edited by Bob Rubendunst
;	Added SET PACKETSTART option
;	Deleted code to save & restore jcb jobtyp word (not used)
;[016] 22 November 1991 13:27	Edited by Bob Rubendunst
;	Added AUTORECEIVE command
;	Changed SEND logic to send a Break packet if no files sent.
;	Corrected some help text with Karen Bojda's help.
;	Streamlined INUSE subroutine
;	Added code to revive job when attaching JCB & TCB
;	Completed graceful abort code for SENDing
;	Corrected tests for maximum retries - some were BNE instead of BLOS
;[015] 31 October 1991 16:49	Edited by Bob Rubendunst
;	Added wildcarding via CMDLIN.SYS. Kudos to Tom Niccum of KW fame.
;	Added totals statistics.
;	Added code to make SEND automatically send KERMIT and REC commands
;	to remote Kermit. Can be de-activated with SET AUTOSEND OFF.
;	Changed filenames to lower case for Unix compatibility.
;	Added 3 byte CRC check type. Should eliminate problems with
;	PC Kermits that do 2 byte CRCs wrong (Select either 1 or 3 byte option
;	in Procomm Plus - vers 2.0 STILL does 2 byte checksums wrong.)
;	Added SY$M40 symbol for possible AM4000 machine.
;	Added code to avoid T.SEM problems with smart I/O cards
;	Enhanced file size calcs to work under extended directories
;	Added file closes to make compatible with AMOS 2.x
;	Kermit only delays five seconds before SENDING in REMOTE mode instead
;	of fifteen.
;	Changed VMAJOR to 2.
;[014] 28 March 1991 12:38	Edited by Bob Rubendunst
;	Added routine to adjust sleep value for faster baud rates.
;	Note that this does improve performance at higher baud rates,
;	especially for file transfers. Due to limitations in TTYIN monitor
;	call, Kermit can still lose characters at higher baud rates.
;	Fixed bug in effective baud rate calculation when calculating
;	date rollover at midnight.
;[013] 28 March 1991 12:08	Edited by Bob Rubendunst
;	Corrected problems with received filenames being expanded to 6 & 3
;	even if they were shorter.
;	Fixed problem in edit 12 with max packetsize not being defaulted
;	at startup.
;[012] 06 February 1990 09:23	Edited by Bob Rubendunst
;	Corrected a few bugs in checking for previous or next packet
;	needing to be ACKed. Also fixed parameter display to display
;	active END-OF-LINE caharcter, rather than default end-of-line.
;[011] 02 Dec 1988
;	made compare for ESCAPE character 7 bits instead of 8 bits
; 	added BLOCKSIZE to SET command
;[010] 11 Sept 1988
;	Changed handling of port busy bit so that REMOTE users do not monitor
;	or  change the terminal busy bit. Defines new SY$ symbols for 68020 & 
;	68030 if not already defined.
;[009] 29 Jun 1988
;	Completed basic compatibility with AM3000 systems
;[008] May 1988
;	Started compatibility with AM3000 systems.
;[007] 24 Oct 1986
;	Changed CONNEC routine to properly set T.DAT bit and T.XLT bits so 
;	nulls can be sent from keyboard.
;[006] 29 Jul 1986
;	Tidied up SHOW command, added dot for every packet of data sent or
;	rec'd, SET ? now shows SET list.
;[005] ??
;	Change Kermit to accept running under AMOS/32. rpr
;[004] 12 May 1986
;       straightened out 8-bit quoting problem in RPAR
;	updated INUSE bit to use new bit under 1.3B
;	transformed SET BINQUOTE feature into SET PARITY feature
;	(does not set parity, but info is used to determine 7 or 8 bit modes.)
;	corrected checkbyte size detection problem when used with unix c
;	where ACK to F contained new filename under c. Alpha-Kermit thought
;	this was an ACK to an I packet and used the wrong checkbyte type.
;	Fixed 255 to 255. in max retries entry code 6/27/85 rpr
;	Fix requires keeping track of the ACKing of the I packet via RIACK(A0)
;	Fixed QBIN not defined on short received SINIT packet 4/24/85 rpr
;	AMUS release (clean-up same TCB use) 12/3/84 rpr
; 	Added 7 bit mode to allow use with ELS... 10/23/84 rpr
;	First non-alpha transfers 10/5/84 with ibm pc
;[000]	07 Sept 1984 project begun

; Permission is granted to any individual or institution to copy or use this
; software and the routines described in it, except for explicitly commercial
; purposes. This software must not be sold to any person or institution.

;;;;;;;;;;;;;;;;;;;;;;;;;;;; D I S C L A I M E R ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; No warranty of the software or of the accuracy of the documentation     ;;
;; surrounding it is expressed or implied, and neither the authors,        ;;
;; Columbia University, Soft Machines, or AMUS acknowledge any liability   ;;
;; resulting from program or documentation errors.                         ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; usage format:
;	KERMIT <terminal-name> <escape character>
; then enter ? or HELP for use hints.

	SEARCH	SYS
	SEARCH	SYSSYM
	SEARCH	TRM
	COPY	CMDSYM

IF	NDF,SY$M20, SY$M20 = ^O20000	; supply missing symbols [010]
IF	NDF,SY$M30, SY$M30 = ^O100000	; supply missing symbols [010]
IF	NDF,SY$M40, SY$M40 = ^O2000000000 ; support possible 68040 [015]
IF	NDF,SY$EXT, SY$EXT = ^O10000000 ; support 8 bit terminals [021]
IF	NDF,TD$EXT, TD$EXT = ^O1000000000 ; support 8 bit terminals [021]
IF	NDF,T$EXT, T$EXT = ^O20000 ; support 8 bit terminals [021]

; supplementary symbols for finding file type & size
D.LEN=D.WRK
D.ACT=D.LEN+4
D.1ST=D.ACT+10

; symbols to define byte-word-lword relationships
; The Alpha Micro uses byte-swap logic to switch the sense of UDS & LDS
; in hardware, so that BYTE ACCESS of data is the opposite of normal 68000s.
; (This was done because the WD-16 processor used Intel style byte access,
; were the MSB of a word is stored at higher addresses. Motorola CPUs
; store words MSB at lower addresses.)
; (WORD & LWORD ACCESS is not affected, only BYTE ACCESS.)
; (change these definitions for non-AM style hardware!!)
	.B0W7	=	0	; access LS byte of a 16 bit word
	.B8W15	=	1	; access MS byte of a 16 bit word
	.B0L7	=	2	; access bits 00-07 of a 32 bit word	
	.B8L15	=	3	; access bits 08-15 of a long word
	.B16L23	=	0	; access bits 16-23 of a long word
	.B24L31	=	1	; access bits 24-31 of a long word
	.W0L15	=	2	; access LS word of long word
	.W16L31	=	0	; access MS word of long word

; symbol definitions
TRUE	=	-1
FALSE	=	1


PAKSIZ	=	94.		; max packet size
SOH	=	1.		; default MARK character
CR	=	13.		; ASCII carriage return
SPACE	=	32.		; ASCII SP
DEL	=	127.		; ASCII DEL
ESCCHR	=	'^		; default escape character
A.BEL	=	7.		; ASCII bell [24]

TRIES	=	10.		; number of packet tries
MYQUOT	=	'#		; control-quoting
MYPAD	=	0		; number of pad chars
MYPCHR	=	0		; the pad character I need
MYEOL	=	0		; my end of line character
MYTIME	=	08.		; seconds before timeout
MYBIN	=	'Y		; binary qoute mode
MYCHK	=	'3		; try to use 3 byte check bytes
MAXCHK	=	3		; maximum check type supported
MAXTIM	=	60.		; maximum timeout
MINTIM	=	2		; minimum timeout period

; This macro is used to read a packet
DEFINE	RPACK	LEN,SEQ,PACKET,TYPE
	LEA	A3,PACKET
	CALL	RECPAK
	SSTS	D7
	MARG	MOVB,	D2,LEN
	MARG	MOVB,	D3,SEQ
	MARG	MOVB,	D4,TYPE
	LCC	D7
	ENDM

; This macro sends a packet to the REMOTE
DEFINE	SPACK	TYPE,SEQ,SIZE,PACKET
	LEA	A3,PACKET
	CCLR	SIZE,D2
	CCLR	SEQ,D3
	CCLR	TYPE,D4
	MARG	MOVB,	SIZE,D2
	MARG	MOVB,	SEQ,D3
	MARG	MOVB,	TYPE,D4
	CALL	SNDPAK
	ENDM

; This macro assembles argument linkage opcodes only where the default
; argument is not used. This provides more readable code without adding
; unnecessary instructions.
; For example, if D2 is the standard data link register, the macro
;	MARG	MOVW	D2,D2
; will not produce an assembly line, but
;	MARG	MOVW	D2,D3
; will assemble the line MOVW D2,D3	
DEFINE	MARG	OPCODE, SRC, DST
	NTYPE	...X,SRC
	NTYPE	...Y,DST
	IF	NE,...X-...Y,OPCODE	SRC,DST
	ENDM
	ASECT


; This macro is used to pre-clear result variables before a packet call
; IF they are not registers.
DEFINE	CCLR	ARG,REG
	NTYPE	...D,ARG
	NTYPE	...E,REG
	IF	NE,...D-...E,CLR REG
	ENDM

	.=0
; define the impure area for KERMIT.
	NOSYM
; CONNECT command variables and general REMOTE/LOCAL channel variable
TNAME:	BLKW	2			; terminal name packed RAD50
SAVTDV:	BLKL	1			; address of saved TDV
PSEUDO:	BLKL	1			; address of PSEUDO driver
SAVSTS:	BLKW	1			; saved TCB status
SAVJCB:	BLKL	1			; saved attached JCB index
REMOTE:	BLKL	1			; index to remote TCB
LOCAL:	BLKL	1			; index to local TCB
STIME:	BLKL	1			; start time of event
FSIZE:	BLKL	1			; size of file in bytes
KMETA:	BLKB	1			; escape character
DONE:	BLKB	1			; done with kermit flag
NOTALK:	BLKB	1			; flag that remote TCB is job's.
ECHO:	BLKB	1			; duplex flag 0 for full, 377 for half
CCOUNT:	BLKB	1			; control-c count
AUTOS:	BLKB	1			; autosend option for SEND
AUTOR:	BLKB	1			; AUTORECEIVE option for REC
COMSER:	BLKB	1			; flag -1 if COMSER routines O.K.
EXTEND:	BLKB	1			; extended device support flag
ABORTB:	BLKB	1			; -1 if send batch to be aborted
ABORTF:	BLKB	1			; -1 if send file to be aborted
WILDOK:	BLKB	1			; -1 if wildcarding O.K.
CMASK:	BLKB	1			; bit mask for 7 or 8 bit characters
CFLAG:	BLKB	1			; flag we have breifed user on CONNECT
ATERM:	BLKB	7			; terminal name in ASCII & null
	EVEN
FIO:	BLKB	D.DDB			; file I/O ddb area
SIO:	BLKB	D.DDB			; ddb just for file spec & cmdlin
; KERMIT packet receiver variables
ASSUM:	BLKW	1		; checksum storage
FRMSUM:	BLKW	1		; CRC storage
RTOUT:	BLKL	1		; time's up in seconds from midnight.
FUDGE:	BLKL	1		; fudge factor for midnight wrap-around
TIMINT:	BLKL	1		; # of seconds for timeout on sends
DF.TIM:	BLKL	1		; default timeout
; Global variables for file section
LOGIC:	BLKB	1		;  1=false, -1=true
LDATA:	BLKB	1		; size of present data
SPSIZ:	BLKB	1		; max send packet size
PAD:	BLKB	1		; # of padding chars to send
PADCHR:	BLKB	1		; pad character
EOL:	BLKB	1		; EOL character to send
N:	BLKB	1		; packet number
MAXTRY:	BLKB	1		; max # of tries
NUMTRY:	BLKB	1		; times this packet retried
OLDTRY:	BLKB	1		; times previous packet retried
BUFCNT:	BLKB	1		; # of data bytes for packet
DEBUGO:	BLKB	1		; level of debug output (0=none)
DING:	BLKB	1		; ding after each command flag (#0=yes)
DF.EOL:	BLKB	1		; default EOL character
DF.CHK:	BLKB	1		; default check type character
PARITY:	BLKB	1		; parity mode (None, Odd, Even, Space.)
STATE:	BLKB	1		; present state of file transfer automaton
QUOTE:	BLKB	1		; incoming quote char
QBIN:	BLKB	1		; storage & flag controlling 8 bit quoting:
				; 0  indicates 8 bit path, no quoting
				; -1 indicates 7 bit path, no quoting
				; all other values 33.-62. 96.-126. are valid
				; 8 bit quote characters (usually &)
CHKT:	BLKB	1		; checkbyte method as ascii character
CHKNOW:	BLKB	1		; checkbyte in use for this packet
REPT:	BLKB	1		; repeat byte (not implemented yet)
FLLEN:	BLKB	1		; filename length
RMARK:	BLKB	1		; the MARK character
RIACK:	BLKB	1		; flag we got an ACK to an I packet
MXPKSZ:	BLKB	1		; maximum packet size allowed
STLCHR:	BLKB	1		; stall character time in 100ths of a second
RECPKT:	BLKB	PAKSIZ		; buffer for receiving packets
PACKET:	BLKB	PAKSIZ		;  another one
NFILNM:	BLKB	4		; room for MARK,LEN,SEQ,TYPE
FILNAM:	BLKB	60.		; current filename
	BLKB	20.
COPY:	BLKB	60.		;	; copied filename
	BLKB	PAKSIZ-80.
	EVEN
SLPVAL:	BLKL	1		; sleep value in ticks for GETREM routine
TFILES:	BLKL	1		; total files sent or received
TBYTES:	BLKL	1		; total bytes in files sent or received
TTIME:	BLKL	1		; total elapsed times
CLDDB:	BLKB	D.DDB		; CMDLIN.SYS ddb area
CMDERR:	BLKL	1		; CMDLIN.SYS .CMINI error cod
CMDPTR:	BLKL	1		; ptr to CMDLIN.SYS module
SAVSPC:	BLKL	1		; ptr to user's command line
CMNEXT:	BLKL	1		; saved flags from CM.NXT in CMDLIN routines
NXTCNT:	BLKB	1		; count of times NXTSPC called w/o wildcard
CMDFLG:	BLKB	1		; flag we have CMDLIN.SYS
	EVEN
CMDIMP:	BLKB	IMP.SZ+100.	; room for CMDLIN.SYS
	EVEN
KSIZE=.
	.=0
; definition of KERMIT packet offsets
MARK:	BLKB	1		; the MARK character
LEN:	BLKB	1		; received LEN
SEQ:	BLKB	1		; received sequence
TYPE:	BLKB	1		; received type
DATA:	BLKB	1		; beginning of DATA
; 1, 2, or 3 byte check bytes follow the data and end the packet
	.=0
	SYM


REMMOD = T$IMI!T$ECS!T$DAT	; IMAGE, NOECHO mode bits


; The following macros define character tranlation functions needed to
; implement the KERMIT protocol.
; MACROs to perform CHAR, UNCHAR & CTL functions via register argument.


; C H A R  - change control character to printable character
DEFINE	CHAR	DST
	ADDB	#SPACE,DST
	ENDM

; U N C H A R  -change CHARed control character back into a control character
DEFINE	UNCHAR	DST
	SUBB	#SPACE,DST
	ENDM

; CTL - UNCONTROLIFY a CHARACTER. CTL(CTL(CHAR)) leaves CHAR unchanged.
DEFINE	CTL	DST
	XORB	#64.,DST
	ENDM


	PSECT


;  K E R M I T
; Main Kermit routine. The first time executed, KERMIT builds its impure area,
; KERMIT.IMP. Then the main routine accepts and performs user commands.
; 
	VMAJOR =2
	VMINOR =0
	VSUB = 0
	VEDIT = 024.
	VWHO =0

	RADIX	8.		; default numbers in octal

KERMIT:	PHDR	-1,PV$RSM!PV$WSM!PV$RPD!PV$WPD,PH$REE!PH$REU
	CMPB	@A2,#'/			; flag?
	BNE	2$
	INC	A2
	CMPB	@A2,#'?			; help?
	BEQ	1$
	TTYI
	ASCII	"undefined switch - assuming /? switch"
	BYTE	CR,A.BEL,0
	EVEN
1$:	TTYL	USAGE
	EXIT

; make sure we are running under an OS that supports TTYOUT.
2$:	CALL	KERTTL			; show title and version
	MOV	SYSTEM,D5		; get system word
	AND	#SY$M20!SY$M30!SY$M40,D5 ; mask to just AMOS/32
	BNE	10$			;  we are on AMOS/32, has TTYOUT
	CMPB	PH.VER+.B8W15,#1.	; MAJOR higher than 1?
	BHI	10$			;  yes-use new value
	MOVB	PH.VER+.B16L23,D5	;  no- get sub release
	ANDB	#^O17,D5		; strip out VWHO in top 4 bits
	CMPB	D5,#2.			; is this 1.2 or later?
	BHIS	10$			;  yes- we can execute
					;  no- time to update the system!
	TTYI
	ASCII	"%This software requires AMOS/L 1.2 or later O/S."
	BYTE	CR,0
	EVEN
	EXIT

10$:	CALL	INIMEM			; initial memory area
	 BNE	EXEUNT			;  need more memory-abort
	 BMI	20$			; TCB already assigned
; first time entry. Check for CONNECT terminal name
	BYP				; scan past blanks
	CALL	FNDASN			; find and assign user supplied terminal-name
	 BNE	EXEUNT			;  no match
	ORW	#FIL!LOK,-10(A0)	; set file and locked in memo flags
20$:	JOBIDX				; index A6 to JCB
	ANDW	#^C<J.CCC>,@A6		; clear control-c
	CALL	CHOICE			; get user's command choice
	BNE	20$			;  no such command!
	CALL	PROCES			; perform user's command
	TSTB	DONE(A0)		; done ?
	 BEQ	20$			;  no, accept another command.

40$:	CLRB	DONE(A0)

; E X E U N T  - exit back to AMOS
EXEUNT:	EXIT

; I N I M E M 
; This routine builds, clears and initializes the user's impure area.
INIMEM:	LEA	A6,IMPNAM		; index impure module name
	SRCH	@A6,A0,F.USR		; search user area for kermit
	BEQ	10$			; already present-done
	GETIMP	KSIZE,A0,100$		; allocate impure area
	CLEAR	@A0,KSIZE		; clear it (redundant now, so what!)
	LEA	A6,IMPNAM
	MOV	(A6)+,-6(A0)		; set module name to program name
	MOVW	@A6,-2(A0)		;  set module extension to .IMP
; do first time-only inits
	CALL	INI2			; get JCB & attached TCB addresses
	CALL	INIXFR			; init xfer section once.
	CALL	OSVER			; determine O/S version
	CALL	TRMVER			; determine terminal driver version
	MOVB	#ESCCHR,KMETA(A0)	; set CONNECT ESCAPE character
	MOVB	#PAKSIZ,MXPKSZ(A0)	; set maximum packet size allowed [13]
	MOV	#100.,SLPVAL(A0)	; set sleep ticks for GETREM [14]
	MOVB	#-1,AUTOS(A0)		; invoke auto-send [15]
	MOVB	#-1,AUTOR(A0)		; invoke auto-receive [16]
	LCC	#PS.Z
	RTN

; finish re-entry inits
10$:	CALL	INI2			; get JCB & attached TCB AGAIN
	BYP				; [024]
	LIN				; [024] port named?
	BEQ	20$			; [024]   no
	TTYL	RENTER			; [024]   yes, been there, done that!
20$:	LCC	#PS.N!PS.Z		; set N and Z if impure already there
	RTN

; not enough memory, so depart
100$:	TYPECR	<?Insufficient memory for KERMIT.>
	LCC	#0			; flag no memory
	RTN

; OSVER plays twenty questions games to find out what resources are
; available in current operating system.
OSVER:	MOV	SYSTEM,D7
	AND	#SY$EXD,D7		; system supports extended disks?
	SETNE	EXTEND(A0)		; set flag -1 if extended disk O.K.
	CLRB	COMSER(A0)		; assume we don't have new comm stuff
	MOV	SYSTEM,D7		; get system word
	AND	#SY$M20!SY$M30!SY$M40,D7 ; mask to just AMOS/32
	BNE	10$			; all AMOS/32 has COMSER, CMDLIN
	CMPB	PH.VER+.B8W15,#1.	; MAJOR higher than 1?
	BHI	10$			;  yes-use new value
	MOVB	PH.VER+.B16L23,D7	;  no- get sub release
	ANDB	#^O17,D7		; strip out VWHO in top 4 bits
	CMPB	D7,#3.			; is this 1.3?
	BLO	30$			;  no-1.2 or older, no COMSER
	BHI	10$			;  no-1.4 or higher COMSER fur sure!
	SETB	WILDOK(A0)		; wildcarding started in 1.3
	MOVB	PH.VER+.B8L15,D7	;  exactly 1.3 - check for B
	LSRB	D7,#4.			; bring it to ground zero.
	CMPB	D7,#'I-'@		; is it B or higher?
	BEQ	30$			; 1.3I comes before 1.3B (go figure)
	CMPB	D7,#'B-'@		; is it B or higher?
	BLO	30$			;  yes-use new value
10$:	SETB	WILDOK(A0)		; O.K. to user CMDLIN.SYS
20$:	SETB	COMSER(A0)		; O/S has COMSER routines
30$:	RTN				; O/S has got not a lot...

; determine terminal driver resources (7 or 8 bit system & terminal driver)
TRMVER:	MOVB	#^B01111111,CMASK(A0)	; preset mask for 7 bit terminal
	MOV	SYSTEM,D7		; get system type
	AND	#SY$EXT,D7		; does system support 8 bit terms?
	BEQ	10$			;  no
	MOV	LOCAL(A0),A5		; A5 indexs local TCB
	MOV	T.TDV(A5),A6		; index terminal driver
	MOVW	TD.TYP(A6),D7		; get type word
	ANDW	#TD$NEW,D7		; is it a "new" TDV
	BEQ	10$			;  no, use 7 bit mask
	MOV	TD.FLG(A6),D7		;  yes, get tdv's flag bits
	AND	#TD$EXT,D7		;  mask
	BEQ	10$			; tdv is recent, but only 7 bit!
	MOVB	#-1,CMASK(A0)		;  TDV supports 8 bit terminals
10$:	RTN


; These values are inited every time KERMIT is executed.
INI2:	JOBIDX	A6			; index A6 to JCB
	MOV	JOBTRM(A6),LOCAL(A0)	; save address of local TCB
	RTN

; I N I X F R
; Initialize the the file transfer area
INIXFR:	MOVB	#MYEOL,DF.EOL(A0)	; set default EOL [17]
	MOVB	#MYCHK,DF.CHK(A0)	; set default check type
	MOVB	#'N,PARITY(A0)		; set parity to NONE.
	MOVB	#PAKSIZ,SPSIZ(A0)	; set max send size
;
	MOVB	#SOH,RMARK(A0)		; define start of packet byte
	MOVB	#MYQUOT,QUOTE(A0)	; set quote char
	MOV	LOCAL(A0),A5		; set index
	MOVB	#MYPAD,PAD(A0)		; pad count
	MOVB	#MYPCHR,PADCHR(A0)	; & character
	MOVB	#TRIES,MAXTRY(A0)	; set max tries
	MOVB	#'1,CHKT(A0)		; checkbyte type
	MOV	#08.,TIMINT(A0)		; set timeout period
	MOV	#08.,DF.TIM(A0)		; set default timeout period
	RTN	

;  F N D A S N
; FNDASN finds the user specified TCB, and marks it as busy if found.
; The "busy" bit in the TCB depends on the O/S version.
; If the O/S version is before 1.3B AMOS/L, the busy bit is bit 11. of T.STS
; If the O/S is AMOS/32, or AMOS/L 1.3B or later, the busy is bit 9. of T.STS
FNDASN:	JOBIDX	A6			; index A6 to JCB
	MOV	JOBTRM(A6),A5		; index our own TCB as default
	LIN				; user provide terminal name
	BEQ	25$			;  no-use our own terminal
	LEA	A1,TNAME(A0)		; index terminal name storage
	PUSH	A1			; save for unpack
	PACK
	PACK				; pack the terminal name RAD50
	POP	A1
	LEA	A2,ATERM(A0)		; then unpack it for later
	UNPACK
	UNPACK
	CLRB	@A2			; save ASCII version for SHOW.
	MOV	TNAME(A0),D6		; D6 gets whole RAD50 terminal name
	LEA	A3,TRMDFC		; index the head of the TCB chain
10$:	MOV	@A3,D7			; get link to next entry
	JEQ	100$			;  no matching TCB name          [010]
	MOV	D7,A3			; A3 indexs next element
20$:	CMPL	D6,4(A3)		; compare to this entry
	BNE	10$			;  try next one if no match
; TCB with matching name is found. Check for prior use
	LEA	A6,10(A3)		; index A6 to remote TCB         [010]
	CMP	A5,A6			; using specified own terminal?  [010]
	BNE	22$			;  no
	CLRB	ATERM(A0)		;  yes-clear name of terminal to [010]
					;  to flag comm port & user's    [010]
					;  port are the same.            [010]
22$:	MOV	A6,A5			; index A5 to comm port          [010]
25$:	MOVW	@A5,SAVSTS(A0)		; save the TCB status      
	CALL	INUSE			; get proper in-use bits
	TSTB	ATERM(A0)		; user & comm port the same?     [010]
	BEQ	250$			;  yes-leave busy bit as is      [010]
	BSET	D6,1(A5)		; set "assigned" bit
	BNE	110$			;  already set by prior use-.
250$:	MOV	A5,REMOTE(A0)		; save pointer to remote TCB     [010]
	MOV	T.TDV(A5),SAVTDV(A0)	; save old TDV address
; find address of PSEUDO TCB in memory for data transfer use.
	MOV	SAVTDV(A0),PSEUDO(A0)	; preset any TDV in case PSEUDO is gone!
	MOV	TRMTDC,A6		; get base of tdv chain
	MOV	#[PSE]_16.+[UDO],D7	; D7 gets PSEUDO in RAD50 notation
30$:	CMP	D7,4(A6)		; match ?
	BEQ	40$			;  yes
	MOV	@A6,A6			;  no-get next link
	MOV	A6,D6			; set flags
	BNE	30$			;  keep trying
	BR	50$ 			; give up
40$:	ADD	#^O10,A6		; add offset size of link word and name
	MOV	A6,PSEUDO(A0)		; save address of PSEUDO driver
50$:	CMP	A5,LOCAL(A0)		; TCB same as job's terminal's?
	SETEQ	NOTALK(A0)		;  yes-flag KERMIT owns the data TCB
	BEQ	60$			;   and bypass TDV swap.
; swap in PSEUDO terminal driver instead of normal TDV because some TDVs will
; use multi-byte capture sequences or other translate routines, which will
; mess up incoming or outgoing data.
; (There is a cleaner way to do this in newer O/Ss, but it isn't
; backwards compatible, so we won't bother - rpr 12/31/91)
	MOV	PSEUDO(A0),T.TDV(A5)	; substitute PSEUDO driver on remote
; unless TCB is owned by KERMIT job, detach all TCB <=> JCB links
60$:	MOV	T.JLK(A5),A6		; get JCB link
	MOV	A6,SAVJCB(A0)		; save the JCB address for EXIT
	BEQ	70$			;  TCB already detached-done
	TSTB	NOTALK(A0)		; TCB owned by KERMIT job?
	BNE	70$			;  yes-leave it attached
	CLR	JOBTRM(A6)		;   else detach TCB from job
	CLR	T.JLK(A5)		;    and job from TCB
70$:	LCC	#PS.Z
	RTN

100$:	TTYL	NMTN
	LCC	#0
	RTN
110$:	TYPECR	<?terminal is being used by another job.>
	LCC	#0
	RTN

; INUSE - routine to determine the proper INUSE bit values for this OS.
; The "busy" bit in the TCB depends on the O/S version.
; If the O/S version is before 1.3B AMOS/L, the busy bit is bit 11. of T.STS
; If the O/S is AMOS/32, or AMOS/L 1.3B or later, the busy is bit 9. of T.STS
; delivers status bit value for BTST to D6
INUSE:
	MOV	#1+8.,D6		; D6 gets new INUSE bit value
	TSTB	COMSER(A0)		; do we have COMSER?
	BNE	20$			;  yes
	MOV	#3.+8.,D6		; set old INUSE bit
20$:	RTN


; R A W T R M  - set datacomm TCB to pass all data intact, character mode.
RAWTRM:	MOV	REMOTE(A0),A5		; get index to the TCB
	MOVW	#REMMOD,D1		; remote mode bits
	CALL	SETSTS			; set the status
	RTN

; L I N T R M  -  set datacomm TCB for normal AMOSL line mode.
; except echo is supressed if same TCB for comm & commands
LINTRM:	TSTB	NOTALK(A0)		; same TCB for comm and job?
	BEQ	10$			;  no-just return
; enable line input mode so user can enter commands
	MOV	REMOTE(A0),A5		;  yes-get index to the TCB
	MOVW	#^C<REMMOD>,D1		; clear remote mode bits
	CALL	SETSTS			; clear the status
10$:	RTN

; P S E T D V  - assign PSEUDO driver if data TCB is owned by KERMIT job.
PSETDV:	TSTB	NOTALK(A0)		; TCB owned by KERMIT job?
	BEQ	10$			;  no-no need to swap
	MOV	PSEUDO(A0),T.TDV(A5)	; swap in PSEUDO driver
10$:	RTN

; O R G T D V  - set normal terminal driver if data TCB is owned by KERMIT job.
ORGTDV:	TSTB	NOTALK(A0)		; TCB owned by KERMIT job?
	BEQ	10$			;  no-no need to swap
	MOV	SAVTDV(A0),T.TDV(A5)	; swap back real terminal driver
10$:	RTN

; S E T S L P  - set SLEEP delay time based on serial baud rate
; added in edit [14]
SETSLP:	MOV	#100.,D6		; set default value
	CLR	D7
	MOVW	T.BAU(A5),D7		; get baud rate code
	CMPW	D7,#^O23		; is it defined in our table?
	BHI	10$			;  no, use default
	LSLW	D7			; double index value
	MOVW	SLPTBL[D7],D7		; get table value in D7
	BEQ	10$	
	MOV	D7,D6
10$:	MOV	D6,SLPVAL(A0)	; set sleep value
	RTN

; sleep time in ticks for one character at all defined alpha baud rates
SLPTBL:	WORD	100000./50.
	WORD	100000./75.
	WORD	100000./110.
	WORD	100000./134.
	WORD	100000./150.
	WORD	100000./200.
	WORD	100000./300.
	WORD	100000./600.
	WORD	100000./1200.
	WORD	100000./1800.
	WORD	100000./2000.
	WORD	100000./2400.
	WORD	100000./3600.
	WORD	100000./4800.
	WORD	100000./7200.
	WORD	100000./9600.
	WORD	100000./19200.
	WORD	100000./38400.
	WORD	100000./57600.
	WORD	100000./76800.
; end [14] additions for SETSLP

; S N O O Z E - delay if data TCB owned by KERMIT job. This gives user
; time to escape back to the other KERMIT and enter REC.
SNOOZE:	TSTB	NOTALK(A0)		; data TCB same as KERMITs?
	BEQ	10$			;  no - do not wait.
	SLEEP	#5.*10000.		;  yes - wait 5 seconds
10$:	RTN

;  E V L C H R
; EVLCHR evaluates the next non-blank character indexed by A2 and
; returns its value in D1.
; At exit, A2 is updated, and D1 contains the new character or 0.
; The Z flag is set if a character was encountered, else Z is clear.
EVLCHR:	CLR	D1			; pre-clear
	BYP
	LIN				; end of line?
	BEQ	100$			;  yes-no characters to process
	NUM				;  else check for numeric
	BNE	10$			;   not numeric
	GTDEC				;   get the value
	BR	40$			;    and use it

; process non-numeric
10$:	MOVB	(A2)+,D1
	CMPB	D1,#'^			; control character prefix ?
	BNE	20$			;  no-use straight ASCII.
	LIN				;  yes-check again for end of line
	BEQ	40$			;   treat as the ^ character [21]
	MOVB	(A2)+,D1		;   else get next character
	AND 	#^O37,D1		;   mask to control character
	BR	40$			;   and exit

20$:	CMPB	D1,#SPACE		; compare to ASCII space
	BLO	100$			;  invalid argument
	LIN
	BNE	100$			; bad input, too many chars
	
40$:	LCC	#PS.Z			;  arg ok, value in D1
	RTN

100$:	LCC	#0			; arg is bad.
	RTN

; P R O M P T  displays the KERMIT command prompt.
PROMPT:
	MOV	#CR,D1
	TTY
	TSTB	ATERM(A0)		; is this kermit the REMOTE?
	BNE	10$			;  no
	TYPE	<REMOTE >		;  yes-give user different prompts
10$:	TTYI				;  for local & remote kermies.
	ASCII	/Alpha-Kermit >/
	BYTE	0
	EVEN
	RTN

; C H O I C E - prompts the user for command & gets the command.
CHOICE:	CALL	PROMPT			; prompt the user
	KBD	25$			; get a command line in line mode
	BYP				; scan past blanks
	LIN				; end of line?
	BEQ	CHOICE			;  ignore blank lines
	LEA	A1,KERCOM		; index argument list
	CALL	COMAND			; match the command
	BEQ	30$			;  command matched
;  no match - show user bad news.
	TYPE<? >			
10$:	LIN
	BEQ	20$			; end of line.
	MOVB	(A2)+,D1		;  else
	TTY				;  type the
	BR	10$			; character and loop
20$:	TYPECR	<? - undefined command.>; end error display
25$:	LCC	#0			; flag no command
	RTN				; return
30$:	LCC	#PS.Z			; flag valid command
	RTN				; return

; C O M A N D - This subroutine compares the user's command string 
; to the command list indexed by A1 (e.g. KERCOM).
; If a match is found, A1 will index the command offset for a tabled call.
; At entry, A1 indexs the command/subcommand list. A2 indexs user's string.
; At exit, Z is set to indicate the command was valid.
; If Z is set, A1 indexs the command offset word.
;
; This routine will match the entire command, or to a valid and unique subset
; of the command name as defined in the table structure.
; e.g. The string CON will match the command name CONNECT.

COMAND:	SUB	#2,A1			; adjustment for first entry
	BYP				; scan past seperators
	PUSH	A2			; save string address for compares
	  LIN				; end of line?
	  BEQ	CHO.5			;  no command-exit.
; calculate address of next entry and place in A1.
CHO.1:	  MOV	@SP,A2			; restore string pointer
	  LEA	A3,2(A1)		; A3 indexs next entry
	  TSTW	@A3			;  end of table ?
	  BEQ	CHO.5			;   yes-no match.
	  MOV	A3,A1			;   no-get address of command size word
	  ADDW	(A3)+,A1		;  and index to next command.
	  CLR	D5
	  MOVB	(A3)+,D5		; D5 gets qualifier size in bytes

CHO.2:	  TRM				; check for end of word
	  BEQ	CHO.4			;  yes-check match count
	  TSTB	@A3			;  check for end of table entry
	  BEQ	CHO.1			;  must be wrong if so.
CHO.3:	  MOVB	@A2,D1
	  UCS				; convert to upper case
	  CMPB	D1,(A3)+		; compare strings
	  BNE	CHO.4			;  until no match
	  ADD	#1,A2			; advance A2
	  TST	D5			; check for minimum match length
	  BEQ	CHO.2			;  made it-stop counting
	  SUB	#1,D5			; decrement byte count
	  BR	CHO.2			;  keep testing till line is terminated

CHO.4:	  TST	D5			; good match has zero count
	  BNE	CHO.1			;  no good-try next
	  TRM				; good match has no more data
	  BNE	CHO.1
	POP				; toss old A2
	LCC	#PS.Z			; flag command match found
	RTN

; undefined command - Clear Z flag
CHO.5:	POP	A2			; update A2 to index args
	LCC	#0
	RTN

; P R O C E S
; Process performs the process defined by the user command.
; At Entry, A1 indexs the word offset (from A1) of the command address
PROCES:	ADDW	@A1,A1			; do a tabled called by adding
	CALL	@A1			; offset @A1 to A1 and executing at
	RTN				; that new address.

; S E N D sends a file to the remote KERMIT using the KERMIT protocol.
SEND:	TSTB	NOTALK(A0)
	BNE	4$			; AUTOsend doesn't make sense in REMOTE
	TSTB	AUTOS(A0)		; automatically sending KERMIT & RECEIVE?
	BEQ	4$			;  no
	TYPECR	<Sending KERMIT and RECEIVE commands to remote Kermit>
	LEA	A1,PRESND		; index commands for remote kermit
	CALL	SREMOT			; send to remote
4$:	CALL	PREBAT			; init wildcarding, if present
	BYP
5$:	CALL	GETNXT			; get next filename
; delay inspection of no files error until we are ready to send F packet,
; then, just send a B packet.
	TSTB	FIO+D.ERR(A0)		; file error?
	BEQ	6$			;  no
	CALL	LFERR			;  yes, display it
	BR	5$			;  and try for another spec
6$:	CALL	GTSIZE			; save file size in bytes
	CALL	STARTT			; set start time
	CALL	RAWTRM			; put remote in data mode
	CALL	SNOOZE			; delay if TCB owned by KERMIT
	CALL	PSETDV			; swap in PSEUDO driver if needed
	CALL	SETSLP			; set sleep parameter
	CALL	SENDSW			; else send the file
	CALL	LINTRM			; put remote in line mode
	CALL	ORGTDV			; put back real TDV if PSEUDO used
	TSTB	LOGIC(A0)		; did it work?
	BMI	10$			;  yes
	TYPECR	<?SEND failed>		;  no
10$:	CALL	STATS
20$:	RTN
	
100$:	CALL	LFERR
	RTN

; L F E R R
; LFERR displays local file errors on the user's CRT
LFERR:	TSTB	NOTALK(A0)		; do we have a user terminal?
	BNE	10$			;  no-do not print message.
	TYPE	<Local file error, >
	PFILE	FIO(A0)			; show filename
	ERRMSG	FIO+D.ERR(A0), OT$TRM!OT$LSP	; and error message
	CRLF
10$:	RTN

; R E C E I V - receive a file from remote KERMIT using the KERMIT protocol.
RECEIV:
	MOV	A2,SAVSPC(A0)		; save user's string ptr
	MOVB	#1,NXTCNT(A0)		; set count for output spec
	CALL	SCNSTR			; scan string for AUTO-receive
	CLR	TFILES(A0)
	CLR	TBYTES(A0)
	CLR	TTIME(A0)		; clear total stat amounts
	MOV	#60.,TIMINT(A0)		; 60 second timeout
	CALL	SETSLP			; set sleep parameter
	CALL	PSETDV			; swap in PSEUDO terminal driver
	CALL	RAWTRM			; remote TCB to character mode
	CALL	RECSW			; call receive state manager/switcher
	CALL	LINTRM			; remote TCB to line mode
	CALL	ORGTDV			; return to real TDV if PSEUDO used
	TSTB	LOGIC(A0)		;  test for sucess
	BMI	10$			;   it worked
	TYPECR	<?RECEIVE failed.>	;   it didn't work
10$:	CALL	STATS			; show elapsed time & speed
	RTN

; scan user spec for = and spec following it. If found, send remote Kermit
; the commands KERMIT^M, and SEND followed by the user's filespec.
SCNSTR:	
	SAVE	A2
	TSTB	NOTALK(A0)
	BNE	100$			; AUTOREC doesn't make sense in REMOTE
	TSTB	AUTOR(A0)		; automatically sending KERMIT & SEND?
	BEQ	100$			;  no
	BYP
	LIN				; any parms?
	BEQ	100$			;  no
	CMPB	@A2,#'=			; do we have an equal sign?
	BEQ	20$			;  yes
	FSPEC	FIO(A0),LST		;  no, use FSPEC to skip past outspec
	BYP
20$:	CMPB	(A2)+,#'=		; do we have AUTO spec?
	BNE	100$			;  no
					;  yes
	TYPECR	<Sending KERMIT and SEND commands to remote Kermit>
	LEA	A1,PREREC		; index commands for remote kermit
	CALL	SREMOT			; send to remote
	MOV	A2,A1
	CALL	SREMOT			; send user string ( even CR & LF)
100$:	REST	A2
	RTN

; G F I L N M
; This routine gets a filename and places it in FILNAM(A0)
; At entry, the filename has been loaded in ddb FIO(A0)
; On exit, FLLEN(A0) contains the length in bytes.
; Z is set if the filename was valid.
GFILNM:
; now convert the name to KERMIT standard form which is NAME.EXT.		
; We must delete all spaces from the filespec.
	LEA	A2,FILNAM(A0)		; index the target area
	PUSH	A2			;  and save the index
	LEA	A1,FIO+D.FIL(A0)	; index the filname in the ddb
	UNPACK
	UNPACK				; put the ASCII filename @A1
	MOVB	#'.,(A2)+		; add the comma
	UNPACK
	CLRB	@A2			; terminate it
; clean up the filespec by deleting space & other illegal characters.
	POP	A2			; restore pointer to filnam
	MOV	A2,A1			; A1 will be write pointer
	CLR	D0			; D0 counts valid chars we found
10$:	MOVB	@A2,D1			; get current char in D7
	BEQ	20$			;  end of line
	LCS				; convert to lower case [15]
	CMPB	D1,#'.			; current char a dot?
	BEQ	20$			;  yes -it is ok
	ALF				; is it alpha ?
	BEQ	20$			;  yes-use it.
	NUM				; or numeric ?
	BNE	25$			;  yes-use it

20$:	MOVB	D1,(A1)+
	BEQ	30$			; end of string
	ADD	#1,D0			; count how many we found
25$:	ADD	#1,A2			; bump pointer
	BR	10$			; continue scan

30$:	CMP	D0,#3			; got at least x.x?
	BLO	100$			; no-invalid filename
	MOVB	D0,FLLEN(A0)		; save the length
	LCC	#PS.Z			; valid filename received
	RTN

100$:	LCC	#0			; bad filename given.
	RTN
	
; R F I L N M
; This routine gets the remote filename from NFILNM(A0) 
; and places it in the FIO(A0) DDB.
; It then opens the file for input and returns the OPEN condition codes
; to the caller. Z is set if the open was succesful.
; [13] revised to not extend filenames or extensions rpr
RFILNM:
	LEA	A2,FILNAM(A0)		; index the filname
	LEA	A1,COPY(A0)		; index copy buffer
	CLR	D2
	MOVB	LDATA(A0),D2		; d2 gets total length of filename
					; from remote kermit
	CMP	D2,#30.-1		; compare to max allowed by definition
	BLOS	10$
	MOV	#30.-1,D2		; set max
; terminate filename part to 6 characters
10$:	MOV	#6.,D0			; set limit for filename
20$:	ALF
	BEQ	30$			; letters ok
	NUM
	BEQ	30$			; numbers ok, too.
	CMPB	@A2,#'.			; period?
	BEQ	60$			;  yes-end of filename!
	BNE	40$			;  no-toss bad char & continue

30$:	MOVB	@A2,(A1)+		; save good character
40$:	ADD	#1,A2			; advance pointer
	SUB	#1,D2			; count down total filename size
	BEQ	100$			;  end of filename (use .KMT extension)
	SUB	#1,D0			; adjust allowed filename chars
	BNE	20$			;  more allowed
					;  else wait for a period.
; truncate file names longer than 6 characters by waiting for a period
; wait for a period
50$:	CMPB	@A2,#'.			; period
	BEQ	60$			;  yes-ok.
	ADD	#1,A2			;  no-advance ptr
	SUB	#1,D2			; count down total filename size
	BNE	50$			;  until period or end of file
	BR	100$			;  no period found
; we found the period (and truncated a long filename)
60$:	ADD	#1,A2			;  no-advance
	SUB	#1,D2			; count down original filename size
	BEQ	100$			;  no more filename, use default ext!
	MOVB	#'.,(A1)+		; buffer a period
	MOV	#3.,D0			; max size of extension.
70$:	ALF
	BEQ	80$			; ok
	NUM
	BNE	90$			; not ok
80$:	MOVB	@A2,(A1)+		; buffer o.k. character
90$:	ADD	#1,A2			; advance pointer
	SUB	#1,D2			; count down original filename size
	BEQ	100$			; until a period
	SUB	#1,D0			; count down
	BNE	70$			;  yes
100$:	CLRB	(A1)+			;  no- end with a null
; add code to override the name of first file received, if user gave a name
	TSTB	NXTCNT(A0)		; been here before?
	BEQ	106$			;  yes, not first time
	MOV	SAVSPC(A0),A2		;  no, get user spec
	BYP
	LIN				; do we have text?
	BEQ	106$			;  no, user name from F packet
	CMPB	@A2,#'=			;  yes, is text a filename?
	BNE	107$			;   yes, override filename!
	INC	A2			; else use name from F packet
	BYP
106$:	CLRB	NXTCNT(A0)
	LEA	A2,COPY(A0)		; index the new filename
107$:	INIT	FIO(A0)			; init the ddb
	FSPEC	FIO(A0),KMT		; load the ddb with filespec
	LOOKUP	FIO(A0)			; does file already exist?
	BNE	110$			;  no
	DSKDEL	FIO(A0)			;  yes-erase the old one
110$:	OPENO	FIO(A0)			; open it sequentially
	BNE	120$
	CALL	STARTT			; start counting
	CLR	D7			; clear Z flag
120$:	RTN				; Z is set if file found

; C O N N E C
; CONNEC is the local terminal <--> remote terminal conversational routine.
; User keypresses are sent (except the ESCAPE or KMETA character) to the
; remote computer & incoming characters form the remote are displayed on 
; the user's CRT screen.
CONNEC:	TSTB	NOTALK(A0)		; using same TCB for in & out?
	BEQ	4$			;  no-ok.
	TTYL	NONONO			;  tell user it is a no-no
	RTN

4$:	TAS	CFLAG(A0)		; have we been here before?
	BNE	5$			;  yes
	TTYL	CUSAGE			;  no, explain CONNECT to user
5$:	CALL	RAWTRM			; set remote in "raw" mode.
	CALL	SETSLP			; set sleep parameter
	CALL	SHOESC			; show the escape character in effect.
	MOV	LOCAL(A0),A5		; A5 indexs local TCB
	MOVW	#REMMOD,D1		; allow function key xlation
	TSTB	CMASK(A0)
	BPL	6$			;  7 bit terminal
	ORW	#T$EXT,D1		;  8 bit terminal
6$:	CALL	SETSTS			; set them via breakpoint
	MOV	A5,A4			; A4 will be the local TCB pointer
	MOV	REMOTE(A0),A5		; now A5 indexs REMOTE 
10$:	CTRLC	15$			;  user entered control-c?
	TST	T.ICC(A4)		; LOCAL chars present ?
	BNE	20$			;  something to do
	TST	T.ICC(A5)		; REMOTE chars present ?
	BNE	20$			;  something to do
	SLEEP	SLPVAL(A0)		; take a one character nap. [14]
	BR	10$			; see if the store needs minding now.

; handle control-c's by trapping them, unflagging them and sending them out.
15$:	JOBIDX				; index A6 to JCB
	ANDW	#^C<J.CCC>,@A6		; clear control-c flag
	MOV	#3,D1			; get ASCII equivalent
	BR	37$			; send it out

; enter here when we have some communications data to move
20$:	TST	T.ICC(A5)		; have remote input ?
	BEQ	30$			;  no
	TTYIN				;  yes-grab a character
	CMPB	PARITY(A0),#'N
	BEQ	25$
	ANDB	#^B01111111,D1		; strip to seven if PARITY is on [22]
25$:	TTY				; print it
30$:	TCKI				; have LOCAL input ?
	BNE	40$			;  no local input
	KBD				;  yes-get local input via KBD
35$:	MOVB	D1,D7
	ANDB	CMASK(A0),D7		; mask character to 7 or 8 bits
	CMPB	D7,KMETA(A0)		; escape character ?
	BEQ	100$			;  yes-leave
; check for half duplex echoing
	TSTB	ECHO(A0)		; got echoing?
	BEQ	37$			;  no-full duplex
	CMPB	D7,#SPACE		; printable?
	BHIS	36$			; yes-echo it
	CMPB	D7,#CR			; CR?
	BEQ	36$ 			; yes-echo
	CMPB	D7,#08.			; backspace?
	BEQ	36$ 			; yes-echo
	CMPB	D7,#12			; line feed ?
	BNE	37$			;   ignore other ctl chars
36$:	TTY				;  yes-half duplex,
					;	 so echo the character
; transmit a character to the remote site.
37$:	TTYOUT				; send byte to REMOTE
40$:	BR	10$			; loop	

; exit back to main routine, since user entered ESCAPE character.
100$:	MOV	LOCAL(A0),A5		; index user's TCB
	MOVW	#REMMOD,D1		; get char mode bits
	TSTB	CMASK(A0)
	BPL	110$			;  7 bit terminal
	ORW	#T$EXT,D1		;  8 bit terminal
110$:	COMW	D1			; flip the bits to clear
	CALL	SETSTS			; clear them via breakpoint
;;	CALL	LINTRM			; reset remote TCB to line mode.
	CRLF
	RTN

; H E L P - inform user as to how KERMIT works.
HELP:	TTYL	HLP1
	LEA	A1,KERCOM		; index argument list
	CALL	COMAND			; see if we have an argument
	BNE	100$			;  no-show the whole list.
; show the selected help line by backing up to the start of it
4$:	TSTB	-(A1)			; backup to non-null
	BEQ	4$
10$:	MOVB	-(A1),D1		; look for null byte between command
	BNE	10$			;  and help strings.
	CRLF
	TTYL	1(A1)			; show the help message
	CRLF
	RTN

; Show help lines for all commands
100$:	LEA	A2,KERCOM		; index table
110$:	MOV	A2,A1
	CLR	D7
	MOVW	@A1,D7			; get offset to end
	BEQ	140$			; null is end of table
	MOV	A1,A2			
	ADDW	(A1)+,A2		; A2 indexs the address field
	ADD	#2,A2			; A2 now indexs the next entry
	ADD	#1,A1			; ignore size byte
	CLR	D0
	CALL	PTRTYP			; type command name
	TSTB	@A1
	BNE	120$
	ADD	#1,A1
120$:	CMPB	D0,#09.			; nine characters?
	BHI	130$			;  yes, done spacing
	INC	D0			;  no,
	TYPESP				;   so space
	BR	120$			;         out
130$:	CALL	PTRTYP			; type the help text
	CRLF
	BR	110$

140$:	CRLF
	CRLF
	RTN

; S H O W  - Show user the current optional settings & some packet info.
SHOW:	CALL	KERVER			; show kermit version
	TTYL	SH1.0			; type modem port:
	LEA	A1,ATERM(A0)		; index TCB name	
	TSTB	@A1			; do we have remote? [1]
	BNE	10$			;  yes
	LEA	A1,SH.DAS		;  else index dashes
10$:	TTYL	@A1			; show name or dashes
; [016] display auto-receive
	TTYL	SH2.0
	LEA	A6,SH.ON		
	TSTB	AUTOR(A0)
	BNE	20$
	LEA	A6,SH.OFF
20$:	TTYL
; [015] display auto-send
	TTYL	SH2.1
	LEA	A6,SH.ON		
	TSTB	AUTOS(A0)
	BNE	30$
	LEA	A6,SH.OFF
30$:	TTYL
; display bell
	TTYL	SH2.2			; do end of line 1 & BELL label
	LEA	A6,SH.OFF
	TSTB	DING(A0)
	BEQ	40$
	LEA	A6,SH.ON
40$:	TTYL				; show on or off
; display blockcheck
	TTYL	SH2.3			; blockcheck selected label
	MOVB	DF.CHK(A0),D1
	TTY
; display debug
	TTYL	SH2.4			; show DEBUG label
	LEA	A6,SH.OFF
	TSTB	DEBUGO(A0)
	BEQ	50$
	LEA	A6,SH.ON
50$:	TTYL
; show duplex
	TTYL	SH2.5			; then type duplex label
	LEA	A6,SH.FUL		; assume FULL
	TSTB	ECHO(A0)		; check duplex 0=full, -1=half
	BEQ	60$
	LEA	A6,SH.HAL		; o.k., then, HALF.
60$:	TTYL				; type string @A6
; display user's endline
	TTYL	SH3.2			; end of line 3, ENDLINE label
;[012] display end-of-line character in use, rather than default
	MOVB	DF.EOL(A0),D1		; set end of line char
	BNE	65$
	TTYL	SH.ZIP
	BR	67$			; [015]
65$:	TYPE	< >
	CALL	SHOCHR
67$:
; display ESCAPE
	TTYL	SH2.6			; show ESCAPE label
	CLR	D1			; preclear D1
	MOVB	KMETA(A0),D1
	CALL	SHOCHR			; show escape character
; display PACKETSIZE
	TTYL	SH2.7
	CLR	D1
	MOVB	MXPKSZ(A0),D1		; set max value
	DCVT	4,OT$TRM!OT$ZER
; display PACKETSTART
	TTYL	SH2.7A
	MOVB	RMARK(A0),D1
	CALL	SHOCHR
; display PARITY
	TTYL	SH2.8			; type parity label
	MOVB	PARITY(A0),D1
	CALL	SHOCHR
; display default retries
	TTYL	SH2.8A
	MOVB	MAXTRY(A0),D1
	DCVT	4,OT$TRM!OT$ZER
; display stall time in hundredths of seconds
	TTYL	SH2.9
	CLR	D1
	MOVB	STLCHR(A0),D1
	DCVT	4,OT$TRM!OT$ZER
; display default TIMOUT
	TTYL	SH2.9A			; show timeout label
	MOV	DF.TIM(A0),D1		;  
	DCVT	4,OT$TRM!OT$ZER
	CRLF
; display packet parameters
; display blockchek
	TTYL	SH3.0
	MOVB	CHKT(A0),D1		; get check type
	TTY
; display eight bit quote
	TTYL	SH3.1
	MOVB	QBIN(A0),D1
	BMI	70$			; 7 bit path
	BNE	80$			; we have a real 8B quote, show it
	TTYL	SH.ZIP			; we don't need 8B quote so far
	BR	90$
70$:	MOVB	#'&,D1			; show default 8 bit quote
80$:	TYPE	< >
	CALL	SHOCHR
90$:	
; display endline
	TTYL	SH3.2			; end of line 3, ENDLINE label
;[012] display end-of-line character in use, rather than default
	MOVB	DF.EOL(A0),D1		; set end of line char
	BNE	100$
	TTYL	SH.ZIP
	BR	110$			; [015]
100$:	TYPE	< >
	CALL	SHOCHR
; display max packet size
110$:	TTYL	SH3.3			; do end of line 2, packet parms.
	CLR	D1
	MOVB	SPSIZ(A0),D1		; get packet size
	DCVT	4,OT$TRM!OT$ZER
; display packet end
	TTYL	SH3.4			; show number of pads			
	MOVB	PAD(A0),D1		; 
	DCVT	2,OT$TRM!OT$ZER
	TTYL	SH3.5			; show pad character value
	MOVB	PADCHR(A0),D1		; 
	CALL	SHOCHR
	TTYL	SH3.6			; show timout label
	MOV	TIMINT(A0),D1		;  
	DCVT	4,OT$TRM!OT$ZER
	TTYL	SH3.8
	RTN

; S E T  - allow user to change some parameters.
; SET command accepts a sub-command (or argument) to define the action.
; If no sub-command is given, a short expansion of the subcommands is given.
SET:	BYP
	LIN				; end of line?
	BEQ	100$			;  yes-show user what can be set.
	CMPB	@A2,#'?			; user wants some help?
	BEQ	100$			;  yes-show user what he can set.
	LEA	A1,SETCOM		; index set command list
	CALL	COMAND			; see if we have an argument
	BNE	10$			;  no-show user no can do.
; perform the desired function. Each function does its own error-checking.
	CALL	PROCES			; do the set
	RTN

10$:	TYPE<? >			;  no match - show user bad news.
15$:	LIN				; end of line?
	BEQ	20$			;  yes-done typing user's entry
	MOVB	(A2)+,D1
	TTY				; type a character
	BR	15$			; until the end of line
20$:	TYPECR	<? - undefined command.>
25$:	RTN

; Show explanation for all set commands
100$:	TTYL	SET1
	LEA	A2,SETCOM		; index table
110$:	MOV	A2,A1
	CLR	D7
	MOVW	@A1,D7			; get offset to end
	BEQ	140$			; null is end of table
	MOV	A1,A2			
	ADDW	(A1)+,A2		; A2 indexs the address field
	ADD	#2,A2			; A2 now indexs the next entry
	ADD	#1,A1			; ignore size byte
	CLR	D0			; [015] count characters
	CALL	PTRTYP			; type command name
	TSTB	@A1
	BNE	120$
	ADD	#1,A1
120$:	CMPB	D0,#11.			; eleven characters?
	BHI	130$			;  yes, done spacing
	INC	D0			;  no,
	TYPESP				;   so space
	BR	120$			;         out
130$:	CALL	PTRTYP			; type the help text
	CRLF
	BR	110$

140$:	CRLF
	CRLF
	RTN

;;		S E T   S U B C O M M A N D S

; B E L L - set bell after each command completeion flag.
BELL:	LEA	A1,ONOFF		; index option list
	CALL	GETOPT			; process option
	BNE	10$			;  no good
	MOVB	D1,DING(A0)		; set bell option
10$:	RTN

; D U P L E X - set half or full duplex.
DUPLEX:	LEA	A1,EPLEX		; index echoplex options
	CALL	GETOPT			; process option
	BNE	10$			;  no good
	MOVB	D1,ECHO(A0)		; set duplex option
10$:	RTN


; B L O C K - set default check type. 1, 2 or 3 byte check types
BLOCK:	LEA	A1,ONE23		; index check-type options
	CALL	GETOPT
	BNE	10$			; no good
	MOVB	D1,DF.CHK(A0)		; set default check type
10$:	RTN

; D E B U G - Set debug message print flag.
DEBUG:	LEA	A1,ONOFF		; allow YES or NO.
	CALL	GETOPT
	BNE	10$
	MOVB	D1,DEBUGO(A0)		; set debug option
10$:	RTN

; A U T S N D - Set AUTOSEND option flag.
AUTSND:	LEA	A1,ONOFF		; allow YES or NO.
	CALL	GETOPT
	BNE	10$
	MOVB	D1,AUTOS(A0)		; set autosend option
10$:	RTN

; A U T R E C - Set AUTORECEIVE option flag.
AUTREC:	LEA	A1,ONOFF		; allow YES or NO.
	CALL	GETOPT
	BNE	10$
	MOVB	D1,AUTOR(A0)		; set autosend option
10$:	RTN

; E N D L I N - set optional end of packet character. (normally CR.)
ENDLIN:	CALL	EVLCHR			; get the character
	BNE	10$		
	MOVB	D1,DF.EOL(A0)		; set default EOL
10$:	RTN

; P A K M R K - set optional start of packet character. (normally CR.)
PAKMRK:	CALL	EVLCHR			; get the character
	BNE	10$		
	MOVB	D1,RMARK(A0)		; set default MARK character
10$:	RTN


; E S C A P E - set the escape from CONNECT mode character.
ESCAPE:	CALL	EVLCHR
	BNE	10$			; no good
	ANDB	CMASK(A0),D1		; limit to valid character set range
	MOVB	D1,KMETA(A0)		; set escape character
10$:	RTN

; T I M E R - set the timeout period used in packet transmission.
TIMER:	BYP
	GTDEC				; get decimal number
	CMP	D1,#MINTIM		; compare to minimum time
	BHIS	10$			; allow 2 or more
	MOV	#MINTIM,D1		;  force minimum
	TYPECR	<Setting timeout to 2 second minimum.>
10$:	MOV	D1,DF.TIM(A0)		; set default and
	MOV	D1,TIMINT(A0)		; current timer value
	RTN

; N E W T R Y   - sets the maximum # of tries for a packet.
NEWTRY:	BYP
	GTDEC
	TST	D1			; test new value
	BEQ	20$			; zero is too few!
	CMP	D1,#255.		; this is max was ^O255
	BHI	20$			;  too high-leave as is
	MOVB	D1,MAXTRY(A0)		; set max value
	RTN
20$:	TTYI
	ASCII	/?value out of range?/
	BYTE	A.BEL,CR,0
	EVEN
	RTN

; P A K M A X - set maximum packet size supported
PAKMAX:	BYP
	GTDEC
	CMP	D1,#10.			; compare to minimum
	BLO	20$			;  too small [16]
	CMP	D1,#PAKSIZ		; compare to max size allowed
	BHI	20$			;  too high-leave as is
	MOVB	D1,MXPKSZ(A0)		; set max value
	MOVB	D1,SPSIZ(A0)		; set max send size, too!
	RTN

20$:	TTYI
	ASCII	/?select a packet size from 10 to 94 bytes./
	BYTE	A.BEL,CR,0
	EVEN
	RTN

; S E T P A R - set the parity type (already in use) by the remote
; This allows Alpha-Kermit to know whether 8bit quoting is needed, or not.
SETPAR:	LEA	A1,PARLST		; allow YES or NO.
	CALL	GETOPT
	BNE	10$
	MOVB	D1,PARITY(A0)		; set parity
	CMPB	D1,#'N			; no parity?
	SETNE	QBIN(A0)
	TTYL	NOSET			; tell user limitations
10$:	RTN

; S T L V A L  - set # of 100ths of seconds to stall between output
; characters for file transfers.
STLVAL:	BYP
	GTDEC
	TST	D1			; test new value
	BEQ	20$			; zero is too few!
	CMP	D1,#255.		; this is max was ^O255
	BHI	20$			;  too high-leave as is
	MOVB	D1,STLCHR(A0)		; set max value
	RTN
20$:	TTYI
	ASCII	/?STALL range is 0 to 255 hundredths of seconds./
	BYTE	A.BEL,CR,0
	EVEN
	RTN


; G E T O P T  - compares the input option @A2 to the option list @A1.
; If there is a match, the match number is returned in D1 and Z is set.
; No match returns Z clear and displays the error message at  the end of the
; option list.
GETOPT:	SUB	#2,A1			; adjustment for first entry
	BYP				; scan past seperators
	PUSH	A2			; save string address for compares
; calculate address of next entry and place in A1.
OPT.1:	MOV	@SP,A2			; restore string pointer
	LEA	A3,2(A1)		; A3 indexs next entry
	TSTW	@A3			;  end of table ?
	BEQ	OPT.5			;   yes-no match.
	MOV	A3,A1			;   no-get address of command size word
	ADDW	(A3)+,A1		;  and index to next command.
	CLR	D5
	MOVB	(A3)+,D5		; D5 gets qualifier size in bytes

OPT.2:	TRM				; check for end of word
	BEQ	OPT.4			;  yes-check match count
	TSTB	@A3			;  check for end of table entry
	BEQ	OPT.1			;  must be wrong if so.
OPT.3:	MOVB	@A2,D1
	UCS				; convert to upper case
	CMPB	D1,(A3)+		; compare strings
	BNE	OPT.4			;  until no match
	ADD	#1,A2			; advance A2
	TST	D5			; check for minimum match length
	BEQ	OPT.2			;  made it-stop counting
	SUB	#1,D5			; decrement byte count
	BR	OPT.2			;  keep testing till line is terminated

OPT.4:	TST	D5			; good match has zero count
	BNE	OPT.1			;  no good-try next
	TRM				; good match has no more data
	BNE	OPT.1
	POP				; toss old A2
	CLR	D1
	MOVB	@A1,D1			; D1 gets argument value
	LCC	#PS.Z			; flag command match found
	RTN

; undefined command - Clear Z flag
OPT.5:	POP	A2
	TTYL	2(A3)			; display error message at end of list
	CRLF				; [15]
	LCC	#0
	RTN				; return with Z clear

; P T R T Y P  - print the string indexed by A1 until a null is found.
PTRTYP:	MOVB	(A1)+,D1
	BEQ	10$
	INC	D0			; count characters
	TTY
	BR	PTRTYP
10$:	RTN

; G O O D B Y  - exit from KERMIT to AMOS for good.
; re-attach comm TCB to its former JCB, if any.
GOODBY:	ANDW	#^C<FIL!LOK>,-10(A0)	; clear file and locked in mem flags
	MOV	REMOTE(A0),A5
	MOV	#^C<REMMOD>,D1		; clear bits we set (except OIP)
	CALL	INUSE			; get in-use bit
	TSTB	ATERM(A0)		; user & comm port the same?     [010]
	BEQ	4$			;  yes-leave busy bit as is      [010]
	BCLR	D6,D1			; clear it for bit clear mask
4$:	CALL	SETSTS			; clear all those bits
	CLR	D1
	MOVW	SAVSTS(A0),D1		; get saved status
	AND	#^CT$OIP,D1		;  less OIP bit which hangs output!
	CALL	SETSTS			; set the saved bits
	MOV	SAVJCB(A0),A6
	MOV	A6,T.JLK(A5)		; restore any attached job
	BEQ	10$
	MOV	A5,JOBTRM(A6)		; and JCB, if there was one
10$:	MOV	SAVTDV(A0),T.TDV(A5)	; restore TDV
	SAVE	A0			; [16] JRUN the newly reattached job,
					; if it is waiting for OIP
	MOV	SAVJCB(A0),D7		; get saved job
	BEQ	20$			;  no saved job
	MOV	D7,A0
	MOVW	JOBSTS(A6),D7		; get job status
	ANDW	#J.TOW,D7		; was job waiting for output?
	BEQ	20$			;  no
	JRUN	J.TOW			;  yes
20$:	REST	A0
	SETB	DONE(A0)		; set the we are done flag
	RTN

; A M O S - move to AMOS level temporarily.
AMOS:	SETB	DONE(A0)		; set the we are done flag	
	RTN

; S E T S T S
; This routine sets or clears status bits in D1.
; If D1 is minus, the bits are cleared. If they are +, the bits are set

; This routine is used to set and reset TRMSER status word bits without
; getting T$OIP fouled up and hanging the job's output.
SETSTS:	SUPVR
; This routine runs in SUPVR mode
; Used to change TRMSER status bits.
; Made compatible with smart I/O cards by using new monitor calls if
; O/S is new enough for it.
	SVLOK				; prevent interrupts
	TSTB	COMSER(A0)		; do we have COMSER? [015]
	BEQ	8$			;  no, do it old way
	TSTW	D1			; clear or set bits?
	BMI	4$			; clear bits
; new way to change T.STS word without violating T.SEM rules.
	PUSHW	D1
	TRMRST	D1,@A5			; read status
	ORW	(SP)+,D1		; stir in the new bits
	TRMWST	D1,@A5			; write status
	BR	20$
4$:	PUSHW	D1
	TRMRST	D1,@A5			; read status
	ANDW	(SP)+,D1		; pick out the icky bits
	TRMWST	D1,@A5			; write status
	BR	20$

; old way to change T.STS word
8$:	TSTW	D1			; set or clear bits?
	BMI	10$			;  clear is negative
	ORW	D1,@A5			; set bits if + or 0.
	BR	20$			; done setting...
10$:	ANDW	D1,@A5			; clear those bits
20$:	LSTS	#0			; unlock CPU & return to user mode
	RTN
;;;		 F I L E   T R A N S F E R   R O U T I N E S

; S E N D S W
; SENDSW is the state table switch for file transfers. It loops either
; until it finishes, or an error is encountered. The routines called
; by SENDSW change the automaton state.
SENDSW:
	MOVB	#'S,STATE(A0)		; start with SEND INIT
	CLRB	N(A0)			; clear the seq number
	CLRB	NUMTRY(A0)		;  and the retry count
	CLRB	LOGIC(A0)		; CLEAR LOGIC
	CLRB	RIACK(A0)		; clear the I is ACKed flag
10$:	TSTB	LOGIC(A0)		; test logic flag
	BNE	100$			;  we are done
	CTRLC	ABORT			; exit on control-C
	TSTB	DEBUGO(A0)		; debug on ?
	BEQ	20$			;   no
	TYPE	<SENDSW state >
	MOVB	STATE(A0),D1
	TTY
	CRLF
	CRLF
20$:	LEA	A6,SWSTAT-4		; index the state table
	MOVB	STATE(A0),D7		; D7 gets the current state
30$:	ADD	#4.,A6			; pre-advance
	MOVB	@A6,D6
	BEQ	100$			; undefined state - so exit
	CMPB	D6,D7			;  matching state ?
	BNE	30$			;   no
	ADD	#2.,A6			; yes - advance to offset
	ADDW	@A6,A6			; calc address of new routine
	CALL	@A6			; execute it
	BR	10$			; loop till we exit
100$:	RTN

ABORT:	MOVB	#'A,STATE(A0)		; flag it as bad.
	MOVB	#FALSE,LOGIC(A0)
	CALL	CLOSER
	RTN

COMPLT:	MOVB	#TRUE,LOGIC(A0)		; flag complete o.k.
	RTN


; S I N I T
; Send (I) Initiate Packet & receive REMOTEs reply

SINIT:	ADDB	#1,NUMTRY(A0)		; bump # of tries
	CMMB	NUMTRY(A0),MAXTRY(A0)	; beyond the max?
	BLOS	20$
	MOVB	#'A,STATE(A0)
10$:	RTN

20$:	LEA	A3,PACKET(A0)		; index the packet area
	CALL	SPAR			; load default data for S packet
	CALL	FLUSH			; flush pending input
	MOVB	DF.EOL(A0),EOL(A0)	; use default EOL
	SPACK	#'S,N(A0),#PARSIZ,PACKET(A0)	; send an S packet
; just in case host requires an EOL character, send the default EOL value.
	MOVB	#CR,D1			; send universal EOL value
	CALL	OUTBYT			; output the EOL to get remote going
;	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,RECPKT(A0),D4	; receive a packet
	BNE	1000$			; no packet received ; timeout
					;  or damaged packet
	CMPB	D4,#'N			; NAK, try again
	JEQ	1000$			;  just return, leave state as is.
	CMPB	D4,#'Y			; ACK ?
	BNE	30$			;  no ACK
	CMPB	D3,N(A0)		;  yes-same # as I sent?
	BNE	1000$			;   no-return, same state
; get other side's init info.
	SETB	RIACK(A0)		; flag we got ACK to I packet
	LEA	A3,RECPKT(A0)		; index work area
	CALL	RPAR			; load parameters from work area
	CMPB	QUOTE(A0),#SPACE	; check for space or null
	BHI	32$
	MOVB	#MYQUOT,QUOTE(A0)	; reset to #
32$:	CLRB	NUMTRY(A0)		; clear retries
	CALL	BUMPP			; bump N mod 64.
	MOVB	#'F,STATE(A0)		; move to state F
	JMP	1000$			; done
30$:	CMPB	D4,#'E			; error packet received ?
	BNE	40$			;  no
	CALL	PRTERR			; show error
; move to abort state on any undefined TYPEs
40$:	MOVB	#'A,STATE(A0)		; move to abort state.
1000$:	RTN

; S F I L E sends the file header.
SFILE:	TSTB	FIO+D.ERR(A0)		; error on input file?
	BNE	2$			;  yes, move to break state
	MOV	CMNEXT(A0),D7
	AND	#NX$END,D7		; end of specs?
	BEQ	4$			;  no
2$:	MOVB	#'B,STATE(A0)		;  yes, send a break
	RTN

4$:	INCB	NUMTRY(A0)		; bump the count
	CMMB	NUMTRY(A0),MAXTRY(A0)	; beyond the max?
	BLOS	10$			;  no
	MOVB	#'A,STATE(A0)		; set state to abort
	RTN

10$:	CLR	D2
	MOVB	FLLEN(A0),D2
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'F,N(A0),D2,NFILNM(A0)	; send the F packet

; 	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,RECPKT(A0),D4		; wait for reply
	BNE	1000$				; no reply
; compare received sequence # to expected #
	CMPB	D4,#'N			; NAK ?
	BNE	30$			;  no NAK here
; check to see if NAK is for next block, which we will
; interpret as being an ACK for this block.
	CALL	NEXTN			; D1 gets NEXT packet #
	CMPB	D1,D3			; NAK for next block ?
	BNE	1000$			;  no-return with state unchanged
	BR	35$			;  yes-treat as ACK for this block

30$:	CMPB	D4,#'Y			; ACK ?
	BNE	40$			;  no
	MOVB	N(A0),D1		; D1 gets current SEQ #
	CMPB	D3,D1			;  yes-is it expected SEQ?
	BNE	1000$			;   no-return state unchanged
35$:	CLRB	NUMTRY(A0)		;   yes-clear retries count
	CALL	BUMPP
	LEA	A3,PACKET(A0)
	CALL	BUFFIL			; fill a buffer @A3
	MOVB	#'D,STATE(A0)		; goto Data state
	JMP	1000$

40$:	CMPB	D4,#'E			; Error packet received
	BNE	50$
	CALL	PRTERR			; show the error
; if any other case, move to abort case
50$:	MOVB	#'A,STATE(A0)		; move to abort state
1000$:	RTN

; S D A T A  - sends a portion of file contents
SDATA:	INCB	NUMTRY(A0)		; bump try count
	CMMB	NUMTRY(A0),MAXTRY(A0)	; maxxed out ?
	BLOS	10$			;  no	
	MOVB	#'A,STATE(A0)		;  yes-move to abort state
	RTN

10$:	
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'D,N(A0),BUFCNT(A0),PACKET(A0)	; send data packet
;	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,RECPKT(A0),D4	; receive a packet
	JNE	1000$			;  no data received
	CMPB	D4,#'N			; NAK ?
	BNE	15$			;  no
	CALL	NEXTN			; D1 gets N
	CMPB	D1,D3			; NAK for N+1?
	BEQ	40$			;  yes-treat as lost ACK for N
	JMP	1000$			; else exit state unchanged

15$:	CMPB	D4,#'Y			; ACK ?
	BNE	70$			; no
	CMPB	D3,N(A0)		; right SEQ of ACK?
	BNE	1000$			;  no-state unchanged
	TSTB	LDATA(A0)		; is data length zero?
	BEQ	30$			;  yes
;test for graceful abort request from RECeiving Kermit.
	MOVB	RECPKT+DATA(A0),D7	;  no-get the byte
	ANDB	#^O177,D7		; strip to ACSII
	CMPB	D7,#'Z			; is it abort batch?
	BNE	20$			;  no
	SETB	ABORTB(A0)		;  yes, set abort batch flag
	BR	30$			; 
20$:	CMPB	D7,#'X			; is it abort file?
	BNE	30$			;  yes
	SETB	ABORTF(A0)
30$:	CALL	SHODOT			; tell user we moved some data
40$:	CALL	BUMPP			; bump packet count
	TSTB	ABORTF(A0)		; abort file?
	BNE	50$			;  yes
	CLRB	NUMTRY(A0)		; clear the try count
	LEA	A3,PACKET(A0)		; index the Packet
	CALL	BUFFIL			; get a buffer
	TSTB	BUFCNT(A0)		; any data to send ?
	BNE	60$	
50$:	CALL	CLOSER			; close file
	MOVB	#'Z,STATE(A0)		; move to Z state (end of file)
	JMP	1000$
60$:	MOVB	#'D,STATE(A0)		; stay in D state
	JMP	1000$
70$:	CMPB	D4,#'E			; Error packet ?
	BNE	1000$
	CALL	PRTERR
	MOVB	#'A,STATE(A0)		; move to A state.
1000$:	RTN
	
; S E O F  - send the end of file packet.
SEOF:	INCB	NUMTRY(A0)
	CMMB	NUMTRY(A0),MAXTRY(A0)
	BLOS	10$
	MOVB	#'A,STATE(A0)
	RTN

10$:	CLR	D2			; D2 is packet size
	TSTB	ABORTF(A0)		; aborting this file ( or batch)?
	BEQ	20$			;  no
	MOV	#1,D2			;  yes, set size to 1 byte
	MOVB	#'D,PACKET+DATA(A0)	; flag "DISCARD" to remote
20$:
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Z,N(A0),D2,PACKET(A0)	; send a Z packet
;	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,RECPKT(A0),D4	; get a reply
	BNE	1000$			; 
	CMPB	D4,#'N			; NAK ?
	BNE	30$
	CALL	NEXTN			; D1 gets next N mod 64.
	CMPB	D1,D3			; NAK for SEQ+1?
	BEQ	40$			; yes-treat as ACK.
	JMP	1000$			; return as is

30$:	CMPB	D4,#'Y			; ACK ?
	BNE	60$			;  no
	CMPB	D3,N(A0)		; matching SEQ #?
	BNE	1000$			;  no-return as is
40$:	CALL	BUMPP			; bump the N value
	CALL	ENDTM			; display speed stats
	CALL	DINGEM			; [015]
	TSTB	ABORTB(A0)		; abort batch? [015]
	BNE	50$			;  yes [015]
	CALL	GETNXT			; any more files?
	BVS	50$			;  no
	TSTB	FIO+D.ERR(A0)		;  file error?
	BNE	50$			;  yes, end transfer
	CALL	GTSIZE			; calc file size
	CALL	STARTT			; set start time
	MOVB	#'F,STATE(A0)		; reset state for more files
;	CLRB	N(A0)			; clear the seq number
	CLRB	NUMTRY(A0)		;  and the retry count
	JMP	1000$

; we found the "free time" for multiple files in 1991!
50$:	MOVB	#'B,STATE(A0)		; goto Break state
	JMP	1000$

60$:	CMPB	D4,#'E			; error packet ?
	BNE	70$			;  no
	CALL	PRTERR			;  yes-print erorrrr.
	JMP	1000$
70$:	MOVB	#'A,STATE(A0)		; abort on undefined types
1000$:	RTN

;  S B R E A K -  sends a break frame (no more files to send).
SBREAK:	INCB	NUMTRY(A0)		; bump the try count
	CMMB	NUMTRY(A0),MAXTRY(A0)	; maxxed out?
	BLOS	10$			;  no
	MOVB	#'A,STATE(A0)		;  yes-abort state
	RTN

10$:	
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'B,N(A0),#0,PACKET(A0)	; send a B packet
;	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,RECPKT(A0),D4	; get a reply
	BNE	1000$			; no reply
	CMPB	D4,#'N			; NAK ?
	BNE	20$
	CALL	NEXTN			; D1 gets next N mod 64.
	CMPB	D1,D3			; NAK for SEQ+1?
	BEQ	30$			; yes-treat as ACK.
	JMP	1000$			; return as is

20$:	CMPB	D4,#'Y			; ACK ?
	BNE	40$			;  no
	CMPB	D3,N(A0)		; matching SEQ #?
	BNE	1000$			;  no-return as is
30$:	CALL	BUMPP			; bump the N value
	MOVB	#'C,STATE(A0)		; goto Complete state
	JMP	1000$

40$:	CMPB	D4,#'E			; error packet ?
	BNE	50$			;  no
	CALL	PRTERR			;  yes-print erorrrr.
	JMP	1000$

50$:	MOVB	#'A,STATE(A0)		; abort on undefined types
1000$:	RTN

; R E C S W  - is the state table switch for receiving files.
RECSW:	MOVB	#'R,STATE(A0)		; start with RECV INIT state
	CLRB	N(A0)			; clear the seq number
	CLRB	NUMTRY(A0)		;  and the retry count
	CLRB	LOGIC(A0)		; clear logic
	CLRB	RIACK(A0)		; clear the I is ACKed flag
10$:	TSTB	LOGIC(A0)		; test logic flag
	BNE	100$			;  we are done
	CTRLC	RABOR			;  or user wants out
	TSTB	DEBUGO(A0)		; debug on ?
	BEQ	20$			;   no
	TYPE	<RECSW state >
	MOVB	STATE(A0),D1
	TTY
	CRLF
20$:	LEA	A6,RCSTAT-4		; index the state table
	MOVB	STATE(A0),D7		; D7 gets the current state
30$:	ADD	#4.,A6			; pre-advance
	MOVB	@A6,D6
	BEQ	100$			; undefined state - so exit
	CMPB	D6,D7			;  matching state ?
	BNE	30$			;   no
	ADD	#2.,A6			; yes - advance to offset
	ADDW	@A6,A6			; calc address of new routine
	CALL	@A6			; execute it
	BR	10$			; loop till we exit
100$:	RTN

RABOR:	MOVB	#'A,STATE(A0)		; flag transfer as bad
	MOVB	#FALSE,LOGIC(A0)
	RTN

RCOMP:	MOVB	#TRUE,LOGIC(A0)		; flag complete o.k.
	RTN

; R I N I T - is the receive init routine
; Wait for the send-init packet from sending Kermit.
RINIT:	ADDB	#1,NUMTRY(A0)		; count the tries
	CMMB	NUMTRY(A0),MAXTRY(A0)	; beyond the max?
	BLOS	20$
	MOVB	#'A,STATE(A0)
	RTN

20$:	
;	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,PACKET(A0),D4	; receive a packet
	BNE	50$			;  no packet received ; timeout
	CMPB	D4,#'S			;  got an S packet ?
	BNE	30$			;   no S packet
; get other side's init data
	LEA	A3,PACKET(A0)		; index data packet address
	CALL	RPAR			; get parameters
	LEA	A3,PACKET(A0)		; index data packet address
	CALL	SPAR			;  send our parameters
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Y,N(A0),#PARSIZ,PACKET(A0); send ACK with reply
	SETB	RIACK(A0)		; flag ACK to I has been sent
	MOVB	NUMTRY(A0),OLDTRY(A0)	; save try count
	CLRB	NUMTRY(A0)		; clear count
	CALL	BUMPP			; bump packet #
	MOVB	#'F,STATE(A0)		; bump state
	JMP	1000$			; end

30$:	CMPB	D4,#'E			; error received ?
	BNE	40$
	CALL	PRTERR			; display the error.
	MOVB	#'A,STATE(A0)
	JMP	1000$			; done
; all others default to A state
40$:	MOVB	#'A,STATE(A0)		; received junk-abort
	JMP	1000$
; no packet received - send a NAK
50$:	SPACK	#'N,N(A0),#0,NFILNM(A0)	; send a NAK packet
					; return without state change
1000$:	RTN

; R F I L E  - receive a file header frame with the filename.
RFILE:	ADDB	#1,NUMTRY(A0)		; count the tries
	CMMB	NUMTRY(A0),MAXTRY(A0)	; beyond the max?
	BLOS	20$
	MOVB	#'A,STATE(A0)
	RTN

20$:	

;	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,NFILNM(A0),D4	; receive a packet (expecting filename)
	JNE	500$			;  no packet received ; timeout
	CMPB	D4,#'S			;  got an S packet ?
	BNE	50$			;   no
; SEND-INIT received, maybe ACK was lost.
	CALL	NEXTO			; D1 gets next OLDTRY value
	CMPB	D1,MAXTRY(A0)		;  time to give up?
	BLOS	30$			;   no
	MOVB	#'A,STATE(A0)
	JMP	1000$			; yes-goto abort state.

30$:	MOVB	N(A0),D1		; D1 gets current packet #
	CALL	PREVP			; get previous packet #
	CMPB	D1,D3			; previous packet ?
	BNE	40$			;  no
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Y,D3,#PARSIZ,PACKET(A0)	;   yes-ack again with SEND-INIT
	CLRB	NUMTRY(A0)		; clear retry count
	JMP	1000$			;  stay in state.

40$:	MOVB	#'A,STATE(A0)		; goto abort
	JMP	1000$			;  done

50$:	CMPB	D4,#'Z			; end of file?
	BNE	80$			;  no
	CALL	NEXTO			; D1 gets next oldtry
	CMPB	D1,MAXTRY(A0)		;  time to give up?
	BLOS	60$			;   no
	MOVB	#'A,STATE(A0)		;   yes-abort
	JMP	1000$			; done

60$:	MOVB	N(A0),D1		; get N
	CALL	PREVP			; calc previous packet # to D1
	CMPB	D1,D3			;  same ?
	BNE	70$			;  no
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Y,D3,#0,PACKET(A0)	;   yes-ack Z from file before!
	CLRB	NUMTRY(A0)		; reset tries
	JMP	1000$			;  done

70$:	MOVB	#'A,STATE(A0)		; goto ABORT otherwise.
	JMP	1000$

80$:	CMPB	D4,#'F			; is it the blessed file header yet?
	JNE	200$			;  no	
	CMPB	D3,N(A0)		;  yes-is the packet # correct?
	BNE	70$			;   no-move to abort state.
	CALL	RFILNM			; process the filename & open.
	BEQ	90$			; it opened ok
	CALL	LFERR			; show local file error
	MOVB	#'A,STATE(A0)		; move to abort state
	JMP	1000$			; done
90$:	TSTB	NOTALK(A0)		; do we have a user terminal?
	BNE	120$			;  no-bypass message
	CRLF
	TYPE	<Receiving >
	CLR	D0
	MOVB	LDATA(A0),D0
	LEA	A1,FILNAM(A0)
	BR	110$
100$:	MOVB	(A1)+,D1
	TTY
110$:	DBF	D0,100$
	TYPE	< as >
	PFILE	FIO(A0)
	CRLF
120$:
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Y,N(A0),#0,PACKET(A0)	;   send ACK for the F packet
	MOVB	NUMTRY(A0),OLDTRY(A0)	; reset try counters
	CLRB	NUMTRY(A0)
	CALL	BUMPP			; get next packet #
	MOVB	#'D,STATE(A0)		; move to data state
	JMP	1000$

200$:	CMPB	D4,#'B			; break ?
	BNE	300$			;  no
	CMPB	D3,N(A0)		;  yes-is packet # correct?
	BNE	310$	
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Y,N(A0),#0,PACKET(A0)	;   send ACK for the B packet
	MOVB	#'C,STATE(A0)		; and move to Complete state
	JMP	1000$			; end

300$:	CMPB	D4,#'E			; error frame ?
	BNE	400$			;  no
	CALL	PRTERR			;  show it
310$:	MOVB	#'A,STATE(A0)		; move to abort
	JMP	1000$
400$:	MOVB	#'A,STATE(A0)		; goto abort state
	JMP	1000$

; didnt get a packet
500$:
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'N,N(A0),#0,PACKET(A0)	;   send NAK 
1000$:	RTN

; R D A T A -  receives the data packets that make up the file.
RDATA:	ADDB	#1,NUMTRY(A0)		; count the tries
	CMMB	NUMTRY(A0),MAXTRY(A0)	; beyond the max?
	BLOS	20$
	MOVB	#'A,STATE(A0)
	RTN

20$:	
;	RPACK	LEN,SEQ,PACKET,TYPE
	RPACK	D2,D3,PACKET(A0),D4	; receive a packet (expecting filename)
	JNE	500$			;  no packet received ; timeout
	CMPB	D4,#'D			; got a Data packet ?
	JNE	60$			;  no
	CMPB	D3,N(A0)		;  yes-is it right packet # ?
	BEQ	50$			;   YES
	CALL	NEXTO			;   NO-get next OLDTRY value in D1
	CMPB	D1,MAXTRY(A0)		;  
	BLOS	25$
	MOVB	#'A,STATE(A0)		; abort -retries exceeded
	JMP	1000$			;  done

25$:	MOVB	N(A0),D1		; D1 gets current packet #
	CALL	PREVP			; get previous packet #
	CMPB	D1,D3			; previous packet ?
	BNE	40$			;  no
;	SPACK	TYPE,SEQ,SIZE,PACKET	
	SPACK	#'Y,D3,#6,PACKET(A0)	;   yes-re-ack.
	CLRB	NUMTRY(A0)		; clear retry count
	JMP	1000$			;  stay in state.

40$:	MOVB	#'A,STATE(A0)		; goto abort
	JMP	1000$			;  done

; received valid data frame - output it
50$:	CALL	BUFEMP			; empty the buffer to disk
;	SPACK	TYPE,SEQ,SIZE,PACKET	
	SPACK	#'Y,N(A0),#0,PACKET(A0)	;   ack the data
	MOVB	NUMTRY(A0),OLDTRY(A0)	; reset the try counters
	CLRB	NUMTRY(A0)		; clear retry count
	CALL	BUMPP			; bump the packet #
	MOVB	#'D,STATE(A0)		; stick in D state.
	CALL	SHODOT			; tell user we moved some data
	JMP	1000$			;  stay in state.

60$:	CMPB	D4,#'F			; file header?
	BNE	80$			;  no
	CALL	NEXTO			; D1 gets next oldtry
	CMPB	D1,MAXTRY(A0)		;  time to give up?
	BLOS	70$			;   no
65$:	MOVB	#'A,STATE(A0)		;   yes-abort
	JMP	1000$			; done
70$:	MOVB	N(A0),D1		; get N
	CALL	PREVP			; calc previous packet # to D1
	CMPB	D1,D3			;  same ?
	BNE	65$			;  no
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Y,D3,#0,PACKET(A0)	;   yes-ack again
	CLRB	NUMTRY(A0)		; reset tries
	JMP	1000$			;  done

80$:	CMPB	D4,#'Z			; end of file?
	BNE	200$			;  no	
	CMPB	D3,N(A0)		;  yes-is the packet # correct?
	BNE	65$			;   no-move to abort state.
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'Y,D3,#0,PACKET(A0)	;   ack the Z
	CALL	CLOSER
	LOOKUP	FIO(A0)			; do file lookup
	CALL	GTSIZE			; to get file size
	CALL	ENDTM			; show elapsed time & speed
	CALL	DINGEM			; [015] alert user
	CALL	BUMPP			; bumpthepacket#
	MOVB	#'F,STATE(A0)		; return the F state
	BR	1000$

200$:	CALL	CLOSER			; close file if open
	CMPB	D4,#'E			; error frame ?
	BNE	400$			;  no
	CALL	PRTERR			;  show it
	MOVB	#'A,STATE(A0)		; move to abort
	JMP	1000$

400$:	MOVB	#'A,STATE(A0)		; goto abort state
	JMP	1000$
; didnt get a packet
500$:
;	SPACK	TYPE,SEQ,SIZE,PACKET
	SPACK	#'N,N(A0),#0,PACKET(A0)	;   send NAK 
1000$:	RTN

;;;		       P A C K E T   U T I L I T I E S

; B U M P P - bumps the current packet mod 64. The new N is returned in D1,
; and is also updated in N(A0).
BUMPP:	BCALL	NEXTN
	MOVB	D1,N(A0)
	RTN

; N E X T N - returns the next N(A0) value in D1. It does NOT update N(A0).
NEXTN:	CLR	D1
	MOVB	N(A0),D1
	ADD	#1,D1
	ANDB	#63.,D1
	RTN

; N E X T O - returns the next OLDTRY(A0) value in D1. 
; It does not update OLDTRY(A0).
NEXTO:	CLR	D1
	MOVB	OLDTRY(A0),D1
	ADD	#1,D1
	ANDB	#63.,D1
	RTN

; P R E V P - returns the prior packet to D1 in D1. ( D1-1 mod 64. )
PREVP:	SUB	#1,D1
	AND	#63.,D1
	RTN

; P R T E R R - prints the error message contained in the Error packet
PRTERR:	CLR	D0			; 
	MOVB	LDATA(A0),D0		; get length of data field
	LEA	A1,DATA(A3)
	TTYL	ABTTTL
	BR	30$
20$:	MOVB	(A1)+,D1
	TTY
30$:	DBF	D0,20$
	CRLF
	RTN

; R P A R  -  get the REMOTE's send-init parameters.
; At entry, A3 indexs the packet area
; revised [21]
RPAR:	MOVB	#'1,CHKT(A0)		; default to 1 char checksum
	MOVB	#SPACE,REPT(A0)		; and no repeat
	CLRB	QBIN(A0)		; default to no quoting, 7 bit path
10$:	LEA	A1,DATA(A3)		; index the payload area
	CLR	D1
	MOVB	(A1)+,D1		; get MAXL byte
	AND	#177,D1			; strip to ASCII in case of parity
	UNCHAR	D1
	CMPB	D1,#PAKSIZ		; bigger than protocol max?
	BHI	19$			;  yes, use default
15$:	CMPB	D1,MXPKSZ(A0)		; compare to user's max
	BLO	18$			;  but no higher
	MOVB	MXPKSZ(A0),D1		; use our local max
18$:	CMPB	D1,#10.			; MAXL should be at least 10.
	BHIS	30$
19$:	MOV	#80.,D1			; yes, use default MAXL of 80.
30$:	MOVB	D1,SPSIZ(A0)		; set send packet size
	MOVB	(A1)+,D1 		; get TIME byte
	UNCHAR	D1
	MOV	D1,TIMINT(A0)		; set when I should time out
	MOVB	(A1)+,D1		; get NPAD byte
	UNCHAR	D1
	MOVB	D1,PAD(A0)		; set pad count.
	MOVB	(A1)+,D1		; get PADC byte
	CTL	D1
	MOVB	D1,PADCHR(A0)		; set pad character
	MOVB	(A1)+,D1		; get EOL byte
	UNCHAR	D1
	MOVB	D1,EOL(A0)		; set end of line char
	MOVB	(A1)+,D1		; get QCTL byte
	CMPB	D1,#SPACE
	BHI	40$
	MOV	#MYQUOT,D1		; default it
40$:	MOVB	D1,QUOTE(A0)		; set control-quote.
	CLR	D2
	MOVB	LDATA(A0),D2		; get size of data area
	SUB	#6,D2			; have more than basic 6 bytes?
	JLOS	140$			; no more data
; get QBIN
	MOVB	(A1)+,D1		; get QBIN byte
	AND	#177,D1			; strip to ASCII
	CMPB	D1,#'Y			; will quote if we request?
	BNE	50$			;  no
	MOV	#1,D0			;  yes
	BR	80$
; allowable ranges are decimal 33-62 & 96-126. Reject all others.
50$:	CMPB	D1,#SPACE		; was it a space through null?
	BLOS	70$			;  not legal 8b quote value
	CMPB	D1,#62.			; ASCII 33-62?
	BLOS	60$			;  yes-use it
	CMPB	D1,#127.		; check high boundary of 2nd range
	BHIS	70$			;  not legal 8b quote value
	CMPB	D1,#96.			; check lower bound of 2nd range
	BHIS	60$			;  legal
	BR	70$			;  not legal
60$:	MOV	#2,D0			; set case 2 - we have valid 8b q
	BR	80$
70$:	MOV	#0,D0			; case 0 - we have no 8b q info
; D0 is 0, 1 or 2
80$:	DEC	D0			; was it 0?
	BCC	90$			;  no
	CMPB	PARITY(A0),#'N		; do we have NO parity?
	SETNE	QBIN(A0)		;  P=None, allow full 8 bits
					;  P=other, mask to 7 bits
	BR	110$
90$:	DEC	D0			; was it 1? (quote if needed only)
	BCC	100$			;  no
	CMPB	PARITY(A0),#'N		; do we have NO parity?
	BEQ	95$			;  yes-flag 8 bits, no quoting
	MOVB	#'&,QBIN(A0)		; else 7 bits, default quote
	BR	110$
95$:	CLRB	QBIN(A0)		
	BR	110$
100$:	MOVB	D1,QBIN(A0)		; got QBIN - 7 bits w/quoting
110$:	SUB	#1,D2
	BEQ	140$			; no more
; get CHKT
	MOVB	(A1)+,D1		; get CHKT byte
;;[023]	CMPB	D1,#'2			; higher than 2?
	CMPB	D1,DF.CHK(A0)		; higher than max user value? [023]
	BHI	120$			;  yes-force to one
	BEQ	130$			;  no-allow it
	CMPB	D1,#1			; do not allow zero
	BEQ	130$
120$:	MOV	#'1,D1			; force to 1 if BOTH SIDES don't agree
130$:	MOVB	D1,CHKT(A0)		; set checksum method
	SUB	#1,D2
	BEQ	140$
; get REPT
	MOVB	(A1)+,D1		; get REPT byte
	UNCHAR	D1
	MOVB	D1,REPT(A0)		; set repeat prefix
140$:	CMPB	QUOTE(A0),#SPACE	; quote undefined ?
	BNE	150$			;  no-defined
	MOVB	#'#,QUOTE(A0)		;  yes-use default
150$:	RTN


; S P A R  - fill data area with send-init parameters
SPAR:	LEA	A1,DATA(A3)	; index payload area
	CLR	D1
	MOVB	MXPKSZ(A0),D1		; get max packet size
	CHAR	D1
	MOVB	D1,(A1)+		; 1 max packet size
	MOV 	DF.TIM(A0),D1		; get our default value
	CHAR	D1
	MOVB	D1,(A1)+		; 2 # of seconds to my timeout
	MOV	#MYPAD,D1
	CHAR	D1
	MOVB	D1,(A1)+		; 3 # of padding characters
	MOV	#MYPCHR,D1
	CTL	D1			; the pad character translated
	MOVB	D1,(A1)+		; 4
	MOV	#0,D1			; we do not need an EOL this end.
	CHAR	D1
	MOVB	D1,(A1)+		; 5 end of line character
	MOV	#MYQUOT,D1
	MOVB	D1,(A1)+		; 6 control quoting character
; handle QBIN
	MOVB	QBIN(A0),D1		; get QBIN
	BEQ	40$			;  only quote on request
	CMPB	D1,#^O377		; is QBIN already defined?
	BNE	60$			;  yes, else
40$:	MOVB	#'Y,D1			; default to quoting on request
60$:	MOVB	D1,(A1)+		; 7 the optional binary quoter
	MOVB	DF.CHK(A0),(A1)+	; 8 the optional checkbyte type
	PARSIZ	=8.
	RTN


; FLUSH deletes all pending input from the input buffer
FLUSH:	MOV	REMOTE(A0),A5
10$:	TST	T.ICC(A5)		; more data?
	BEQ	20$			;  no, done
	TTYIN				; dump a byte
	BR	10$
20$:	RTN

; B U F F I L  -  fills a packet @A3 with data.
; we will limit data size to 3 less than actual size to allow the last
; character to be control and 8bit quoted, without look-ahead schemes.
; the worst cases are '# = &## and '& = &#&.
; data count goes to BUFCNT(A0).
; At entry, 	A3 must index the data packet area to be filled,
;		CHKNOW(A0) must contain the binary checkbyte size
BUFFIL:	CLR	D0
	MOVB	SPSIZ(A0),D0		; D0 gets max msg size to remote
	SUBB	CHKNOW(A0),D0		; less size of checkbyte
	SUB	#<3.>,D0		;  less overhead bytes	
	LEA	A1,DATA(A3)		; index the data area
10$:	CALL	INBYTE			; get a data byte
	TST	FIO+D.SIZ(A0)		; end of file ?
	BEQ	100$			;  yes
; test for high bit
	BTST	#7.,D1			;  no-test for eighth bit set.
	BEQ	30$			;   bit 7 is clear
; handle high bit prefixing, if any
	MOVB	QBIN(A0),D7		; get 8bit quote character.
	BMI	20$			;  no high bit can be used
	BEQ	30$			;  no 8 bit quoting needed!
	MOVB	D7,(A1)+		; buffer the 8bit quote
	SUB	#1,D0			; decrement the count
20$:	AND	#^O177,D1		; strip to ascii
30$:	MOVB	D1,D2		
	ANDB	#^O177,D2		; D2 gets stripped version
	CMPB	D2,#DEL			; is it a DEL
	BEQ	35$			;   this is non-printable.
; also prefix the prefix, and the high bit prefix with the prefix!
	CMPB	D2,QUOTE(A0)		; is this character the prefix?
	BNE	32$			;   no
	MOVB	D2,(A1)+		;   yes-prefix it with itself
	SUB	#1,D0
32$:	TSTB	QBIN(A0)		; check 8 bit quoting
	BLE	34$			;  none
	CMPB	D2,QBIN(A0)		; matching?
	BNE	34$			;  no-      [10/23/84 rpr]
	MOVB	QUOTE(A0),(A1)+		;  yes-quote it first
	SUB	#1,D0			; less one for quote
34$:	CMPB	D2,#SPACE		; is it control ?
	BHIS	50$			;  no-prinatble
; unctrol-ify the character, while preserving possible bit7.
35$:	CTL	D1			; uncontrol-ify
40$:	MOVB	QUOTE(A0),(A1)+
	SUB	#1,D0
50$:	MOVB	D1,(A1)+
	SUB	#1,D0
	BGT	10$			; loop till filled up
100$:	LEA	A6,DATA(A3)		; ptr to start of data
	MOV	A1,D1			; get ending ptr
	SUB	A6,D1			; D1 gets outgoing data size
	MOVB	D1,BUFCNT(A0)		; set data count
	RTN

; INBYTE gets a byte from a disk file. 
INBYTE:	TST	FIO+D.SIZ(A0)		; EOF already?
	BEQ	10$			;  yes, done
	FILINB	FIO(A0)			; get a byte from file
10$:	RTN

; close file if it is open.
CLOSER:	TSTB	FIO+D.OPN(A0)		; is file open?
	BEQ	10$			;  no
	CLOSE	FIO(A0)			;   yes-close the file
	CLRB	FIO+D.OPN(A0)		; and clear open code!
10$:	RTN


; B U F E M P  -  empties the incoming data contents of the packet @A3 to
; the FIO(A0) file.
BUFEMP:	LEA	A1,DATA(A3)		; index the data area
	CLR	D0
	MOVB	LDATA(A0),D0		; D0 gets the count
	BR	600$			; check for 0 bytes in packet [21]
10$:	CALL	GETBYT			; get an input byte [10/23/84]
; doing 8bit quoting?
	MOVB	QBIN(A0),D2		; get 8bit quote character
	BLE	100$			;  no binary quoting
	CMPB	D2,D1			; is it binary quote ?
	BNE	100$			;  no
; 8bit quote received. Evaluate following characters.
	MOV	#^O200,D3		; set high bit flag
	CALL	GETBYT			; get next byte
	CALL	EVALQ			; evaluate this & next chars
	ORB	D3,D1			; combine evaluated char & top bit
	BR	500$

100$:	CLR	D3			; clear high bit flag
	CALL	EVALQ			; evaluate
500$:	FILOTB	FIO(A0)			; output the data byte
600$:	TST	D0
	BGT	10$			; output all bytes
	RTN

; E V A L Q  - evaluates the byte in D1. Expands quoted control characters,
; quoted quotes, and eighth bit quotes and quoted eighth bit quotes.
EVALQ:	CMPB	D1,QUOTE(A0)		; is it a quote ?
	BNE	100$			;  no-just return with value
	CALL	GETBYT			;  yes - get next byte
	MOVB	D1,D7
	AND	#^O177,D7		; get stripped version of character
	CMPB	D7,QUOTE(A0)		; is it double qoute ?
	BEQ	100$			; yes-pass it literally
	TSTB	QBIN(A0)		; test for 8 bit quote active
	BLE	10$			;  no-sending binaries
	CMPB	D1,QBIN(A0)		; 8bit quote prefixed by ctl quote?
	BEQ	100$			;  yes-use literally.
10$:	CTL	D1			; turn it to control
100$:	RTN		

; G E T B Y T - gets the next data byte for BUFEMP.
GETBYT:	MOVB	(A1)+,D1		; get a byte	
	TSTB	QBIN(A0)		; allowing binaries?
	BEQ	10$			;  yes
	AND	#^O177,D1		;  no-strip to seven	
10$:	SUB	#1,D0			;  adjust count
	RTN

; R E C P A K  -  receives a data packet from the remote computer.
; This routine simply inputs a single packet, without performing
; packet checking or other details.
; On Entry,	A3 indexs the packet destination

; On exit,	D0 is the received checkbyte
;		D1 is the calculated checkbyte
;		D2 is the LEN
;		D3 is the SEQ
;		D4 is the TYPE
;		Z is set if a packet is received
; 		CHKNOW(A0) contains binary 1,2, or 3 for checkbyte size
RECPAK:	
; initialize packet receiver
	CALL	SETEND			; set timer ending time
	MOV	REMOTE(A0),A5		; index the remote TCB
10$:	CALL	GETREM			; get remote character
	JNE	100$			;  timeout, no data
; syncronize the packet to the mark byte (usually ^A)
	AND	#^O177,D1		; strip parity here, always
	CMPB	D1,RMARK(A0)		; start of packet ?
	BNE	10$			;  no-keep looking
20$:	MOV	A3,A1			; use A1 as work register.
	MOVB	D1,(A1)+		;  yes-store it
; get the length from the next byte
	CALL	GETREM			;   get LEN
	JNE	100$			; timeout, no data
	CMPB	D1,RMARK(A0)		; start of packet ?
	BEQ	20$			;  yes-resync.
	MOVB	D1,(A1)+		;  else save the LEN
	CALL	CLRSUM			; clear checkbytes
	CALL	ACCUM
	UNCHAR	D1			; convert to binary
	MOV	D1,D2			; save the LEN
; receive the SEQ byte
30$:	CALL	GETREM			;   get SEQ
	JNE	100$			; timeout, no data
	CMPB	D1,RMARK(A0)		; start of packet ?
	BEQ	20$			;  yes-resync.
	MOVB	D1,(A1)+		;  else save the SEQ
	CALL	ACCUM
	MOV	D1,D3
	UNCHAR	D3			; D3 is sequence #
; receive the TYPE byte
	CALL	GETREM			;   get TYPE
	JNE	100$			; timeout, no data
	CMPB	D1,RMARK(A0)		; start of packet ?
	BEQ	20$			;  yes-resync.
	MOVB	D1,(A1)+		;  else save the TYPE
	CALL	ACCUM			; update checkbyte
	MOV	D1,D4			; D4 gets the type
; calc the data area size.
	MOV	D2,D1			; D1 gets the binary length
	CALL	CALCHK			; calculate checkbyte size
	CLR	D0
	MOVB	CHKNOW(A0),D0		; get checkbyte size
	ADD	#2.,D0			; D0 gets size of SEQ,TYPE
	SUB	D0,D1			;  D1 gets size of data area
	MOVB	D1,LDATA(A0)		; save length of data
	MOV	D1,D0			; D0 gets length
	CMPB	D0,#95.-3.		; is it legal ?
	JHI	10$			;   no-toss it & try again
	BR	45$			; use DBF to control buffering of
					; 0 or more characters.
; buffer the data bytes
40$:	CALL	GETREM			; get a byte
	JNE	100$			;  timeout
	CMPB	D1,RMARK(A0)		; start of packet ?
	BEQ	20$			;  yes-resync.
	MOVB	D1,(A1)+		; store data
	CALL	ACCUM			; update checkbyte
45$:	DBF	D0,40$			;  gather packet.
; now get the checkbyte(s)
	CALL	GETREM			;   get CHECK
	JNE	100$			; timeout, no data
	CMPB	D1,RMARK(A0)		; start of packet ?
	JEQ	20$			;  yes-resync.
	UNCHAR	D1			; convert CHECK
	CLR	D0
	MOVB	D1,D0			; D0 gets checkbyte byte #1
	CMPB	CHKNOW(A0),#3.		; three character checkbyte?
	BNE	50$			;  no-leave CHECK type as normal
; handle 3 byte 16 bit CCITT reverse CRC here
	ANDB	#^B1111,D0		;  yes, mask 1st byte to 4 bits
	RORW	D0,#4.			; move 1st byte bits to B15-B12
	CALL	GETREM			;  and get second byte
	JNE	100$			;  receive data fault
	UNCHAR	D1			; convert it
	LSLW	D1,#6.			; shift 2nd byte to bits 11-6
	ORW	D1,D0			; D0 gets bits 11-0
	CALL	GETREM			;  yes- get 3rd byte
	JNE	100$			;  receive data fault
	UNCHAR	D1			; convert it
	ORW	D1,D0			; D0 gets complete checkbytes
	MOVW	FRMSUM(A0),D1		; D1 gets calculated CRC-ITT
	BR	90$
; handle 2 byte 12 bit checksum here
50$:	CMPB	CHKNOW(A0),#2.		; two character checkbytes?
	BNE	60$			;  no-leave CHECK type as normal
	CALL	GETREM			;  yes- get second byte
	JNE	100$			;  receive data fault
	UNCHAR	D1			; convert it
	LSL	D0,#6.			; shift 1st byte to bits 11-6
	ORW	D1,D0			; D0 gets bits 11-0
	MOVW	ASSUM(A0),D1		; D1 gets calculated ASSUM
	ANDW	#^B0000111111111111,D1	; mask it to 12 bits only
	BR	90$
; handle one byte 6 bit checksum here
60$:	CLR	D1
	MOVB	ASSUM+.B0W7(A0),D1	; {ok} get calculated sum
	MOV	D1,D7			;  twice
	LSRW	D7,#6.			; move bits 7-6 to 1-0
	ANDW	#3,D7			; toss all other bits
	ADDW	D7,D1			; add to sum
	ANDW	#^O77,D1		; strip to 6 bits.
90$:	TSTB	DEBUGO(A0)		; debug mode ?
	JEQ	95$			;  no
	PUSH	D1
	CLR	D1
	TYPE	<==Received Packet # >
	MOV	D3,D1				
	DCVT	2,OT$TRM!OT$TSP		; output as 2 characters
	TYPE	<, Type >	
	MOV	D4,D1
	TTY
	TYPE	< Length: >
	MOV	D2,D1
	DCVT	2,OT$TRM
	CRLF
	TYPE	<Checkbytes >	
	MOV	@SP,D1			; get calced sum
	CMPW	D0,D1			; do they match ?
	BNE	93$			;  no
	TYPE	<match (>
	DCVT	0,OT$TRM
	TYPE	<)>
	BR	94$

93$:	TYPE	<calculated = >
	DCVT	0,OT$TRM
	TYPE	<, received = >
	MOV	D0,D1
	DCVT	0,OT$TRM
94$:	CRLF
	CRLF
	POP	D1
95$:	TSTB	NOTALK(A0)		; are we showing crc errors?
	BNE	98$			;  no
	CMPW	D0,D1			; compare checkbytes
	BEQ	96$			;  no error
	TYPE	c
	BR	98$
; come here if packet is O.K. Check for NAK. If NAK, put n on screen
96$:	CMPB	D4,#'N			; was it a NAK?
	BNE	98$
	TYPE	n
98$:	CMPW	D0,D1			; compare checkbytes
	RTN

; come here on timeout while waiting for packets.
; show timeouts as t's if there is a user watching.
100$:	TSTB	NOTALK(A0)		; TCB owned by KERMIT job?
	BNE	110$			;  yes - do not type anything
	TYPE	<t>			;  no-go ahead & show user kermit
110$:	LCC	#0			; flag timeout
	RTN				;  



; S N D P A K  -  sends a packet.
; On Entry,	A3 indexs the packet destination
;		D2 is the LEN
;		D3 is the SEQ
;		D4 is the TYPE
; At exit,	CHKNOW(A0) contains the checkbyte size used.
SNDPAK:	TSTB	DEBUGO(A0)
	BEQ	30$
	TYPE	<Sending ">
	MOVB	D4,D1
	TTY
	TYPE	<" packet # >
	CLR	D1	
	MOVB	D3,D1
	DCVT	0,OT$TRM
	TYPE	< of length >
	MOVB	D2,D1
	DCVT	0,OT$TRM
	CRLF
	TYPE	<Data =">
	SAVE	A2,D0
	LEA	A2,DATA(A3)
	MOV	D2,D0
	SUB	#1,D0
	BMI	20$
10$:	MOVB	(A2)+,D1
	TTY
	DBF	D0,10$
20$:	REST	A2,D0
	TYPECR	<">
	CRLF
; send a packet to the remote KERMIT
30$:	MOV	REMOTE(A0),A5		; index remote TCB
	CLR	D0
	MOVB	PAD(A0),D0		; get pad count
	MOVB	PADCHR(A0),D1		; and pad character
	BR	50$
40$:	TTYOUT				; send the pad character
	CALL	STALL			; stall, if needed
50$:	DBF	D0,40$			; output pad chars while D0#0
	MOV	A3,A1			; A1 is work pointer
	MOVB	RMARK(A0),(A1)+		; buffer MARK character
	MOV	D2,D1			; D1 gets LEN
	CALL	CALCHK			; calculate checkbyte size
	ADDB	CHKNOW(A0),D1		; add size of checkbyte
	ADD	#2.,D1			; plus SEQ & TYPE
	CHAR	D1			; make it printable
	MOVB	D1,(A1)+		; store LEN	
	CALL	CLRSUM
	CALL	ACCUM			; update checkbyte & CRC
	MOV	D3,D1
	CHAR	D1
	MOVB	D1,(A1)+		; store SEQ
	CALL	ACCUM			; update checkbyte & CRC
	MOVB	D4,(A1)+		; store TYPE	
	MOVB	D4,D1
	CALL	ACCUM			; update checkbyte & CRC
; data (if any) is already in buffer. Add it to checkbyte
	CLR	D1
	BR	70$			
60$:	MOVB	(A1)+,D1		; get a byte
	CALL	ACCUM
70$:	DBF	D2,60$			; loop till all data checked
; handle checkbyte(s) translation
; [015] add code for three character CRC
75$:	CMPB	CHKNOW(A0),#3.		; three character checkbyte ?
	BNE	80$			;  no - try for two!
; three character checkbyte
	CLR	D1
	MOVW	FRMSUM(A0),D1		; get all bits
	CLR	D7
	MOVW	D1,D7			;  in two regs
	ROLW	D7,#4.			; position bits D15-D12
	ANDW	#^B1111,D7		; strip to 4 bits
	CHAR	D7			; make it printable
	MOVB	D7,(A1)+		; store D15-D12
	MOVW	D1,D7			;  in two regs
	LSRW	D7,#6.			; get bits D11-D6 in low 6
	ANDW	#^B111111,D7		; strip to 6 bits
	CHAR	D7			; make it printable
	MOVB	D7,(A1)+		; store D11-D6
	ANDW	#^B111111,D1		; strip to 6 bits
	CHAR	D1			; make it printable
	MOVB	D1,(A1)+		; store checkbyte bits D5-D0
	BR	100$

80$:	CMPB	CHKNOW(A0),#2.		; two character checkbyte ?
	BNE	90$			;  no - must be one character
; two character checkbyte
	MOVW	ASSUM(A0),D1		; get all bits
	MOV	D1,D7			;  in two regs
	LSR	D7,#6.			; position bits D11-D6
	AND	#^O77,D7		; strip to 6 bits
	CHAR	D7			; make it printable
	MOVB	D7,(A1)+		; store D11-D6
	AND	#^O77,D1		; strip to 6 bits
	CHAR	D1			; make it printable
	MOVB	D1,(A1)+		; store checkbyte bits D5-D0
	BR	100$

90$:	MOVB	ASSUM+.B0W7(A0),D1	; {ok} D1 gets low eight of sum
	MOV	D1,D7			; D7 gets same
	AND	#^O300,D7		; take just bits 7-6.
	LSR	D7,#6.			; shift to bits 1-0
	ADD	D7,D1			; D1 gets sum
	AND	#63.,D1			; make it six bits again.
	CHAR	D1			; make it prinatble
	MOVB	D1,(A1)+		; store checkbyte
; check for EOL character
100$:	MOVB	EOL(A0),D7		; remote need any EOL ?
	BEQ	110$			;  no
	MOVB	D7,(A1)+		;  yes-store it
; calculate size of buffered packet from pointer displacement
110$:	MOV	A1,D0			; current position
	SUB	A3,D0			;  less start is length
	SUB	#1,D0
120$:	MOVB	(A3)+,D1		; get a byte
	TTYOUT				; output it to REMOTE
	CALL	STALL			; stall ,if needed
	DBF	D0,120$			;  till packet is sent
	RTN

; O U T B Y T   - This routine outputs the byte in D1 to the remote.
OUTBYT:	MOV	REMOTE(A0),A5		; get TCB pointer for remote
	TTYOUT				; send the byte out
	RTN

; S T A L L - stalls a certain amount of time after output in progress
; is lowered. At entry, A5 must index the output TCB.
STALL:	TSTB	STLCHR(A0)		; do we need to stall?
	BEQ	20$			;  no
10$:	CTRLC	20$			; abort - CTS must be low
	TSTB	@A5
	BMI	10$			; wait for OIP to drop
	CLR	D7
	MOVB	STLCHR(A0),D7
	MUL	D7,#10000./100.		; transform to ticks
	SLEEP	D7
20$:	RTN

; SREMOT - send the A1 string to the remote
SREMOT:	MOV	REMOTE(A0),A5		;  index to remote TCB
10$:	MOVB	(A1)+,D1
	BEQ	100$
	CMPB	D1,#-1			; is it wait byte?
	BNE	20$			;  no
	SLEEP	#10000./2.		; yes, wait .5 seconds
	BR	10$		
20$:	TTYOUT
	BR	10$
100$:	RTN

; C A L C H K  -  determines the current checkbyte size.
; This routine unifies the logic needed to force 1 byte checkbytes on SEND-INIT
; fields and their ACKS.
; At entry,
;	D2 contains the LEN in binary
;	D4 contains the packet type
; At exit, CHKNOW(A0) contains the binary value of the current checkbyte size.
CALCHK:	CLR	D7
	MOVB	CHKT(A0),D7		; get checkbyte type
	SUBB	#'0,D7			;  less ASCII bias
; if NAK, we can deduce packet size from LEN
; this is useful if the 1st packet after changing checkbyte types is damaged.
; The other side will NAK, and we can recover the right length from the LEN
; of the NAK packet. (ACK packets may have filenames or discard info appended
; their size is not predictable.)
	CMPB	D4,#'N			; is it a NAK?
	BNE	10$			;  no- use selected type
	MOVB	D2,D6			;  yes-get LEN
	SUBB	#2.,D6			; less 2 gives checkbyte size
	CMPB	D6,#MAXCHK		; compare to largest supported type	
	BHI	30$			;  out of range - ignore bad advice	
	MOVB	D6,D7			; well
	ADDB	#'0,D6			; D6 gets character
	MOVB	D6,CHKT(A0)		; force proper check type
	BR	30$			; and set binary type as well
; handle all but NAKs here
10$:	TSTB	RIACK(A0)		; have we recv'd "S" packet? 
	BNE	30$			;  yes, use 
	MOV	#1,D7			;   no-force checkbyte type 1
30$:	MOVB	D7,CHKNOW(A0)		; save current checkbyte choice
	RTN

; G E T R E M  -  gets a single character from the remote computer. 
; At entry, A5 must index the REMOTE TCB
; At exit, D1 will contain the character, or a -1 for no character.
; Z will be set if a character was available for input.
GETREM:	MOV	#-1,D1			; preset for no data
	BR	20$
10$:	SLEEP	SLPVAL(A0)		; wait for more data [14]
; wait 1 character time for more date for higher throughput [14]
	CTRLC	100$
	GTIMEI	D7
	SUB	FUDGE(A0),D7		; less the fudge factor for wraparound
	CMP	D7,RTOUT(A0)		; EXPIRED?
	BGT	200$			;  YES
20$:	TST	T.ICC(A5)		; any data to input ?
	BEQ	10$			;  no input
	CLR	D1			; pre-clear D1
	TTYIN				; get a character
	TSTB	QBIN(A0)		; are we allowing 8 data bits?
	BEQ	30$			;  yes
	AND	#^O177,D1		;  no-strip parity bit
30$:	CMPB	D1,#3.			; control-c?
	BNE	40$			; no
	COMB	CCOUNT(A0)		; yes-toggle /2 counter
	BNE	50$			; only one detected
	JOBIDX
	ORW	#J.CCC,@A6		; two detected - set control-c flag
40$:	CLRB	CCOUNT(A0)		; clear control-c count
50$:	LCC	#PS.Z
	RTN
100$:	LCC	#0
	RTN
200$:	LCC	#PS.V			; flag overflow for timeout
	RTN

; S E T E N D  -  calculates and stores the value of the timeout point 
; in internal format.
SETEND:	CLR	FUDGE(A0)		; clear wrap-around value
	GTIMEI	D7			; D6 gets internal format time.
	ADD	TIMINT(A0),D7
	MOV	#24.*60.*60.,D6		; D6 gets highest internal time+1
	CMP	D7,D6
	BLO	10$ 			; o.k. - no wraparound
	SUB	D6,D7			; handle wrap-around
	MOV	D6,FUDGE(A0)		; set fudge factor to indicate
					; time wraparound
10$:	MOV	D7,RTOUT(A0)		; SET TIME-OUT TIME
	RTN


; G T S I Z E  -  gets file size in bytes. Destroys D6,D7. Assumes file 
; has been looked up on FIO(A0). FSIZE(A0) contains the size on exit.
GTSIZE:	MOV	FIO+D.SIZ(A0),D7	; D7 gets record size
	MOV	FIO+D.LEN(A0),D6	; D6 gets # of blocks
	TSTW	FIO+D.ACT+.W0L15(A0)	; random file ?
	BMI	10$			;  yep-straight multiply
	SUB	#2.,D7			;  no-subtract pointer bytes.
	TSTB	EXTEND(A0)		;  O/S support extended disks?
	BEQ	8$			;   no
	SUBW	FIO+D.FMT(A0),D7	;   yes, get extra link bytes (if any)
8$:	SUB	#1,D6			;  and less last block
10$:	MUL	D7,D6			; block payload size * blocks
	TSTW	FIO+D.ACT+.W0l15(A0)	; random file ?
	BMI	20$			;  yep.
	ADD	FIO+D.ACT(A0),D7	;  sequential-add last block's count
	SUB	#2.,D7			; less link word in last block
	TSTB	EXTEND(A0)		;  O/S support extended disks?
	BEQ	20$			;  no
	SUBW	FIO+D.FMT(A0),D7	;  yes, get extra link bytes (if any)
20$:	MOV	D7,FSIZE(A0)		; size of the file
	RTN

; send the user terminal a BELL if SET ALARM ON.
DINGEM:	TSTB	DING(A0)		; wake the user up?
	BEQ	20$			;  no
	TTYI				;  yes
	BYTE	A.BEL,0
	EVEN
20$:	RTN


; S T A R T T  - gets the current time and saves it in STIME(A0).
; Used to determine the elapsed time in file transfers.
STARTT:	GTIMEI	STIME(A0)		; save the start time
	RTN

; E N D T M  - calculate and display the elapsed time & effective baud rate
; for a file transfer.
; At entry, FSIZE must contain the file size in bytes.
ENDTM:	TSTB	NOTALK(A0)		; do we have a user terminal?
	BNE	30$
	TSTB	ABORTF(A0)		; file aborted?
	BNE	40$
	GTIMEI	D2			; get current time
	SUB	STIME(A0),D2		; less start time
	BCC	10$			;  no midnight wraparound
	ADD	#24.*60.*60.,D2		;  else add 24 hours of seconds [14]
10$:	ADD	D2,TTIME(A0)		; add to total time
	MOV	FSIZE(A0),D7
	ADD	D7,TBYTES(A0)		; accum total bytes
	INC	TFILES(A0)		; accum total files
	MOV	D2,D4			; save for effective baud rate
	MOV	FSIZE(A0),D3		; get characters
	CRLF
	CALL	ELAPSE
30$:	RTN
40$:	CRLF
	TYPECR	<File transfer interrupted.>
	RTN

STATS:	TSTB	NOTALK(A0)
	BNE	100$			; no user to talk to
	TYPE	<A total of>
	MOV	TBYTES(A0),D1
	DCVT	0,OT$TRM!OT$TSP!OT$LSP
	TYPE	<byte>
	CALL	PLURAL
	TYPE	< in>
	MOV	TFILES(A0),D1
	DCVT	0,OT$TRM!OT$TSP!OT$LSP
	TYPE	<file>
	CALL	PLURAL
20$:	TYPECR	< transferred.>
	CMP	D1,#1
	BLOS	100$			; show cumulative effect for <1 file
	MOV	TBYTES(A0),D3		; get characters
	MOV	TTIME(A0),D2		; get seconds
	TYPE	<Total >
	CALL	ELAPSE
100$:	RTN

; PLURAL - print an "s" if D1 is not 1.
PLURAL:	CMP	D1,#1	; is it singular?
	BEQ	20$	;  yes
	TYPE	<s>	; no, plural
20$:	RTN

	
; ELAPSE displays the elapsed time & baud rate
; At entry, D2 contains the time, and D3 contains the number of bytes xferred
; trashes D4,D1,D6,D7,A6
ELAPSE:	TYPE	<elapsed time was >
	CLR	D1
	MOV	D2,D4
	DIV	D4,#60.*60.		; convert to hours
	MOVW	D4,D1
	DCVT	2,OT$TRM!OT$ZER		; display hours
	TYPE	:
	CLRW	D4
	SWAP	D4			; remainder to lower 16 bits
	DIV	D4,#60.			; make it minutes
	MOVW	D4,D1
	DCVT	2,OT$TRM		; display minutes
	TYPE	:
	CLRW	D4
	SWAP	D4			; seconds remiander to low 16
	MOV	D4,D1
	DCVT	2,OT$TRM		; display seconds
	TST	D2			; were seconds 0?
	BEQ	20$			;  baud rate is infinite!
	TYPE	<, effective baud rate was >
	MOV	D3,D1
; multiply by 10 by adding 2*D1 and 8*D1
	MOV	D1,D7			; duplicate
	ADD	D1,D1			;  double
	LSL	D7,#3.			;   shift to make 8* old D1
	ADD	D7,D1			;    add to make 10 * old D1
	DIV	D1,D2			;  divided by seconds
	AND	#^O177777,D1		; strip off remainder
	DCVT	0,OT$TRM		; display it
20$:	TYPECR	<.>			; new line
30$:	RTN


; S H O E S C  displays the current escape from connect mode character.
SHOESC:	TYPE	<Escape character is >
	MOVB	KMETA(A0),D1
	CALL	SHOCHR
	CRLF
	RTN

; S H O C H R  -  displays in printable form the character in D1.
SHOCHR:	PUSH	D1
	TSTB	CMASK(A0)		; 7 or 8 bit terminal?
	BMI	10$			;  terminal is 8 bits!
	BTST	#7.,D1
	BEQ	10$
	TYPE	<%>
	BR	15$
10$:	TYPE	< >
15$:	ANDB	CMASK(A0),D1
	CMPB	D1,#DEL
	BNE	18$
	TYPE	DEL
	BR	50$
18$:	CMPB	D1,#SPACE
	BHIS	20$
	PUSH	D1
	MOVW	#177400!11.,D1
	TCRT
	TYPE	^
	MOVW	#177400!12.,D1
	TCRT
	POP	D1
	CTL	D1			; un-controlify it
	BR	30$
20$:	TYPE	< >
30$:	TTY	
50$:	POP	D1
	RTN

; show the notice & title & version
KERTTL:	TTYL	TITLE		; show the title
; show the program name & version
KERVER:	TTYL	TITL2
	VCVT	KERMIT+PH.VER,OT$TRM	; show the version #
	CRLF
	RTN

; S H O D O T  - print a dot on user's terminal whenever a packet has been
; sent or recvd. (But don't do it when using user's terminal for I/O.)
SHODOT:	TSTB	NOTALK(A0)		; TCB owned by KERMIT job?
	BNE	10$			;  yes - do not type dot!
	TYPE	<.>			;  no-go ahead & show user kermit
10$:	RTN				;  is working

; initialize wildcarder
PREBAT:
	ORB	#D$BYP!D$ERC,FIO+D.FLG(A0) ; bypass error messages
	CLRB	ABORTB(A0)		; clear batch abort flag
	CLR	TFILES(A0)
	CLR	TBYTES(A0)
	CLR	TTIME(A0)		; clear total stat amounts
	MOV	A2,SAVSPC(A0)		; save user's file spec
	CLR	CMDPTR(A0)		; clear ptr to CMDLIN.SYS
	CLR	CMDERR(A0)		; clear CMDLIN error value
	CLRB	NXTCNT(A0)		; pre-clear # of times GETNXT called
	TSTB	WILDOK(A0)		; O.K. to use wildcarding?
	JEQ	100$			;  no, don't even try!
	LEA	A2,CMDLNS
	FSPEC	CLDDB(A0)		; load the DDB
; fetch or find CMDLIN.SYS module - often in system memory
	FETCH	CLDDB(A0),A6		; find or fetch it
	BNE	100$			;  not found
	MOV	A6,CMDPTR(A0)
	SAVE	A0,A5
	 LEA	A5,CMDIMP(A0)
	 MOV	CMDPTR(A0),A6	
	 MOV	A6,D7
	 ADD	#PH.SIZ,A6
; set up CMDLIN's internal ptrs in our impure area
	 MOV	(A6)+,CMINI$(A5)	; CMINI offset
	 MOV	(A6)+,CMNXT$(A5)	; CMNXT offset
	 MOV	(A6)+,CMQRY$(A5)	; CMQRY offset
	 MOV	(A6)+,CMCMP$(A5)	; CMCMP offset
	 MOV	(A6)+,CMSKP$(A5)	; CMSKP offset
	 MOV	(A6)+,CMFSP$(A5)	; CMFSP offset
	 ADD	D7,CMINI$(A5)		; CMINI address
	 ADD	D7,CMNXT$(A5)		; CMNXT address
	 ADD	D7,CMQRY$(A5)		; CMQRY address
	 ADD	D7,CMCMP$(A5)		; CMCMP address
	 ADD	D7,CMSKP$(A5)		; CMSKP address
	 ADD	D7,CMFSP$(A5)		; CMFSP address
; now init CMDLIN	
	 MOV	SAVSPC(A0),A2		; user's spec
	 LEA	A0,DFAULT		; default spec
	 CLR	D7			; operation flags
	 .CMINI
	REST	A0,A5			; restore regs CMDLIN uses
	MOV	D6,CMDERR(A0)		; save CMDLIN error, if any
	SETB	CMDFLG(A0)		; flag we have CMDLIN.SYS
100$:	MOV	SAVSPC(A0),A2
	RTN


; wildcard next spec routine
; handles a single spec if CMDLIN.SYS is not available.
; 	V set if end of spec 
GETNXT:
	PUSHB	FIO+D.FLG(A0)		; save flags
	 PUSH	FIO+D.BUF(A0)		; save buffer address (if any)
	  CLEAR	FIO(A0),D.DDB		; clean the ddb for re-use
	 POP	FIO+D.BUF(A0)		; 
	POPB	FIO+D.FLG(A0)		; restore buffer address & flags
	CLRB	ABORTF(A0)		; clear abort file flag
	TSTB	CMDFLG(A0)		; do we have CMDLIN?
	BNE	10$			;  yes
	TSTB	NXTCNT(A0)		;  no, bump count
	JNE	60$			;  done	
	INCB	NXTCNT(A0)
	MOV	SAVSPC(A0),A2
	ORB	#D$BYP!D$ERC,SIO+D.FLG(A0) ; bypass error messages
	FSPEC	SIO(A0),LST
	BR	20$			; transfer

; handle file request via system wildcarder.
10$:	MOV	SAVSPC(A0),A2		; index the spec
	PUSH	A5
	 LEA	A5,CMDIMP(A0)		; index CMDLIN impure ptr
	.CMNXT	SIO(A0)			
	 MOV	D7,CMNEXT(A0)
	POP	A5
	MOV	A2,SAVSPC(A0)		; save the spec
	MOV	CMNEXT(A0),D7		; get the flags
	AND	#NX$END,D7		; end of specs?
	JNE	60$			;  yes-end
; handle /Q logic if not invoking send remotely
	TSTB	NOTALK(A0)		; invoked remotely?
	BNE	20$			;  yes, no user to query
	PFILE	SIO(A0)
	SAVE	A5
	 LEA	A5,CMDIMP(A0)		; index CMDLIN impure ptr
	.CMQRY				; ask user
	REST	A5
	BEQ	10$			;  user didn't want to send that file
20$:
; copy filespec to working ddb
	MOVW	SIO+D.DEV(A0),FIO+D.DEV(A0)
	MOVW	SIO+D.DRV(A0),FIO+D.DRV(A0)
	MOV	SIO+D.FIL(A0),FIO+D.FIL(A0)
	MOVW	SIO+D.EXT(A0),FIO+D.EXT(A0)
	MOVW	SIO+D.PPN(A0),FIO+D.PPN(A0)
	MOV	SIO+D.CPU(A0),FIO+D.CPU(A0)
	CALL	GFILNM			; process the filename
	INIT	FIO(A0)
	LOOKUP	FIO(A0)			; does the file exist?	
	BEQ	30$			;  yes-ok, proceed
	NEGB	FIO+D.ERR(A0)		; normalize error code
	BR	50$			; and exit
30$:	TSTW	FIO+D.ACT+.W0L15(A0)	; random file ?
	BPL	40$			;  no
	TSTB	NOTALK(A0)		;   yes-we dont do these!
	BNE	34$			;    no user to show!
	TYPE	<%Bypassing random file >
	PFILE	FIO(A0)
	CRLF
34$:	JMP	10$			; skip the random file

40$:	OPENI	FIO(A0)			; open for input
50$:	MOV	#1,D7			; cheap LCC #0
	BR	70$
60$:	LCC	#PS.V			; end of spec
70$:	RTN

; clear the checkbytes
CLRSUM:	CLRW	ASSUM(A0)		; clear checksum
	CLRW	FRMSUM(A0)		; and clear CRC
	RTN

; accumulate the checksum & CRC
ACCUM:	PUSH	D1
	AND	#^H0FF,D1
	ADDW	D1,ASSUM(A0)		; handle 1 & 2 byte sums
	CALL	CCITT			; handle 3 byte CRC
	POP	D1
	RTN

;	x^16+x^12+x^5+1 REVERSE!!!!!
; Routine to calculate CCITT CRC for byte in D1.
; this routine breaks down the task into two nibble operations.
; based on C routine by andy lowry of columbia university. 
; See page 257 of Da Cruz book.
CCITT:	SAVE	D2,D4,D7
	MOVW	FRMSUM(A0),D4		; get remainder bits
	ANDW	#^H0FF,D1		; mask to 8 bits
	XORB	D4,D1			; combine
	MOVW	D1,D2			; copy
	RORW	D2,#4.			; move bits 7-4 to 3-0
	ANDW	#^B1111,D2		; strip to a nibble
	ANDW	#^B1111,D1		; strip to a nibble
	LSLW	D2,#1
	LSLW	D1,#1			; make them word offsets
; NOTE THAT [~Dx] IS OK SINCE D1 & D2 ARE STRIPPED TO A NIBBLE!
; (got to watch sign extend on word ops!)
	MOVW	CRCTB2[~D1],D1
	MOVW	CRCTAB[~D2],D7
	XORW	D7,D1
	RORW	D4,#8.			; get old B15-B8 in lo 8
	ANDW	#^O377,D4
	XORW	D1,D4			; xor in new bits
	MOVW	D4,FRMSUM(A0)		; store CRC
	REST	D2,D4,D7
	RTN

; Data tables for CRC-CCITT generation
CRCTAB:	word	0
	word	10201
	word	20402
	word	30603
	word	41004
	word	51205
	word	61406
	word	71607
	word	102010
	word	112211
	word	122412
	word	132613
	word	143014
	word	153215
	word	163416
	word	173617

CRCTB2:	word	0
	word	10611
	word	21422
	word	31233
	word	43044
	word	53655
	word	62466
	word	72277
	word	106110
	word	116701
	word	127532
	word	137323
	word	145154
	word	155745
	word	164576
	word	174367




IMPNAM:	RAD50	/KERMITIMP/		; name of user's variables module.

; This table defines the KERMIT commands and the subroutine address
DEFINE	KCOM	NAME, KSIZE, ADDR, HELP
	WORD	10$$-.
	BYTE	KSIZE
	ASCII	/NAME/
	BYTE	0
	EVEN
	ASCII	/HELP/
	BYTE	0
	EVEN
10$$:	WORD	ADDR-.
	ENDM

; K E R C O M   is the main commands table for KERMIT.
KERCOM:	
KCOM	AMOS,1,AMOS,<Execute an AMOS command.>
KCOM	CONNECT,1,CONNEC,<Connects your terminal to the remote KERMIT site.>
KCOM	EXIT,1,GOODBY,<Exit from KERMIT to AMOS.>
KCOM	HELP,1,HELP,<Types a summary of KERMIT commands and what they do.>
KCOM	RECEIVE,1,RECEIV,<RECEIVE {filespec} receives one or more files from the remote KERMIT.>
KCOM	SEND,1,SEND,<SEND {filespec} sends one or more files to remote KERMIT.>
KCOM	SET,3,SET,<Set controls options: enter SET ? for more help.>
KCOM	SHOW,2,SHOW,<Show displays the current SET options.>
KCOM	?,1,HELP,<The shorthand version of HELP.>
	WORD	0

; S E T C O M  is the SET subcommands table for SET.
SETCOM:	
KCOM	AUTORECEIVE,5,AUTREC,<RECEIVE command automatically sends KERMIT & SEND to remote Kermit.>
KCOM	AUTOSEND,5,AUTSND,<SEND command automatically sends KERMIT & RECEIVE to remote Kermit.>
KCOM	BELL,2,BELL,<Beep after each file transfer.>
KCOM	BLOCKCHECK,2,BLOCK,<Block-check type: 1, 2, or 3 check bytes.>	
KCOM	DEBUG,2,DEBUG,<Debug option ON or OFF.>
KCOM	DUPLEX,2,DUPLEX,<Set FULL or HALF duplex.>
KCOM	ENDLINE,2, ENDLIN,<Packet terminator character.>
KCOM	ESCAPE,2,ESCAPE,<Escape character for CONNECT.>
KCOM	PACKETSIZE,8.,PAKMAX,<Maximum packet size.>
KCOM	PACKETSTART,8.,PAKMRK,<Packet starting character.>
KCOM	PARITY,2,SETPAR,<Denote parity type for NON-alpha remotes.>
KCOM	RETRIES,1,NEWTRY,<Number of failed packet attempts that cause abort.>
KCOM	STALL,1,STLVAL,<Number of hundreths of seconds to pause between characters.>
KCOM	TIMEOUT,1,TIMER,<Packet time-out value in seconds.>
	WORD	0

; This table defines the GETOPT list for options arguments.
DEFINE	OPT	NAME, KSIZE, VALUE
	WORD	10$$-.	; offset to next entry
	BYTE	KSIZE	; # of unique bytes in entry
	ASCII	/NAME/	; entry text
	BYTE	0	; terminator
	EVEN		; word oriented table
10$$:	WORD	VALUE	; associated value
	ENDM

; This defines the format of the end of the options list.
DEFINE	OMSG	STRING
	WORD	0
	ASCII	/STRING/
	BYTE	0
	ENDM

; options list for logical options (YES, NO, 1,0, TRUE, FALSE are valid)
ONOFF:
YESNO:	OPT	YES,1,377
	OPT	NO,1,0
	OPT	ON,2,377
	OPT	OFF,2,0
	OPT	TRUE,1,377
	OPT	FALSE,1,0
	OPT	1,1,377
	OPT	0,1,0
	OMSG	<%Use YES or NO, ON or OFF, TRUE or FALSE, 1 or 0.>
	EVEN	

; options list for block check size
ONE23:	OPT	1,1,'1
	OPT	2,1,'2
	OPT	3,1,'3
	OPT	ONE,1,'1
	OPT	TWO,2,'2
	OPT	THREE,2,'3
	OPT	III,3,'3
	OPT	II,2,'2
	OPT	I,1,'1
	OMSG	<%Use 1, 2, 3, ONE ,TWO, THREE, I, II, III to set check value size.>
	EVEN

; list of valid parity settings, so you can't set parity George, but you
; can set parity Mark.
PARLST:	OPT	NONE,1,'N
	OPT	EVEN,1,'E
	OPT	ODD,1,'O
	OPT	MARK,1,'M
	OPT	SPACE,1,'S
	OPT	YES,1,'Y
	OMSG	<%Use None, Even, Odd, Mark, or Space.>
	EVEN

; options for echoplex (see DUPLEX:)
EPLEX:	OPT	FULL,1,0
	OPT	HALF,1,377
	OMSG	<%Use FULL or HALF to set duplex options.>
	EVEN


; S W C A S E - macro to define the switcher state table
DEFINE	SWCASE	STATE, ROUTE
	BYTE	STATE
	EVEN
	OFFSET	ROUTE
	ENDM

; S W S T A T  is the table of valid SEND FILE states for KERMIT,
; and the offsets to the corresponding next routines.
SWSTAT:	SWCASE	'S,SINIT
	SWCASE	'F,SFILE
	SWCASE	'D,SDATA
	SWCASE	'Z,SEOF
	SWCASE	'B,SBREAK
	SWCASE	'C,COMPLT
	SWCASE	'A,ABORT
	BYTE	0

	EVEN

; R C S T A T  is the table of valid RECEIVE FILE states for KERMIT,
; and the offsets to the corresponding next routines.
RCSTAT:	SWCASE	'R,RINIT			; receive init
	SWCASE	'F,RFILE			; receive file
	SWCASE	'D,RDATA			; receive data
	SWCASE	'C,RCOMP			; receive complete
	SWCASE	'A,RABOR			; receieve abort
	BYTE	0



HLP1:	ASCII	/          ========== Alpha-Kermit help ==========/
	BYTE	CR,CR,0	

ABTTTL:	ASCII	/KERMIT aborting with the following error from REMOTE host:/
	BYTE	CR,0

; tables for GETOPT subroutine

DEFINE	OPT	CHAR,CODE = BYTE	CHAR,CODE


SET1:	ASCII	/ SET allows you to change the following parameters./
	BYTE	CR,CR,0

NONONO:	ASCII	/%You cannot CONNECT to your own terminal!/
	BYTE	CR
	ASCII	/You must specify the communications port name when KERMIT is invoked:/
	BYTE	CR
	ASCII	/     e.g.  KERMIT MODEM uses the MODEM communications port./
	BYTE	CR,0

TITLE:
	ASCII	'Copyright 1984, 1994 Robert P. Rubendunst.'
	BYTE	CR	
	ASCII	'Alpha-Kermit by Soft Machines.'
	BYTE	CR
	ASCII	'Permission is granted to use this software at no charge'
	BYTE	CR
	ASCII	'provided that this message is not changed or deleted from'
	BYTE	CR
	ASCII	'any copy of this software.'
	BYTE	CR,0


	DEFINE	TEXT	ARG
	ASCII	~ARG~
	BYTE	CR
	ENDM
USAGE:
	BYTE	CR,CR
	TEXT	<Usage: KERMIT  {communications-port}>
	BYTE	CR
	TEXT	<   NOTE: KERMIT has two modes of operation - Local and Remote!>
	BYTE	CR
	TEXT	<   LOCAL mode supports serial communications and file transfers through>
	TEXT	<   a separate communications port, e.g. MODEM1.>
	TEXT	<   For LOCAL mode, enter KERMIT and the name of the communications port,>
	TEXT	<   and then a carriage return, e.g. KERMIT MODEM1.>
	BYTE	CR
	TEXT	<   REMOTE mode is used to support only file transfers for REMOTE users,>
	TEXT	<   e.g. PC users signed on to the Alpha Micro.>
	TEXT	<   REMOTE mode uses the same port for commands and file transfers.>
	TEXT	<   For REMOTE mode, just enter KERMIT and return.>
	BYTE	CR,CR
	TEXT	<KERMIT will display the prompt Alpha-Kermit> if you have selected LOCAL mode,>
	TEXT	<or REMOTE Alpha-Kermit if you have selected REMOTE mode.>
	BYTE	0

CUSAGE:
	BYTE	CR
	TEXT	<You are now communicating with whatever device is connected>
	TEXT	<to the serial port (e.g. your modem, or another system.)>
	TEXT	<Data received by the serial port will be displayed on this screen.>
	TEXT	<Until you press the special escape character, all of your keypresses>
	TEXT	<will be sent out of the serial port.>
	TEXT	<Pressing the escape character returns you to Alpha-Kermit's command mode.>
	BYTE	CR
	TEXT	<If you are using a modem, your terminal is now "connected">
	TEXT	<to the modem. Consult your modem manual for instructions on>
	TEXT	<dialing, hanging up, changing modem settings, etc.>
	BYTE	CR
	TEXT	<Special tips for most modem users:>
	TEXT	<  Before dialing, enter the characters ATE1Q0 and a return,>
	TEXT	<  even though your keypresses may not be echoed on the screen.>
	TEXT	<  Before exiting CONNECT, enter ATE0Q1 and a return!>
	BYTE	CR
	TEXT	<Have fun!>
	BYTE	CR,CR,0

; string that SEND command sends to remote Kermit to automatically get it
; ready to receive data.
PRESND:	ASCII	"KERMIT"
	BYTE	CR,-1
	ASCII	"RECEIVE"
	BYTE	CR,0
; string that RECEIVE command sends to remote Kermit to automatically get it
; ready to send data.
PREREC:	ASCII	"KERMIT"
	BYTE	CR,-1
	ASCII	"SEND "	; note no CR - RECEIVE will send the filespec later!
	BYTE	0
; show command strings
SH1.0:	ASCIZ	"Modem Port: "
SH2.0:	BYTE	CR
	TEXT	<             SET Options>
	ASCIZ	" Autoreceive:  "
SH2.1:	ASCIZ	"      Autosend:  "
SH2.2:	BYTE	CR
	ASCIZ	"        Bell:  "
SH2.3:	ASCIZ	"    Blockcheck:    "
SH2.4:	BYTE	CR
	ASCIZ	"       Debug:  "
SH2.5:	ASCIZ	"        Duplex: "
SH2.6:	ASCIZ	"        Escape:  "
SH2.7:	BYTE	CR
	ASCIZ	" Packet Size: "
SH2.7A:
	ASCIZ	"  Packet Start:  "
SH2.8:	BYTE	CR
	ASCIZ	"      Parity:  "
SH2.8A:	ASCIZ	"       Retries: "
SH2.9:	BYTE	CR
	ASCIZ	"       Stall: "
SH2.9A:	ASCIZ	"/100   Timeout: "
SH3.0:	BYTE	CR
	TEXT	<Received or Default Packet Parameters>
	ASCIZ	"  Blockcheck:    "
SH3.1:	ASCIZ	"    8Bit Quote: "
SH3.2:	BYTE	CR
	ASCIZ	"     Endline: "
SH3.3:	ASCIZ	"  Maximum Size: "
SH3.4:	BYTE	CR
	ASCIZ	"   Pad Count:   "
SH3.5:	ASCIZ	"     Pad Value:  "
SH3.6:	BYTE	CR
	ASCIZ	"     Timeout: "
SH3.8:	BYTE	CR,CR,0
	
SH.DAS:	ASCIZ	"------"
SH.OFF:	ASCIZ	"OFF"
SH.ON:	ASCIZ	" ON"
SH.FUL:	ASCIZ	"FULL"
SH.HAL:	ASCIZ	"HALF"
SH.ZIP:	ASCIZ	"NONE"
NOSET:	BYTE	CR
	ASCII	/%Kermit cannot change the communications port parity, but setting is noted./
	BYTE	CR,0
TITL2:	BYTE	CR
	ASCII	'Alpha-Kermit version '
	BYTE	0
CMDLNS:	ASCIZ	"DSK0:CMDLIN.SYS[1,4]"
DFAULT:	ASCIZ	"*.*"
NMTN:	ASCII	"?No matching terminal name"
	BYTE	CR,0
RENTER:	ASCII	"Note: Kermit session already in progress - new port name ignored."
	BYTE	CR,A.BEL,0
	EVEN

	END END END
				  Glossary
JCB - Job Control Block. Used to access & control job related resources
TCB - Terminal control block. Used to access & control terminal resources

			     Kermit Packet Types
Type	Name		Function
----	------------	-----------------------------------------------------
S	Send-Init	Sends local Kermit Parameters to remote Kermit
Y	Acknowledge	Receiver verifies reception of packet
Y	(Acknowledge)	Returns Kermit parameters to instigating Kermit
F	File Header	Contains name of file to be transferred
D	File Data	Contains a portion of the data file contents
Z	End of File	Signals receiver that all data file contents sent
B	Break		Signals receiver to conclude file transfer (batch)
N	Negative Ack.	Signal that receiver didn't get or like last packet
E	Fatal Error	Signal that other Kermit cannot proceed normally

ALPHA MICRO KERMIT

Program:		Bob Rubendunst (Soft Machines)
Language:		M68 (Alpha Micro 68000 assembler)
Documentation:		Karen Bojda (Soft Machines)
Version:		2.0(24)
Date:			March 16, 1994

Alpha-Kermit capabilities at a glance:
	Local operation:		Yes
	Remote operation:		Yes
	Login scripts:			No
	Transfer text files:		Yes
	Transfer binary files:		Yes
	Wildcard send:			Yes
	File transfer interruption:	No
	Filename collision avoidance:	No
	Can time out:			Yes
	8th bit prefixing:		Yes
	Repeat count prefixing:		No
	Alternate block checks:		Yes
	Terminal emulation:		Yes (Dumb or native terminal)
	Communications settings:	Duplex
	XON/XOFF:			No
	Transmit BREAK:			No
	IBM mainframe communications:	No
	Transaction logging:		No
	Session logging:		No
	Debug Logging:			No
	Packet logging:			No
	Act as server:			No
	Talk to server:			No
	Advanced server functions:	No
	Local file management:		No
	Command/Init files:		No
	Key redifinition/macros:	No
	File attributes packets:	No
	Command macros:			No
	Raw file transmit:		No
	Long packets:			No
	Sliding windows:		No