-- File: HostWatcherPoke.mesa, Last Edit: HGM March 28, 1981 3:32 PM
DIRECTORY
Ascii USING [CR, LF, SP],
InlineDefs USING [BcplLongNumber, BcplToMesaLongNumber],
String USING [
AppendString, AppendChar, WordsForString, EquivalentString, AppendLongNumber],
Time USING [Current],
Librarian USING [PropertyList, PropertyPair, PropertyNumber],
LibrarianPN USING [IDName, StringName],
LibrarianOps USING [LibjectMessage, LibjectMessageType, ValidLibrarianMessage],
Stream USING [Delete, GetChar, Handle, TimeOut],
FTPDefs USING [
FTPUser, FTPCreateUser, FTPDestroyUser, FTPError, FTPInitialize, FTPFinalize,
FTPOpenConnection, SomeFilePrimitives, PupCommunicationPrimitives],
GateControlDefs USING [
gateControlStatsSend, gateControlStatsAck, GateControlStatsEntry],
PupStream USING [PupByteStreamCreate, StreamClosing],
PupDefs USING [
GetFreePupBuffer, ReturnFreePupBuffer, PupBuffer, PupSocket, PupSocketDestroy,
PupSocketMake, SecondsToTocks, SetPupContentsWords, GetPupContentsBytes,
veryLongWait],
PupTypes USING [fillInSocketID, PupAddress, PupType],
HostWatcherOps USING [Info, ShowErrorPup, State];
HostWatcherPoke: PROGRAM
IMPORTS
String, Time, InlineDefs, Stream, FTPDefs, PupDefs, PupStream, HostWatcherOps
EXPORTS HostWatcherOps =
BEGIN OPEN PupDefs, PupTypes;
Info: TYPE = HostWatcherOps.Info;
debug: BOOLEAN ← FALSE;
PokeGateway: PUBLIC PROCEDURE [info: Info] =
BEGIN
b: PupBuffer ← NIL;
packetNumber: CARDINAL ← NextSequenceNumber[];
mySoc: PupSocket ← PupSocketMake[
fillInSocketID, info.address, SecondsToTocks[5]];
tries: CARDINAL ← 10;
THROUGH [0..tries) DO
b ← GetFreePupBuffer[];
b.pupID.a ← 27182;
b.pupID.b ← (packetNumber ← packetNumber + 1);
b.pupType ← GateControlDefs.gateControlStatsSend;
SetPupContentsWords[b, 0];
mySoc.put[b];
UNTIL (b ← mySoc.get[]) = NIL DO
SELECT TRUE FROM
(b.pupType = error AND b.errorCode = noProcessPupErrorCode) =>
BEGIN
FOR i: CARDINAL IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pupType = error) => HostWatcherOps.ShowErrorPup[b];
(b.pupType = GateControlDefs.gateControlStatsAck)
AND (b.pupID.b = packetNumber) =>
BEGIN
gse: LONG POINTER TO GateControlDefs.GateControlStatsEntry;
gse ← LOOPHOLE[@b.pupBody];
FOR i: CARDINAL IN [0..gse.versionText.length) DO
String.AppendChar[info.text, gse.versionText.char[i]]; ENDLOOP;
AppendUpTime[info.text, gse.startTime];
GOTO Up;
END;
ENDCASE => NULL;
ReturnFreePupBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Up => info.state ← up;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN ReturnFreePupBuffer[b];
PupSocketDestroy[mySoc];
END;
AppendUpTime: PROCEDURE [s: STRING, startTime: InlineDefs.BcplLongNumber] =
BEGIN
now, then: LONG INTEGER;
sec: LONG INTEGER;
min: LONG INTEGER;
hours: LONG INTEGER;
String.AppendString[s, " up "L];
then ← InlineDefs.BcplToMesaLongNumber[startTime];
now ← Time.Current[];
sec ← now - then;
IF sec < 0 THEN
BEGIN -- Startup glitch
sec ← -sec;
String.AppendChar[s, '-];
END;
hours ← sec/3600;
sec ← sec - hours*3600;
min ← sec/60;
sec ← sec - min*60;
String.AppendLongNumber[s, hours, 10];
String.AppendChar[s, ':];
IF min < 10 THEN String.AppendChar[s, '0];
String.AppendLongNumber[s, min, 10];
String.AppendChar[s, ':];
IF sec < 10 THEN String.AppendChar[s, '0];
String.AppendLongNumber[s, sec, 10];
END;
PokeChat: PUBLIC PROCEDURE [info: Info] =
BEGIN
sh: Stream.Handle ← NIL;
state: HostWatcherOps.State ← up;
BEGIN
ENABLE
BEGIN
PupStream.StreamClosing =>
BEGIN
IF text # NIL THEN String.AppendString[info.text, text];
SELECT why FROM
transmissionTimeout => state ← timeout;
remoteReject => state ← rejecting;
ENDCASE =>
BEGIN
LookAtThis: SIGNAL = CODE;
IF debug THEN SIGNAL LookAtThis;
state ← unknown;
END;
IF CheckForFull[info.text] THEN state ← full;
CONTINUE;
END;
Stream.TimeOut => {state ← timeout; CONTINUE; }
END;
sh ← PupStream.PupByteStreamCreate[info.address, PupDefs.veryLongWait];
IF sh # NIL THEN
BEGIN
DO
c: CHARACTER ← Stream.GetChar[sh];
IF c = Ascii.LF THEN LOOP;
IF c = Ascii.CR THEN {IF info.text.length = 0 THEN LOOP ELSE EXIT; };
String.AppendChar[info.text, c];
ENDLOOP;
Stream.Delete[sh];
END;
END;
info.state ← state;
END;
CheckForFull: PROCEDURE [text: STRING] RETURNS [full: BOOLEAN] =
BEGIN
IF String.EquivalentString[text, "RFC Refused"L] THEN RETURN[TRUE]; -- Alto: FTP.run
IF String.EquivalentString[text, "Server full, try again later"L] THEN
RETURN[TRUE]; -- Maxc
IF String.EquivalentString[text, "No dial-out lines available"L] THEN
RETURN[TRUE]; -- DLS
IF String.EquivalentString[text, "Server is full"L] THEN RETURN[TRUE]; -- Juniper
IF String.EquivalentString[text, "IFS is full - try later"L] THEN
RETURN[TRUE];
IF String.EquivalentString[text, "Server full"L] THEN RETURN[TRUE]; -- Grapevine
IF String.EquivalentString[text, "Sorry, we are full now"L] THEN RETURN[TRUE];
-- Gateway
RETURN[FALSE];
END;
PokeFtp: PUBLIC PROCEDURE [info: Info] =
BEGIN OPEN FTPDefs;
ftpUser: FTPUser ← NIL;
state: HostWatcherOps.State ← up;
FTPInitialize[];
ftpUser ← FTPCreateUser[SomeFilePrimitives[], PupCommunicationPrimitives[]];
FTPOpenConnection[
ftpUser, info.name, files, info.text !
FTPError =>
BEGIN
IF message # NIL THEN String.AppendString[info.text, message];
SELECT ftpError FROM
connectionTimedOut => state ← timeout;
connectionRejected => state ← rejecting;
ENDCASE =>
BEGIN
LookAtThis: SIGNAL = CODE;
IF debug THEN SIGNAL LookAtThis;
state ← unknown;
END;
IF CheckForFull[info.text] THEN state ← full;
CONTINUE;
END];
info.state ← state;
FTPDestroyUser[ftpUser ! FTPError => CONTINUE];
FTPFinalize[];
END;
PokeMail: PUBLIC PROCEDURE [info: Info] =
BEGIN OPEN FTPDefs;
ftpUser: FTPUser ← NIL;
state: HostWatcherOps.State ← up;
FTPInitialize[];
ftpUser ← FTPCreateUser[NIL, PupCommunicationPrimitives[]];
FTPOpenConnection[
ftpUser, info.name, mail, info.text !
FTPError =>
BEGIN
IF message # NIL THEN String.AppendString[info.text, message];
SELECT ftpError FROM
connectionTimedOut => state ← timeout;
connectionRejected => state ← rejecting;
ENDCASE =>
BEGIN
LookAtThis: SIGNAL = CODE;
IF debug THEN SIGNAL LookAtThis;
state ← unknown;
END;
IF CheckForFull[info.text] THEN state ← full;
CONTINUE;
END];
info.state ← state;
FTPDestroyUser[ftpUser ! FTPError => CONTINUE];
FTPFinalize[];
END;
PokeLibrarian: PUBLIC PROCEDURE [info: Info] =
BEGIN OPEN Librarian, LibrarianPN, LibrarianOps;
request: LibjectMessageType = FindID;
b: PupBuffer;
message: LONG POINTER TO LibjectMessage;
plist: LONG POINTER TO ARRAY [0..2) OF PropertyPair;
transactionID: CARDINAL ← NextSequenceNumber[];
socket: PupSocket;
socket ← PupSocketMake[fillInSocketID, info.address, SecondsToTocks[15]];
FOR i: CARDINAL IN [0..5) DO
b ← GetFreePupBuffer[];
b.pupID ← [transactionID, i];
message ← LOOPHOLE[@b.pupWords];
message.id ← transactionID;
message.password ← ValidLibrarianMessage;
message.type ← request;
message.plist ← DESCRIPTOR[NIL, 2];
plist ← LOOPHOLE[message + SIZE[LibjectMessage]];
message.nextfree ← LOOPHOLE[SIZE[LibjectMessage] + 2*SIZE[PropertyPair]];
BEGIN
COPY: PROCEDURE [from: POINTER, nwords: CARDINAL, to: LONG POINTER] =
BEGIN
FOR i: CARDINAL IN [0..nwords) DO (to + i)↑ ← (from + i)↑; ENDLOOP;
END;
string: STRING = "HostWatcher"L;
wordsforstring: CARDINAL = String.WordsForString[string.length];
dataArea: LONG POINTER ← message + LOOPHOLE[message.nextfree, CARDINAL];
plist[0] ← PropertyPair[
empty: FALSE, pn: StringName,
body: String[
length: string.length, string: LOOPHOLE[2*SIZE[PropertyPair]]]];
COPY[from: string, nwords: wordsforstring, to: dataArea];
message.nextfree ← message.nextfree + wordsforstring;
END;
plist[1] ← PropertyPair[empty: TRUE, pn: IDName, body: TwoWord[[lc[0]]]];
SetPupContentsWords[b, LOOPHOLE[message.nextfree, INTEGER]];
socket.put[b];
UNTIL (b ← socket.get[]) = NIL DO
message ← LOOPHOLE[@b.pupWords];
SELECT TRUE FROM
(b.pupType = error AND b.errorCode = noProcessPupErrorCode) =>
BEGIN
i: CARDINAL;
FOR i IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pupType = error) => HostWatcherOps.ShowErrorPup[b];
message.password = ValidLibrarianMessage AND message.id = transactionID
=> GOTO Up;
ENDCASE => NULL; -- I wonder what this is
ReturnFreePupBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Up => info.state ← up;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN ReturnFreePupBuffer[b];
PupSocketDestroy[socket];
END;
PokeSpruce: PUBLIC PROCEDURE [info: Info] =
BEGIN
spruceStatusRequest: PupType = LOOPHOLE[200B];
spruceStatusReply: PupType = LOOPHOLE[201B];
b: PupBuffer ← NIL;
packetNumber: CARDINAL ← NextSequenceNumber[];
mySoc: PupSocket ← PupSocketMake[
fillInSocketID, info.address, SecondsToTocks[5]];
THROUGH [0..20) DO
b ← GetFreePupBuffer[];
b.pupID.a ← b.pupID.b ← packetNumber;
b.pupType ← spruceStatusRequest;
SetPupContentsWords[b, 0];
mySoc.put[b];
UNTIL (b ← mySoc.get[]) = NIL DO
SELECT TRUE FROM
(b.pupType = error AND b.errorCode = noProcessPupErrorCode) =>
BEGIN
FOR i: CARDINAL IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pupType = error) => HostWatcherOps.ShowErrorPup[b];
((b.pupType # spruceStatusReply) OR (b.pupID.a # packetNumber)
OR (b.pupID.b # packetNumber)) => NULL;
ENDCASE =>
BEGIN
FOR i: CARDINAL IN [2..GetPupContentsBytes[b] - 1) DO
c: CHARACTER ← b.pupChars[i];
IF c = Ascii.CR THEN c ← Ascii.SP;
String.AppendChar[info.text, c];
ENDLOOP;
SELECT b.pupWords[0] FROM
1 => GOTO Down; -- Not Spooling
2 => GOTO Up; -- Spooler is idle
3 => GOTO Up; -- Spooler is busy
ENDCASE => NULL;
GOTO Up;
END;
ReturnFreePupBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Down => info.state ← down;
Up => info.state ← up;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN ReturnFreePupBuffer[b];
PupSocketDestroy[mySoc];
END;
PokeEftp: PUBLIC PROCEDURE [info: Info] =
BEGIN
b: PupBuffer ← NIL;
mySoc: PupSocket ← PupSocketMake[
fillInSocketID, info.address, SecondsToTocks[5]];
THROUGH [0..20) DO
b ← GetFreePupBuffer[];
b.pupID.a ← b.pupID.b ← 0;
b.pupType ← eData;
SetPupContentsWords[b, 0];
mySoc.put[b];
UNTIL (b ← mySoc.get[]) = NIL DO
SELECT TRUE FROM
(b.pupType = eAbort) =>
BEGIN
FOR i: CARDINAL IN [0..GetPupContentsBytes[b] - 2) DO
String.AppendChar[info.text, b.pupChars[i + 2]]; ENDLOOP;
GOTO Rejecting;
END;
(b.pupType = error AND b.errorCode = noProcessPupErrorCode) =>
BEGIN
FOR i: CARDINAL IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pupType = error) => HostWatcherOps.ShowErrorPup[b];
((b.pupType = eAck) AND (b.pupID.a = 0) AND (b.pupID.b = 0)) => GOTO Up;
ENDCASE => HostWatcherOps.ShowErrorPup[b];
ReturnFreePupBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Up => info.state ← up;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN ReturnFreePupBuffer[b];
PupSocketDestroy[mySoc];
END;
sequenceNumber: CARDINAL ← 0;
NextSequenceNumber: PROCEDURE RETURNS [CARDINAL] =
BEGIN RETURN[sequenceNumber ← sequenceNumber + 1]; END;
END.