-- File: TrapBadPups.mesa
--  Edit: HGM  March 24, 1981  1:40 AM
--  Edit: BLyon  January 16, 1981  5:44 PM

DIRECTORY
  Ascii USING [CR, SP],
  CmFile USING [OpenSection, NextItem, Close],
  Put USING [Text, Line],
  Runtime USING [IsBound],
  Storage USING [FreeString],
  String USING [
    AppendChar, AppendDecimal, AppendNumber, AppendString, EquivalentString],
  Time USING [AppendCurrent],
  Indirect USING [GetParmFileName],
  Mailer USING [Level, SendMail],
  BufferDefs USING [PupBuffer],
  DriverDefs USING [Network],
  DriverTypes USING [Encapsulation],
  PupDefs USING [GetPupContentsBytes],
  ForwarderDefs USING [],
  PupRouterDefs USING [RejectPupWithBadChecksum, SetPupChecksum];

TrapBadPups: MONITOR
  IMPORTS
    CmFile, Put, Runtime, Storage, String, Time,
    Indirect, Mailer, PupDefs, PupRouterDefs
  EXPORTS BufferDefs, ForwarderDefs
  SHARES BufferDefs =
  BEGIN

  -- EXPORTed TYPEs
  Network: PUBLIC TYPE = DriverDefs.Network;

  to, cc: STRING ← NIL;
  troubles: STRING ← NIL;  -- Also used as from

  badSequenceAppendNumber: CARDINAL ← 0;
  recent: CARDINAL ← 0;

  CollectInfo: PROCEDURE =
    BEGIN
    parmFileName: STRING ← NIL;
    sectionName: STRING = "TrapBadPups"L;
    token, arg: STRING ← NIL;
    IF Runtime.IsBound[Indirect.GetParmFileName] THEN
      parmFileName ← Indirect.GetParmFileName[];
    IF parmFileName = NIL THEN RETURN;
    IF ~CmFile.OpenSection[parmFileName, sectionName] THEN
      BEGIN
      Problem["Can't find [TrapBadPups] section."L];
      RETURN;
      END;
    DO
      [token, arg] ← CmFile.NextItem[];
      SELECT TRUE FROM
	token = NIL => EXIT;
	String.EquivalentString[token, "Troubles"L] =>
	  BEGIN
	  CheckForRegistry[arg];
	  Storage.FreeString[troubles];
	  troubles ← arg;
	  END;
	String.EquivalentString[token, "To"L] =>
	  BEGIN
	  CheckForRegistry[arg];
	  Storage.FreeString[to];
	  to ← arg;
	  END;
	String.EquivalentString[token, "cc"L] =>
	  BEGIN
	  CheckForRegistry[arg];
	  Storage.FreeString[cc];
	  cc ← arg;
	  END;
	ENDCASE =>
	  BEGIN
	  IF token[0] # '; THEN Problem["Unknown keyword: "L, token];
	  Storage.FreeString[arg];
	  END;
      Storage.FreeString[token];
      ENDLOOP;
    CmFile.Close[parmFileName];
    IF troubles = NIL THEN
      Problem["Please specify somebody in case of TROUBLES"L];
    IF to = NIL THEN
      Problem["Please specify somebody to send the message to"L];
    RETURN;
    END;

  CheckForRegistry: PROCEDURE [s: STRING] =
    BEGIN
    dot: BOOLEAN ← FALSE;
    FOR i: CARDINAL IN [0..s.length) DO
      SELECT s[i] FROM
	'. => dot ← TRUE;
	', =>
	  BEGIN
	  IF ~dot THEN
	    BEGIN Problem["Registry expected in arg: "L, s]; RETURN; END;
	  dot ← FALSE;
	  END;
	ENDCASE => NULL;
      ENDLOOP;
    IF ~dot THEN BEGIN Problem["Registry expected in arg: "L, s]; RETURN; END;
    END;

  Problem: PROCEDURE [one, two, three: STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    Time.AppendCurrent[text];
    String.AppendString[text, "  TrapBadPups: "L];
    String.AppendString[text, one];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    LogString[text];
    END;

  PrintBadPup: PUBLIC PROCEDURE [b: BufferDefs.PupBuffer] =
    BEGIN
    IF b = NIL THEN RETURN;
    IF troubles#NIL AND to#NIL THEN
      BEGIN
      badSequenceAppendNumber ← badSequenceAppendNumber + 1;
      IF recent < 30 THEN -- average of one every 10 min, but allow clumps of 3
	BEGIN recent ← recent + 10; MailBadPup[b]; END;
      END;
    PupRouterDefs.RejectPupWithBadChecksum[b];
    END;

  maxWords: CARDINAL = 300;
  maxBytes: CARDINAL = 500 + maxWords*8;

  MailBadPup: PUBLIC PROCEDURE [b: BufferDefs.PupBuffer] =
    BEGIN
    body: STRING = [maxBytes];
    size: CARDINAL ← (b.pupLength - 1)/2;
    checksumLoc: LONG POINTER ← @b.pupLength + size;
    words: CARDINAL ← (PupDefs.GetPupContentsBytes[b] + 1)/2;
    i: CARDINAL;
    p: LONG POINTER;
    network: Network = b.network;
    Info: PROCEDURE [s: STRING, level: Mailer.Level] = {LogString[s]; };
    O7: PROCEDURE [n: WORD] =
      BEGIN
      temp: STRING = [10];
      String.AppendNumber[temp, n, 8];
      THROUGH [temp.length..7) DO String.AppendChar[body, Ascii.SP]; ENDLOOP;
      String.AppendNumber[body, n, 8];
      END;
    Time.AppendCurrent[body];
    String.AppendString[body, "  *****  Bad software checksum on Pup from net "L];
    String.AppendNumber[body, network.netNumber.b, 8];
    String.AppendChar[body, Ascii.CR];
    String.AppendString[body, "Bad pup number "L];
    String.AppendDecimal[body, badSequenceAppendNumber];
    String.AppendString[body, " has a checksum of "L];
    String.AppendNumber[body, checksumLoc↑, 8];
    PupRouterDefs.SetPupChecksum[b]; -- Fix it up
    String.AppendString[body, ", but it should be "L];
    String.AppendNumber[body, checksumLoc↑, 8];
    String.AppendChar[body, Ascii.CR];
    String.AppendString[body, "Encap: "L];
    p ← @b.encapsulation;
    FOR i IN [0..SIZE[DriverTypes.Encapsulation]) DO O7[(p + i)↑]; ENDLOOP;
    String.AppendChar[body, Ascii.CR];
    String.AppendString[body, "Header:"L];
    p ← @b.bufferBody;
    FOR i IN [0..11 - 1) DO O7[(p + i)↑]; ENDLOOP;
    FOR i ← 0, i + 1 UNTIL i >= MIN[words, maxWords] DO
      IF (i MOD 10) = 0 THEN
	BEGIN
	String.AppendChar[body, Ascii.CR];
	String.AppendString[body, IF i = 0 THEN "Body:  "L ELSE "       "L];
	END;
      O7[b.pupWords[i]];
      ENDLOOP;
    String.AppendChar[body, Ascii.CR];
    Put.Text[NIL, body];
    IF Runtime.IsBound[Mailer.SendMail] THEN
    [] ← Mailer.SendMail[
      "TrapBadPups"L, "Bad Checksum info"L, to, cc, body, troubles, NIL, Info];
    END;

  LogString: PROCEDURE [s: STRING] = {Put.Line[NIL, s]};

  -- initialization
  CollectInfo[];
  END.