-- Copyright (C) 1984, 1985  by Xerox Corporation. All rights reserved. 
-- NetDirBuilderMain.Mesa, HGM, 25-Jun-85  8:31:12

DIRECTORY
  Ascii USING [CR],
  Environment USING [],
  Process USING [SetTimeout, MsecToTicks],
  Put USING [Char, Text, Line, Decimal],
  String USING [AppendChar, AppendString, EqualString],
  Time USING [AppendCurrent],
  UserInput USING [ResetUserAbort, UserAbort],
  Window USING [Handle],

  Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer],
  NameServerDefs USING [
    StartProbingForDirectory, PupDirServerOn, PupDirServerOff, PupNameServerOff],
  PupDefs USING [
    AppendHostName, defaultNumberOfNetworks, GetHopsToNetwork, GetPupContentsBytes,
    MsToTocks, PupBuffer, PupRouterSendThis, PupSocket,
    PupSocketMake, SecondsToTocks, SetPupContentsWords, PupSocketDestroy, PupPackageMake,
    PupPackageDestroy],
  PupTypes USING [
    PupAddress, allNets, allHosts, fillInPupAddress, fillInSocketID, miscSrvSoc],
  
  NetDirDefs,
  NetDirBuilderOps USING [];

NetDirBuilderMain: MONITOR
  IMPORTS
    Process, Put, String, Time, UserInput,
    Buffer, NameServerDefs, PupDefs
  EXPORTS NameServerDefs, NetDirBuilderOps =
  BEGIN OPEN NetDirDefs;


  debug: PUBLIC BOOLEAN ← FALSE; -- If debug is on, this program should produce a new directory that is EXACTLY like the current one.  If you are changing the way this program operates (rather than the format/contents of the output file), turn debug on and run it.  Then FTP Compare can be used to verify that your changes have not done anything horrible.

  log: PUBLIC Window.Handle ← NIL;


  UpdatePicture: PUBLIC PROCEDURE = {};  -- Avoid binder's complaints

  version: CARDINAL ← 0;

  GetNewVersionNumber: PUBLIC PROCEDURE RETURNS [CARDINAL] =
    BEGIN
    RETURN[version];
    END;
    
  FindVersionNumber: PUBLIC PROCEDURE [banzai: LONG STRING] RETURNS [BOOLEAN] =
    BEGIN OPEN PupDefs, PupTypes;
    pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 10];
    socket: PupSocket;
    b: PupBuffer;
    Announce["Probing for current version number..."];
    IF ~debug THEN
      Put.Line[
        log, "  This takes a while since we are searching the whole internet."L];
    version ← 0;
    [] ← PupPackageMake[];
    socket ← PupSocketMake[fillInSocketID, fillInPupAddress, MsToTocks[250]];
    THROUGH [0..5) DO
      IF debug AND version # 0 THEN EXIT;
      FOR net: CARDINAL IN [0..defaultNumberOfNetworks) DO
        IF GetHopsToNetwork[[net]] > 100 THEN LOOP;
        b ← Buffer.GetBuffer[pup, pool, send];
        b.pup.source ← socket.getLocalAddress[];
        b.pup.dest ← [[net], PupTypes.allHosts, PupTypes.miscSrvSoc];
        b.pup.pupType ← netDirVersion;
        b.pup.pupWords[0] ← 0;
        b.pup.pupWords[1] ← 0;
        SetPupContentsWords[b, 2];
        PupRouterSendThis[b];
        UNTIL b = NIL DO
          b ← socket.get[];
          IF b # NIL THEN
            BEGIN
            IF b.pup.pupType = netDirVersion THEN
	      BEGIN
	      IF b.pup.pupWords[0] > version THEN version ← b.pup.pupWords[0];
	      IF GetPupContentsBytes[b] > 2 THEN
                IF b.pup.pupWords[1] > version THEN version ← b.pup.pupWords[1];
	      END;
            Buffer.ReturnBuffer[b];
            END;
          ENDLOOP;
        ENDLOOP;
      ENDLOOP;
    PupSocketDestroy[socket];
    Buffer.DestroyPool[pool];
    PupPackageDestroy[];
    IF version = 0 THEN
      BEGIN
      IF ~String.EqualString[banzai, "BANZAI"L] THEN RETURN[FALSE];
      Put.Line[
        log,
        "***  Creating a new directory.  I hope you know what you are doing."L];
      version ← 1;
      END;
    IF ~debug THEN version ← version + 1;
    Put.Text[log, "The new version number will be "];
    Put.Decimal[log, version];
    Put.Line[log, "."];
    RETURN[TRUE];
    END;

  SendOutDirectories: PUBLIC ENTRY PROCEDURE =
    BEGIN OPEN PupDefs, PupTypes;
    pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 10];
    socket: PupSocket;
    b: PupBuffer;
    cycle, stop: CARDINAL ← 0;
    pause: CONDITION;
    Announce["Starting Directory Server..."];
    Process.SetTimeout[@pause, Process.MsecToTicks[10000]];
    [] ← PupDefs.PupPackageMake[];
    socket ← PupSocketMake[fillInSocketID, fillInPupAddress, SecondsToTocks[2]];
    NameServerDefs.PupDirServerOn[];
    NameServerDefs.StartProbingForDirectory[];
    UserInput.ResetUserAbort[log];
    UNTIL stop > 10 OR UserInput.UserAbort[log] DO
      -- Note: We can't simply send one copy of the new directory, because an IFS might take it, and they won't send it on to others unless the name server is activated.
      stop ← stop + 1;
      b ← Buffer.GetBuffer[pup, pool, send];
      b.pup.source ← socket.getLocalAddress[];
      b.pup.dest ← [PupTypes.allNets, PupTypes.allHosts, PupTypes.miscSrvSoc];
      b.pup.pupType ← netDirVersion;
      b.pup.pupWords[0] ← 0;
      b.pup.pupWords[1] ← 0;
      SetPupContentsWords[b, 2];
      PupRouterSendThis[b];
      DO
        b ← socket.get[];
        IF b # NIL THEN
          BEGIN
          IF b.pup.pupType = netDirVersion THEN
	    BEGIN
	    old, new: BOOLEAN ← FALSE;
	    IF b.pup.pupWords[0] < version THEN old ← TRUE;
	    IF GetPupContentsBytes[b] > 2 AND b.pup.pupWords[1] < version THEN new ← TRUE;
	    IF old OR new THEN stop ← 0;
	    IF (old OR new) AND cycle > 5 AND (cycle MOD 3) = 0 THEN
              BEGIN
              text: STRING = [100];
              Time.AppendCurrent[text];
              String.AppendString[text, "  Waiting for "L];
              PupDefs.AppendHostName[text, b.pup.source];
	      IF old AND ~new THEN String.AppendString[text, " (old only)"L];
	      IF ~old AND new THEN String.AppendString[text, " (new only)"L];
              String.AppendChar[text, '.];
              String.AppendChar[text, Ascii.CR];
              Put.Text[log, text];
              END;
            END;
          Buffer.ReturnBuffer[b];
          END;
        IF b = NIL THEN EXIT;
        ENDLOOP;
      WAIT pause;
      cycle ← cycle + 1;
      ENDLOOP;
    PupSocketDestroy[socket];
    Buffer.DestroyPool[pool];
    NameServerDefs.PupDirServerOff[];
    NameServerDefs.PupDirServerOff[];  -- It may turn itself on automatically
    NameServerDefs.PupNameServerOff[];
    PupDefs.PupPackageDestroy[];
    Announce["Finished!"];
    END;

  Announce: PROCEDURE [s: LONG STRING] =
    BEGIN
    text: STRING = [30];
    Time.AppendCurrent[text];
    Put.Text[log, text];
    Put.Char[log, ' ];
    Put.Char[log, ' ];
    Put.Line[log, s];
    END;

  END.