file: STPsA.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
Andrew Birrell June 1, 1983 3:03 pm
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 =
BEGIN OPEN PupStream, STPOps;
Global Data
Error: PUBLIC SIGNAL [
stp: STPOps.Handle, code: STP.ErrorCode, error: Rope.ROPE, 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[stp: stp, code: noConnection, error: "Attempt to Close a NIL connection"];
END;
CloseInternal: PUBLIC PROCEDURE [stp: STPOps.Handle] =
BEGIN
IF stp = NIL THEN RETURN;
stp.plist ← DestroyPList[stp.plist];
IF stp.byteStream # NIL THEN
BEGIN
stp.byteStream.Close[ ! PupStream.StreamClosing => CONTINUE];
stp.byteStream ← NIL;
END;
END;
Create: PUBLIC PROCEDURE RETURNS [stp: STPOps.Handle] =
BEGIN OPEN PupTypes;
PupStream.PupPackageMake[];
stp ← NEW[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];
PupStream.PupPackageDestroy[];
RETURN[NIL];
END;
Open: PUBLIC PROCEDURE [stp: STPOps.Handle, host: Rope.ROPE]
RETURNS [herald: Rope.ROPE] =
BEGIN
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?"];
BEGIN
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}];
BEGIN
code: CHARACTER;
mark: [0..256);
[mark, code, herald] ← GetCommand[stp];
IF mark # markIAmVersion THEN GenerateProtocolError[stp, badVersion, mark, code];
ErrorIfNextNotEOC[stp];
END;
EXITS streamClosing => {CloseInternal[stp]; GenerateStreamClosingError[stp, reason]};
END;
END;
PList Utilities
DestroyPList: PUBLIC PROCEDURE [plist: PList] RETURNS [PList] =
BEGIN
RETURN[NIL]
END;
MakePList: PUBLIC PROCEDURE RETURNS [plist: PList] =
BEGIN
RETURN[ NEW[PListArray ← ALL[NIL]] ];
END;
Error generation routines
ErrorCodeToSTPErrorCode: PUBLIC PROCEDURE [
errorCode: STP.ErrorCode, code: CHARACTER]
RETURNS [STP.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 => 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: Rope.ROPE, code: CHARACTER ← 0C] =
BEGIN
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];
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: [0..256), code: CHARACTER ← 0C] =
BEGIN
text: Rope.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];
END;
SelectError: PUBLIC PROCEDURE [
stp: STPOps.Handle, s: Rope.ROPE , mark: [0..256)] =
BEGIN
code: CHARACTER ← 0C;
IF mark = markNo OR mark = markComment THEN
BEGIN
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];
END
ELSE GenerateProtocolError[stp, badMark, mark, code];
END;
END. -- of STPsA