// RemoteVMemInit1.bcpl - handles pulling in remote sysout
// Last change August 1, 1983  5:50 PM by Bill van Melle
// Last change January 21, 1983  11:10 AM by Bill van Melle
// Last change June 8, 1982  10:42 PM by Bill van Melle
// Last change April 11, 1982  5:40 PM by Bill van Melle
// Last change December 29, 1981  11:50 AM by Bill van Melle
// Last change November 30, 1981  9:59 PM by Bill van Melle
// Last change September 7, 1981  1:04 PM by Bill van Melle

	get "LispBcpl.decl"
	get "VMem.decl"
	get "FtpProt.decl"
	get "AltoDefs.d"

external [	// procedures defined here
	Retrieve; Wss; FixPassword

		// O.S. procedures
	CallSwat; Puts; PositionPage; WriteBlock; Ws
	UNPACKDT; WRITEUDT

		// misc procedures used
	CheckIPage; ReadStrng; AppendString 
		// pup procs
	BSPReadBlock; UserClose; ReleasePBI
		// statics used
	LispFmap 
	CtxRunning
	VmemStream; UserName; UserPassword; dsp; SysinName
		// statics from RemoteVMemInit.bcpl
	sysoutFailed; nameInSysinIndex; ftpBadPup
	]

manifest [
	firstMouseY = 50
	lastMouseY = 800
	]

//----------------------------------------------------------------------------
structure String: [ length byte; char↑1,255 byte ]
//----------------------------------------------------------------------------

let Retrieve (remotePL, localPL) = valof
[		// this two-level action needed to approve the file,
		// then retrieve it
Ws ("*n")
SysinName>>String.length = nameInSysinIndex-1	
	// fill in correct name now.  remotePL is ephemeral, so copy
AppendString(SysinName, remotePL>>PL.SFIL)
Ws (SysinName)
Ws (", ")
let utv = vec 7
UNPACKDT (lv remotePL>>PL.CDAT, utv)
WRITEUDT (dsp, utv)
Ws ("...")	// print filename to show what we're doing
resultis LispRetrieveFile
]

and LispRetrieveFile (remotePL, localPL) = valof
[
 PositionPage (VmemStream, FirstVmemBlock)
 let bspStream = CtxRunning>>FtpCtx.bspStream
 let buffer = CtxRunning>>FtpCtx.buffer
 let bufferLength = CtxRunning>>FtpCtx.bufferLength
 for i = 1 to FirstVmemBlock
 		// start at page 1--IFS has no leader page
    do BSPReadBlock (bspStream, buffer, 0, WordsPerPage lshift 1)
		// skip over the silly pages before the good stuff
 FlipCursor()
 CheckIPage(buffer)
 WriteBlock (VmemStream, buffer, WordsPerPage)
 let nPages = @(buffer + IFPNActivePages) - FirstVmemBlock
					// number of pages left to go
 let bufSize = bufferLength / WordsPerPage
 bufferLength = bufSize * WordsPerPage	// make sure multiple of page size
 let nbufs = nPages / bufSize
		// number of buffers full it will take to retrieve this
 let mouseInc = ((lastMouseY-firstMouseY) lshift 4) / nbufs
 let mouseOff = mouseInc
		// thus the mouse crawls down screen as we read.
		// mouseInc is 2↑4 times amount to move per buffer full
		// mouseOff = mouseInc*pgno
 let bufBytes = bufferLength lshift 1
 [ let bytesRead = BSPReadBlock (bspStream, buffer, 0, bufBytes)
   FlipCursor()	// flip once per buffer full (at same rate as ftp if 6 bufs)
   @mouseY = firstMouseY + (mouseOff rshift 4)
   if bytesRead eq 0
      then CallSwat("Sysout too short")		// done
   if (bytesRead & #777) ne 0
      then CallSwat ("Sysout not integral number of pages")
   WriteBlock (VmemStream, buffer, bytesRead rshift 1)
   nPages = nPages - bufSize
   if nPages le 0
      then [ 	// last useful page has been read.
		// quickly eat the rest of the stream
		// better would be to abort the BSP connection
// [ bytesRead = BSPReadBlock (bspStream, buffer, 0, bufBytes) ] repeatuntil bytesRead eq 0
	   sysoutFailed = false
	   if ftpBadPup
		then [ ReleasePBI(ftpBadPup); ftpBadPup = 0 ]
			// or else BSPCloseSocket will hang
	   if BSPReadBlock (bspStream, buffer, 0, bufBytes) gr 0
		then // still stuff to read
		     [
		     UserClose(true)	// abort connection
		     ]
 	   break
	   ]
   mouseOff = mouseOff + mouseInc
 ] repeat
 resultis true
]

and FlipCursor () be

[ for i = 0 to 15 do cursorBitMap!i = not cursorBitMap!i ]

and Wss (stream, str) be

[ for i = 1 to str>>String.length
     do Puts(stream, str>>String.char↑i)
]

and FixPassword (host) be

[
Ws ("*n{")
Ws (host)
Ws ("} Login user: ")
let haveDefaultName = UserName>>String.length gr 0
if haveDefaultName
   then Ws (UserName)
unless ReadStrng (UserName, (UserName!-1 lshift 1) - 1, haveDefaultName) loop
Ws (" (password) ")
if ReadStrng (UserPassword, (UserPassword!-1 lshift 1) - 1, false, true) 
   then return
] repeat