-- Copyright (C) 1981, 1984  by Xerox Corporation. All rights reserved. 
-- ReadForward.mesa, Transport Mechanism Mail Server - algorithm to process forward queue --

-- HGM: 15-Dec-84 22:46:03
-- Randy Gobbel		19-May-81 11:57:02 --
-- Andrew Birrell	29-Dec-81 14:53:38 --
-- Hankins	30-Jul-84 14:22:52	Klamath update (BufferDefs)

DIRECTORY
  BodyDefs USING [RName],
  Buffer,
  HeapDefs USING [
    ObjectNumber, HeapReadData, HeapStartRead, ReaderHandle, HeapEndRead,
    SendObj],
  LocalNameDefs USING [ReadMSName],
  LogDefs USING [WriteLogEntry],
  PolicyDefs USING [EndOperation, WaitOperation],
  Process USING [Detach],
  ProtocolDefs USING [
    AppendTimestamp, CreateStream, DestroyStream, Failed, Handle, Password,
    ReceiveAck, SendRName, SendTimestamp],
  RestartDefs USING [],
  ServerDefs USING [
    ServerAddr, ServerHandle, ServerNotUp, ServerUp, DownServer, NoSuchServer],
  SLDefs USING [
    GetCount, SLHeader, SLStartRead, SLReadHandle, SLEndRead, SLTransfer],
  String USING [AppendString];

ReadForward: PROGRAM
  IMPORTS
    HeapDefs, LocalNameDefs, LogDefs, PolicyDefs, Process, ProtocolDefs,
    ServerDefs, SLDefs, String
  EXPORTS RestartDefs --PROGRAM-- =

  BEGIN

  NoRecipients: ERROR = CODE;  --not caught; should not occur--

  ForwardMain: PROCEDURE =
    BEGIN
    -- multiple instantiations of this procedure are allowed --
    DO
      BEGIN
      str: ProtocolDefs.Handle ← NIL;
      SLobj: HeapDefs.ReaderHandle;
      SLhandle: SLDefs.SLReadHandle;
      bodyObj: HeapDefs.ObjectNumber;
      slHeader: SLDefs.SLHeader;
      outcome: {ok, down} ← ok;

      [SLhandle, bodyObj, SLobj] ← SLDefs.SLStartRead[forward];
      PolicyDefs.WaitOperation[readForward];
      BEGIN
      -- read SL header --
      ended: BOOLEAN;
      used: CARDINAL;
      [ended, used] ← HeapDefs.HeapReadData[
        SLobj, [@slHeader, SIZE[SLDefs.SLHeader]]];
      IF ended THEN ERROR NoRecipients[];
      END;
      IF NOT ServerDefs.ServerUp[slHeader.server] THEN {
        HeapDefs.HeapEndRead[SLobj]; outcome ← down}
      ELSE
        BEGIN
        str ← ProtocolDefs.CreateStream[
          ServerDefs.ServerAddr[
          slHeader.server !
          ServerDefs.ServerNotUp, ServerDefs.NoSuchServer => GOTO noAddr] !
          ProtocolDefs.Failed => GOTO noStr];
        BEGIN
        ENABLE
          ProtocolDefs.Failed => {HeapDefs.HeapEndRead[SLobj]; GOTO wentDown};
        myName: BodyDefs.RName;
        myKey: ProtocolDefs.Password;
        [name: myName, key: myKey, password:] ← LocalNameDefs.ReadMSName[];
        ProtocolDefs.SendRName[str, myName];
        ProtocolDefs.SendTimestamp[str, slHeader.created];
        END;
        BEGIN
        ENABLE ProtocolDefs.Failed => GOTO wentDown;
        HeapDefs.SendObj[SLobj, str];
        HeapDefs.SendObj[HeapDefs.HeapStartRead[bodyObj], str];
        ProtocolDefs.ReceiveAck[str];
        END;

        ProtocolDefs.DestroyStream[str];

        EXITS
          noAddr => {HeapDefs.HeapEndRead[SLobj]; outcome ← down};
          noStr =>
            BEGIN
            HeapDefs.HeapEndRead[SLobj];
            ServerDefs.DownServer[slHeader.server];
            outcome ← down;
            END;
          wentDown =>
            BEGIN
            ProtocolDefs.DestroyStream[str];
            ServerDefs.DownServer[slHeader.server];
            outcome ← down;
            END;
        END;

      BEGIN
      log: STRING = [128];
      String.AppendString[log, "Forwarded  "L];
      ProtocolDefs.AppendTimestamp[log, slHeader.created];
      String.AppendString[log, " to "L];
      WITH slHeader.server.name SELECT FROM
        rName => String.AppendString[log, value];
        ENDCASE;
      IF outcome # ok THEN String.AppendString[log, ": failed"L];
      LogDefs.WriteLogEntry[log];
      END;

      SELECT outcome FROM
        ok => SLDefs.SLEndRead[SLhandle];
        down => SLDefs.SLTransfer[SLhandle, input];
        ENDCASE => ERROR;
      END;
      PolicyDefs.EndOperation[readForward];
      ENDLOOP;
    END;

  ForwardRestart: PROCEDURE =
    BEGIN
    -- on restart, must transfer everything to input, since ServerHandles
    -- are no longer valid --
    THROUGH [0..SLDefs.GetCount[forward]) DO
      handle: SLDefs.SLReadHandle;
      body: HeapDefs.ObjectNumber;
      SL: HeapDefs.ReaderHandle;
      [handle, body, SL] ← SLDefs.SLStartRead[forward];
      HeapDefs.HeapEndRead[SL];
      SLDefs.SLTransfer[handle, input];
      ENDLOOP;
    END;

  ForwardRestart[];
  Process.Detach[FORK ForwardMain[]];

  END.