-- FTPPupComHot.mesa, Edited by: HGM July 31, 1980  5:50 PM  

-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  FTPDefs,
  FTPPrivateDefs,
  FTPPupComDefs USING [PupConnection, AbortBecauseStreamClosing],
  PupStream USING [StreamClosing],
  Stream USING [
    Block, CompletionCode, defaultInputOptions, GetBlock, GetByte, InputOptions,
    PutBlock, PutByte, SendNow, SetInputOptions, SetSST, SSTChange, TimeOut];

FTPPupComHot: PROGRAM
  IMPORTS PupStream, Stream, FTPPrivateDefs, FTPPupComDefs
  EXPORTS FTPPupComDefs
  SHARES FTPDefs =
  BEGIN OPEN FTPDefs, FTPPrivateDefs;


  -- **********************!  Constants  !***********************

  ftpsystem: POINTER TO FTPSystem = LocateFtpSystemObject[];



  SendBytes: PUBLIC PROCEDURE [
    communicationSystem: CommunicationSystem, connection: Connection,
    bytePointer: BytePointer] =
    BEGIN
    -- catchphrase
    ENABLE
      BEGIN
      PupStream.StreamClosing =>
	FTPPupComDefs.AbortBecauseStreamClosing[why, text];
      Stream.TimeOut => Abort[connectionTimedOut];
      END;
    -- local constants
    pupConnection: FTPPupComDefs.PupConnection = LOOPHOLE[connection];
    startIndex: CARDINAL = IF bytePointer.offset THEN 1 ELSE 0;
    -- local variables
    block: Stream.Block =
      [blockPointer: LONG[bytePointer.address], startIndex: startIndex,
	stopIndexPlusOne: startIndex + bytePointer.count];
    -- abort if output discontinuity
    IF pupConnection.outputDiscontinuity THEN
      Abort[outputDiscontinuityUnexpected];
    -- send bytes
    Stream.PutBlock[pupConnection.streamHandle, block, FALSE];
    -- advance caller's byte pointer
    AdvanceBytePointer[bytePointer, bytePointer.count];
    END;

  ReceiveBytes: PUBLIC PROCEDURE [
    communicationSystem: CommunicationSystem, connection: Connection,
    bytePointer: BytePointer, settleForLess: BOOLEAN] =
    BEGIN
    -- catchphrase
    ENABLE
      BEGIN
      PupStream.StreamClosing =>
	FTPPupComDefs.AbortBecauseStreamClosing[why, text];
      Stream.TimeOut => Abort[connectionTimedOut];
      END;
    -- local constants
    pupConnection: FTPPupComDefs.PupConnection = LOOPHOLE[connection];
    startIndex: CARDINAL = IF bytePointer.offset THEN 1 ELSE 0;
    -- local variables
    inputOptions: Stream.InputOptions ← Stream.defaultInputOptions;
    block: Stream.Block =
      [blockPointer: LONG[bytePointer.address], startIndex: startIndex,
	stopIndexPlusOne: startIndex + bytePointer.count];
    bytesTransferred: CARDINAL ← 0;
    completionCode: Stream.CompletionCode ← normal;
    -- return if no operation
    IF bytePointer.count = 0 THEN RETURN;
    -- abort if input discontinuity
    IF pupConnection.inputDiscontinuity OR
      pupConnection.inputDiscontinuityConsumed THEN
      Abort[inputDiscontinuityUnexpected];
    -- adjust input options if necessary
    IF settleForLess # pupConnection.terminateOnEndPhysicalRecord THEN
      BEGIN
      -- select and record new input option
      inputOptions.terminateOnEndPhysicalRecord ←
	pupConnection.terminateOnEndPhysicalRecord ← settleForLess;
      -- instate new input option
      Stream.SetInputOptions[pupConnection.streamHandle, inputOptions];
      END;
    -- receive bytes
    [bytesTransferred, completionCode, pupConnection.mark] ← Stream.GetBlock[
      pupConnection.streamHandle, block];
    -- note input discontinuity if any
    pupConnection.inputDiscontinuity ← completionCode = sstChange;
    -- advance caller's byte pointer
    AdvanceBytePointer[bytePointer, bytesTransferred];
    END;

  SendByte: PUBLIC PROCEDURE [
    communicationSystem: CommunicationSystem, connection: Connection,
    byte: Byte] =
    BEGIN
    -- catchphrase
    ENABLE
      BEGIN
      PupStream.StreamClosing =>
	FTPPupComDefs.AbortBecauseStreamClosing[why, text];
      Stream.TimeOut => Abort[connectionTimedOut];
      END;
    -- local constants
    pupConnection: FTPPupComDefs.PupConnection = LOOPHOLE[connection];
    -- send mark
    IF pupConnection.outputDiscontinuity THEN
      BEGIN
      pupConnection.outputDiscontinuity ← FALSE;
      Stream.SetSST[pupConnection.streamHandle, byte];
      END
      -- send byte

    ELSE Stream.PutByte[pupConnection.streamHandle, byte];
    END;

  ReceiveByte: PUBLIC PROCEDURE [
    communicationSystem: CommunicationSystem, connection: Connection,
    settleForNone: BOOLEAN] RETURNS [byte: Byte, settledForNone: BOOLEAN] =
    BEGIN
    -- catchphrase
    ENABLE
      BEGIN
      PupStream.StreamClosing =>
	FTPPupComDefs.AbortBecauseStreamClosing[why, text];
      Stream.TimeOut => Abort[connectionTimedOut];
      END;
    -- local constants
    pupConnection: FTPPupComDefs.PupConnection = LOOPHOLE[connection];
    -- settle for none or abort if input discontinuity
    IF pupConnection.inputDiscontinuity THEN
      IF settleForNone THEN RETURN[byte, TRUE]
      ELSE Abort[inputDiscontinuityUnexpected];
    -- assume won't have to settle for none
    settledForNone ← FALSE;
    -- return mark
    IF pupConnection.inputDiscontinuityConsumed THEN
      BEGIN
      pupConnection.inputDiscontinuityConsumed ← FALSE;
      byte ← pupConnection.mark;
      END
      -- receive byte

    ELSE
      byte ← Stream.GetByte[
	pupConnection.streamHandle !
	Stream.SSTChange =>
	  IF settleForNone THEN
	    BEGIN
	    pupConnection.inputDiscontinuity ← TRUE;
	    pupConnection.mark ← sst;
	    settledForNone ← TRUE;
	    CONTINUE;
	    END
	  ELSE Abort[inputDiscontinuityUnexpected]];
    END;

  ProduceDiscontinuity: PUBLIC PROCEDURE [
    communicationSystem: CommunicationSystem, connection: Connection] =
    BEGIN
    -- Note:  Extra calls to this procedure without intervening data
    --   are treated as no operations. 
    -- local constants
    pupConnection: FTPPupComDefs.PupConnection = LOOPHOLE[connection];
    -- produce output discontinuity
    pupConnection.outputDiscontinuity ← TRUE;
    END;

  ConsumeDiscontinuity: PUBLIC PROCEDURE [
    communicationSystem: CommunicationSystem, connection: Connection] =
    BEGIN
    -- Note:  Extra calls to this procedure without intervening data
    --   are treated as no operations. 
    -- local constants
    pupConnection: FTPPupComDefs.PupConnection = LOOPHOLE[connection];
    -- consume input discontinuity
    IF pupConnection.inputDiscontinuity THEN
      BEGIN
      pupConnection.inputDiscontinuity ← FALSE;
      pupConnection.inputDiscontinuityConsumed ← TRUE;
      END;
    END;

  ForceOutput: PUBLIC PROCEDURE [
    communicationSystem: CommunicationSystem, connection: Connection] =
    BEGIN
    -- catchphrase
    ENABLE
      BEGIN
      PupStream.StreamClosing =>
	FTPPupComDefs.AbortBecauseStreamClosing[why, text];
      Stream.TimeOut => Abort[connectionTimedOut];
      END;
    -- local constants
    pupConnection: FTPPupComDefs.PupConnection = LOOPHOLE[connection];
    -- force output
    Stream.SendNow[pupConnection.streamHandle];
    END;



  -- **********************!  Main Program  !***********************

  -- no operation

  END. -- of FTPPupComHot