<> <> <> <> <> <> <> <> <> <> <> DIRECTORY BasicTime USING [GMT], IO USING [EndOf, EndOfStream, Error, GetBlock, GetChar, GetIndex, GetLength, int, PutBlock, PutFR, 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, SetPListItem, UserStateToPList], STPReplyCode USING[ReplyCode]; STPsB: CEDAR PROGRAM IMPORTS IO, PupStream, STP, STPOps EXPORTS STP, STPOps = { OPEN PupStream, STPOps; <> Object: PUBLIC TYPE = STPOps.Object; <> Delete: PUBLIC PROC [stp: STPOps.Handle, name: Rope.ROPE, confirm: STP.ConfirmProcType, complete: STP.CompletionProcType] = { DoFiles[stp, name, confirm, complete, delete]; }; Enumerate: PUBLIC PROC [stp: STPOps.Handle, name: Rope.ROPE, proc: STP.NoteFileProcType] = { Foo1: STP.ConfirmProcType = { RETURN[answer: IF proc[file] = yes THEN do ELSE abort, localStream: NIL]; }; Foo2: STP.CompletionProcType = { }; DoFiles[stp, name, Foo1, Foo2, directory]; }; Rename: PUBLIC PROC [stp: STPOps.Handle, old, new: Rope.ROPE] = { mark, saveMark: [0..256); code: CHAR _ 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]; }; Retrieve: PUBLIC PROC [stp: STPOps.Handle, file: Rope.ROPE, confirm: STP.ConfirmProcType _ NIL, complete: STP.CompletionProcType _ NIL] = { DoFiles[stp, file, confirm, complete, retrieve]; }; Store: PUBLIC PROC [stp: STPOps.Handle, file: Rope.ROPE, stream: IO.STREAM, noteFile: STP.NoteFileProcType _ NIL, fileType: STP.Type, creation: BasicTime.GMT] = { size: INT _ 0; 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]; size _ stream.GetLength[ ! IO.Error => CONTINUE;]; IF size # 0 THEN STPOps.SetPListItem[stp.plist, "Size", IO.PutFR["%g", IO.int[size]]]; DoFiles[stp, file, Confirm, NIL, store]; }; <> DoFiles: PUBLIC PROC [stp: STPOps.Handle, file: Rope.ROPE, confirm: STP.ConfirmProcType, complete: STP.CompletionProcType, op: STPOps.Operation] = { reason: PupStream.CloseReason; reply: STP.Confirmation; string: Rope.ROPE _ NIL; local: IO.STREAM _ NIL; killConnection: BOOLEAN _ TRUE; CleanUp: PROC = { IF killConnection THEN SmashClosed[stp]; }; {ENABLE { PupStream.StreamClosing => {reason _ why; GOTO streamClosing}; PupStream.TimeOut => {reason _ transmissionTimeout; GOTO streamClosing}; UNWIND => CleanUp[]}; IF op # store THEN { CheckConnection[stp]; ResetPList[stp.plist]; UserStateToPList[stp]; NameToPList[stp.plist, file, alto]; }; 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: CHAR _ 0C; mark: [0..256); PutCommand[stp, markYes, 0C, "Yes, please"]; [mark, code, stp.remoteString] _ GetCommand[stp]; SELECT mark FROM markYes => completion _ ok; markNo => IF complete = NIL THEN GenerateErrorString[stp, requestRefused, stp.remoteString, code] ELSE completion _ error; ENDCASE => GenerateErrorString[stp, protocolError, stp.remoteString, code]}; retrieve => { code: CHAR _ 0C; gotIt: BOOLEAN; PutCommand[stp, markYes, 0C, "Yes, please"]; [gotIt, code] _ GetFile[stp, local, stp.plist[nameBody]]; completion _ IF gotIt THEN ok ELSE error; IF completion = error AND complete = NIL THEN GenerateErrorString[stp, requestRefused, stp.remoteString, code]}; 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: CHAR; [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]}; }; 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 => { code: CHAR = CollectCode[stp]; errorCode: STP.ErrorCode = ErrorCodeToSTPErrorCode[requestRefused, code]; stp.remoteString _ CollectString[stp]; ErrorIfNextNotEOC[stp]; SELECT errorCode FROM protocolError, requestRefused => RETURN[tryOldDirectory]; <> ENDCASE; IF LOOPHOLE[code, STPReplyCode.ReplyCode] = badCommand THEN RETURN[tryOldDirectory]; GenerateErrorString[stp, errorCode, stp.remoteString, code]; }; ENDCASE => GenerateProtocolError[stp, badMark, mark, 0C]; ENDLOOP; }; <> GetFile: PUBLIC PROC [ stp: STPOps.Handle, stream: IO.STREAM, file: Rope.ROPE] RETURNS[gotIt: BOOLEAN, code: CHAR] = { mark: [0..256); CheckConnection[stp]; SELECT (mark _ MyGetMark[stp]) FROM markHereIsFile => NULL; markNo => { code _ CollectCode[stp]; stp.remoteString _ CollectString[stp]; gotIt _ FALSE; RETURN}; 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 gotIt _ TRUE; RETURN }; PutFile: PUBLIC PROC [ stp: STPOps.Handle, stream: IO.STREAM, file: Rope.ROPE, sendEOC: BOOLEAN _ TRUE] = { CheckConnection[stp]; PupStream.SendMark[stp.byteStream, markHereIsFile]; TransferTheFile[stp: stp, from: stream, to: stp.byteStream]; PutCommand[stp, markYes, 0C, "Transfer Completed", sendEOC]; }; TransferTheFile: PROC [stp: STPOps.Handle, from, to: IO.STREAM] = { buffer: REF TEXT = NEW[TEXT[1024]]; buffer.length _ buffer.maxLength; DO nBytes: NAT = from.GetBlock[buffer, 0, buffer.maxLength]; to.PutBlock[buffer, 0, nBytes]; IF from.EndOf[] THEN EXIT; ENDLOOP; }; SmashClosed: PUBLIC PROC [stp: STPOps.Handle] = { IF stp = NIL OR stp.byteStream = NIL THEN RETURN; <> PupStream.PupByteStreamAbort[stp.byteStream, "Unwinding..."]; STP.Close[stp ! STP.Error => IF code = noConnection THEN CONTINUE]; }; FindFileType: PUBLIC PROC [stream: IO.STREAM] RETURNS [fileType: STP.Type] = { 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; }; }. <> <> <> <<>> <<>>