-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- SloshRecv.mesa, HGM, 24-Sep-83 17:39:42

DIRECTORY
  Ascii USING [CR],
  Environment USING [Byte, bytesPerPage],
  Inline USING [LowHalf],
  Put USING [Text],
  Stream USING [Delete, Handle, PutBlock],
  String USING [AppendChar, AppendString, AppendLongDecimal],
  System USING [GetClockPulses],
  Time USING [AppendCurrent],
  Volume USING [GetAttributes, InsufficientSpace, SystemID],
  Window USING [Handle],

  Slosh USING [RecvStatus],
  EFTPDefs USING [
    EFTPOpenForReceiving, EFTPAbortReceiving, EFTPGetBlock, EFTPFinishReceiving,
    EFTPEndReceiving, EFTPTimeOut, EFTPTroubleReceiving, EFTPSetRecvTimeout],
  PupTypes USING [PupAddress];

SloshRecv: MONITOR
  IMPORTS Inline, Put, Stream, String, System, Time, Volume, EFTPDefs
  EXPORTS Slosh =
  BEGIN

  verbose: BOOLEAN = TRUE;

  RecvFile: PUBLIC ENTRY PROCEDURE [
    who: Window.Handle, fileName: LONG STRING, file: Stream.Handle,
    me: PupTypes.PupAddress, ask: PROCEDURE] RETURNS [status: Slosh.RecvStatus] =
    BEGIN OPEN EFTPDefs;
    FixThingsUp: PROCEDURE [e: LONG STRING, why: Slosh.RecvStatus] =
      BEGIN message ← e; EFTPAbortReceiving[message]; status ← why; END;
    buffer: PACKED ARRAY [0..Environment.bytesPerPage) OF Environment.Byte;
    total: LONG CARDINAL ← 0;
    message: LONG STRING ← NIL;
    trouble: STRING = [100];
    EFTPSetRecvTimeout[1000];
    BEGIN
    ENABLE
      BEGIN
      EFTPTroubleReceiving =>
        BEGIN String.AppendString[trouble, s]; GOTO EFTPTrouble; END;
      EFTPTimeOut => GOTO EFTPTimeout;
      END;
    pokes: CARDINAL ← 0;
    bytes: CARDINAL;
    [] ← EFTPOpenForReceiving[
      me !
      EFTPTimeOut =>
        BEGIN  -- We expect to get here once since we haven't asked yet
        IF (pokes ← pokes + 1) > 3 THEN GOTO OpenFailed;
        ask[];
        RESUME
        ;
        END];
    EFTPSetRecvTimeout[60000];
    -- This is a silly place to check, but it simplifies recovery
    DO
      bytes ← EFTPGetBlock[
        @buffer, Environment.bytesPerPage ! EFTPEndReceiving => EXIT];
      Stream.PutBlock[
        file, [@buffer, 0, bytes] !
        Volume.InsufficientSpace => GOTO TempFull];
      total ← total + bytes;
      ENDLOOP;
    EFTPFinishReceiving[];
    status ← statusStoreOk;
    EXITS
      OpenFailed => FixThingsUp["EFTP Open Failed"L, statusEFTPFailed];
      EFTPTrouble => FixThingsUp["EFTP Trouble"L, statusEFTPFailed];
      EFTPTimeout => FixThingsUp["EFTP Timeout"L, statusEFTPFailed];
      TempFull =>
        FixThingsUp[
          "Disk Full while buffering into buffer file"L, statusDiskFull];
    END;
    Stream.Delete[file];
    IF verbose THEN
      BEGIN
      text: STRING = [200];
      pagesLeft: LONG CARDINAL ← Volume.GetAttributes[
        Volume.SystemID[]].freePageCount;
      Time.AppendCurrent[text];
      IF message = NIL THEN
        BEGIN
        String.AppendString[text, "  Got "L];
        String.AppendString[text, fileName];
        String.AppendString[text, " ok.  Length="L];
        String.AppendLongDecimal[text, total/Environment.bytesPerPage];
        String.AppendChar[text, '.];
        String.AppendLongDecimal[text, total MOD Environment.bytesPerPage];
        END
      ELSE
        BEGIN
        String.AppendString[text, "  Recv aborted because: "L];
        String.AppendString[text, message];
        IF trouble.length # 0 THEN
          BEGIN
          String.AppendString[text, "("L];
          String.AppendString[text, trouble];
          String.AppendString[text, ") "L];
          END;
        String.AppendString[text, " after page "L];
        String.AppendLongDecimal[text, total/Environment.bytesPerPage];
        END;
      String.AppendString[text, ", pages left="L];
      String.AppendLongDecimal[text, pagesLeft];
      LogString[who, text];
      END;
    END;

  LogString: PROCEDURE [msg: Window.Handle, text: LONG STRING] =
    BEGIN
    String.AppendChar[text, '.];
    String.AppendChar[text, Ascii.CR];
    Put.Text[NIL, text];
    IF msg # NIL THEN Put.Text[msg, text];
    END;

  RetransmissionInterval: PUBLIC PROCEDURE RETURNS [seconds: CARDINAL] =
    BEGIN
    RETURN[Inline.LowHalf[System.GetClockPulses[]] MOD 5*60];  -- 5 min
    END;

  END.