-- Copyright (C) 1981, 1983, 1984  by Xerox Corporation. All rights reserved. 
-- ReceiveInput.mesa, Transport Mechanism Mail Server - input from other GV servers --

-- HGM, 10-Dec-85 22:12:37
-- Andrew Birrell	12-Jan-81 16:09:58 --
-- Mike Schroeder	25-Jan-83 16:11:56 --

DIRECTORY
  BodyDefs USING [maxRNameLength, RName, Timestamp],
  Heap USING [systemZone],
  HeapDefs USING [
    ObjectNumber, HeapAbandonWrite, HeapStartWrite, HeapWriteData, ReceiveObj,
    HeapEndWrite, GetWriterOffset, WriterHandle],
  LogDefs USING [ShowRejection, WriteChar, WriteLogEntry],
  NameInfoDefs USING [IsMemberDirect],
  PolicyDefs USING [CheckOperation, EndOperation],
  ProtocolDefs USING [
    AppendTimestamp, Failed, Handle, mailServerServerSocket, ReceiveRName,
    ReceiveTimestamp, SendAck, SendNow],
  PupDefs USING [AppendHostName, PupAddress, SecondsToTocks],
  PupStream USING [CreatePupByteStreamListener, RejectThisRequest],
  RestartDefs USING [] --EXPORT only-- ,
  SLDefs USING [SLHeader, SLWrite],
  String USING [AppendLongDecimal, AppendString],
  Time USING [Current];

ReceiveInput: PROGRAM
  IMPORTS
    Heap, HeapDefs, LogDefs, NameInfoDefs, PolicyDefs, ProtocolDefs, PupDefs, PupStream,
    SLDefs, String, Time
  EXPORTS RestartDefs --PROGRAM-- =

  BEGIN

  Filter: PROCEDURE [from: PupDefs.PupAddress] =
    BEGIN
    IF NOT PolicyDefs.CheckOperation[serverInput] THEN
      BEGIN
      LogDefs.ShowRejection["ServerInput", from]; -- No L
      ERROR PupStream.RejectThisRequest["Server full"L]
      END;
    END;

  Receiver: PROCEDURE [str: ProtocolDefs.Handle, fromAddr: PupDefs.PupAddress] =
    BEGIN OPEN ProtocolDefs;
    fromName: BodyDefs.RName = [BodyDefs.maxRNameLength];
    express: BOOLEAN ← FALSE;
    ReceiveRName[str, fromName ! Failed => GOTO badName];
    IF NameInfoDefs.IsMemberDirect["*.MS"L, fromName] # yes THEN GOTO badName;
    IF FinkyGGW[fromName] THEN express ← TRUE;
    DO
      BEGIN
      bodyHandle: HeapDefs.WriterHandle = HeapDefs.HeapStartWrite[body];
      SLhandle: HeapDefs.WriterHandle = HeapDefs.HeapStartWrite[SLinput];
      Accept: PROCEDURE [obj: HeapDefs.ObjectNumber] =
        BEGIN
	IF express THEN SLDefs.SLWrite[obj, SLhandle, express]
	ELSE SLDefs.SLWrite[obj, SLhandle, input];
	END;
      header: SLDefs.SLHeader;
      header.received.host ← fromAddr.host;
      header.received.net ← fromAddr.net;
      header.received.time ← Time.Current[];
      header.server ← NIL;
      BEGIN
      ENABLE Failed => GOTO bad;
      header.created ← ProtocolDefs.ReceiveTimestamp[str];
      HeapDefs.HeapWriteData[SLhandle, [@header, SIZE[SLDefs.SLHeader]]];
      HeapDefs.ReceiveObj[SLhandle, str];
      HeapDefs.ReceiveObj[bodyHandle, str];
      LogReceived[header.created, fromName, HeapDefs.GetWriterOffset[bodyHandle], express];
      LogDefs.WriteChar['S];
      HeapDefs.HeapEndWrite[bodyHandle, Accept];
      EXITS
        bad =>
          BEGIN
          HeapDefs.HeapAbandonWrite[bodyHandle];
          HeapDefs.HeapAbandonWrite[SLhandle];
          EXIT
          END;
      END;
      END;
      BEGIN
      ENABLE ProtocolDefs.Failed => EXIT;
      ProtocolDefs.SendAck[str];  -- all is on disk --
      ProtocolDefs.SendNow[str];
      END;

      -- wait for sender to start a new message, possibly --
      ENDLOOP;

    PolicyDefs.EndOperation[serverInput];
    str.delete[str];

    EXITS
      badName =>
        BEGIN
        PolicyDefs.EndOperation[serverInput];
        str.delete[str];
        LogBad[fromAddr];
        END;
    END;

  -- Record ugly hackery: This depends upon GGWs, and only GGWs, being named with a dash:
  -- PA-Gateway.ms, WBST-Gateway.ms .... but ArpaGateway.ms
  FinkyGGW: PROC [name: LONG STRING] RETURNS [fink: BOOL] =
    BEGIN
    FOR i: CARDINAL IN [0..name.length) DO
      IF name.text[i] = '- THEN RETURN[TRUE];
      ENDLOOP;
    RETURN[FALSE];
    END;

  LogReceived: PROC [
    created: BodyDefs.Timestamp, from: BodyDefs.RName, words: LONG CARDINAL, express: BOOL] =
    BEGIN
    log: LONG STRING ← Heap.systemZone.NEW[StringBody[200]];
    String.AppendString[log, "Server input from "L];
    String.AppendString[log, from];
    String.AppendString[log, ": "L];
    ProtocolDefs.AppendTimestamp[log, created];
    String.AppendString[log, "; "L];
    String.AppendLongDecimal[log, words];
    String.AppendString[log, " words"L];
    IF express THEN String.AppendString[log, ", express"L];
    LogDefs.WriteLogEntry[log];
    Heap.systemZone.FREE[@log];
    END;

  LogBad: PROC [fromAddr: PupDefs.PupAddress] =
    BEGIN
    log: LONG STRING ← Heap.systemZone.NEW[StringBody[200]];
    String.AppendString[log, "Illegal MS-input request from host "L];
    PupDefs.AppendHostName[log, fromAddr];
    LogDefs.WriteLogEntry[log];
    Heap.systemZone.FREE[@log];
    END;

  [] ← PupStream.CreatePupByteStreamListener[
    ProtocolDefs.mailServerServerSocket, Receiver, PupDefs.SecondsToTocks[60],
    Filter];


  END.