-- 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