// EFTPFile.bcpl
// June 17, 1976 10:57 PM bk, jfs
// last modified on June 3, 1979 11:47 AM by Taft
// Copyright Xerox Corporation 1979
get "PupEFTP.decl" // that will also get pup-related stuff
external
[
//incoming procedures
InitEFTPPackage; OpenEFTPSoc; CloseEFTPSoc
ReceiveEFTPBlock; SendEFTPBlock; SendEFTPEnd; GetEFTPAbort
Endofs; ReadBlock; WriteBlock; Puts; FilePos
Ws; Wo; Wns; Wl; Zero
// incoming statics, for common use, space allocated elsewhere
EFTPLclPort; EFTPFrnPort; EFTPSocket; dsp
//outgoing procedures
EFTPSendFile; EFTPReceiveFile
]
static
[
// for use in this program, allocated in this module
bytecount; totalbytecount
packetcount; blockcount
]
// These routines will be called from the FrontEnd, and may be
// called more than once in the life of a program
//-----------------------------------------------------------------
let EFTPSendFile(diskstream, foreignport) = valof
//-----------------------------------------------------------------
[
OpenEFTPSoc(EFTPSocket, 0, foreignport)
packetcount = 0
totalbytecount = 0
let maxBufferBytes = 2*256*6 //enough to buffer 6 disk pages
let tempvec = vec 256*6 //in words
let bytesLeftInBuffer = 0
let nextAddr = tempvec
let result = nil
// A loop, to read pages and send off blocks
[Sendloop
//See if we need more input
if bytesLeftInBuffer eq 0 then
[
//See if time to quit
if Endofs(diskstream) then break
bytesLeftInBuffer =
FillFromDisk(diskstream, tempvec, maxBufferBytes)
totalbytecount = totalbytecount + bytesLeftInBuffer
nextAddr = tempvec //reset address pointer
]
//data remains to be sent, at nextAddr
packetcount = packetcount + 1
test bytesLeftInBuffer ls 512
ifso bytecount = bytesLeftInBuffer
ifnot bytecount = 512
[dummyLoop
result =
SendEFTPBlock(EFTPSocket, nextAddr, bytecount, longBlockTimeout)
if result eq EFTPTimeout &
EFTPSocket>>EFTPSoc.TransferNotStarted then
[
Wl("No answer yet, will keep trying...")
loop
]
break
]dummyLoop repeat
//Something happened...
if result ge 0 then
[
bytesLeftInBuffer = bytesLeftInBuffer - bytecount
nextAddr = nextAddr + bytecount/2
loop //it went properly
]
//If we get here, had a real failure....
switchon result into
[resultCase
case EFTPTimeout:
[
Ws("EFTPSend timed out while sending....")
endcase
]
case EFTPAbortSent:
[
Ws("EFTPAbort had to be sent....")
endcase
]
case EFTPAbortReceived:
[
Ws("EFTPAbort received while sending....")
let temppbi = GetEFTPAbort(EFTPSocket)
PrintAbortPBI(temppbi)
endcase
]
default:
[
Ws("Unknown error from EFTPSend....")
]
]resultCase
CloseEFTPSoc(EFTPSocket)
resultis false //bail out
]Sendloop repeat //keep going, til you break out
// All of the data has been sent; now do an end sequence
result = SendEFTPEnd(EFTPSocket, longBlockTimeout)
CloseEFTPSoc(EFTPSocket)
test result
ifso [ Wns(dsp, totalbytecount, 0, 10); Ws(" bytes sent. ") ]
ifnot Ws("SendEnd sequence failed.....")
resultis result
]
//---------------------------------------------------------------
and FillFromDisk(diskstream, addr, maxbytes) = valof
//---------------------------------------------------------------
[
//Returns the number of bytes read into the buffer
// Watch out, Readblock returns a word count
let bytecount =
ReadBlock(diskstream, addr, maxbytes rshift 1) lshift 1
if bytecount eq 0 then resultis 0 // hit eof, quit early
if bytecount < maxbytes then
[
// got the last page; we have to do some hacking here
let filepos = vec 1
FilePos(diskstream, filepos)
//see if the files total byte count is odd
if ((filepos!1) & 1) eq 1 then bytecount=bytecount-1
]
resultis bytecount
]
//---------------------------------------------------------------
and DumpToDisk(diskstream, addr, bytecount) = valof
//---------------------------------------------------------------
[
// Watch out for an odd bytecount
WriteBlock(diskstream, addr, bytecount rshift 1)
// May have failed to write one byte
if (bytecount & 1) eq 1 then Puts(diskstream, addr>>Byte↑bytecount)
]
//---------------------------------------------------------------
and EFTPReceiveFile(diskstream, foreignport) = valof
//---------------------------------------------------------------
[
//use EFTPLclPort, allocated elsewhere
Zero(EFTPLclPort, lenPort)
EFTPLclPort>>Port.socket↑2 = socketEFTPReceive
OpenEFTPSoc(EFTPSocket, EFTPLclPort, foreignport)
packetcount = 0
totalbytecount = 0
let maxBufferBytes = 2*256*6 //6 disk pages
let tempvec = vec 256*6 //in words
let bytesLeftInBuffer = 0
let nextAddr = tempvec
// a loop to get blocks, and write to the disk
[Receiveloop
//Make sure there is enough free space
if maxBufferBytes-bytesLeftInBuffer ls 512 then
[
totalbytecount = totalbytecount + bytesLeftInBuffer
DumpToDisk(diskstream, tempvec, bytesLeftInBuffer)
nextAddr = tempvec
bytesLeftInBuffer = 0
]
let bytecount=
ReceiveEFTPBlock(EFTPSocket, nextAddr, longBlockTimeout)
if bytecount eq 0 then
[
//Received an End....
if bytesLeftInBuffer gr 0 then
DumpToDisk(diskstream, tempvec, bytesLeftInBuffer)
totalbytecount = totalbytecount + bytesLeftInBuffer
break // end has been properly received
]
if bytecount gr 0 then
[
// odd bytecounts are not legal, except in the last packet
bytesLeftInBuffer = bytesLeftInBuffer + bytecount
nextAddr = nextAddr + bytecount rshift 1
packetcount = packetcount + 1
loop
]
//Some form of error return, figure it out here and punt
switchon bytecount into
[ReceiveCaseBlock
case EFTPTimeout:
[
if EFTPSocket>>EFTPSoc.TransferNotStarted then
[
Wl("Nothing received yet, will keep listening...")
loop
]
Ws("Receiver timed out....")
endcase
]
case EFTPAbortSent:
[
Ws("Abort had to be sent from receiver....")
endcase
]
case EFTPAbortReceived:
[
Ws("EFTPAbort received while receiving....")
let temppbi = GetEFTPAbort(EFTPSocket)
PrintAbortPBI(temppbi)
endcase
]
case EFTPResetReceived:
[
Ws("Asked to reset....[Not implemented here]")
endcase
]
]ReceiveCaseBlock
CloseEFTPSoc(EFTPSocket)
resultis false
]Receiveloop repeat
//End has been received, time to clean up and leave
CloseEFTPSoc(EFTPSocket)
Wns(dsp, totalbytecount, 0, 10); Ws(" bytes received. ")
resultis true
]
//---------------------------------------------------------------
and PrintAbortPBI(pbi) be
//---------------------------------------------------------------
[
Puts(dsp, $*N); Wo(pbi>>PBI.pup.words↑1); Ws(" - Abort: ")
for i = 3 to (3 + (pbi>>PBI.pup.length-(pupOvBytes+2)) - 1) do
Puts(dsp, pbi>>PBI.pup.bytes↑i)
]