-- file: OthelloFTP.mesa
-- Edited by
-- Lichtenberg 6-Jul-84 18:54:38 - Lisp stuff
-- Johnsson, 15-Sep-83 15:40:26
-- Sandman, October 11, 1979 8:33 AM
-- Gobbel, February 14, 1980 7:30 PM
-- Forrest, 13-Jan-82 10:22:30
-- Bruce, 28-Dec-81 10:19:42
DIRECTORY
Environment USING [bytesPerPage, bytesPerWord],
Heap USING [systemZone],
File USING [
Create, Delete, File, MakePermanent, nullFile, PageNumber, PageCount, GetSize, SetSize, Unknown],
FileTypes USING [tUntypedFile],
OthelloDefs,
OthelloOps USING [
BootFileType, GetVolumeBootFile,
MakeBootable, MakeUnbootable, SetPhysicalVolumeBootFile,
SetVolumeBootFile],
PhysicalVolume USING [ID],
Process USING [Detach, Pause, SecondsToTicks],
Space USING [Map, ScratchMap, Unmap],
STP USING [
Close, Connect, Create, CreateRemoteStream, Enumerate, Error,
ErrorCode, FileInfo, GetFileInfo, Handle, IsOpen, Login, NextFileName,
NoteFileProcType, Open, SetDirectory, SetHost],
Stream USING [EndOfStream, GetBlock, Handle],
String USING [
AppendChar, AppendCharAndGrow, AppendExtensionIfNeeded,
AppendStringAndGrow, CopyToNewString, Length],
TemporaryBooting USING [InvalidParameters],
Volume USING [Close, ID, InsufficientSpace, Open, GetAttributes];
OthelloFTP: PROGRAM
IMPORTS
File, Heap, OthelloDefs, OthelloOps,
Process, Space, STP, Stream, String, TemporaryBooting, Volume
EXPORTS OthelloDefs =
BEGIN OPEN OthelloOps;
host: LONG STRING ← NIL;
userName: LONG STRING ← NIL;
userPassword: LONG STRING ← NIL;
connectName: LONG STRING ← NIL;
connectPassword: LONG STRING ← NIL;
directory: LONG STRING ← NIL;
cmFile: LONG STRING ← NIL;
fileName: LONG STRING ← NIL;
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- String/Credentials Commands
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Directory: PROC = {
OthelloDefs.MyNameIs[
myNameIs: "Directory"L,
myHelpIs: "Set Default FTP directory"L];
OthelloDefs.GetName["Directory: "L, @directory]};
GetConnectNamePassword: PROC = {
OthelloDefs.MyNameIs[
myNameIs: "Connect"L, myHelpIs: "Set secondary Credentials"L];
OthelloDefs.GetName["Directory: "L, @connectName];
OthelloDefs.GetName["Password: "L, @connectPassword, stars]};
GetUserNamePassword: PROC = {
OthelloDefs.MyNameIs[
myNameIs: "Login"L, myHelpIs: "Set user name-password"L];
OthelloDefs.GetName["User: "L, @userName];
OthelloDefs.GetName["Password: "L, @userPassword, stars]};
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Basic Fetch Commands
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FetchBoot: PROC = {
Fetch[pilot, "Boot file name: "L, "Fetch Boot File"L, "Fetch Boot File"L, "boot"L, FALSE]};
FetchGerm: PROC = {
Fetch[germ, "Germ file name: "L, "Germ Fetch"L, "Fetch Germ"L, "germ"L, FALSE]};
FetchPilotMicrocode: PROC = {
Fetch[
softMicrocode,
"Pilot microcode file name: "L,
"Pilot Microcode Fetch"L,
"Fetch and Install Pilot Microcode"L,
"db"L,
FALSE]};
-- Fetch Lisp sysout command: Installs a Lisp sysout on the volume.
FetchLispSysout: PROC = {
Fetch[
hardMicrocode,
"Lisp sysout file name: "L,
"Lisp Sysout Fetch"L,
"Fetch and Install Lisp Sysout"L,
"sysout"L,
TRUE]};
FetchDiagnosticMicrocode: PROC = {
Fetch[
hardMicrocode,
"Diagnostic microcode file name: "L,
"Diagnostic Microcode Fetch"L,
"Fetch and Install Diagnostic Microcode"L,
"db"L,
FALSE]};
Fetch: PROC [type: BootFileType, prompt, name, helpMsg, extension: STRING, lispSysout: BOOLEAN] =
BEGIN
created: BOOLEAN ← FALSE;
file: File.File;
firstPage: File.PageNumber;
lvID: Volume.ID;
OthelloDefs.MyNameIs[myNameIs: name, myHelpIs: helpMsg];
IF ~ConnectionOpen[] AND ~ReOpen[] THEN
OthelloDefs.AbortingCommand["Please open a connection"L];
lvID ← OthelloDefs.GetLvIDFromUser[].lvID;
OthelloDefs.GetName[prompt, @fileName];
[] ← String.AppendExtensionIfNeeded[@fileName, extension, Heap.systemZone];
Volume.Open[lvID];
[file, firstPage] ← GetVolumeBootFile[lvID, type];
IF (created ← file = File.nullFile) THEN
file ← File.Create[lvID, 1, FileTypes.tUntypedFile]
ELSE MakeUnbootable[file, type, firstPage !
File.Unknown => CONTINUE;
TemporaryBooting.InvalidParameters => {
OthelloDefs.WriteLine["Warning, trouble making unbootable"L];
CONTINUE}];
Retrieve[destination: [pilotFileSystemWrite[file]]
! UNWIND => {IF created THEN File.Delete[file]; Volume.Close[lvID]}];
OthelloDefs.WriteString["Installing..."L];
SetVolumeBootFile[file, type, OthelloDefs.leaderPages];
File.MakePermanent[file];
-- IF lispSysout THEN {
-- OthelloDefs.WriteString["Expanding to fill volume..."L];
-- SetBootFileSize[file,lvID];
-- OthelloDefs.WriteString["OK..."L];
-- };
MakeBootable[file, type, OthelloDefs.leaderPages
! TemporaryBooting.InvalidParameters => {
OthelloDefs.WriteLine["Warning, trouble making bootable"L]; CONTINUE}];
OthelloDefs.WriteLine["Done."L];
IF lispSysout THEN OthelloDefs.WriteLine["[Remember to use Expand VMem command if necessary]"L];
IF lispSysout THEN {IF OthelloDefs.Yes["Shall I also make this the default boot lisp? "L
! UNWIND => Volume.Close[lvID]] THEN
SetPhysicalVolumeBootFile[file,type,OthelloDefs.leaderPages];
}
ELSE
IF type IN [hardMicrocode..germ] AND
OthelloDefs.Yes["Shall I also use this for the Physical Volume? "L
! UNWIND => Volume.Close[lvID]] THEN
SetPhysicalVolumeBootFile[file, type, OthelloDefs.leaderPages];
Volume.Close[lvID];
END;
-- UGH.. This kludge sets the file's size to be as big as Pilot will let it be, on 100 page increments.
SetBootFileSize: PRIVATE PROC[file: File.File, lvID: Volume.ID] = BEGIN
newSize: File.PageCount ← File.GetSize[file] + Volume.GetAttributes[lvID].freePageCount;
File.SetSize[file, newSize
! File.Unknown => {OthelloDefs.WriteLine["Warning: Trouble making file fill volume - File.Unknown"L];
CONTINUE};
Volume.InsufficientSpace => {OthelloDefs.WriteString["."L]; newSize ← newSize - 100; RETRY}];
END;
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Initial Ucode Fetch Command
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FetchInitialMicrocode: PUBLIC PROC [
InstallProc: PROC [getPage: PROC RETURNS [LONG POINTER]]] = {
IF ~ConnectionOpen[] AND ~ReOpen[] THEN
OthelloDefs.AbortingCommand["Please open a connection"L];
OthelloDefs.GetName["File name: "L, @fileName];
OthelloDefs.Confirm[];
Retrieve[destination: [rawWrite[InstallProc]]]};
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Indirect command files
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AlternateGetCMFile: PUBLIC PROC [s: STRING] = {
Heap.systemZone.FREE[@cmFile];
cmFile ← Heap.systemZone.NEW[StringBody[s.length]];
FOR i: CARDINAL IN [1..s.length) DO
String.AppendChar[cmFile, s[i]] ENDLOOP;
DoIndirect[]};
Indirect: PROC = {
OthelloDefs.MyNameIs[
myNameIs: "@", myHelpIs: "Run command file from IFS"L];
OthelloDefs.GetName["Command file: "L, @cmFile
! OthelloDefs.Question => {
OthelloDefs.WriteLine["[Host]<Dir>Filename"L]; RESUME}];
[] ← String.AppendExtensionIfNeeded[@cmFile, "hello"L, Heap.systemZone];
DoIndirect[]};
DoIndirect: PROC =
BEGIN
ParseCmFileName: PROC = {
hostEnd: CARDINAL;
IF cmFile.length = 0 THEN RETURN;
FOR i: CARDINAL IN [0..cmFile.length) DO
c: CHARACTER = cmFile[i];
SELECT c FROM
'[ => LOOP; '] => {hostEnd ← i; EXIT};
ENDCASE => String.AppendCharAndGrow[@host, c, Heap.systemZone];
REPEAT FINISHED => {Heap.systemZone.FREE[@host]; RETURN}
ENDLOOP;
-- hostEnd points at ']
FOR i: CARDINAL IN (hostEnd..cmFile.length) DO
IF cmFile[i] = '< AND directory#NIL THEN directory.length ← 0;
String.AppendCharAndGrow[@fileName, cmFile[i], Heap.systemZone];
IF cmFile[i] = '> THEN {
FOR j: CARDINAL IN [0..fileName.length) DO
String.AppendCharAndGrow[@directory, fileName[j], Heap.systemZone] ENDLOOP;
fileName.length ← 0};
ENDLOOP};
s: LONG STRING ← NIL;
GetString: PROC [c: LONG STRING] = {s ← String.CopyToNewString[c, Heap.systemZone]};
Heap.systemZone.FREE[@host];
Heap.systemZone.FREE[@directory];
Heap.systemZone.FREE[@fileName];
ParseCmFileName[];
CloseCmd[]; Open[];
Retrieve[destination: [string[GetString]]
! UNWIND => Heap.systemZone.FREE[@s]];
OthelloDefs.WriteLine["done"L];
OthelloDefs.SetCommandString[s];
Close[];
END;
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- MISC Stuff/Commands
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
userOpened: BOOLEAN ← FALSE;
OpenCmd: PROC = {
OthelloDefs.MyNameIs[myNameIs: "Open"L, myHelpIs: "STP Open"L];
CloseCmd[];
OthelloDefs.GetName["Open connection to "L, @host];
Open[]; userOpened ← TRUE};
ReOpen: PROC RETURNS [BOOLEAN] = {
IF userOpened=FALSE THEN RETURN[FALSE];
Open[]; RETURN[TRUE]};
CloseCmd: PROC = {
OthelloDefs.MyNameIs[myNameIs: "Close"L, myHelpIs: "STP Close"L];
userOpened ← FALSE; Close[]};
RemoteList: PROC = {
OthelloDefs.MyNameIs[
myNameIs: "List Remote Files"L, myHelpIs: "List Remote Files"L];
IF ~ConnectionOpen[] AND ~ReOpen[] THEN
OthelloDefs.AbortingCommand["Please open a connection"L];
OthelloDefs.GetName["Pattern: "L, @fileName];
IF String.Length[fileName] = 0 THEN
String.AppendCharAndGrow[@fileName, '*, Heap.systemZone];
ListFiles[]};
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Central commands
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
commandProcessor: OthelloDefs.CommandProcessor ← [FtpCommands];
FtpCommands: PROC [index: CARDINAL] = {
SELECT index FROM
0 => Indirect[];
1 => GetConnectNamePassword[];
2 => Directory[];
3 => GetUserNamePassword[];
4 => OpenCmd[];
5 => CloseCmd[];
6 => FetchBoot[];
7 => FetchDiagnosticMicrocode[];
8 => FetchGerm[];
9 => FetchPilotMicrocode[];
10 => RemoteList[];
11 => FetchLispSysout[];
ENDCASE => OthelloDefs.IndexTooLarge};
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- STP Stuff/Commands
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
stp: STP.Handle ← NIL;
ConnectionOpen: PROC RETURNS [BOOLEAN] = {
RETURN[stp # NIL AND STP.IsOpen[stp]]};
-- all callers close the connection first
Open: PROC = {
herald: LONG STRING ← NIL;
IF stp = NIL THEN stp ← STP.Create[];
DO
herald ← STP.Open[stp, host
! STP.Error => SELECT code FROM
connectionTimedOut, connectionClosed, noRouteToNetwork,
noNameLookupResponse, connectionRejected => {
OthelloDefs.WriteLine[error]; CONTINUE};
ENDCASE => OthelloDefs.AbortingCommand[error]];
IF herald # NIL THEN EXIT;
Process.Pause[Process.SecondsToTicks[10]];
OthelloDefs.CheckUserAbort[];
ENDLOOP;
OthelloDefs.WriteLine[herald];
Heap.systemZone.FREE[@herald];
STP.SetHost[stp, host]};
CloseFetch: PUBLIC PROC = {
Close[! OthelloDefs.AbortingCommand => {
OthelloDefs.WriteString[reason];
OthelloDefs.WriteLine[reasonOne];
CONTINUE}]};
Close: PROC = {
IF ~ConnectionOpen[] THEN RETURN;
STP.Close[stp ! STP.Error => OthelloDefs.AbortingCommand[error]];
OthelloDefs.WriteLine["connection closed"L]};
-- could mess with directories.
-- who cares
ListFiles: PROC = {
ListOne: STP.NoteFileProcType = {
info: STP.FileInfo = STP.GetFileInfo[stp];
OthelloDefs.WriteString[file];
THROUGH [file.length..80-info.create.length) DO
OthelloDefs.WriteChar[' ] ENDLOOP;
OthelloDefs.WriteLine[info.create];
--OthelloDefs.WriteChar[' ];
--OthelloDefs.WriteLine[info.author];
--OthelloDefs.WriteChar[' ];
--OthelloDefs.WriteLongNumber[info.size];
--OthelloDefs.WriteLine[" bytes]"L];
OthelloDefs.CheckUserAbort[];
RETURN[yes]};
STP.Login[stp, userName, userPassword];
STP.Connect[stp, connectName, connectPassword];
STP.SetDirectory[stp, directory];
STP.Enumerate[stp, fileName, ListOne
! STP.Error => OthelloDefs.AbortingCommand[error]]};
Destination: TYPE = RECORD [
SELECT type: * FROM
pilotFileSystemWrite => [localFile: File.File],
string => [stringProc: PROC [LONG STRING]],
rawWrite => [
linkProc: PROC [getPage: PROC RETURNS [LONG POINTER]]],
ENDCASE];
StartFeedback: SIGNAL = CODE;
Retrieve: PROC [destination: Destination] = {
rs: Stream.Handle;
rsSize: LONG CARDINAL;
note: LONG STRING ← NIL;
Cleanup: PROC = {
rs.delete[rs];
OthelloDefs.SetCursor[pointer];
Heap.systemZone.FREE[@note]};
[rs, rsSize, note] ← GetReadStream[
! STP.Error => OthelloDefs.AbortingCommand[error]];
IF rs=NIL THEN RETURN;
GrabBits[rs, rsSize, destination, note
! STP.Error => OthelloDefs.AbortingCommand[error];
StartFeedback => {
OthelloDefs.WriteString["Fetching..."L];
OthelloDefs.SetCursor[ftp];
RESUME};
UNWIND => Cleanup[]];
Cleanup[]};
HasWildCard: PROC [s: LONG STRING] RETURNS [BOOLEAN] = {
IF s#NIL THEN FOR i: CARDINAL IN [0..s.length) DO
IF s[i] = '* THEN RETURN[TRUE] ENDLOOP;
RETURN[FALSE]};
PagesForBytes: PROC [bytes: LONG CARDINAL] RETURNS [LONG CARDINAL] = INLINE {
OPEN Environment; RETURN[(bytes + bytesPerPage - 1)/bytesPerPage]};
GetReadStream: PROC RETURNS [rs: Stream.Handle, rsSize: LONG CARDINAL, note: LONG STRING ← NIL] = {
wild: BOOLEAN = HasWildCard[directory] OR HasWildCard[fileName];
info: STP.FileInfo;
STP.Login[stp, userName, userPassword];
STP.Connect[stp, connectName, connectPassword];
STP.SetDirectory[stp, directory];
rs ← STP.CreateRemoteStream[stp, fileName, read];
rs.options.signalEndOfStream ← TRUE;
DO
s: LONG STRING ← STP.NextFileName[rs ! UNWIND => rs.delete[rs]];
IF s = NIL THEN {rs.delete[rs]; RETURN[NIL, 0, NIL]};
info ← STP.GetFileInfo[stp ! UNWIND => rs.delete[rs]];
rsSize ← PagesForBytes[info.size];
OthelloDefs.WriteString[s];
Heap.systemZone.FREE[@s];
OthelloDefs.WriteChar['[]; OthelloDefs.WriteString[info.create];
OthelloDefs.WriteString[", pages = "]; OthelloDefs.WriteLongNumber[rsSize];
OthelloDefs.WriteChar[']];
IF ~wild THEN {OthelloDefs.NewLine[]; EXIT};
IF OthelloDefs.Yes[" [Confirm]: "L ! UNWIND => rs.delete[rs]] THEN EXIT;
ENDLOOP;
note ← Heap.systemZone.NEW[StringBody[60]];
String.AppendChar[note, '[];
String.AppendStringAndGrow[@note, host, Heap.systemZone];
String.AppendCharAndGrow[@note, '], Heap.systemZone];
IF String.Length[info.directory] # 0 THEN {
String.AppendCharAndGrow[@note, '<, Heap.systemZone];
String.AppendStringAndGrow[@note, info.directory, Heap.systemZone];
String.AppendCharAndGrow[@note, '>, Heap.systemZone]};
String.AppendStringAndGrow[@note, info.body, Heap.systemZone];
String.AppendStringAndGrow[@note, " ("L, Heap.systemZone];
String.AppendStringAndGrow[@note, info.create, Heap.systemZone];
String.AppendCharAndGrow[@note, '), Heap.systemZone];
RETURN};
bufPages: CARDINAL = 8;
GrabBits: PROC [
rs: Stream.Handle, rsSizePages: LONG CARDINAL, destination: Destination, note: LONG STRING ← NIL] = {
WITH destination SELECT FROM
pilotFileSystemWrite => {
buffer: LONG POINTER ← NIL;
base: File.PageNumber ← 0;
got: CARDINAL;
File.SetSize[localFile, rsSizePages + OthelloDefs.leaderPages
! Volume.InsufficientSpace => OthelloDefs.AbortingCommand["Volume Full"L]];
SetLeaderPage[localFile, note];
SIGNAL StartFeedback;
WHILE base < rsSizePages DO
thisPages: CARDINAL = CARDINAL[MIN[rsSizePages-base, bufPages]];
size: CARDINAL = thisPages*Environment.bytesPerPage;
start: CARDINAL ← 0;
buffer ← Space.Map[
window:[localFile, base+OthelloDefs.leaderPages, thisPages],
life: dead].pointer;
DO
[bytesTransferred: got] ← rs.GetBlock[[
blockPointer: buffer, startIndex: start, stopIndexPlusOne: size] !
Stream.EndOfStream => {
got ← 0; start ← start + nextIndex; CONTINUE};
UNWIND => [] ← Space.Unmap[buffer]];
IF got = 0 THEN {[] ← Space.Unmap[buffer]; RETURN};
IF (start ← start + got) = size THEN EXIT;
ENDLOOP;
--buffer ← Space.Unmap[buffer, return];
Process.Detach[LOOPHOLE[FORK Space.Unmap[buffer]]]; buffer ← NIL;
OthelloDefs.FlipCursor[];
base ← base + thisPages;
ENDLOOP;
buffer ← Space.ScratchMap[1]; -- check for any leftover stuff
[bytesTransferred: got] ← rs.GetBlock[[
blockPointer: buffer, startIndex: 0,
stopIndexPlusOne: Environment.bytesPerPage] !
Stream.EndOfStream => {got ← nextIndex; CONTINUE};
UNWIND => [] ← Space.Unmap[buffer]];
[] ← Space.Unmap[buffer];
IF got # 0 THEN OthelloDefs.AbortingCommand[
"File longer than advertised length"L]};
string => {
SIGNAL StartFeedback;
DO
stringOverhead: CARDINAL = SIZE[StringBody]*Environment.bytesPerWord;
string: LONG STRING = Space.ScratchMap[bufPages];
string↑ ← [
length: 0,
maxlength: bufPages*Environment.bytesPerPage - stringOverhead,
text: ];
WHILE string.length < string.maxlength DO
got: CARDINAL;
[bytesTransferred: got] ← rs.get[
rs,
[blockPointer: LOOPHOLE[@string.text],
startIndex: string.length, stopIndexPlusOne: string.maxlength],
rs.options
! Stream.EndOfStream => {
got ← 0; string.length ← string.length + nextIndex; CONTINUE};
UNWIND => [] ← Space.Unmap[string]];
IF got = 0 THEN {
stringProc[string! UNWIND => [] ← Space.Unmap[string]];
[] ← Space.Unmap[string]; RETURN};
string.length ← string.length + got;
ENDLOOP;
[] ← Space.Unmap[string];
OthelloDefs.AbortingCommand["Command file too long!"L];
ENDLOOP};
rawWrite =>{
buffer: LONG POINTER = Space.ScratchMap[1];
done: BOOLEAN ← FALSE;
first: BOOLEAN ← TRUE;
GetPage: PROC RETURNS [LONG POINTER] = {
got: CARDINAL; index: CARDINAL ← 0;
IF first THEN {SIGNAL StartFeedback; first ← FALSE};
WHILE ~done DO
[bytesTransferred: got] ← rs.get[
rs,
[blockPointer: buffer, startIndex: index,
stopIndexPlusOne: Environment.bytesPerPage],
rs.options
! Stream.EndOfStream => {got ← nextIndex; done ← TRUE; CONTINUE}];
IF (index ← index + got) = Environment.bytesPerPage
OR done THEN {OthelloDefs.FlipCursor[]; EXIT}
ENDLOOP;
RETURN[IF done AND index = 0 THEN NIL ELSE buffer]};
linkProc[GetPage ! UNWIND => [] ← Space.Unmap[buffer]];
WHILE ~done DO [] ← GetPage[! UNWIND => [] ← Space.Unmap[buffer]] ENDLOOP;
[] ← Space.Unmap[buffer]};
ENDCASE => ERROR};
SetLeaderPage: PROCEDURE [file: File.File, note: LONG STRING] =
BEGIN
lp: LONG POINTER TO OthelloDefs.LeaderPage ← Space.Map[[file, 0, OthelloDefs.leaderPages]].pointer;
lp.version ← OthelloDefs.lpVersion;
lp.length ← MIN[note.length, OthelloDefs.lpNoteLength];
FOR i: CARDINAL IN [0..lp.length) DO
lp.note[i] ← note[i];
ENDLOOP;
[] ← Space.Unmap[lp];
END;
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- initialization
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
StringInit: PROC = {
OthelloDefs.SetCommandString[String.CopyToNewString["Online RD0"L, Heap.systemZone]]};
OthelloDefs.RegisterCommandProc[@commandProcessor];
StringInit[];
END.....
-- November 13, 1979 10:16 AM By Forrest Changed to InitializeFTP once (and never Finalize), to use a bigger chunk in transfering (should use two buffers); increased size of directory string to 60 from 50; Add twiddle cursor hack since people were worried about ftp dying; export Server*loaded and UserMailLoaded to eliminate 3 modules from FTP
-- January 12, 1980 4:46 PM By Forrest Changed to used new Othello FTP and support calls to writing Raw Data
-- February 14, 1980 7:30 PM By Gobbel Notice if we didn't really retrieve any files
-- July 26, 1980 7:04 PM By Forrest Change name to OthelloFTP, export OthelloDefs
-- April 14, 1981 1:53 PM By Bruce Added string variant to dest; fixed AR4051
; Add twiddle cursor hack since people were worried about ftp dying; export Server*loaded and UserMailLoaded to eliminate 3 modules from FTP
-- January 12, 1980 4:46 PM By Forrest Changed to used new Othello FTP and support calls to writing Raw Data
-- February 14, 1980 7:30 PM By Gobbel Notice if we didn't really retrieve any files
-- July 26, 1980 7:04 PM By Forrest Change name to OthelloFTP, export OthelloDefs
-- April 14, 1981 1:53 PM By Bruce Added string variant to dest; fixed AR4051
-- 11-Nov-81 16:54:09 By Forrest added missing catch phrase to Retrieve
-- 28-Dec-81 10:21:01 By Bruce removed Guest Guest and set signalEndOfStream TRUE
-- 13-Jan-82 10:23:20 By Forrest removed extra ! UNWIND => Space.Unmap[space] from Initial ucode fetch.
-- 11-Dec-82 15:28:08 By Johnsson removed Storage; added default extensions.
-- 13-Apr-83 9:38:39 By Johnsson Klamath conversion.