-- file: STPsA.mesa - Simple/Stream Transfer Protocol -- Initialization and Error stuff in here -- Edited by: -- Smokey on: 12-Mar-81 13:23:33 -- Karlton on: Oct 26, 1980 4:07 PM -- Evans on: Nov 14, 1980 9:35 AM DIRECTORY Format USING [Octal, StringProc], HeapString USING [AppendString], STP USING [ defaultOptions, Error, ErrorCode, FileInfoObject], STPOps USING [ CollectCode, CollectString, ErrorIfNextNotEOC, GetCommand, GetServerType, Handle, markComment, markIAmVersion, markNo, maxStringLength, Object, PList, PListArray, ProtocolError, PutCommand, UserProperties, ValidProperties], STPReplyCode, PupStream USING [ CloseReason, GetPupAddress, PupAddress, PupByteStreamCreate, PupNameTrouble, PupPackageDestroy, PupPackageMake, StreamClosing, veryLongWait], PupTypes USING [fillInHostID, fillInNetID], Stream USING [ GetProcedure, Handle, InputOptions, PutProcedure, SendAttentionProcedure, SetSSTProcedure, SubSequenceType, WaitAttentionProcedure], Storage USING [ EmptyString, Free, FreeNodeNil, FreeString, FreeStringNil, Node, String, StringLength]; STPsA: PROGRAM IMPORTS Format, HeapString, PupStream, Storage, STP, STPOps EXPORTS STP, STPOps = BEGIN OPEN PupStream, STPOps; -- Global Data Error: PUBLIC SIGNAL [ code: STP.ErrorCode, error: STRING, reply: CHARACTER ← 0C] = CODE; Object: PUBLIC TYPE = STPOps.Object; -- Public Interface Routines Close: PUBLIC PROCEDURE [stp: STPOps.Handle] = BEGIN nilByteStream: BOOLEAN; IF stp = NIL THEN RETURN; nilByteStream ← stp.byteStream = NIL; CloseInternal[stp]; IF nilByteStream THEN ERROR Error[code: noConnection, error: "Attempt to Close a NIL connection"L]; END; CloseInternal: PUBLIC PROCEDURE [stp: STPOps.Handle] = BEGIN IF stp = NIL THEN RETURN; stp.plist ← DestroyPList[stp.plist]; stp.info ← Storage.FreeNodeNil[stp.info]; stp.remoteString ← Storage.FreeStringNil[stp.remoteString]; IF stp.byteStream # NIL THEN BEGIN stp.byteStream.delete[stp.byteStream ! PupStream.StreamClosing => CONTINUE]; stp.byteStream ← NIL; END; END; Create: PUBLIC PROCEDURE RETURNS [stp: STPOps.Handle] = BEGIN OPEN PupTypes; ENABLE UNWIND => Storage.Free[stp]; stp ← Storage.Node[SIZE[STPOps.Object]]; PupStream.PupPackageMake[]; stp↑ ← STPOps.Object[]; RETURN[stp]; END; Destroy: PUBLIC PROCEDURE [stp: STPOps.Handle] RETURNS [Handle] = BEGIN IF stp = NIL THEN RETURN[NIL]; IF stp.byteStream # NIL THEN Close[stp]; stp.host ← Storage.FreeStringNil[stp.host]; FOR i: STPOps.UserProperties IN STPOps.UserProperties DO stp.userState[i] ← Storage.FreeStringNil[stp.userState[i]]; ENDLOOP; Storage.Free[stp]; PupStream.PupPackageDestroy[]; RETURN[NIL]; END; Open: PUBLIC PROCEDURE [stp: STPOps.Handle, host: STRING] RETURNS [herald: STRING] = BEGIN reason: PupStream.CloseReason; IF stp = NIL THEN RETURN[NIL]; IF stp.byteStream # NIL THEN ERROR Error[alreadyAConnection, "You already have a connection?"L]; BEGIN server: PupStream.PupAddress ← [PupTypes.fillInNetID, PupTypes.fillInHostID, [0, 3]]; server.socket ← [0, 3]; PupStream.GetPupAddress[ @server, host ! PupStream.PupNameTrouble => GenerateErrorString[noSuchHost, e]]; stp.byteStream ← PupStream.PupByteStreamCreate[ server, PupStream.veryLongWait ! PupStream.StreamClosing => {reason ← why; GOTO streamClosing}]; stp.byteStream.options ← STP.defaultOptions; stp.remoteString ← Storage.String[maxStringLength]; stp.plist ← MakePList[]; stp.info ← Storage.Node[SIZE[STP.FileInfoObject]]; stp.info↑ ← []; stp.gotMark ← FALSE; stp.serverType ← GetServerType[host]; PutCommand[stp, markIAmVersion, 1C, "STP calling"L ! PupStream.StreamClosing => {reason ← why; GOTO streamClosing}]; herald ← Storage.String[80]; BEGIN ENABLE UNWIND => Storage.Free[herald]; code: CHARACTER; mark: Stream.SubSequenceType; [mark, code] ← GetCommand[stp, @herald]; IF mark # markIAmVersion THEN GenerateProtocolError[badVersion, mark, code]; ErrorIfNextNotEOC[stp]; END; RETURN[herald]; EXITS streamClosing => {CloseInternal[stp]; GenerateStreamClosingError[reason]}; END; END; -- PList Utilities DestroyPList: PUBLIC PROCEDURE [plist: PList] RETURNS [PList] = BEGIN i: STPOps.ValidProperties; IF plist # NIL THEN BEGIN FOR i IN STPOps.ValidProperties DO Storage.FreeString[plist[i]]; ENDLOOP; Storage.Free[plist]; END; RETURN[NIL] END; MakePList: PUBLIC PROCEDURE RETURNS [plist: PList] = BEGIN i: STPOps.ValidProperties; plist ← Storage.Node[SIZE[PListArray]]; FOR i IN STPOps.ValidProperties DO plist[i] ← NIL; ENDLOOP; END; -- Error generation routines ErrorCodeToSTPErrorCode: PUBLIC PROCEDURE [ errorCode: STP.ErrorCode, code: CHARACTER] RETURNS [STP.ErrorCode] = {OPEN STPReplyCode; RETURN[SELECT code FROM null => errorCode, badCommand => protocolError, noUserName => illegalUserName, illegalCommand => protocolError, badPList => protocolError, illegalServerFilename => illegalFileName, illegalDirectory => illegalFileName, illegalNameBody => illegalFileName, illegalVersion => illegalFileName, illegalType => accessError, illegalCHARACTERSize => accessError, illegalEOLConversion => accessError, illegalUserName => illegalUserName, illegalUserPassword => illegalUserPassword, illegalUserAccount => illegalUserAccount, illegalConnectName => illegalConnectName, illegalConnectPassword => illegalConnectPassword, illegalCreationDate => illegalFileName, illegalWriteDate => illegalFileName, illegalReadDate => illegalFileName, illegalAuthor => illegalFileName, illegalDevice => illegalFileName, fileNotFound => noSuchFile, accessDenied => accessDenied, inconsistent => protocolError, fileDataError => errorCode, tooLong => errorCode, dontSend => errorCode, notCompleted => errorCode, transientError => errorCode, permanentError => errorCode, fileBusy => errorCode, ENDCASE => errorCode] -- can't do any better--}; GenerateErrorString: PUBLIC PROCEDURE [ errorCode: STP.ErrorCode, string: STRING, code: CHARACTER ← 0C] = BEGIN ERROR Error[ ErrorCodeToSTPErrorCode[errorCode, code], IF Storage.StringLength[string] # 0 THEN string ELSE SELECT errorCode FROM noSuchHost => "No such host!"L, noRouteToNetwork => "No route to network!"L, noNameLookupResponse => "Name lookup server is not responding"L, alreadyAConnection => "You already have a connection!"L, noConnection => "Please open a connection!"L, connectionClosed => "Connection closed (local or remote)!"L, connectionRejected => "Connection rejected by remote host!"L, connectionTimedOut => "Connection timed out!"L, accessDenied => "Access denied by remote server!"L, illegalUserName => "Invalid or illegal UserName!"L, illegalUserPassword => "Invalid or illegal UserPassword!"L, illegalUserAccount => "Invalid or illegal UserAccount!"L, illegalConnectName => "Invalid or illegal ConnectName!"L, illegalConnectPassword => "Invalid or illegal ConnectPassword!"L, credentailsMissing => "Name and/or Password not supplied!"L, protocolError => "Internal FTP protocol error!"L, illegalFileName => "Illegal filename!"L, noSuchFile => "File not found!"L, requestRefused => "Request refused by remote host!"L, accessError => "Illegal access attempt on remote stream!"L, undefinedError => "Undefined error!"L, ENDCASE => ERROR, code]; END; GenerateStreamClosingError: PUBLIC PROCEDURE [why: PupStream.CloseReason] = BEGIN GenerateErrorString[ SELECT why FROM localClose, remoteClose => connectionClosed, noRouteToNetwork => noRouteToNetwork, transmissionTimeout => connectionTimedOut, remoteReject => connectionRejected, ENDCASE => ERROR, NIL]; END; GenerateProtocolError: PUBLIC PROCEDURE [ type: ProtocolError, mark: Stream.SubSequenceType, code: CHARACTER ← 0C] = BEGIN string: STRING ← NIL; MyAppend: Format.StringProc = BEGIN HeapString.AppendString[to: @string, from: s]; END; HeapString.AppendString[ to: @string, from: SELECT type FROM badVersion => "Incompatable protocol version"L, badMark => "Invalid or undefined mark byte"L, badPList => "Invalid or malformed property list"L, eocExpected => "End-Of-Command mark byte expected"L, noCode => "error code is required after error mark byte"L, ENDCASE => ERROR]; HeapString.AppendString[to: @string, from: ", mark ="L]; Format.Octal[mark, MyAppend]; HeapString.AppendString[to: @string, from: ", code ="L]; Format.Octal[code, MyAppend]; ERROR Error[ protocolError, string, code ! UNWIND => Storage.FreeString[string]]; END; SelectError: PUBLIC PROCEDURE [ stp: STPOps.Handle, s: STRING, mark: Stream.SubSequenceType] = BEGIN code: CHARACTER ← 0C; IF mark = markNo OR mark = markComment THEN BEGIN IF mark # markComment THEN code ← CollectCode[stp]; CollectString[stp, @stp.remoteString]; ErrorIfNextNotEOC[stp]; GenerateErrorString[ requestRefused, IF Storage.EmptyString[stp.remoteString] THEN s ELSE stp.remoteString, code]; END ELSE GenerateProtocolError[badMark, mark, code]; END; -- NOP and ERROR Stream routines GetError: PUBLIC Stream.GetProcedure = { ERROR STP.Error[accessError, "Attempt to Get from a store stream"L]}; PutError: PUBLIC Stream.PutProcedure = { ERROR STP.Error[accessError, "Attempt to Put on a retrieve stream"L]}; SetSSTNop: PUBLIC Stream.SetSSTProcedure = BEGIN END; SendAttentionNop: PUBLIC Stream.SendAttentionProcedure = BEGIN END; WaitAttentionNop: PUBLIC Stream.WaitAttentionProcedure = BEGIN RETURN[0B] END; END. -- of STPsA