-- file: [Igor]<Emerson>STP>UnsafeSTPsA.mesa - Simple/Stream Transfer Protocol -- Initialization and Error stuff in here -- Edited by: -- Smokey, 16-Jul-81 14:54:32 -- Karlton, 9-Dec-81 18:23:36 -- Evans, Nov 14, 1980 9:35 AM -- Davirro, 24-Sep-82 9:03:45 -- Schmidt January 20, 1983 6:05 pm DIRECTORY Format USING [Octal, StringProc], Heap USING [systemZone], LongString USING [AppendString], UnsafeSTP USING [Error, ErrorCode, FileInfoObject], UnsafeSTPOps USING [ CollectCode, CollectString, ErrorIfNextNotEOC, GetCommand, GetServerType, Handle, markComment, markIAmVersion, markNo, maxStringLength, Object, PList, PListArray, ProtocolError, PutCommand, UserProperties, ValidProperties], UnsafeSTPReplyCode USING [ReplyCode], UnsafeSTPRubicon USING[AppendStringAndGrow, EmptyString, StringLength], 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]; UnsafeSTPsA: PROGRAM IMPORTS Format, Heap, PupStream, LongString, STP: UnsafeSTP, STPOps: UnsafeSTPOps, STPRubicon: UnsafeSTPRubicon EXPORTS UnsafeSTP, UnsafeSTPOps = BEGIN OPEN PupStream, STPOps; -- Global Data Error: PUBLIC SIGNAL [ stp: STPOps.Handle, code: STP.ErrorCode, error: LONG STRING, reply: CHARACTER ← 0C] = CODE; Object: PUBLIC TYPE = STPOps.Object; z: UNCOUNTED ZONE = Heap.systemZone; -- 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[stp: stp, 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]; IF stp.info ~= NIL THEN z.FREE[@stp.info]; IF stp.remoteString ~= NIL THEN z.FREE[@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 => z.FREE[@stp]; stp ← z.NEW[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]; IF stp.host ~= NIL THEN z.FREE[@stp.host]; FOR i: STPOps.UserProperties IN STPOps.UserProperties DO IF stp.userState[i] ~= NIL THEN z.FREE[@stp.userState[i]]; ENDLOOP; z.FREE[@stp]; PupStream.PupPackageDestroy[]; RETURN[NIL]; END; Open: PUBLIC PROCEDURE [stp: STPOps.Handle, host: LONG STRING] RETURNS [herald: LONG STRING] = BEGIN reason: PupStream.CloseReason; IF stp = NIL THEN RETURN[NIL]; IF stp.byteStream # NIL THEN ERROR Error[stp, alreadyAConnection, "You already have a connection?"L]; BEGIN shortHost: STRING ← [40]; server: PupStream.PupAddress ← [PupTypes.fillInNetID, PupTypes.fillInHostID, [0, 3]]; stpOptions: Stream.InputOptions = [ -- signalAttention: TRUE,-- terminateOnEndPhysicalRecord: FALSE, signalLongBlock: FALSE, signalShortBlock: FALSE, signalSSTChange: TRUE, signalEndOfStream: TRUE]; server.socket ← [0, 3]; LongString.AppendString[shortHost, host]; PupStream.GetPupAddress[ @server, shortHost ! PupStream.PupNameTrouble => GenerateErrorString[stp, noSuchHost, e]]; stp.byteStream ← PupStream.PupByteStreamCreate[ server, PupStream.veryLongWait ! PupStream.StreamClosing => {reason ← why; GOTO streamClosing}]; stp.byteStream.options ← stpOptions; stp.remoteString ← z.NEW[StringBody[maxStringLength]]; stp.plist ← MakePList[]; stp.info ← z.NEW[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 ← z.NEW[StringBody[80]]; BEGIN ENABLE UNWIND => z.FREE[@herald]; code: CHARACTER; mark: Stream.SubSequenceType; [mark, code] ← GetCommand[stp, @herald]; IF mark # markIAmVersion THEN GenerateProtocolError[stp, badVersion, mark, code]; ErrorIfNextNotEOC[stp]; END; RETURN[herald]; EXITS streamClosing => {CloseInternal[stp]; GenerateStreamClosingError[stp, 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 IF plist[i] ~= NIL THEN z.FREE[@plist[i]]; ENDLOOP; z.FREE[@plist]; END; RETURN[NIL] END; MakePList: PUBLIC PROCEDURE RETURNS [plist: PList] = BEGIN i: STPOps.ValidProperties; plist ← z.NEW[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] = { replyCode: UnsafeSTPReplyCode.ReplyCode = LOOPHOLE[code]; RETURN[SELECT replyCode 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 [ stp: STPOps.Handle, errorCode: STP.ErrorCode, string: LONG STRING , code: CHARACTER ← 0C] = BEGIN ERROR Error[stp, ErrorCodeToSTPErrorCode[errorCode, code], IF STPRubicon.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 [stp: STPOps.Handle, why: PupStream.CloseReason] = BEGIN GenerateErrorString[stp, SELECT why FROM localClose, remoteClose => connectionClosed, noRouteToNetwork => noRouteToNetwork, transmissionTimeout => connectionTimedOut, remoteReject => connectionRejected, ENDCASE => ERROR, NIL]; END; GenerateProtocolError: PUBLIC PROCEDURE [ stp: STPOps.Handle, type: ProtocolError, mark: Stream.SubSequenceType, code: CHARACTER ← 0C] = BEGIN string: LONG STRING ← NIL; MyAppend: Format.StringProc = BEGIN STPRubicon.AppendStringAndGrow[to: @string, from: s, z: z]; END; STPRubicon.AppendStringAndGrow[ 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, z: z]; STPRubicon.AppendStringAndGrow[to: @string, from: ", mark ="L, z: z]; Format.Octal[proc: MyAppend, n: mark]; STPRubicon.AppendStringAndGrow[to: @string, from: ", code ="L, z: z]; Format.Octal[proc: MyAppend, n: code]; ERROR Error[stp, protocolError, string, code ! UNWIND => z.FREE[@string]]; END; SelectError: PUBLIC PROCEDURE [ stp: STPOps.Handle, s: LONG 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]; GenerateErrorString[ stp, requestRefused, IF STPRubicon.EmptyString[stp.remoteString] THEN s ELSE stp.remoteString, code]; END ELSE GenerateProtocolError[stp, badMark, mark, code]; END; -- NOP and ERROR Stream routines GetError: PUBLIC Stream.GetProcedure = { ERROR STP.Error[NIL, accessError, "Attempt to Get from a store stream"L]}; PutError: PUBLIC Stream.PutProcedure = { ERROR STP.Error[NIL, 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