-- SendPress.mesa,  Edit: Johnsson, 15-Apr-81 18:01:59

DIRECTORY
  EFTPDefs USING [
    EFTPAbortSending, EFTPFinishSending, EFTPOpenForSending,
    EFTPSendBlock, EFTPTimeOut, EFTPTroubleSending],
  Inline USING [LongDivMod],
  LongString USING [AppendString],
  PressFormat USING [DDV, PressPasswd],
  PressUtilities USING [hardcopyUserName, ParameterProc],
  PupDefs USING [GetPupAddress, PupAddress, PupPackageDestroy, PupPackageMake],
  PupTypes USING [eftpReceiveSoc],
  Runtime USING [IsBound],
  Segments USING [
    DeleteSegment, FHandle, SegmentAddress,
    SHandle, GetFileLength, LockFile, NewFile, NewSegment, Read,
    ReleaseFile, SwapIn, Unlock, UnlockFile],
  Streams USING [CreateStream, Destroy, GetBlock, Handle],
  System USING [gmtEpoch, GreenwichMeanTime];

SendPress: PROGRAM
  IMPORTS EFTPDefs, Inline, LongString, PressUtilities, Runtime, Segments, Streams, PupDefs
  EXPORTS PressUtilities =
  BEGIN
  
  ServerBusy: PUBLIC SIGNAL = CODE;
  ServerTimeout: PUBLIC SIGNAL = CODE;
  ServerTrouble: PUBLIC ERROR [message: STRING] = CODE;

  wordsPerPressRecord: CARDINAL = 256;
  bytesPerPressRecord: CARDINAL = 512;
  
  FileNotPressFormat: PUBLIC ERROR = CODE;
  
  IsPressFile: PUBLIC PROCEDURE [fh: Segments.FHandle]
    RETURNS [isPressFile: BOOLEAN, lastPage: CARDINAL] =
    BEGIN OPEN Segments;
    seg: SHandle;
    p: LONG POINTER TO ARRAY OF CARDINAL;
    byte: CARDINAL;
    [lastPage, byte] ← Inline.LongDivMod[GetFileLength[fh], bytesPerPressRecord];
    IF byte # 0 THEN RETURN[FALSE, 0];
    seg ← NewSegment[fh, lastPage, 1, Read];
    SwapIn[seg];
    p ← SegmentAddress[seg];
    isPressFile ← p[0] = PressFormat.PressPasswd AND p[1] = lastPage;
    Unlock[seg];
    LockFile[fh];
    DeleteSegment[seg];
    UnlockFile[fh];
    RETURN
    END;
    
  SendPressFile: PUBLIC PROCEDURE [
    fileName, host: LONG STRING, copies: CARDINAL ← 1,
    parameterProc: PressUtilities.ParameterProc ← NIL] =
    BEGIN OPEN Segments;
    shortName: STRING = [40];
    fh: FHandle;
    lastPage: CARDINAL;
    isPressFormat: BOOLEAN;
    LongString.AppendString[shortName, fileName];
    fh ← NewFile[shortName, Read];
    [isPressFormat, lastPage] ← IsPressFile[fh];
    IF ~isPressFormat THEN BEGIN ReleaseFile[fh]; ERROR FileNotPressFormat END
    ELSE
      BEGIN
      sh: Streams.Handle ← Streams.CreateStream[fh];
      SendPressStream[
	sh, lastPage, host, copies, parameterProc ! UNWIND => Streams.Destroy[sh]];
      Streams.Destroy[sh];
      END;
    RETURN
    END;
    
  SendPressStream: PUBLIC PROCEDURE [
    stream: Streams.Handle, nPages: CARDINAL, host: LONG STRING,
    copies: CARDINAL ← 1, parameterProc: PressUtilities.ParameterProc ← NIL,
    fileName: LONG STRING ← NIL, date: System.GreenwichMeanTime ← System.gmtEpoch] =
    BEGIN OPEN EFTPDefs;
    ENABLE UNWIND => EFTPAbortSending[""]; -- oops, this may be too often
    ba: ARRAY [0..wordsPerPressRecord) OF WORD;
    buffer: POINTER TO ARRAY [0..wordsPerPressRecord) OF WORD ← @ba;
    who: PupDefs.PupAddress ← [, , PupTypes.eftpReceiveSoc];
    shortName: STRING = [40];
    PupDefs.PupPackageMake[];
    LongString.AppendString[shortName, host];
    PupDefs.GetPupAddress[@who, shortName];
    EFTPOpenForSending[
      who ! EFTPTimeOut => {SIGNAL ServerTimeout; RESUME};
      EFTPTroubleSending => {
      	IF e = eftpReceiverBusyAbort THEN {SIGNAL ServerBusy; RETRY};
	ERROR ServerTrouble[s]}];
    IF parameterProc # NIL THEN
      BEGIN
      bytes: CARDINAL ← parameterProc[buffer];
      IF bytes # 0 THEN EFTPSendBlock[buffer, bytes !
	EFTPTimeOut => ERROR ServerTrouble["Timeout"L];
	EFTPTroubleSending => ERROR ServerTrouble[s]];
      END;
    FOR i: CARDINAL IN [1..nPages] DO
      SELECT Streams.GetBlock[stream, buffer, wordsPerPressRecord] FROM
	wordsPerPressRecord =>
	  BEGIN
	  IF i = nPages THEN FillInDDV[LOOPHOLE[buffer], copies];
	  EFTPSendBlock[buffer, bytesPerPressRecord !
	    EFTPTimeOut => ERROR ServerTrouble["Timeout"L];
	    EFTPTroubleSending => ERROR ServerTrouble[s]];
	  END;
	0 => EXIT;
	ENDCASE => ERROR FileNotPressFormat; -- must be whole records
      ENDLOOP;
    EFTPFinishSending[];
    PupDefs.PupPackageDestroy[];
    END;
    
  FillInDDV: PROCEDURE [ddv: POINTER TO PressFormat.DDV, copies: CARDINAL] =
    BEGIN OPEN PressUtilities;
    IF ddv.Passwd # PressFormat.PressPasswd THEN ERROR FileNotPressFormat;
    IF Runtime.IsBound[@hardcopyUserName] AND hardcopyUserName # NIL AND
      hardcopyUserName.length < LENGTH[ddv.CreatStr]*2 THEN {
      p: POINTER TO PACKED ARRAY [0..0) OF CHARACTER = LOOPHOLE[@ddv.CreatStr];
      FOR i: CARDINAL IN [0..hardcopyUserName.length) DO p[i+1] ← hardcopyUserName[i] ENDLOOP;
      p[0] ← LOOPHOLE[hardcopyUserName.length]};
    ddv.fCopy ← 1;
    ddv.lCopy ← copies;
    END;
    
  
  END.