-- file: [Igor]STP>Private>UnsafeSTPsC.mesa - Simple/Stream Transfer Protocol -- Remote Stream stuff in here -- Edited by: -- Smokey 16-Jul-81 17:24:59 -- Sandman 17-Aug-81 11:32:55 -- Karlton 9-Dec-81 18:36:06 -- SHayes 11-Sep-81 16:15:34 -- Bruce 20-Oct-81 11:24:17 -- Johnsson 16-Dec-81 17:39:42 -- Daniels 21-Sep-82 13:06:31 -- Davirro 24-Sep-82 10:45:37 -- Schmidt January 20, 1983 7:10 pm DIRECTORY Heap USING [systemMDSZone, systemZone], PupStream USING [CloseReason, StreamClosing], UnsafeSTP USING [Access, CredentialsErrors, Error, FileErrors, Type], UnsafeSTPOps USING [ CheckConnection, ErrorIfNextNotEOC, ErrorIfNextNotYes, GenerateProtocolError, GenerateStreamClosingError, GetHereIsAndPList, Handle, LookAtMark, MakeRemoteName, markEOC, markHereIsFile, markHereIsPList, markNewStore, markNo, markRetrieve, markYes, MyGetMark, NameToPList, Object, ResetPList, PList, PutCommand, PutPList, RemoteObject, RemoteStream, SelectError, SetByteSize, SetCreateTime, SetFileType, SmashClosed, UserStateToPList, SetSSTNop, SendAttentionNop, WaitAttentionNop], Stream USING [ Block, Byte, CompletionCode, -- defaultObject, -- DeleteProcedure, EndOfStream, GetBlock, GetProcedure, Handle, InputOptions, Object, PutBlock, PutByte, PutProcedure, -- SendNow, SendNowProcedure, -- SetSST, SSTChange, SubSequenceType, Word], UnsafeSTPRubicon USING [Replace], Time USING [Packed]; UnsafeSTPsC: PROGRAM IMPORTS Heap, PupStream, STP: UnsafeSTP, STPOps: UnsafeSTPOps, UnsafeSTPRubicon, Stream EXPORTS UnsafeSTP, UnsafeSTPOps = BEGIN OPEN PupStream, STPOps; z: UNCOUNTED ZONE = Heap.systemZone; Object: PUBLIC TYPE = STPOps.Object; -- Procedures implementing STP interface CreateRemoteStream: PUBLIC PROCEDURE [ stp: STPOps.Handle, file: LONG STRING, access: STP.Access, fileType: STP.Type, options: Stream.InputOptions, creation: Time.Packed] RETURNS [stream: Stream.Handle] = BEGIN rs: STPOps.RemoteStream; CheckConnection[stp]; IF stp.remoteStream # NIL THEN ERROR STP.Error[stp, accessError, "Remote Stream Exists"L]; rs _ Heap.systemMDSZone.NEW[STPOps.RemoteObject]; rs^ _ STPOps.RemoteObject[ access: access, state: initial, stp: stp, stream: [ options: options, get: GetBlock, put: PutBlock, getByte: GetByte, putByte: PutByte, getWord: GetWord, putWord: PutWord, setSST: STPOps.SetSSTNop, sendAttention: STPOps.SendAttentionNop, waitAttention: STPOps.WaitAttentionNop, -- sendNow: SendNow,-- delete: DeleteRemoteStream --, getPosition: Stream.defaultObject.getPosition, -- setPosition: Stream.defaultObject.setPosition-- ]]; ResetPList[stp.plist]; UserStateToPList[stp]; NameToPList[stp.plist, file, alto]; SetFileType[stp, fileType]; IF access = write THEN { STPOps.SetCreateTime[stp, creation]; SetByteSize[stp, fileType]}; IF fileType = text THEN UnsafeSTPRubicon.Replace[@stp.plist[eolConversion], "CR"L, z]; stp.remoteStream _ rs; RETURN[@rs.stream] END; NextFileName: PUBLIC PROCEDURE [remoteStream: Stream.Handle] RETURNS [file: LONG STRING] = BEGIN rs: RemoteStream _ ConvertHandle[remoteStream]; reason: PupStream.CloseReason; IF rs.access # read THEN ERROR STP.Error[rs.stp, accessError, NIL]; BEGIN ENABLE PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; SELECT rs.state FROM initial => RequestRetrieve[rs]; confirm => BEGIN PutCommand[rs.stp, markNo, 0C, "No Thanks"L]; IF LookAtMark[rs.stp] = markEOC THEN {[] _ MyGetMark[rs.stp]; rs.state _ end} ELSE GetHereIsAndPList[rs.stp]; END; data => BEGIN ErrorIfNextNotYes[rs.stp]; IF LookAtMark[rs.stp] = markEOC THEN {[] _ MyGetMark[rs.stp]; rs.state _ end} ELSE {GetHereIsAndPList[rs.stp]; rs.state _ confirm}; END; complete => IF LookAtMark[rs.stp] = markEOC THEN {[] _ MyGetMark[rs.stp]; rs.state _ end} ELSE {GetHereIsAndPList[rs.stp]; rs.state _ confirm}; end => NULL; ENDCASE; EXITS streamClosing => GenerateStreamClosingError[rs.stp, reason]; END; RETURN[IF rs.state = end THEN NIL ELSE MakeRemoteName[rs.stp.plist, alto]] END; -- Procedures for Remote streams conversionFudge: CARDINAL = LOOPHOLE[@LOOPHOLE[0, RemoteStream].stream]; ConvertHandle: PROCEDURE [h: Stream.Handle] RETURNS [rs: RemoteStream] = INLINE BEGIN RETURN[LOOPHOLE[h - conversionFudge]] END; DeleteRemoteStream: PUBLIC Stream.DeleteProcedure = BEGIN rs: RemoteStream _ ConvertHandle[sH]; stp: STPOps.Handle = rs.stp; {ENABLE UNWIND => {stp.remoteStream _ NIL; Heap.systemMDSZone.FREE[@rs]}; IF rs.access = read THEN {IF rs.state # end THEN SmashClosed[stp]} -- in mid-transfer ELSE SELECT rs.state FROM initial => NULL; data => { PutCommand[rs.stp, markYes, 0C, "Transfer Completed"L ! PupStream.StreamClosing => CONTINUE]; -- OK, if closed in advance ErrorIfNextNotYes[rs.stp]; ErrorIfNextNotEOC[rs.stp]}; confirm, complete, end => NULL; -- worry about later ENDCASE; stp.remoteStream _ NIL; Heap.systemMDSZone.FREE[@rs]}; END; GetByte: PUBLIC PROCEDURE [sH: Stream.Handle] RETURNS [byte: Stream.Byte] = BEGIN options: Stream.InputOptions = [FALSE, FALSE, TRUE, TRUE, TRUE]; rs: RemoteStream _ ConvertHandle[sH]; bytesTransferred: CARDINAL; charArray: PACKED ARRAY [0..1] OF Stream.Byte; block: Stream.Block _ [@charArray, 0, 1]; [bytesTransferred,,] _ GetBlock[sH, block, options]; RETURN[IF bytesTransferred # 0 THEN charArray[0] ELSE 0] END; GetWord: PUBLIC PROCEDURE [sH: Stream.Handle] RETURNS [word: Stream.Word] = BEGIN t: UNSPECIFIED = CARDINAL[GetByte[sH]]*256; RETURN[t + GetByte[sH]]; END; GetBlock: PUBLIC Stream.GetProcedure = BEGIN rs: RemoteStream _ ConvertHandle[sH]; reason: PupStream.CloseReason; BEGIN ENABLE PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; IF rs.state # data THEN BEGIN StartRemote[rs, read]; IF rs.state = end THEN GOTO done; END; [bytesTransferred, why, sst] _ Stream.GetBlock[ rs.stp.byteStream, block ! Stream.EndOfStream => {bytesTransferred _ nextIndex; GOTO done}; Stream.SSTChange => { rs.stp.mark _ sst; rs.stp.gotMark _ TRUE; bytesTransferred _ nextIndex - block.startIndex; CONTINUE}]; IF rs.stp.gotMark THEN {SetupForNextOrEnd[rs.stp]; GOTO done}; EXITS streamClosing => {rs.state _ end; GenerateStreamClosingError[rs.stp, reason]}; done => BEGIN why _ endOfStream; IF options.signalEndOfStream THEN Stream.EndOfStream[nextIndex: bytesTransferred]; END; END; END; PutByte: PUBLIC PROCEDURE [sH: Stream.Handle, byte: Stream.Byte] = BEGIN rs: RemoteStream _ ConvertHandle[sH]; reason: PupStream.CloseReason; BEGIN ENABLE PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; IF rs.state # data THEN StartRemote[rs, write]; Stream.PutByte[rs.stp.byteStream, byte]; EXITS streamClosing => {rs.state _ end; GenerateStreamClosingError[rs.stp, reason]}; END; END; PutWord: PUBLIC PROCEDURE [sH: Stream.Handle, word: Stream.Word] = BEGIN PutByte[sH, CARDINAL[word]/256]; PutByte[sH, CARDINAL[word] MOD 256]; END; PutBlock: PUBLIC Stream.PutProcedure = BEGIN rs: RemoteStream _ ConvertHandle[sH]; reason: PupStream.CloseReason; BEGIN ENABLE PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; IF rs.state # data THEN StartRemote[rs, write]; Stream.PutBlock[rs.stp.byteStream, block, FALSE]; EXITS streamClosing => {rs.state _ end; GenerateStreamClosingError[rs.stp, reason]}; END; END; -- SendNow: PUBLIC Stream.SendNowProcedure = -- BEGIN -- rs: RemoteStream _ ConvertHandle[sH]; -- reason: PupStream.CloseReason; -- BEGIN -- ENABLE PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; -- IF rs.state # data THEN StartRemote[rs, write]; -- Stream.SendNow[rs.stp.byteStream, TRUE]; -- EXITS streamClosing => {rs.state _ end; GenerateStreamClosingError[rs.stp, reason]}; -- END; -- END; -- Utilities SetupForNextOrEnd: PROCEDURE [stp: STPOps.Handle] = BEGIN ErrorIfNextNotYes[stp]; SELECT LookAtMark[stp] FROM markEOC => {[] _ MyGetMark[stp]; stp.remoteStream.state _ end}; markHereIsPList => stp.remoteStream.state _ complete; ENDCASE => GenerateProtocolError[stp, badMark, MyGetMark[stp]]; END; RequestRetrieve: PROCEDURE [rs: RemoteStream] = BEGIN PutPList[rs.stp, markRetrieve]; GetHereIsAndPList[rs.stp ! STP.Error => SELECT code FROM IN STP.CredentialsErrors, IN STP.FileErrors => rs.state _ end; ENDCASE]; rs.state _ confirm; END; StartRemote: PROCEDURE [rs: RemoteStream, access: STP.Access] = BEGIN reason: PupStream.CloseReason; IF rs.access # access THEN ERROR STP.Error[rs.stp, accessError, "Remote stream access Error"L]; BEGIN ENABLE PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; SELECT access FROM read => BEGIN IF rs.state = initial THEN RequestRetrieve[rs]; IF rs.state = complete THEN { IF LookAtMark[rs.stp] = markEOC THEN {rs.state _ end; RETURN} ELSE GetHereIsAndPList[rs.stp]; rs.state _ confirm}; IF rs.state = confirm THEN BEGIN mark: Stream.SubSequenceType; PutCommand[rs.stp, markYes, 0C, "Yes, please"L]; SELECT (mark _ MyGetMark[rs.stp]) FROM markHereIsFile => NULL; markNo => {rs.state _ complete; SelectError[rs.stp, "He says NO"L, mark]}; ENDCASE => SelectError[rs.stp, "HereIsFile Expected"L, mark]; END; END; write => BEGIN PutPList[rs.stp, markNewStore]; GetHereIsAndPList[rs.stp]; Stream.SetSST[rs.stp.byteStream, markHereIsFile]; END; ENDCASE => ERROR; rs.state _ data; EXITS streamClosing => GenerateStreamClosingError[rs.stp, reason]; END; END; END. of STPsC