-- Copyright (C) 1987 by Xerox Corporation. All rights reserved.
-- PhoneLineWatcher.mesa, Tim Diebert, 6-Aug-87 7:22:27
DIRECTORY
Ascii USING [CR],
CmFile USING [Handle, TableError],
Format USING [HostNumber],
Heap USING [Create, systemZone],
MFile USING [AddNotifyProc, Handle],
MStream USING [ReadWrite, Error, GetLength],
Put USING [Text],
SpecialSystem USING [clockSlipping],
Stream USING [Delete, Handle, PutString, SetPosition],
String USING [AppendChar, AppendDecimal, AppendString, AppendStringAndGrow,
CopyToNewString, Replace],
StringLookUp USING [noMatch, TableDesc],
Time USING [AppendCurrent],
Token USING [Boolean, Filtered, FreeTokenString, Item, Line],
Window USING [Handle],
GateDefs USING [typescript],
Indirect USING [Close, GetParmFileName, NextValue, OpenSection],
Mailer USING [Level, SendGVMail],
PhoneNetFriends USING [Change, RegisterStateChangeProc, StateChangeProc],
TimeServerClockExtras USING [Inconsistent, RequestTime]
;
PhoneLineWatcher: MONITOR
IMPORTS
CmFile, Format, Heap, MFile, MStream, Put,
SpecialSystem, Stream, String, Time, Token,
GateDefs, Indirect, Mailer, PhoneNetFriends, TimeServerClockExtras =
BEGIN
z: UNCOUNTED ZONE = Heap.Create[1];
timesAround: CARDINAL ← 0;
parmFileName: LONG STRING ← Indirect.GetParmFileName[];
pleaseStop: BOOLEAN ← FALSE;
updateTime: BOOLEAN ← FALSE;
watcher: PROCESS ← NIL;
lastState: PhoneNetFriends.Change ← other;
notify, to, cc: LONG STRING ← NIL;
mail: LONG STRING ← NIL;
Init: ENTRY PROCEDURE = BEGIN
MFile.AddNotifyProc[Inspect, [parmFileName, null, readOnly], NIL];
Starter[];
END;
Starter: INTERNAL PROCEDURE = BEGIN
IF NOT FindParams[] THEN RETURN;
PhoneNetFriends.RegisterStateChangeProc[WatchStateChangeProc];
timesAround ← 0;
pleaseStop ← FALSE;
-- watcher ← FORK Watcher[];
END;
Stopper: INTERNAL PROCEDURE = BEGIN
pleaseStop ← TRUE;
-- JOIN watcher[];
-- watcher ← NIL;
END;
FindParams: PROCEDURE RETURNS [BOOLEAN] = BEGIN
cmFile: CmFile.Handle;
Option: TYPE = MACHINE DEPENDENT{
updateTime(0), notify, to, cc, noMatch(StringLookUp.noMatch)};
DefinedOption: TYPE = Option [updateTime..cc];
CheckType: PROCEDURE [h: CmFile.Handle, table: StringLookUp.TableDesc]
RETURNS [index: CARDINAL] = Indirect.NextValue;
MyNextValue: PROCEDURE [h: CmFile.Handle,
table: LONG DESCRIPTOR FOR ARRAY DefinedOption OF LONG STRING]
RETURNS [index: Option] = LOOPHOLE[CheckType];
optionTable: ARRAY DefinedOption OF LONG STRING ← [
updateTime: "UpdateTime"L,
notify: "Notify"L, to: "to"L, cc: "cc"L];
cmFile ← Indirect.OpenSection["PhoneLineWatcher"L];
IF cmFile = NIL THEN
BEGIN
Message["Can't find [PhoneLineWatcher] section in parameter file"L];
RETURN[FALSE];
END;
DO
option: Option;
option ← MyNextValue[cmFile, DESCRIPTOR[optionTable] !
CmFile.TableError =>
BEGIN
IF name[0] # '; THEN Message["Unrecognized parameter: ", name];
RETRY;
END];
SELECT option FROM
noMatch => EXIT;
updateTime => BEGIN
updateTime ← Token.Boolean[cmFile];
IF updateTime
THEN Message["Time will be updated when new connection"L]
ELSE Message["Time will not be updated when new connection"L];
LOOP;
END;
notify => BEGIN
temp: LONG STRING ← Token.Item[cmFile, FALSE];
String.Replace[@notify, temp, z];
CheckForRegistry[notify];
[] ← Token.FreeTokenString[temp];
Message["Grapevine will send connection reports to "L, notify];
LOOP;
END;
to => BEGIN
temp: LONG STRING ←
Token.Filtered[cmFile, NIL, Token.Line, whiteSpace, FALSE];
String.Replace[@to, temp, z];
CheckForRegistry[to];
[] ← Token.FreeTokenString[temp];
Message["Mail will be sent to "L, to];
LOOP;
END;
cc => BEGIN
temp: LONG STRING ←
Token.Filtered[cmFile, NIL, Token.Line, whiteSpace, FALSE];
String.Replace[@cc, temp, z];
CheckForRegistry[cc];
[] ← Token.FreeTokenString[temp];
Message["Copies will be sent to "L, cc];
LOOP;
END;
ENDCASE => ERROR;
ENDLOOP;
Indirect.Close[cmFile];
RETURN[TRUE];
END;
CheckForRegistry: PROCEDURE [s: LONG STRING] = BEGIN
dot: BOOLEAN ← FALSE;
FOR i: CARDINAL IN [0..s.length) DO
SELECT s[i] FROM
'. => dot ← TRUE;
', =>
BEGIN
IF ~dot THEN
BEGIN Message["Registry expected in arg: "L, s]; RETURN; END;
dot ← FALSE;
END;
ENDCASE => NULL;
ENDLOOP;
IF ~dot THEN BEGIN Message["Registry expected in arg: "L, s]; RETURN; END;
END;
ForgetTargets: INTERNAL PROCEDURE = BEGIN
END;
WatchStateChangeProc: PhoneNetFriends.StateChangeProc = BEGIN
-- lineNumber: CARDINAL, clientData: LONG UNSPECIFIED,
-- change: Change, farHost: System.HostNumber
-- farHost is valid only if change = connectionEstablished
ts: Window.Handle ← GateDefs.typescript; -- our copy
text: LONG STRING = [250]; -- just for grins
temp: LONG STRING = [50];
Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
BEGIN String.AppendString[text, s]; END;
Time.AppendCurrent[text];
IF lastState = change THEN RETURN[];
String.AppendString[to: temp, from: (SELECT change FROM
mediumUp => "Physical medium is now available"L,
entityClassClash => "Wrong type of entity tried to connect to us"L,
connectionEstablished => "Connection established"L,
connectionNotEstablished => "Connection closed"L,
mediumDown => "Physical medium isn't available"L,
loopbackDetected => "We are looped back"L,
-- the following events cause the line to be reset --
tooLongSinceLastPkt => "Data pkts stopped arriving"L,
versionMisMatch => "Mismatch in version ranges"L,
entityClassRejected => "Entity class was rejected"L,
sizeRejected => "Maximum packet size was unsuitable"L,
terminated => "Connection terminated"L,
noResponse => "No response from far end after medium UP"L,
other => "Unknown error"L,
ENDCASE => "Don't know"L)];
String.AppendString[text, " PhoneLineWatcher: Line "L];
String.AppendDecimal[text, lineNumber];
String.AppendChar[text, ' ];
String.AppendString[text, temp];
String.AppendChar[text, ' ];
Format.HostNumber[Append, farHost, octal];
String.AppendChar[text, '\n];
SELECT change FROM
mediumUp, mediumDown => NULL;
connectionEstablished, connectionNotEstablished, tooLongSinceLastPkt,
versionMisMatch, entityClassClash, entityClassRejected, sizeRejected,
terminated, noResponse, other => BEGIN
IF to # NIL THEN BEGIN
AppendToMail[text];
SendMail[];
END;
END;
ENDCASE => NULL;
Put.Text[ts, text];
IF change = connectionEstablished AND updateTime THEN BEGIN
IF NOT SpecialSystem.clockSlipping
THEN TimeServerClockExtras.RequestTime[
! TimeServerClockExtras.Inconsistent => RETRY];
END;
END;
Message: PROCEDURE [one, two, three: LONG STRING ← NIL] = BEGIN
text: STRING = [250];
Time.AppendCurrent[text];
String.AppendString[text, " PhoneLineWatcher: "L];
String.AppendString[text, one];
IF two # NIL THEN String.AppendString[text, two];
IF three # NIL THEN String.AppendString[text, three];
LogString[text];
END;
LogString: PROCEDURE [text: LONG STRING] = BEGIN
String.AppendChar[text, '.];
String.AppendChar[text, Ascii.CR];
Put.Text[NIL, text];
END;
AppendToLogFile: PROCEDURE [s: LONG STRING] = BEGIN
sh: Stream.Handle ← NIL;
sh ← MStream.ReadWrite["TimeServer.log"L, [], text
! MStream.Error => CONTINUE ];
IF sh = NIL THEN RETURN;
Stream.SetPosition[sh, MStream.GetLength[sh]];
Stream.PutString[sh, s];
Stream.Delete[sh];
AppendToMail[s];
END;
AppendToMail: PROCEDURE [s: LONG STRING] = BEGIN
String.AppendStringAndGrow[@mail, s, z];
END;
SendMail: PROCEDURE = BEGIN
subject: STRING = "Report from PhoneLineWatcher"L;
Info: PROCEDURE [s: LONG STRING, level: Mailer.Level] = BEGIN
copy: LONG STRING ← String.CopyToNewString[s, Heap.systemZone, 2];
LogString[copy];
Heap.systemZone.FREE[@copy];
END;
IF to # NIL THEN
[] ← Mailer.SendGVMail[subject, to, cc, mail, notify, Info];
z.FREE[@mail];
END;
Inspect: ENTRY PROCEDURE [
name: LONG STRING, file: MFile.Handle, clientInstanceData: LONG POINTER]
RETURNS [BOOLEAN] =
BEGIN
IF parmFileName = NIL THEN RETURN[FALSE];
Message["Recycling because a new version of "L, parmFileName, " arrived"L];
IF watcher # NIL THEN Stopper[];
Starter[];
RETURN[FALSE]
END;
Init[];
END.