-- Copyright (C) 1981, 1982, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- Restart.mesa, Transport Mechanism: Restart and main control --

-- HGM, 17-May-85  8:58:39
-- Brenda Hankins	23-Aug-84 10:39:20
-- Mark Johnson 	18-Jan-82 13:28:02 --
-- Randy Gobbel		11-Aug-81 17:07:20 --
-- Andrew Birrell	30-Dec-81 15:15:26 --
-- Ted Wobber		 1-Nov-82 13:37:42 --

DIRECTORY
  Ascii USING [
    BS, ControlA, ControlC, ControlT, ControlV, ControlW, CR, DEL, ESC, SP, TAB],
  BodyDefs USING [Connect, maxConnectLength, maxRNameLength, RName],
  HeapDefs USING [Compactor, HeapEndWrite, HeapRestart, HeapStartWrite],
  LocalNameDefs USING [LocalName, ReadMSName, ReadRSName],
  LogDefs USING [
    EnableLogSpilling, ShowLine, StatisticsOn, TypescriptOn, WriteChar,
    WriteLogEntry, WriteLine, WriteString],
  LogPrivateDefs USING [tty],
  NameInfoDefs USING [GetConnect],
  ObjectDirDefs USING [Enumerate, ObjectNumber, UseObject],
  PolicyDefs USING [Operation, SetOperationAllowed, SetTelnetAllowed],
  Process USING [Detach],
  ProtocolDefs USING [Init, SetTestingMode],
  PupDefs USING [
    AdjustBufferParms, GetPupPackageUseCount, PupPackageDestroy, PupPackageMake],
  RestartDefs USING [
    Enquiry, MailboxRestart, MiscSoc1, MiscSoc2, MSMail,
    ReadForward, ReadInput1, ReadInput2, ReadMail, ReceiveInput, ReceiveMail, RegRestartInit1,
    RegRestartInit2, SLRestart, StartKeyWatcher, WatchDiskErrors, Test],
  Runtime USING [GetBcdTime, IsBound],
  String USING [AppendChar, AppendString, EquivalentString, StringBoundsFault],
  System USING [switches],
  Time USING [Append, Unpack],
  TTY USING [CharsAvailable, GetChar],
  VMDefs USING [InitializeVM];

Restart: PROGRAM
  IMPORTS
    HeapDefs, LocalNameDefs, LogDefs, LogPrivateDefs, NameInfoDefs, ObjectDirDefs,
    PolicyDefs, Process, ProtocolDefs, PupDefs, RestartDefs, Runtime, String,
    System, Time, TTY, VMDefs =

  BEGIN

  mail: BOOLEAN = Runtime.IsBound[LOOPHOLE[RestartDefs.MailboxRestart]];
  reg: BOOLEAN = Runtime.IsBound[LOOPHOLE[RestartDefs.RegRestartInit1]];
  test: BOOLEAN = Runtime.IsBound[LOOPHOLE[RestartDefs.Test]];

  WriteVersion: PROCEDURE [where: {disk, screen}] =
    BEGIN
    s: STRING = [256];
    String.AppendString[s, "Version of "L];
    Time.Append[s, Time.Unpack[Runtime.GetBcdTime[]], TRUE];
    IF where = disk THEN LogDefs.WriteLogEntry[s] ELSE LogDefs.WriteLine[s];
    END;

  testMode: BOOLEAN ← FALSE;
  testModeAllowed: BOOLEAN ← TRUE;  -- may be reset from debugger --

  KeepTestModeObject: PROCEDURE [obj: ObjectDirDefs.ObjectNumber] =
    BEGIN
    IF testModeAllowed THEN
      BEGIN
      IF NOT testMode THEN
        BEGIN
        ProtocolDefs.SetTestingMode[];
        LogDefs.ShowLine["*** Testing mode ***"L];
        ObjectDirDefs.UseObject[obj];
        testMode ← TRUE;
        END;
      END
    ELSE LogDefs.ShowLine["*** Testing mode cancelled ***"L];
    END;

  Confirm: PROC [prompt, real: STRING] RETURNS [BOOLEAN] =
    BEGIN
    -- Note: for security, this source file should contain only a one-way
    -- function of the password.  However, it's actually only an idiot
    -- check, so using clear-text passwords in the source is ok.
    pwd: STRING = [16];
    DO
      LogDefs.WriteString[prompt];
      LogDefs.WriteString[" [Type password or DEL] "L];
      pwd.length ← 0;
      DO
        c: CHARACTER = TTY.GetChar[LogPrivateDefs.tty];
        SELECT c FROM
          Ascii.SP, Ascii.TAB, Ascii.CR, Ascii.ESC => EXIT;
          Ascii.BS, Ascii.ControlA =>
            IF pwd.length > 0 THEN
              BEGIN pwd.length ← pwd.length - 1; LogDefs.WriteChar[134C]; END;
          Ascii.ControlW => {pwd.length ← 0; LogDefs.WriteChar['←]};
          Ascii.DEL, Ascii.ControlC => {
            LogDefs.WriteLine[" XXX"L]; RETURN[FALSE]};
          ENDCASE =>
            IF pwd.length < pwd.maxlength THEN
              BEGIN
              pwd[pwd.length] ← c;
              pwd.length ← pwd.length + 1;
              LogDefs.WriteChar['*];
              END;
        ENDLOOP;
      IF String.EquivalentString[pwd, real] THEN {
        LogDefs.WriteLine[" ok"L]; RETURN[TRUE]};
      LogDefs.WriteLine[" incorrect"L];
      ENDLOOP;
    END;

  SetTestingMode: PROCEDURE =
    BEGIN
    c: CHARACTER ← 000C;  -- NUL value
    IF TTY.CharsAvailable[LogPrivateDefs.tty] # 0 THEN
      c ← TTY.GetChar[LogPrivateDefs.tty];
    IF System.switches['t] = down OR c = Ascii.ControlT THEN
      BEGIN
      IF Confirm["Set testing mode?"L, "Botrytis"L] THEN
        HeapDefs.HeapEndWrite[
          HeapDefs.HeapStartWrite[testMode], KeepTestModeObject];
      END;
    IF System.switches['t] = down OR System.switches['v] = down
      OR c = Ascii.ControlT OR c = Ascii.ControlV THEN
      BEGIN
      IF Confirm["Viticulturists entrance only?"L, "Viticulture"L] THEN {
        FOR op: PolicyDefs.Operation IN PolicyDefs.Operation DO
          PolicyDefs.SetOperationAllowed[op, FALSE] ENDLOOP;
        PolicyDefs.SetTelnetAllowed[];
        LogDefs.WriteLogEntry["Viticulturists only"L]};
      END;
    END;

  CheckTestMode: PROCEDURE [obj: ObjectDirDefs.ObjectNumber] RETURNS [BOOLEAN] = {
    KeepTestModeObject[obj]; RETURN[TRUE --found-- ]};

  StartCompactor: PROC = {START HeapDefs.Compactor};

  StartDisk: PROCEDURE =
    BEGIN
    Compactor: PROC =
      BEGIN
      LogDefs.ShowLine["Starting compactor"L];
      Process.Detach[FORK StartCompactor[]];
      END;
    initHeap: BOOLEAN = START HeapDefs.HeapRestart[];

    RestartDefs.WatchDiskErrors[];

    IF initHeap THEN Compactor[];

    SetTestingMode[];

    [] ← ObjectDirDefs.Enumerate[testMode, CheckTestMode];

    ProtocolDefs.Init[];

    START LocalNameDefs.LocalName[initHeap];

    IF mail THEN
      BEGIN
      LogDefs.ShowLine["Restarting SL Queues"L];
      START RestartDefs.SLRestart[initHeap] --allow internal mail-- ;
      END;

    -- Registration server --
    IF reg THEN
      BEGIN
      LogDefs.ShowLine["Restarting RServer database"L];
      RestartDefs.RegRestartInit1[initHeap];
      [] ← LocalNameDefs.ReadRSName[];
      END;

    -- Mail Server --
    IF mail THEN
      BEGIN
      LogDefs.ShowLine["Restarting MServer database"L];
      START RestartDefs.MailboxRestart[initHeap];
      [] ← LocalNameDefs.ReadMSName[];
      END;

    -- Log spilling --
    IF mail OR reg THEN
      BEGIN
      name: STRING =
        IF mail THEN LocalNameDefs.ReadMSName[].name
        ELSE LocalNameDefs.ReadRSName[].name;
      pwd: STRING =
        IF mail THEN LocalNameDefs.ReadMSName[].password
        ELSE LocalNameDefs.ReadRSName[].password;
      host: BodyDefs.Connect = [BodyDefs.maxConnectLength];
      path: BodyDefs.Connect = [BodyDefs.maxConnectLength];
      IF GetHostPath[name, host, path] THEN
        LogDefs.EnableLogSpilling[name, pwd, host, path]
      ELSE LogDefs.ShowLine["No log spilling enabled"L];
      END;

    LogDefs.ShowLine["Disk restart complete"L];

    IF test THEN START RestartDefs.Test;

    IF NOT initHeap THEN Compactor[];

    END;

  GetHostPath: PROC [name: BodyDefs.RName, host, path: BodyDefs.Connect]
    RETURNS [BOOLEAN] =
    BEGIN
    logName: BodyDefs.RName = [BodyDefs.maxRNameLength];
    String.AppendString[logName, "Log-"L];
    String.AppendString[logName, name ! String.StringBoundsFault => GOTO cant];
    SELECT NameInfoDefs.GetConnect[logName, logName] FROM
      individual => NULL;
      ENDCASE => GOTO cant;
    -- logName should be "[Ivy]<DMS>Log>" --
    IF logName[0] # '[ THEN GOTO cant;
    FOR i: CARDINAL IN [1..logName.length) DO
      IF logName[i] = '] THEN EXIT;
      String.AppendChar[host, logName[i]];
      REPEAT FINISHED => GOTO cant
      ENDLOOP;
    FOR i: CARDINAL IN [host.length + 2..logName.length) DO
      String.AppendChar[path, logName[i]] ENDLOOP;
    IF path.length < 2 OR path[0] # '< OR path[path.length - 1] # '> THEN
      GOTO cant;
    RETURN[TRUE]
    EXITS cant => RETURN[FALSE];
    END;

  StartStats: PROCEDURE =
    BEGIN OPEN String;
    s: STRING = [256];
    AppendString[s, IF testMode THEN "*** Testing: "L ELSE "Grapevine: "L];
    IF reg THEN
      BEGIN
      AppendString[s, "Registration Server "L];
      AppendString[s, LocalNameDefs.ReadRSName[].name];
      IF mail THEN AppendString[s, ",  "L];
      END;
    IF mail THEN
      BEGIN
      AppendString[s, "Mail Server "L];
      AppendString[s, LocalNameDefs.ReadMSName[].name];
      END;
    RestartDefs.ReadInput1[];
    LogDefs.StatisticsOn[s];
    LogDefs.WriteLogEntry[s];
    END;

  StartListeners: PROC =
    BEGIN
    START RestartDefs.Enquiry;
    LogDefs.ShowLine["Starting SL-queue readers"L];
    START RestartDefs.ReadForward;
    RestartDefs.ReadInput2[];
    LogDefs.ShowLine["Starting listeners"L];
    IF reg THEN RestartDefs.RegRestartInit2[];
    IF mail THEN
      BEGIN
      START RestartDefs.ReceiveInput;
      START RestartDefs.ReceiveMail;
      START RestartDefs.ReadMail;
      RestartDefs.MiscSoc2[];
      START RestartDefs.MSMail;
      END;
    RestartDefs.StartKeyWatcher[];
    END;


  -- Main program --

  pupUseCount: CARDINAL;

  LogDefs.TypescriptOn[];
  WriteVersion[screen];

  pupUseCount ← PupDefs.GetPupPackageUseCount[];
  FOR i: CARDINAL IN [0..pupUseCount) DO PupDefs.PupPackageDestroy[] ENDLOOP;
  PupDefs.AdjustBufferParms[bufferPoolSize: 40 --buffers-- ];
  -- used to take a parameter "bufferSize: 0  (no change)" --
  FOR i: CARDINAL IN [0..pupUseCount] DO PupDefs.PupPackageMake[] ENDLOOP;

  VMDefs.InitializeVM[min: 30 --pages-- , max: 45 --pages, JRG suggestion-- ];

  WriteVersion[disk];

  StartDisk[];

  RestartDefs.MiscSoc1[];
  StartStats[];

  StartListeners[];

  LogDefs.ShowLine["Running"L];

  END.