-- Transport Mechanism: Restart and main control --

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

-- Andrew Birrell  20-Sep-82  9:25:11 --

DIRECTORY
Ascii		USING[ BS, ControlA, ControlC, ControlT, ControlV,
		       ControlW, CR, DEL, ESC, SP, TAB],
BodyDefs	USING[ Connect, maxConnectLength, maxRNameLength, RName ],
DisplayDefs	USING[ DisplayOff, StopCursor ],
DriverDefs	USING[ freeQueue ],
FrameDefs	USING[ IsBound ],
HeapDefs	USING[ Compactor, HeapEndWrite, HeapRestart, HeapStartWrite ],
IODefs		USING[ GetInputStream, SetOutputStream ],
ImageDefs	USING[ BcdTime ],
LocalNameDefs	USING[ LocalName, ReadMSName, ReadRSName ],
LogDefs		USING[ DisplayNumber, EnableLogSpilling,
		       SetTypescriptParameters, StatisticsOn,
		       TypescriptOn, WriteChar, WriteLogEntry, WriteLine,
                       WriteString ],
NameInfoDefs	USING[ GetConnect ],
ObjectDirDefs	USING[ Enumerate, ObjectNumber, UseObject ],
PolicyDefs	USING[ Operation, SetOperationAllowed, SetTelnetAllowed ],
ProcessDefs	USING[ Detach ],
ProtocolDefs	USING[ Init, SetTestingMode ],
PupDefs		USING[ AdjustBufferParms, GetPupPackageUseCount,
		       PupPackageMake ],
PupRouterDefs	USING[ numberOfNetworks ],
RestartDefs,
StreamDefs	USING[ DestroyKeyHandler, StreamHandle, StreamObject ],
StringDefs	USING[ AppendChar, AppendString, EquivalentString,
		       StringBoundsFault ],
TimeDefs	USING[ AppendFullDayTime, UnpackDT ],
VMDefs		USING[ InitializeVM ];

Restart: PROGRAM
IMPORTS DisplayDefs, DriverDefs, FrameDefs,
        HeapDefs, IODefs, ImageDefs, LocalNameDefs, LogDefs,
        NameInfoDefs, ObjectDirDefs, PolicyDefs,
        ProcessDefs, ProtocolDefs, PupDefs, PupRouterDefs, RestartDefs,
        StreamDefs, StringDefs, TimeDefs, VMDefs =

BEGIN

PutDisplay: PROCEDURE[ handle: StreamDefs.StreamHandle, char: UNSPECIFIED] =
   BEGIN
   LogDefs.WriteChar[char];
   END;

outStream: StreamDefs.StreamObject ←
   [reset:   NIL,
    get:     NIL,
    putback: NIL,
    put:     PutDisplay,
    endof:   NIL,
    destroy: NIL,
    link:    NIL,
    body:    Other[ type: 0, data: NIL ] ];

inStream: StreamDefs.StreamHandle = IODefs.GetInputStream[];

mail:     BOOLEAN = FrameDefs.IsBound[RestartDefs.MailboxRestart];
reg:      BOOLEAN = FrameDefs.IsBound[RestartDefs.RegRestart];
test:     BOOLEAN = FrameDefs.IsBound[RestartDefs.Test];

WriteLine: PROCEDURE[s: STRING] =
   BEGIN
   LogDefs.WriteLogEntry[s]; LogDefs.WriteLine[s];
   END;

WriteVersion: PROCEDURE[where: {disk, screen}] =
   BEGIN
   s: STRING = [256];
   StringDefs.AppendString[s, "Grapevine server starting.  Version of "L];
   TimeDefs.AppendFullDayTime[s, TimeDefs.UnpackDT[ImageDefs.BcdTime[]] ];
   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[];
             WriteLine["*** Testing mode ***"L];
             ObjectDirDefs.UseObject[obj]; testMode ← TRUE;
             END;
        END
   ELSE WriteLine["*** 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];
   UNTIL inStream.endof[inStream] DO [] ← inStream.get[inStream] ENDLOOP;
   DO LogDefs.WriteString[prompt];
      LogDefs.WriteString[" [Type password or DEL] "L];
      pwd.length ← 0;
      DO c: CHARACTER = inStream.get[inStream];
         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['\];
                  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 StringDefs.EquivalentString[pwd, real]
      THEN { LogDefs.WriteLine[" ok"L]; RETURN[TRUE] };
      LogDefs.WriteLine[" incorrect"L];
   ENDLOOP;
   END;

SetTestingMode: PROCEDURE =
   BEGIN
   IF NOT inStream.endof[inStream]
   THEN BEGIN
        c: CHARACTER = inStream.get[inStream];
        IF c = Ascii.ControlT
        THEN BEGIN
             IF Confirm["Set testing mode?"L, "Botrytis"L]
             THEN HeapDefs.HeapEndWrite[HeapDefs.HeapStartWrite[testMode],
                                        KeepTestModeObject];
             END;
        IF 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;
   END;

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

StartCompactor: PROC =
   { START HeapDefs.Compactor };

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

   IF initHeap
   THEN Compactor[];

   SetTestingMode[];

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

   ProtocolDefs.Init[];

   START LocalNameDefs.LocalName[initHeap];

   IF mail
   THEN BEGIN
        WriteLine["Restarting Steering-list Queues"L];
        START RestartDefs.SLRestart[initHeap] --allow internal mail--;
        END;

   -- Registration server --
   IF reg
   THEN BEGIN
        WriteLine["Restarting registration server database"L];
        START RestartDefs.RegRestart[initHeap];
        [] ← LocalNameDefs.ReadRSName[];
        END;

   -- Mail Server --
   IF mail
   THEN BEGIN
        WriteLine["Restarting mail server 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 WriteLine["No log spilling enabled"L];
        END;

   WriteLine["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];
   StringDefs.AppendString[logName, "Log-"L];
   StringDefs.AppendString[logName, name !
                           StringDefs.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;
      StringDefs.AppendChar[host, logName[i]];
   REPEAT FINISHED => GOTO cant
   ENDLOOP;
   FOR i: CARDINAL IN [host.length+2..logName.length)
   DO StringDefs.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 StringDefs;
   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;
   LogDefs.StatisticsOn[s];
   LogDefs.WriteLogEntry[s];
   END;

StartListeners: PROC =
   BEGIN
   START RestartDefs.Enquiry;
   WriteLine["Starting SL-queue readers"L];
   START RestartDefs.ReadForward;
   START RestartDefs.MTPServer;
   START RestartDefs.ReadInput;
   WriteLine["Starting listeners"L];
   IF reg
   THEN RESTART RestartDefs.RegRestart;
   IF mail
   THEN BEGIN
        START RestartDefs.ReceiveInput;
        START RestartDefs.ReceiveMail;
        START RestartDefs.ReadMail;
        START RestartDefs.MiscSoc;
        START RestartDefs.MSMail;
        RESTART RestartDefs.MTPServer;
        END;
   END;


-- Main program --

DisplayDefs.DisplayOff[black]; DisplayDefs.StopCursor[];
LogDefs.SetTypescriptParameters[tsLines:3];
LogDefs.TypescriptOn[];
WriteVersion[screen];
IODefs.SetOutputStream[@outStream];

[] ← PupDefs.GetPupPackageUseCount[]; -- to start PupRouterCold! --
PupRouterDefs.numberOfNetworks ← 255; -- exclude 0; in PupRouterCold --
PupDefs.AdjustBufferParms[54--buffers--, 64--words--];
PupDefs.PupPackageMake[];
LogDefs.DisplayNumber["Free PUPs"L, [short[@DriverDefs.freeQueue.length]]];

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

WriteVersion[disk];

StartDisk[];

StreamDefs.DestroyKeyHandler[];

StartStats[];

StartListeners[];

WriteLine["Running"L];

END.