-- Copyright (C) 1984  by Xerox Corporation. All rights reserved. 
-- NetDirBuilderControl.Mesa, HGM,  6-Nov-84  3:38:31

DIRECTORY
  Cursor USING [Defined, GetInfo, Set, Type],
  FileSW USING [IsEditable],
  FileWindow USING [
    Create, Enumerate, EnumerateProcType, FileInWindow, LoadWindow],
  FileWindowOps USING [EditMCR],
  FormSW USING [
    ClientItemsProcType, ProcType, AllocateItemDescriptor, newLine, Display,
    FindItem, BooleanItem, CommandItem, StringItem],
  MFile USING [Acquire, Delete, Error, GetProperties, Handle, maxNameLength],
  MStream USING [GetFile],
  Process USING [Detach, SetPriority],
  ProcessPriorities USING [priorityClientLow],
  Profile USING [GetUser],
  Put USING [Text, Line],
  Runtime USING [GetBcdTime],
  Stream USING [Handle],
  String USING [AppendChar, AppendDecimal, AppendString, EquivalentString],
  Time USING [Append, Unpack],
  Tool USING [Create, MakeSWsProc, MakeFormSW, MakeFileSW, UnusedLogName],
  UserInput USING [
    CreateIndirectStringInOut, DestroyIndirectStringInOut, GetDefaultWindow,
    WaitForConfirmation],
  Window USING [Handle],

  Password USING [Status, ValidMemberOfGroup],
  NetDirBuilderOps USING [
    Abort, BuildNewDirectory, BuildOldDirectory, debug, FindVersionNumber, Lock, log,
    SendOutDirectories, Unlock];

NetDirBuilderControl: PROGRAM
  IMPORTS
    Cursor, FileSW, FileWindow, FileWindowOps, FormSW, MFile, MStream, Process, Profile,
    Put, Runtime, String, Time, Tool, UserInput, Password, NetDirBuilderOps =
  BEGIN OPEN NetDirBuilderOps;

  form: Window.Handle;
  banzai: LONG STRING ← [20];
  running: BOOLEAN ← FALSE;
  editWindowExists: BOOLEAN ← FALSE;

  LockProc: FormSW.ProcType =
    BEGIN
    IF ~CheckPassword[] THEN RETURN;
    IF Lock[] AND ~editWindowExists THEN
      BEGIN editWindowExists ← TRUE; CreateEditWindow[]; END;
    END;

  CreateEditWindow: PROCEDURE =
    BEGIN
    ew: Window.Handle ← FileWindow.Create[[[0, 0], [0, 0]]];
    FileWindow.LoadWindow[fileName: "Pup-Network.txt", sw: ew];
    [] ← FileWindowOps.EditMCR[ew];
    END;

  AbortProc: FormSW.ProcType =
    BEGIN
    IF FileBeingEdited[] THEN RETURN;
    IF ~CheckPassword[] THEN RETURN;
    IF Abort[] THEN DeleteTheFiles[];
    END;

  DeleteTheFiles: PROCEDURE =
    BEGIN
    MaybeDelete["Pup-Network.txt"];
    MaybeDelete["Pup-Network.txt$"];
    MaybeDelete["Pup-Network.txt$$"];
    editWindowExists ← FALSE;
    END;

  MaybeDelete: PROCEDURE [fileName: STRING] =
    BEGIN
    handle: MFile.Handle ← NIL;
    handle ← MFile.Acquire[fileName, delete, [] ! MFile.Error => CONTINUE];
    IF handle = NIL THEN RETURN;
    Put.Text[log, "Deleting "];
    Put.Text[log, fileName];
    Put.Text[log, ".."];
    MFile.Delete[handle];
    Put.Line[log, "ok."];
    END;

  DoIt: FormSW.ProcType =
    BEGIN
    IF running THEN BEGIN Put.Line[log, "Already running...."L]; RETURN; END;
    IF FileBeingEdited[] THEN RETURN;
    IF ~CheckPassword[] THEN RETURN;
    running ← TRUE;
    Process.Detach[FORK MakeNewDirectory[]];
    END;

  FileBeingEdited: PROCEDURE RETURNS [hit: BOOLEAN] =
    BEGIN
    CheckForEditing: FileWindow.EnumerateProcType =
      BEGIN
      name: LONG STRING = [MFile.maxNameLength];
      s: Stream.Handle = FileWindow.FileInWindow[sw].s;
      IF s = NIL THEN RETURN[continue];  -- Empty Window
      [] ← MFile.GetProperties[MStream.GetFile[s], name];
      IF String.EquivalentString[name, "Pup-Network.txt"]
        AND FileSW.IsEditable[sw] THEN
        BEGIN
        Message["Pup-Network.txt is still being edited.  Please Save it first"];
        hit ← TRUE;
        END;
      RETURN[IF hit THEN stop ELSE continue];
      END;
    hit ← FALSE;
    FileWindow.Enumerate[CheckForEditing];
    END;

  MakeNewDirectory: PROCEDURE =
    BEGIN
    IF ~FindVersionNumber[banzai] THEN
      BEGIN
      Put.Line[log, "***  I can't locate the current version number."L];
      Put.Line[
        log, "***  Put ""BANZAI"" into Banzai to create a new directory."L];
      MakeBanzaiVisible[];
      running ← FALSE;
      RETURN;
      END;
    Process.SetPriority[ProcessPriorities.priorityClientLow];
    IF BuildOldDirectory[] AND BuildNewDirectory[] THEN SendOutDirectories[];
    running ← FALSE;
    END;

  UnlockProc: FormSW.ProcType =
    BEGIN
    IF ~CheckPassword[] THEN RETURN;
    IF Unlock[] THEN DeleteTheFiles[];
    END;

  Confirm: PROCEDURE RETURNS [okay: BOOLEAN] =
    BEGIN
    oldType: Cursor.Type = Cursor.GetInfo[].type;
    Cursor.Set[mouseRed];
    okay ← UserInput.WaitForConfirmation[].okay;
    IF oldType IN Cursor.Defined THEN Cursor.Set[oldType];
    END;


  -- BEWARE: There is an old up-arrow in here:
  -- User/password must be valid, AND user must be a member of Updaters↑.internet.
  backDoor: BOOLEAN ← FALSE;
  CheckPassword: PUBLIC PROCEDURE RETURNS [BOOLEAN] =
    BEGIN
    group: STRING = "Updaters↑.internet"L;
    person: STRING = [100];
    pwd: STRING = [100];
    status: Password.Status;
    SaveUserInfo: PROCEDURE [name, password: LONG STRING] =
      BEGIN
      String.AppendString[person, name];
      String.AppendString[pwd, password];
      END;
    IF backDoor THEN RETURN[TRUE];
    Profile.GetUser[SaveUserInfo, registry];
    status ← Password.ValidMemberOfGroup[person, pwd, group];
    SELECT status FROM
      yes => NULL;
      nil => Message["Name or Password is NIL."L];
      allDown => Message["All Grapevine servers appear to be down"L];
      notFound => Message["Grapevine doesn't like your name"L];
      badPwd => Message["Grapevine doesn't like your password"L];
      group => Message["Grapevine thinks you are a group"L];
      no => Message["You are not in "L, group];
      notGroup => Message["Grapevine doesn't recognize "L, group];
      error => Message["Error from GrapevineUser package"L];
      ENDCASE => ERROR;
    RETURN[status = yes];
    END;

  Message: PROCEDURE [one, two, three, four: STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    IF four # NIL THEN String.AppendString[text, four];
    String.AppendChar[text, '.];
    Put.Line[log, text];
    END;

  MessageDecimal: PROCEDURE [one: STRING, two: UNSPECIFIED, three: STRING] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    String.AppendDecimal[text, two];
    String.AppendString[text, three];
    String.AppendChar[text, '.];
    Put.Line[log, text];
    END;

  MakeSWs: Tool.MakeSWsProc =
    BEGIN
    logFileName: STRING = [40];
    Tool.UnusedLogName[logFileName, "NetDirBuilder.log"L];
    form ← Tool.MakeFormSW[window: window, formProc: MakeForm];
    log ← Tool.MakeFileSW[window: window, name: logFileName];
    END;

  banzaiIX: CARDINAL = 5;
  MakeForm: FormSW.ClientItemsProcType =
    BEGIN
    nParams: CARDINAL = 6;
    items ← FormSW.AllocateItemDescriptor[nParams];
    items[0] ← FormSW.CommandItem[
      tag: "Lock"L, proc: LockProc, place: FormSW.newLine];
    items[1] ← FormSW.CommandItem[tag: "Abort"L, proc: AbortProc];
    items[2] ← FormSW.BooleanItem[tag: "Debug"L, switch: @debug];
    items[3] ← FormSW.CommandItem[tag: "DoIt"L, proc: DoIt];
    items[4] ← FormSW.CommandItem[tag: "Unlock"L, proc: UnlockProc];
    items[5] ← FormSW.StringItem[
      tag: "Banzai"L, string: @banzai, place: FormSW.newLine, invisible: TRUE];
    RETURN[items, TRUE];
    END;

  MakeBanzaiVisible: PROCEDURE =
    BEGIN
    FormSW.FindItem[form, banzaiIX].flags.invisible ← FALSE;
    FormSW.Display[form];
    END;

  Init: PROCEDURE =
    BEGIN
    herald: STRING = [50];
    defaultWindow: Window.Handle = UserInput.GetDefaultWindow[];
    String.AppendString[herald, "NetDirBuilder of "L];
    Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]];
    [] ← Tool.Create[
      name: herald, makeSWsProc: MakeSWs, cmSection: "NetDirBuilder"L];
    UserInput.DestroyIndirectStringInOut[defaultWindow];
    UserInput.CreateIndirectStringInOut[from: defaultWindow, to: log];
    END;


  Init[];
  END.