Last edited by:
Taft, October 7, 1983 2:14 pm
Bob Hagmann March 24, 1985 2:29:34 pm PST
DIRECTORY
Atom USING [PropList],
BasicTime USING [GMT, nullGMT],
FTP,
IO USING [STREAM],
PupStream USING [CloseReason, NameLookupErrorCode],
Rope USING [ROPE];
Handle: TYPE = REF Object;
Object:
TYPE =
RECORD [
byteStream: IO.STREAM ← NIL,
pList: ARRAY LocalOrRemote OF PList,
clientData: REF ANY ← NIL,
buffer: REF TEXT ← NIL];
FilenameType: TYPE = {alto, tenex};
PList: TYPE = REF PListObject;
PListObject:
TYPE =
RECORD [
date: ARRAY DateProperty OF BasicTime.GMT ← ALL[BasicTime.nullGMT],
enumerated: ARRAY EnumeratedProperty OF EnumPropValue ← ALL[nullEnumPropValue],
number: ARRAY NumberProperty OF INT ← ALL[0],
text: ARRAY TextProperty OF ROPE ← ALL[NIL],
userDefined: Atom.PropList ← NIL,
desiredProps: PropertySet ← ALL[FALSE],
desiredUserDefinedProps: LIST OF ATOM ← NIL];
Procedures for sending and receiving FTP protocol commands
GetCommand:
PROCEDURE [h: Handle]
RETURNS [mark: Mark, code: ReplyCode];
First, if the FTP stream is not already positioned at a mark, consumes and discards data from the stream until a mark is reached. Then consumes and returns the mark, and if the mark is one of those that has a code byte, also consumes and returns the code byte. Consumes and discards any comment commands encountered.
GetText:
PROCEDURE [h: Handle, gobbleEOC:
BOOLEAN ←
FALSE]
RETURNS [text:
ROPE];
Consumes data from the stream up to but not including the next mark and returns it as a ROPE. Then, if gobbleEOC=TRUE, consumes and discards the mark byte, raising Failed[protocolError] if it is not an endOfCommand.
GetPList:
PROCEDURE [h: Handle, gobbleEOC:
BOOLEAN ←
FALSE, endOfPropertiesOK:
BOOLEAN ←
FALSE]
RETURNS [pList: PList];
Consumes data from the stream and interprets it as a property list, stopping at the end of that property list. Then, if gobbleEOC=TRUE, consumes and discards the following mark byte, raising Failed[protocolError] if a mark byte does not immediately follow or if it is not an endOfCommand. Ordinarily, if the stream is positioned at a mark at the time of the call, raises Failed[protocolError]; however, if endOfPropertiesOK=TRUE then returns NIL in that case.
GetYesNo:
PROCEDURE [h: Handle, gobbleEOC:
BOOLEAN ←
FALSE, resumable:
BOOLEAN ←
FALSE]
RETURNS [ok:
BOOLEAN];
Calls GetCommand followed by GetText, in expectation of the next command being a Yes or No. If it is Yes, it simply returns TRUE. If it is No, it raises Failed[code, text, resumable], where code and text are from the No reply and resumable is as specified in the call to GetYesNo; if the signal is resumed, GetYesNo returns FALSE. Any other response results in a protocol error.
GetEOC:
PROCEDURE [h: Handle];
Calls GetCommand in expectation of the next command being an End-of-command. If it is not, an error results.
PutCommand:
PROCEDURE [h: Handle, mark: Mark, code: ReplyCode ← unspecified, text:
ROPE ←
NIL, sendEOC:
BOOLEAN ←
FALSE];
Sends the specified mark byte, and if the mark is one of those that has a code byte, also sends the specified code byte. Then, if text#NIL, sends the specified text. Finally, if sendEOC=TRUE, sends an endOfCommand mark byte.
PutPList:
PROCEDURE [h: Handle, pList: PList, sendEOC:
BOOLEAN ←
FALSE];
Unparses and sends the specified property list. Then, if sendEOC=TRUE, sends an endOfCommand mark byte.
PutCommandAndPList:
PROCEDURE [h: Handle, mark: Mark, pList: PList, sendEOC:
BOOLEAN ←
FALSE];
Combines the effects of PutCommand and PutPList.
PutEOC:
PROCEDURE [h: Handle];
Sends an endOfCommand mark byte.
Utility routines
GetBuffer: PROCEDURE [h: Handle] RETURNS [buffer: REF TEXT];
ReleaseBuffer: PROCEDURE [h: Handle, buffer: REF TEXT];
PList Utilities -- most probably obsolete now
NameToPList: PROCEDURE [plist: PList, name: Rope.ROPE, type: FilenameType];
PListToName: PROCEDURE [plist: PList, type: FilenameType] RETURNS[name: Rope.ROPE];
Error handling
GenerateFailed:
PROCEDURE [h: Handle, code: FailureCode, text: Rope.
ROPE ←
NIL, resumable:
BOOLEAN ←
FALSE];
Raises h.Failed[code, text, resumable] after first fabricating a text argument based on code if text=NIL.
GenerateNo:
PROCEDURE [h: Handle, code: FailureCode, text: Rope.
ROPE ←
NIL, sendEOC:
BOOLEAN ←
FALSE];
Generates a "No" response with the specified code and text, after first fabricating a text argument based on code if text=NIL.
GenerateNoAndFailed:
PROCEDURE [h: Handle, code: FailureCode, text: Rope.
ROPE ←
NIL, resumable:
BOOLEAN ←
FALSE];
Combines the actions of GenerateNo and GenerateFailed.
GenerateStreamClosingError: PROCEDURE [h: Handle, why: PupStream.CloseReason];
GenerateProtocolError: PROCEDURE [h: Handle, type: ProtocolError, mark: Mark, code: CHARACTER ← 0C, resumable: BOOLEAN ← FALSE] ;
MapNameLookupError:
PROCEDURE [error: PupStream.NameLookupErrorCode]
RETURNS [FailureCode];
Maps a NameLookupErrorCode to a FailureCode.
MapStreamClosingError:
PROCEDURE [error: PupStream.CloseReason]
RETURNS [FailureCode];
Maps a CloseReason to a FailureCode.
FTP protocol definitions
Mark: TYPE = MACHINE DEPENDENT {retrieve (1), store (2), yes (3), no (4), hereIsFile (5), endOfCommand (6), comment (7), version (8), newStore (9), enumerate (10), hereIsPList (11), newEnumerate (12), delete (14), rename (15), storeMail (16), retrieveMail (17), flushMailbox (18), mailboxException (19), (255)};
ftpVersion: CARDINAL = 1; -- FTP protocol version
END.