<> <> <> <> <> <> <> <> DIRECTORY IO USING [Close, PutFR, STREAM], Rope USING [Length, ROPE], STP USING [ErrorCode, FileInfoObject], STPOps USING [CollectCode, CollectString, ErrorIfNextNotEOC, GetCommand, GetServerType, Handle, markComment, markIAmVersion, markNo, Object, PList, PListArray, ProtocolError, PutCommand, UserProperties], STPReplyCode USING [ReplyCode], PupStream USING [CloseReason, GetPupAddress, PupAddress, PupByteStreamCreate, PupNameTrouble, PupPackageDestroy, PupPackageMake, StreamClosing, veryLongWait], PupTypes USING [ftpSoc]; STPsA: CEDAR PROGRAM IMPORTS IO, PupStream, Rope, STPOps EXPORTS STP, STPOps = { OPEN PupStream, STPOps; ErrorCode: TYPE = STP.ErrorCode; Handle: TYPE = STPOps.Handle; ROPE: TYPE = Rope.ROPE; <> Error: PUBLIC SIGNAL [stp: Handle, code: ErrorCode, error: ROPE, reply: CHAR _ 0C] = CODE; Object: PUBLIC TYPE = STPOps.Object; <> Close: PUBLIC PROCEDURE [stp: Handle] = { 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"]; }; CloseInternal: PUBLIC PROCEDURE [stp: Handle] = { IF stp = NIL THEN RETURN; stp.plist _ DestroyPList[stp.plist]; IF stp.byteStream # NIL THEN { stp.byteStream.Close[ ! PupStream.StreamClosing => CONTINUE]; stp.byteStream _ NIL; }; }; Create: PUBLIC PROCEDURE RETURNS [stp: Handle] = { OPEN PupTypes; PupStream.PupPackageMake[]; stp _ NEW[STPOps.Object _ []]; RETURN[stp]; }; Destroy: PUBLIC PROCEDURE [stp: Handle] RETURNS [Handle] = { IF stp = NIL THEN RETURN[NIL]; IF stp.byteStream # NIL THEN Close[stp]; PupStream.PupPackageDestroy[]; RETURN[NIL]; }; Open: PUBLIC PROCEDURE [stp: Handle, host: ROPE] RETURNS [herald: ROPE] = { reason: PupStream.CloseReason; IF stp = NIL THEN RETURN["\"NIL\" STP handle"]; IF stp.byteStream # NIL THEN ERROR Error[stp, alreadyAConnection, "You already have a connection?"]; { server: PupStream.PupAddress = PupStream.GetPupAddress[PupTypes.ftpSoc, host ! PupStream.PupNameTrouble => GenerateErrorString[stp, noSuchHost, e]]; stp.byteStream _ PupStream.PupByteStreamCreate[ server, PupStream.veryLongWait ! PupStream.StreamClosing => {reason _ why; GOTO streamClosing}]; stp.plist _ MakePList[]; stp.info _ NEW[STP.FileInfoObject _ []]; stp.gotMark _ FALSE; stp.serverType _ GetServerType[host]; PutCommand[stp, markIAmVersion, 1C, "STP calling" ! PupStream.StreamClosing => {reason _ why; GOTO streamClosing}]; { code: CHARACTER; mark: [0..256); [mark, code, herald] _ GetCommand[stp]; IF mark # markIAmVersion THEN GenerateProtocolError[stp, badVersion, mark, code]; ErrorIfNextNotEOC[stp]; }; EXITS streamClosing => {CloseInternal[stp]; GenerateStreamClosingError[stp, reason]}; }; }; <> DestroyPList: PUBLIC PROCEDURE [plist: PList] RETURNS [PList] = { RETURN[NIL] }; MakePList: PUBLIC PROCEDURE RETURNS [plist: PList] = { RETURN[ NEW[PListArray _ ALL[NIL]] ]; }; <> ErrorCodeToSTPErrorCode: PUBLIC PROCEDURE [ errorCode: ErrorCode, code: CHARACTER] RETURNS [ErrorCode] = { replyCode: STPReplyCode.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 => requestRefused, dontSend => errorCode, notCompleted => errorCode, transientError => errorCode, permanentError => errorCode, fileBusy => accessError, ENDCASE => errorCode] -- can't do any better--}; GenerateErrorString: PUBLIC PROCEDURE [ stp: Handle, errorCode: ErrorCode, string: ROPE, code: CHARACTER _ 0C] = { ERROR Error[stp, ErrorCodeToSTPErrorCode[errorCode, code], IF string.Length[] # 0 THEN string ELSE SELECT errorCode FROM noSuchHost => "No such host!", noRouteToNetwork => "No route to network!", noNameLookupResponse => "Name lookup server is not responding", alreadyAConnection => "You already have a connection!", noConnection => "Please open a connection!", connectionClosed => "Connection closed (local or remote)!", connectionRejected => "Connection rejected by remote host!", connectionTimedOut => "Connection timed out!", accessDenied => "Access denied by remote server!", illegalUserName => "Invalid or illegal UserName!", illegalUserPassword => "Invalid or illegal UserPassword!", illegalUserAccount => "Invalid or illegal UserAccount!", illegalConnectName => "Invalid or illegal ConnectName!", illegalConnectPassword => "Invalid or illegal ConnectPassword!", credentailsMissing => "Name and/or Password not supplied!", protocolError => "Internal FTP protocol error!", illegalFileName => "Illegal filename!", noSuchFile => "File not found!", requestRefused => "Request refused by remote host!", accessError => "Illegal access attempt on remote stream!", undefinedError => "Undefined error!", ENDCASE => ERROR, code]; }; GenerateStreamClosingError: PUBLIC PROCEDURE [stp: Handle, why: PupStream.CloseReason] = { GenerateErrorString[stp, SELECT why FROM localClose, remoteClose => connectionClosed, noRouteToNetwork => noRouteToNetwork, transmissionTimeout => connectionTimedOut, remoteReject => connectionRejected, ENDCASE => ERROR, NIL]; }; GenerateProtocolError: PUBLIC PROCEDURE [ stp: Handle, type: ProtocolError, mark: [0..256), code: CHARACTER _ 0C] = { text: ROPE = IO.PutFR["%g, mark = %b, code = %b", [rope[SELECT type FROM badVersion => "Incompatable protocol version", badMark => "Invalid or undefined mark byte", badPList => "Invalid or malformed property list", eocExpected => "End-Of-Command mark byte expected", noCode => "error code is required after error mark byte", ENDCASE => ERROR]], [integer[mark]], [integer[code-0C]] ]; ERROR Error[stp, protocolError, text, code]; }; SelectError: PUBLIC PROCEDURE [ stp: Handle, s: ROPE , mark: [0..256)] = { code: CHARACTER _ 0C; IF mark = markNo OR mark = markComment THEN { IF mark # markComment THEN code _ CollectCode[stp]; stp.remoteString _ CollectString[stp]; GenerateErrorString[ stp, requestRefused, IF stp.remoteString.Length[] = 0 THEN s ELSE stp.remoteString, code]; } ELSE GenerateProtocolError[stp, badMark, mark, code]; }; }. -- of STPsA