-- 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.