STPsA.mesa - Simple/Stream Transfer Protocol (Initialization and Error)
Copyright © 1985 by Xerox Corporation. All rights reserved.
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 =
{ OPEN PupStream, STPOps;
ErrorCode: TYPE = STP.ErrorCode;
Handle: TYPE = STPOps.Handle;
ROPE: TYPE = Rope.ROPE;
Global Data
Error: PUBLIC SIGNAL [stp: Handle, code: ErrorCode, error: ROPE, reply: CHAR ← 0C] = CODE;
Object: PUBLIC TYPE = STPOps.Object;
Public Interface Routines
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]};
};
};
PList Utilities
DestroyPList: PUBLIC PROCEDURE [plist: PList] RETURNS [PList] = {
RETURN[NIL]
};
MakePList: PUBLIC PROCEDURE RETURNS [plist: PList] = {
RETURN[ NEW[PListArray ← ALL[NIL]] ];
};
Error generation routines
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