DIRECTORY BasicTime USING [GMT], IO USING [EndOf, EndOfStream, Error, GetBlock, GetChar, GetIndex, PutBlock, SetIndex, STREAM], PupStream USING [CloseReason, ConsumeMark, PupByteStreamAbort, SendMark, StreamClosing, TimeOut], Rope USING [ROPE], STP USING [ Close, Completion, CompletionProcType, Confirmation, ConfirmProcType, CredentialsErrors, Error, ErrorCode, FileErrors, NoteFileProcType, Type], STPOps USING [ CheckConnection, CollectCode, CollectString, ErrorIfNextNotYes, ErrorIfNextNotEOC, ErrorCodeToSTPErrorCode, GenerateErrorString, GenerateProtocolError, GenerateStreamClosingError, GetCommand, GetHereIsAndPList, GetPList, Handle, LookAtMark, MarkEncountered, MakeRemoteName, markComment, markDelete, markDirectory, markEOC, markHereIsFile, markHereIsPList, markNo, markNewDirectory, markNewStore, markRename, markRetrieve, markYes, MyGetMark, NameToPList, Object, Operation, PList, PutCommand, PutPList, ResetPList, SelectError, SetByteSize, SetCreateTime, SetFileType, UserStateToPList], STPReplyCode USING[ReplyCode]; STPsB: CEDAR PROGRAM IMPORTS IO, PupStream, STP, STPOps EXPORTS STP, STPOps = BEGIN OPEN PupStream, STPOps; Object: PUBLIC TYPE = STPOps.Object; Delete: PUBLIC PROCEDURE [ stp: STPOps.Handle, name: Rope.ROPE, confirm: STP.ConfirmProcType, complete: STP.CompletionProcType] = BEGIN DoFiles[stp, name, confirm, complete, delete]; END; Enumerate: PUBLIC PROCEDURE [ stp: STPOps.Handle, name: Rope.ROPE, proc: STP.NoteFileProcType] = BEGIN Foo1: STP.ConfirmProcType = BEGIN RETURN[answer: IF proc[file] = yes THEN do ELSE abort, localStream: NIL]; END; Foo2: STP.CompletionProcType = BEGIN END; DoFiles[stp, name, Foo1, Foo2, directory]; END; Rename: PUBLIC PROCEDURE [ stp: STPOps.Handle, old, new: Rope.ROPE] = BEGIN mark, saveMark: [0..256); code: CHARACTER _ 0C; CheckConnection[stp]; ResetPList[stp.plist]; UserStateToPList[stp]; NameToPList[stp.plist, old, alto]; PutPList[stp, markRename, FALSE]; ResetPList[stp.plist]; UserStateToPList[stp]; NameToPList[stp.plist, new, alto]; PutPList[stp, 0B]; [saveMark, code, stp.remoteString] _ GetCommand[stp]; IF (mark _ MyGetMark[stp]) # markEOC THEN GenerateProtocolError[stp, eocExpected, mark]; IF saveMark # markYes THEN GenerateErrorString[stp, requestRefused, stp.remoteString, code]; END; Retrieve: PUBLIC PROCEDURE [ stp: STPOps.Handle, file: Rope.ROPE, confirm: STP.ConfirmProcType _ NIL, complete: STP.CompletionProcType _ NIL] = BEGIN DoFiles[stp, file, confirm, complete, retrieve]; END; Store: PUBLIC PROCEDURE [ stp: STPOps.Handle, file: Rope.ROPE, stream: IO.STREAM, noteFile: STP.NoteFileProcType _ NIL, fileType: STP.Type, creation: BasicTime.GMT] = BEGIN Confirm: STP.ConfirmProcType = {IF noteFile = NIL OR noteFile[file] = yes THEN RETURN[do, stream] ELSE RETURN[skip, NIL]}; CheckConnection[stp]; ResetPList[stp.plist]; UserStateToPList[stp]; NameToPList[stp.plist, file, alto]; IF fileType = unknown THEN fileType _ FindFileType[stream]; SetFileType[stp, fileType]; STPOps.SetByteSize[stp, fileType]; STPOps.SetCreateTime[stp, creation]; DoFiles[stp, file, Confirm, NIL, store]; END; DoFiles: PUBLIC PROCEDURE [ stp: STPOps.Handle, file: Rope.ROPE, confirm: STP.ConfirmProcType, complete: STP.CompletionProcType, op: STPOps.Operation] = BEGIN reason: PupStream.CloseReason; reply: STP.Confirmation; string: Rope.ROPE _ NIL; local: IO.STREAM _ NIL; killConnection: BOOLEAN _ TRUE; CleanUp: PROCEDURE = BEGIN IF killConnection THEN SmashClosed[stp]; END; {ENABLE { PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; PupStream.TimeOut => {reason _ transmissionTimeout; GOTO streamClosing}; UNWIND => CleanUp[]}; IF op # store THEN BEGIN CheckConnection[stp]; ResetPList[stp.plist]; UserStateToPList[stp]; NameToPList[stp.plist, file, alto]; END; IF op = directory THEN SELECT TryNewDirectory[stp, confirm ! STP.Error => IF code IN STP.CredentialsErrors OR code IN STP.FileErrors THEN killConnection _ FALSE] FROM finished => RETURN; aborted => {CleanUp[]; RETURN}; tryOldDirectory => NULL; -- just falls thru ENDCASE => ERROR; PutPList[ stp, SELECT op FROM delete => markDelete, directory => markDirectory, retrieve => markRetrieve, store => markNewStore, ENDCASE => ERROR]; DO IF LookAtMark[stp] = markEOC THEN {[] _ MyGetMark[stp]; EXIT}; GetHereIsAndPList[stp, op # directory ! STP.Error => IF code IN STP.CredentialsErrors OR code IN STP.FileErrors THEN killConnection _ FALSE]; SELECT TRUE FROM confirm = NIL => {reply _ do; local _ NIL}; ENDCASE => [reply, local] _ confirm[string _ MakeRemoteName[stp.plist, alto]]; SELECT reply FROM do => { completion: STP.Completion; SELECT op FROM delete => { code: CHARACTER _ 0C; mark: [0..256); PutCommand[stp, markYes, 0C, "Yes, please"]; [mark, code, stp.remoteString] _ GetCommand[stp]; SELECT mark FROM markYes => completion _ ok; markNo => completion _ error; ENDCASE => GenerateErrorString[stp, protocolError, stp.remoteString, code]}; retrieve => { PutCommand[stp, markYes, 0C, "Yes, please"]; completion _ IF GetFile[stp, local, stp.plist[nameBody]] THEN ok ELSE error}; store => { PutFile[stp, local, stp.plist[nameBody]]; ErrorIfNextNotYes[stp]}; ENDCASE; IF complete # NIL THEN complete[completion, stp.remoteString]; IF LookAtMark[stp] = markEOC THEN {[] _ MyGetMark[stp]; EXIT}}; skip => { IF op # directory THEN PutCommand[stp, markNo, 106C, "No Thanks"]; IF op = store THEN { mark: [0..256); code: CHARACTER; [mark, code, stp.remoteString] _ GetCommand[stp]; IF mark # markNo THEN GenerateErrorString[stp, protocolError, stp.remoteString, code]}; }; abort => {CleanUp[]; RETURN}; ENDCASE => ERROR; ResetPList[stp.plist]; ENDLOOP; EXITS streamClosing => GenerateStreamClosingError[stp, reason]}; END; TryNewDirectory: PROC[stp: STPOps.Handle, confirm: STP.ConfirmProcType] RETURNS[{finished, aborted, tryOldDirectory}] = { mark: [0..256); PutPList[stp, markNewDirectory]; DO SELECT (mark _ MyGetMark[stp]) FROM markComment => stp.remoteString _ CollectString[stp]; markHereIsPList => { string: Rope.ROPE; reply: STP.Confirmation; DO GetPList[stp: stp, gobbleEOC: FALSE, propertiesOk: TRUE ! MarkEncountered => { mark: [0..256) _ LookAtMark[stp]; IF mark = markEOC THEN EXIT ELSE GenerateProtocolError[stp, eocExpected, mark] }]; string _ MakeRemoteName[stp.plist, alto]; [answer: reply] _ confirm[string]; IF reply = abort THEN RETURN[aborted]; ENDLOOP; ErrorIfNextNotEOC[stp]; RETURN[finished]; }; markNo => BEGIN code: CHARACTER = CollectCode[stp]; errorCode: STP.ErrorCode = ErrorCodeToSTPErrorCode[requestRefused, code]; stp.remoteString _ CollectString[stp]; ErrorIfNextNotEOC[stp]; IF LOOPHOLE[code, STPReplyCode.ReplyCode] = badCommand THEN RETURN[tryOldDirectory]; GenerateErrorString[stp, errorCode, stp.remoteString, code]; END; ENDCASE => GenerateProtocolError[stp, badMark, mark, 0C]; ENDLOOP; }; GetFile: PUBLIC PROCEDURE [ stp: STPOps.Handle, stream: IO.STREAM, file: Rope.ROPE] RETURNS[gotIt: BOOLEAN] = BEGIN mark: [0..256); CheckConnection[stp]; SELECT (mark _ MyGetMark[stp]) FROM markHereIsFile => NULL; markNo => { [] _ CollectCode[stp]; stp.remoteString _ CollectString[stp]; RETURN[FALSE]}; ENDCASE => SelectError[stp, "HereIsFile Expected", mark]; TransferTheFile[stp: stp, from: stp.byteStream, to: stream]; stp.mark _ PupStream.ConsumeMark[stp.byteStream]; stp.gotMark _ TRUE; ErrorIfNextNotYes[stp]; -- should do something about file on local disk RETURN[TRUE] END; PutFile: PUBLIC PROCEDURE [ stp: STPOps.Handle, stream: IO.STREAM, file: Rope.ROPE, sendEOC: BOOLEAN _ TRUE] = BEGIN CheckConnection[stp]; PupStream.SendMark[stp.byteStream, markHereIsFile]; TransferTheFile[stp: stp, from: stream, to: stp.byteStream]; PutCommand[stp, markYes, 0C, "Transfer Completed", sendEOC]; END; TransferTheFile: PROCEDURE [stp: STPOps.Handle, from, to: IO.STREAM] = BEGIN buffer: REF TEXT = NEW[TEXT[1024]]; DO nBytes: NAT = from.GetBlock[buffer, 0, buffer.maxLength]; to.PutBlock[buffer, 0, nBytes]; IF from.EndOf[] THEN EXIT; ENDLOOP; END; SmashClosed: PUBLIC PROCEDURE [stp: STPOps.Handle] = BEGIN IF stp = NIL OR stp.byteStream = NIL THEN RETURN; PupStream.PupByteStreamAbort[stp.byteStream, "Unwinding..."]; STP.Close[stp ! STP.Error => IF code = noConnection THEN CONTINUE]; END; FindFileType: PUBLIC PROCEDURE [stream: IO.STREAM] RETURNS [fileType: STP.Type] = BEGIN ENABLE IO.Error => IF ec = NotImplementedForThisStream THEN GOTO unknown; currentIndex: INT = stream.GetIndex[]; stream.SetIndex[0]; fileType _ text; DO IF stream.GetChar[ ! IO.EndOfStream => EXIT] > 177C THEN {fileType _ binary; EXIT}; ENDLOOP; stream.SetIndex[currentIndex]; EXITS unknown => fileType _ unknown; END; END. -- of STPsB Nfile: STPsB.mesa - Simple/Stream Transfer Protocol Traditional FTP-like interface stuff in here Edited by: Smokey, 17-Jul-81 7:48:31 JGS, 17-Aug-81 11:26:24 Karlton, 15-Mar-82 17:26:37 Loretta, 10-Nov-81 16:07:59 Davirro, 24-Sep-82 10:35:49 Daniels, 21-Sep-82 13:05:55 Andrew Birrell, June 1, 1983 3:51 pm Data and types Procedures for normal FTP-like interface common routine for Delete, Enumerate and Retrieve Procedures for doing FTP protocol operations First smash connection so it will not give us any grief, THEN close it Ê h˜Jšœ3™3Jšœ,™,Jšœ ™ Jšœ!™!Jšœ&™&Jšœ"™"Jšœ"™"Jšœ"™"Jšœ"™"Jšœ$™$J˜šÏk ˜ Jšœ œœ˜JšœœNœ˜^Jšœ œR˜aJšœœœ˜šœœ˜ J˜EJ˜I—šœœ˜J˜RJ˜J˜SJ˜BJ˜(J˜SJ˜J˜HJ˜JJ˜—Jšœ œ ˜J˜—šœœ˜Jšœœ œ˜"Jšœœ ˜Jšœœ˜J˜—Jšœ™˜Jšœœœ˜$J˜—Jšœ)™)˜šÏnœœ œ˜Jšœœ œ˜BJšœ œ˜#Jšœ0œ˜9J˜—šž œœ œ˜Jšœœœ˜BJš˜šœœ˜Jš˜Jš œ œœœœ˜IJšœ˜—Jšœœœœ˜)J˜*Jšœ˜J˜—šžœœ œ˜Jšœ#œ˜*Jš˜J˜Jšœ œ˜J˜J˜J˜J˜"Jšœœ˜!J˜J˜J˜"J˜J˜5šœ#˜)J˜.—šœ˜J˜A—Jšœ˜J˜—šžœœ œ˜Jšœœ œœ˜HJšœ œœ˜)Jšœ2œ˜;J˜—šžœœ œ˜Jšœœ œœ˜7Jšœ œœ˜%Jšœ œœ˜.Jš˜šœ œ˜Jšœœ œœ˜/Jšœ œœœ˜+—J˜J˜J˜J˜#Jšœœ!˜;J˜J˜"J˜$Jšœœ ˜(Jšœ˜J˜——Jšœ1™1˜šžœœ œ˜Jšœœ œ˜BJšœ œ,˜9Jš˜J˜Jšœœ˜Jšœ œœ˜Jšœœœœ˜Jšœœœ˜šžœ œ˜Jš˜Jšœœ˜(Jšœ˜—šœœ˜ Jšœ*œ˜>Jšœ4œ˜HJšœ˜—šœ ˜Jš˜J˜J˜J˜J˜#Jšœ˜—šœœ˜šœ!œ ˜3šœœœœœœ œ˜@Jšœœ˜——Jšœ œ˜Jšœœ ˜'Jšœœ Ïc˜2Jšœœ˜—˜ J˜šœ˜J˜J˜J˜J˜Jšœœ˜—š˜Jšœœœ˜>šœ(œ ˜4šœœœœœœ œ˜@Jšœœ˜——šœœ˜Jšœ œœ˜+JšœG˜N—šœ˜˜Jšœ œ ˜šœ˜˜ Jšœ œ˜J˜J˜,J˜1šœ˜J˜J˜JšœE˜L——˜ J˜,Jšœ œ*œœ˜M—˜ J˜)J˜—Jšœ˜—Jšœ œœ(˜>Jšœœœ˜?—˜ šœ˜J˜+—šœ œ˜J˜Jšœ œ˜J˜1šœ˜J˜A——J˜—Jšœœ˜Jšœœ˜—J˜Jšœ˜—š˜J˜:—Jšœ˜J˜———šžœœœ˜HJšœ*˜1J˜J˜ š˜Jšœ˜#J˜5˜Jšœ œ˜Jšœœ˜š˜šœœ˜7˜J˜!Jšœœ˜Jšœ.˜2J˜——J˜)J˜"Jšœœœ ˜&Jšœ˜—J˜Jšœ ˜J˜—˜ Jš˜Jšœ œ˜#šœ œ ˜J˜/—J˜&J˜šœœ,˜;Jšœ˜—J˜œœ˜M—Jšœ2˜9—J˜