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