-- Transport Mechanism Mail Server - managing records of other servers --

-- [Indigo]<Grapevine>MS>ServerAlloc.mesa

-- Randy Gobbel		19-May-81 12:36:43 --
-- Andrew Birrell	29-Dec-81 15:34:31 --

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

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

OPEN ServerDefs;

noServer: ServerHandle = NIL;

freeChain:   ServerHandle ← noServer;
mailChain:   ServerHandle ← noServer;


CreateServer: INTERNAL PROCEDURE[ name: ServerName, type: ServerType ]
                         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.type ← type;
   WITH name SELECT FROM
      rName =>
         BEGIN --copy RName into permanent storage--
         size: CARDINAL = BodyDefs.RNameSize[value];
         place: BodyDefs.RName = Storage.Node[size];
         Inline.COPY[value, size, place];
         res.name ← [rName[place]];
--MTP--  FOR index: CARDINAL IN [0..place.length)
--MTP--  DO IF place[index] = '. THEN EXIT;
--MTP--  REPEAT --if no dot, asssume foreign--
--MTP--  FINISHED => { res.type ← foreign; res.name ← [connect[place]] }
--MTP--  ENDLOOP;
         res.addrKnown ← FALSE;
         END;
      connect =>
         BEGIN --copy connect site into permanent storage --
         place: STRING = Storage.String[value.length];
         Inline.COPY[@(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, type: ServerType ]
                              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;
   IF res = noServer THEN res ← CreateServer[name,type];
   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];
      WriteString[", handle="L];
      WriteDecimal[LOOPHOLE[ptr]];
   ENDLOOP;
   END;

END.