.enabl	lc
.nlist	bex,ttm
.title	HHCSPR handles file protocol
.globl	crlf,fbuff,lccvt,remote,send,ttyin,free,sndlin,dext,errwd
.globl	csstat,csexec,escflg,exeflg,csinit
.globl	bufc,errflg,tsxflg
.mcall	.close,.csispc,.enter,.fetch,.lookup
.mcall	.print,.purge,.readw,.ttyout,.writw
.macro doit char,where,?x
	cmpb	r0,char
	bne	x
	jmp	where
x:
.endm
;	The following are used for CSEXEC transfer
cr=15	;carriage return
lf=12	;line feed
errwd=52
NAK=25	;Abort/end transfer
DLE=20	;Transparancy flag
SOH=1	;Start of text
ETX=3	;End of text
EOT=4	;End of transmission
CTRLC=3	;Control C

;	CSEXEC Status word flags

TFTYPE=1	;0=ASCII transfer, 1=Binary Transfer
TRNSFR=2	;1=Data transfer in progress
ESCFLG=4	;1=Escape sequence in progress
EOTFLG=10	;1=EOT received
MSKFLG=20	;0=Ok to mask, 1=do not mask
EXEFLG=40	;1=Executive mode enabled

CSCHAN=5	;CSEXEC channel
;*****************************************************
;Process CSEXEC escape sequences here
CSEXEC:	BIC	#ESCFLG!TRNSFR,CSSTAT	;Clear escape & transfer bits
	CLR	ERRFLG		;Clear error flag
	call	HOSTIN		;Get character from host
	BCS	4$		;Abort?
	doit	#'I,sndid	;Send ID string?
	doit	#'A,mntran	;Initialize for data transmission?
4$:	JMP	ABORT		;Else abort the sequence
;*****************************************************
;Initialize for CSEXEC data transfer
MNTRAN:	.PRINT	#MSGO		;Tell user we are initializing
	MOV	#'0,RECNBR	;Init record number
	call	GET1		;Get a command line
	BCS	6$		;Abort?
	CMPB	1(R3),#'A	;ASCII transfer?
	BEQ	2$		;Yes, continue
	BIS	#TFTYPE,CSSTAT	;Else set Binary transfer
2$:	CMPB	(R3),#'U	;Upload?
	BNE	4$		;no
	JMP	UPLOAD		;Else go do upload
4$:	CMPB	(R3),#'D	;Download?
	BNE	6$		;No, abort
	JMP	DNLOAD		;Else go do download
6$:	JMP	ABORT		;Abort
;*****************************************************
;Routine to pharse filespec
PHARSE:	BIS	#TRNSFR,CSSTAT	;We are transferring now
	MOV	CSBUFF,R3	;Point to buffer
	TST	(R3)+		;Point to filespec
	MOV	FBUFF,R1	;Point to CSI buffer
2$:	CMPB	(R3),#CR	;End of filespec?
	BEQ	4$
	MOVB	(R3)+,(R1)+	;Move byte into buffer
	BR	2$
4$:	MOVB	#'=,(R1)+	;Finish filespec
	CLRB	(R1)
	MOV	SP,R2		;Save stack
	.CSISPC	OUTSP,#DEXT,fbuff	;process filename
	MOV	R2,SP		;Restore stack
	BCC	8$		;Error?
	.PRINT	#MSG9		;Yes, tell user
6$:	SEC			;Set abort flag
	return			;and return
8$:	MOV	FREE,R0		;Get current free area
	.FETCH	R0,OUTSP	;Load handler
	BCC	10$		;Error?
	.PRINT	#MSG1		;Yes, fetch error
	BR	6$		;Abort transfer
10$:	MOV	R0,FREE		;Update free area
	.PURGE	#CSCHAN		;Clear channel first
	tst	tsxflg
	bne	15$
	MOV	@#54,R0		;Force directory read
	CLR	256(R0)		;So we can interchange disks
15$:	CLC			;Clear abort flag
	return
;*****************************************************
;Routine to handle downloading
DNLOAD:	.PRINT	#MSGL		;Download message
	call	PHARSE		;Pharse filespec
	BCC	2$		;Error?
	JMP	ABORT		;Yes, abort it
2$:	.LOOKUP	#CSAREA,#CSCHAN,OUTSP	;See if file exists
	BCS	6$		;No, you can open it ok
	.PRINT	#MSGQ		;Else ask user what to do
	.PURGE	#CSCHAN		;Purge channel first
4$:	call	TTYIN		;Get input
	BCS	4$
	call	LCCVT		;Upper case only
	.TTYOUT			;Echo the response
	call	CRLF		;CR/LF for formatting
	CMPB	R0,#'S		;Supercede?
	BEQ	6$		;Yes
	JMP	ABORT		;Else abort transfer
6$:	MOV	OUTSP,R1	;Get filesize (if any)
	mov	8.(r1),r1
	.ENTER	#CSAREA,#CSCHAN,OUTSP,R1	;Open the file
	BCC	10$		;Error?
8$:	.PRINT	#MSG2		;File open error
	.PURGE	#CSCHAN		;Dump channel
	JMP	ABORT		;and abort transfer
10$:	TST	R0		;No room for file [TSX only]
	BEQ	8$		;Yes, open error
	MOV	R0,CSMAX	;Save size of file
	MOV	BUFC,CSPNT	;Set up buffer pointer
	MOV	#512.,CSCHR	;Character count
	CLR	CSBLK		;Block count
DOWN1:	call	GETBLK	;Get a checksummed block of data
	BCC	2$
	INC	ERRFLG		;Set error flag
	BR	10$		;And attempt to close file
2$:	BIT	#EOTFLG,CSSTAT	;End of transmission?
	BNE	10$		;Yes, wrap it up
	MOVB	(R3)+,@CSPNT	;Move character into buffer
	INC	CSPNT		;Increment pointer
	DEC	CSCHR		;Block full?
	BNE	8$		;No, continue
	.WRITW	#csAREA,#CSCHAN,BUFC,#256.,CSBLK
	BCC	4$		;Error?
	.PRINT	#MSG5		;Write error
	.PURGE	#CSCHAN		;Dump channel
	JMP	ABORT
4$:	INC	CSBLK		;Next block
	CMP	CSBLK,CSMAX	;Is this the last block?
	BLT	6$		;No
	INC	ERRFLG		;Set error flag
	.PRINT	#MSGR		;Tell user
	BR	12$
6$:	MOV	#512.,CSCHR	;Reset pointers
	MOV	BUFC,CSPNT
8$:	DEC	MSGLEN		;Message finished?
	BNE	2$		;No, back for more
	BR	DOWN1		;Else get another line
10$:	MOVB	#0,@CSPNT	;Pad buffer with nulls
	INC	CSPNT
	DEC	CSCHR
	BNE	10$
	.WRITW	#csAREA,#CSCHAN,BUFC,#256.,CSBLK
	BCC	12$
	.PRINT	#MSG5		;Error?
12$:	.CLOSE	#CSCHAN		;Close it
	TST	ERRFLG		;Check if error in progress
	BEQ	14$		;No error, continue
	JMP	ABORT		;Else abort transmission
14$:	MOVB	#'.,R0		;Tell host we got it
	call	SEND
	CLR	CSSTAT		;Clear protocol mode
	return
;*****************************************************
;Routine to handle uploading
UPLOAD:	.PRINT	#MSGM		;Beginning upload message
	call	PHARSE	;Pharse filespec
	BCC	2$		;Error?
	JMP	ABORT		;Yes, abort this
2$:	.LOOKUP	#CSAREA,#CSCHAN,OUTSP	;Open file
	BCC	4$		;File exists?
	.PRINT	#MSG10		;File not found message
	JMP	ABORT		;No, abort transfer
4$:	BIC	#MSKFLG,CSSTAT	;Allow normal masking
	CLR	UPBLK		;Block number to read
	MOVB	#'.,R0		;Tell host we are ready
	call	SEND
	call	HOSTIN	;Get character from host
	BCS	8$		;Abort?
	CMPB	R0,#'.		;Right prompt?
	BNE	8$		;No, abort this
6$:	.READW	#CSAREA,#CSCHAN,BUFC,#256.,UPBLK
	BCC	10$		;error or EOF?
	TSTB	@#ERRWD		;EOF?
	BEQ	16$		;Yes, transfer finished
8$:	.CLOSE	#CSCHAN		;Else read error, close chan
	JMP	ABORT
10$:	MOV	CSBUFF,R3	;Point to start of CS buffer
	MOV	BUFC,R2	;Get address of input file buffer
	CLR	MSGLEN		;Init message length
12$:	MOVB	(R2)+,(R3)+	;Put data in buffer
	INC	MSGLEN		;bump counter
	CMP	MSGLEN,#256.	;Buffer full?
	BNE	12$		;No, back for more
	call	SNDBLK	;Send a checksummed line
	BCS	8$
	MOV	CSBUFF,R3	;Point to start of CS buffer
	CLR	MSGLEN		;Init message length
14$:	MOVB	(R2)+,(R3)+	;put second half of block in
	INC	MSGLEN
	CMP	MSGLEN,#256.	;Buffer full?
	BNE	14$		;No, back for more
	call	SNDBLK	;send a checksummed line
	BCS	8$
	INC	UPBLK		;next block
	BR	6$		;back for another block
16$:	.CLOSE	#CSCHAN		;close input channel
	BIS	#MSKFLG,CSSTAT	;Clear mask
	MOV	#1,MSGLEN	;Message length
	MOV	#EOT,@CSBUFF	;send EOT
	call	SNDBLK	;send checksummed line
	BCS	8$
	CLR	CSSTAT		;Clear protocol mode
	return
;*****************************************************
;Send a checksummed block to remote
SNDBLK:	TST	MSGLEN		;No message?
	BEQ	50$
	INC	RECNBR		;bump record number
	CMPB	RECNBR,#'9	;Roll over?
	BLOS	5$		;No
	MOVB	#'0,RECNBR	;Else reset record number
5$:	MOV	CSBUFF,R3	;point to buffer
	MOV	MSGLEN,R1	;message length
	CLR	CKSUM		;Clear checksum
	MOVB	#SOH,R0		;Start the message
	call	SEND
	MOVB	RECNBR,R0	;send record number
	call	SEND
	call	UPDATE	;update checksum
10$:	MOVB	(R3)+,R0	;Get data byte
	call	UPDATE	;Update checksum
	TSTB	R0		;Is this character a null?
	BEQ	15$		;Yes, don't display it
	BIT	#TFTYPE,CSSTAT	;ASCII transfer?
	BNE	15$		;No, binary, don't display
	.TTYOUT			;Else display is ASCII
15$:	BIT	#MSKFLG,CSSTAT	;Ok to mask?
	BNE	30$		;No, if flag set
	CMPB	R0,#4		;A control character?
	BHI	25$		;no
20$:	BISB	#100,R0		;Mask it
	MOVB	R0,R4		;Save character
	MOVB	#DLE,R0
	call	SEND		;Send mask
	MOVB	R4,R0		;Restore character
25$:	CMPB	R0,#17		;Mask ASCII 17-25
	BLO	30$
	CMPB	R0,#25
	BLOS	20$
30$:	call	SEND		;Send character
	DEC	R1		;Decrement counter
	BNE	10$		;Message finished
	MOVB	#ETX,R0		;Send End of text
	call	SEND
	CMPB	CKSUM,#40	;Cksum <40?
	BHIS	35$		;nope
	MOVB	#DLE,R0		;send it masked
	call	SEND
	BISB	#100,CKSUM	;Mask it
35$:	MOVB	CKSUM,R0	;send it
	call	SEND
40$:	call	HOSTIN	;Get host's reply
	BCS	55$		;Abort?
	BIT	#TFTYPE,CSSTAT	;Binary transfer?
	BEQ	45$		;No, no need to display reply
	.TTYOUT		;Else display the reply
45$:	CMPB	R0,#'.		;Transmission ok?
	BEQ	50$		;Yes, return
	CMPB	R0,#'/		;Invalid transmission?
	BNE	40$		;No, try to get another reply
	.PRINT	#MSGP		;Tell user we are re-sending
	BR	5$
50$:	CLC			;clear abort flag
	return			;and return
55$:	SEC			;Set abort flag
	return
;*****************************************************
;Routine to receive a checksummed block from remote
GETBLK:	MOVB	#'.,R0		;Prompt remote for next record
	call	SEND
	BIT	#TFTYPE,CSSTAT	;Binary transfer?
	BEQ	GET1		;No, don't display prompt
	.TTYOUT			;Else dusplay it (Binary)
GET1:	INC	RECNBR		;bump record number
	CMPB	RECNBR,#'9	;Roll over?
	BLOS	2$		;No
	MOVB	#'0,RECNBR	;Else reset record number
2$:	MOV	CSBUFF,R3	;Get start of buffer
	call	HOSTIN	;Get a character from remote
	BCC	6$		;Abort?
4$:	return			;Yes, return
6$:	CMPB	R0,#SOH		;Start of heading?
	BEQ	8$		;Yes, start receiving the record
	CMPB	R0,#ETX		;ETX by itself is questionable
	BNE	2$
	MOVB	#'/,R0		;Send a logical nak
	call	SEND
	BR	2$
8$:	CLR	CKSUM		;Clear checksum
	BIC	#EOTFLG,CSSTAT	;Clear EOT bit
	CLR	MSGLEN		;and message length
10$:	call	HOSTIN	;Get sender's record number
	BCS	4$
	MOVB	R0,RECHST	;Save host record number
	BR	24$		;and update checksum
12$:	call	HOSTIN	;Get a character
	BCS	4$
	CMPB	R0,#NAK		;A nak?
	BNE	14$
	SEC			;Set for abort
	return
14$:	CMPB	R0,#ETX		;End of text?
	BEQ	26$
	CMPB	R0,#EOT		;End of transmission?
	BNE	16$
	BIS	#EOTFLG,CSSTAT	;set end of transmission flag
16$:	CMPB	R0,#DLE		;Masked character comming?
	BNE	20$		;No
18$:	call	HOSTIN	;Else get next character
	BCS	4$
	BICB	#340,R0		;Make control character
20$:	BIT	#TRNSFR,CSSTAT	;Transfer in progress?
	BEQ	22$		;No, don't display this
	BIT	#TFTYPE,CSSTAT	;Binary transfer?
	BNE	22$		;Yes, don't display this
	TSTB	R0		;Null byte?
	BEQ	22$		;Then don't display it
	.TTYOUT			;Display byte
22$:	MOVB	R0,(R3)+	;Move character into buffer
	INC	MSGLEN		;Bump message length
24$:	call	UPDATE	;Update checksum
	BR	12$		;And back for more
26$:	call	HOSTIN	;Get checksum
	BCS	4$
	CMPB	R0,#DLE		;Masked?
	BNE	30$
28$:	call	HOSTIN	;Get masked character
	BCS	4$
	BICB	#340,R0		;Unmask character
30$:	CMPB	CKSUM,R0	;Checksum match?
	BEQ	34$		;Yes, continue
32$:	.PRINT	#MSGP		;No, tell user
	MOVB	#'/,R0		;and request retransmission
	call	SEND
	BR	2$		;and start over
34$:	CMPB	RECNBR,RECHST	;Record numbers match?
	BEQ	36$		;Yes
	BHI	4$		;Abort if greater than expected
	MOVB	#'.,R0		;Else it must be a duplicate record
	call	SEND		;Accept it, and try again
	BIT	#TFTYPE,CSSTAT	;Binary transfer?
	BEQ	2$		;No, don't display it
	.TTYOUT			;Else display it
	BR	2$
36$:	MOV	CSBUFF,R3	;Point to start of buffer
	return
;*****************************************************
;Routine to update checksum
UPDATE:	MOVB	CKSUM,R4	;Get checksum
	ASLB	R4		;Rotate 1 bit left
	ADC	R4		;Add carry (if any)
	MOVB	R4,R4		;Sign extend it
	ADD	R0,R4		;Add new checksum
	ADC	R4		;Add carry (if any)
	MOVB	R4,CKSUM	;save new checksum
	return
;*****************************************************
;Send ID string to host
SNDID:	.PRINT	#MSGK		;Tell user we are sending ID
	MOV	#SYSID,R1	;Get address of ID string
	call	SNDLIN	;Send it
	return
;*****************************************************
;Routine to get character from Remote
HOSTIN:	call	SCAN		;Check keyboard for abort
	BCC	2$		;Abort this?
	return			;Yes
2$:	call	REMOTE	;Check remote input
	BCS	HOSTIN		;Loop if nothing
4$:	CMPB	R0,#NAK		;Abort this?
	BNE	6$		;No
	SEC		;Else set abort flag
	return
6$:	CLC			;Clear abort flag
	return
;*****************************************************
;Abort CSEXEC mode here
ABORT:	.PRINT	#MSGN		;Inform user
	CLR	CSSTAT		;Clear status word
	MOVB	#NAK,R0		;Send a nak to host
	call	SEND		;to kill transfer
	return
;******************************************************
;Scan keyboard for abort charact
scan:	call	ttyin	;check kb
	bcs	10$
	cmpb	r0,#ctrlc
	beq	20$
	call	send	;send all else
10$:	clc
	return
20$:	sec
	return
;******************************************************
;Initialize
csinit:	mov	free,csbuff
	add	#512.,free
	mov	free,outsp
	add	#78.,free
	return
;******************************************************
; data areas
csstat:	.word	0	;executive status word
upblk:	.word	0
rechst:	.word	0
cksum:	.word	0
recnbr:	.word	0
msglen:	.word	0
csmax:	.word	0
csarea:	.blkw	10
cspnt:	.word	0
csblk:	.word	0
cschr:	.word	0
outsp:	.word	0
csbuff:	.word	0
MSGK:	.ASCIZ	<CR><LF><7>"EXEC-I-Sending CSEXEC System ID to host"
MSGL:	.ASCIZ	<CR><LF>"EXEC-I-Beginning download"
MSGM:	.ASCIZ	<CR><LF>"EXEC-I-Beginning upload"
MSGN:	.ASCIZ	<CR><LF><7>"EXEC-E-Aborting transfer"
MSGO:	.ASCIZ	<CR><LF>"EXEC-I-Initializing file transfer"
MSGP:	.ASCIZ	<CR><LF><7>"EXEC-I-Invalid data block/re-transmitting"
MSGQ:	.ASCII	<CR><LF><7>"File exists - <S>upercede or <A>bort:"
	.BYTE	200
MSGR:	.ASCIZ	<CR><LF><7>"TSTE-E-Receiver file is full"
sysid:	.asciz	"#DEC H11/LSI-11,CC,HC,PA,PL"
MSG1:	.ASCIz	"EXEC-E-Fetch error"
MSG2:	.ASCiz	"EXEC-E-File open error"
MSG5:	.ASCIz	"EXEC-E-Write error"
MSG9:	.ASCIz	"EXEC-E-Illegal filename"
MSG10:	.ASCiz	"EXEC-E-File not found"
	.end
