-- Copyright (C) 1981, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- ServerAlloc.mesa, Transport Mechanism Mail Server - managing records of other servers --

-- HGM: 15-Sep-85  4:40:50
-- Randy Gobbel		19-May-81 12:36:43 --
-- Andrew Birrell	29-Dec-81 15:34:31 --
-- Hankins		22-Oct-84 15:32:04

DIRECTORY
  Ascii USING [CR],
  BodyDefs USING [RName, RNameSize],
  EnquiryDefs USING [],
  GlassDefs USING [Handle],
  Inline USING [LongCOPY],
  Process USING [InitializeMonitor],
  PupDefs USING [AppendPupAddress],
  ServerDefs USING [ServerHandle, ServerData, ServerName],
  Storage USING [Node, String],
  String USING [EquivalentStrings];

ServerAlloc: MONITOR
  IMPORTS BodyDefs, Inline, Process, PupDefs, Storage, String
  EXPORTS EnquiryDefs, ServerDefs
  SHARES ServerDefs =
  BEGIN OPEN ServerDefs;

  noServer: ServerHandle = NIL;
  freeChain: ServerHandle ← noServer;
  mailChain: ServerHandle ← noServer;


  CreateServer: INTERNAL PROCEDURE [name: ServerName, leaf: BOOLEAN]
    RETURNS [res: ServerHandle] =
    BEGIN
    chain: POINTER TO ServerHandle = @mailChain;
    IF freeChain = noServer THEN res ← Storage.Node[SIZE[ServerData]]
    ELSE BEGIN res ← freeChain; freeChain ← freeChain.next; END;
    res.next ← chain↑;
    chain↑ ← res;
    Process.InitializeMonitor[@res.LOCK];
    res.leaf ← leaf;
    WITH name SELECT FROM
      rName =>
        BEGIN  --copy RName into permanent storage--
        size: CARDINAL = BodyDefs.RNameSize[value];
        place: BodyDefs.RName = Storage.Node[size];
        Inline.LongCOPY[value, size, place];
        res.name ← [rName[place]];
        res.addrKnown ← FALSE;
        END;
      connect =>
        BEGIN  --copy connect site into permanent storage --
        place: STRING = Storage.String[value.length];
        Inline.LongCOPY[@(value.text), (1 + value.length) / 2, @(place.text)];
        place.length ← value.length;
        res.name ← [connect[place]];
        res.addrKnown ← FALSE;
        END;
      netAddr =>
        BEGIN
        res.name ← [netAddr[value]];
        res.addr ← value;
        res.addrKnown ← TRUE;
        END;
      ENDCASE => ERROR;
    res.up ← TRUE;
    res.SL ← NIL;
    END;

  GetServer: PUBLIC ENTRY PROCEDURE [name: ServerName] RETURNS [res: ServerHandle] =
    BEGIN
    res ← FindServer[name];
    IF res = noServer THEN res ← CreateServer[name, FALSE];
    END;
  
  GetLeafServer: PUBLIC ENTRY PROCEDURE [name: ServerName] RETURNS [res: ServerHandle] =
    BEGIN
    res ← FindServer[name];
    IF res = noServer THEN res ← CreateServer[name, TRUE];
    END;
  
  FindServer: INTERNAL PROCEDURE [name: ServerName]
    RETURNS [res: ServerHandle] =
    BEGIN
    FOR res ← mailChain, res.next UNTIL res = noServer DO
      IF
        (WITH wanted: name SELECT FROM
           rName =>
             (WITH found: res.name SELECT FROM
                rName => String.EquivalentStrings[found.value, wanted.value],
                --MTP--
                connect =>
                  --MTP-- String.EquivalentStrings[found.value, wanted.value],
                ENDCASE => FALSE),
           connect =>
             (WITH found: res.name SELECT FROM
                connect => String.EquivalentStrings[found.value, wanted.value],
                ENDCASE => FALSE),
           netAddr =>
             (WITH found: res.name SELECT FROM
                netAddr => found.value = wanted.value,
                ENDCASE => FALSE),
           ENDCASE => ERROR) THEN EXIT;
      ENDLOOP;
    END;

  EnumerateAll: PUBLIC ENTRY PROCEDURE [work: PROCEDURE [ServerHandle]] =
    BEGIN
    ENABLE UNWIND => NULL;
    FOR ptr: ServerHandle ← mailChain, ptr.next UNTIL ptr = noServer DO
      work[ptr] ENDLOOP;
    END;

  RemoteServers: PUBLIC PROC [str: GlassDefs.Handle] =
    BEGIN OPEN str;
    FOR ptr: ServerHandle ← mailChain, ptr.next UNTIL ptr = noServer DO
      WriteChar[Ascii.CR];
      WriteString[
        WITH this: ptr.name SELECT FROM
          rName => this.value,
          connect => this.value,
          netAddr => "[net address]"L,
          ENDCASE => "[bad name]"L];
      WriteString[": "L];
      WriteString[IF ptr.up THEN "up"L ELSE "down"L];
      IF ptr.leaf THEN WriteString[", leaf"L];
      IF ptr.addrKnown THEN
        BEGIN
	temp: STRING = [25];
	PupDefs.AppendPupAddress[temp, ptr.addr]; 
	WriteString[", "];
	WriteString[temp];
	END;
      ENDLOOP;
    END;

  END.

LOG:
22-Oct-84 15:31:45 - blh:  remove serverHandle from RemoteServers printout