--Telnet.mesa
--LStewart August 17, 1978 10:42 AM

DIRECTORY
DisplayDefs: FROM "DisplayDefs" USING [SetSystemDisplaySize],
IODefs: FROM "IODefs",
ProcessDefs: FROM "ProcessDefs" USING [Yield],
PupStream: FROM "PupStream",
Stream: FROM "Stream",
StreamDefs: FROM "StreamDefs";

Telnet: PROGRAM IMPORTS DisplayDefs, IODefs, PupStream, Stream, ProcessDefs =

BEGIN OPEN IODefs, PupStream;

ch: CHARACTER;
myWhy: PupStream.CloseReason ← localClose;
whyText: ARRAY PupStream.CloseReason OF STRING ←
[
"localClose", "remoteClose",
"noRouteToNetwork", "transmissionTimeout", "remoteReject" ];

listener: PupListener ← NIL;
socNum: PupSocketID ← [0,1]; --telnet socket
herald: STRING ← "Mesa Server Telnet";
-- user stuff
s: STRING ← [80];
escapeChar: CHARACTER ← 032C; --control Z
address: PupAddress;
mySocket: PupSocketID ← [123,456];
keyStream: StreamDefs.StreamHandle ← GetInputStream[];
myStream: Stream.Handle;
closed, pleaseStop, echoLF, serverStop, connected: BOOLEAN;
rp: PROCESS;

SendMark: PROCEDURE[bs: Stream.Handle, markType: INTEGER, data: INTEGER] =
BEGIN
Stream.SetSST[bs,LOOPHOLE[markType]];
Stream.PutByte[bs,LOOPHOLE[data]];
Stream.SendNow[bs];
END;

Talk: PROCEDURE =
BEGIN
pleaseStop ← FALSE;
rp ← FORK Read[];
Write[];
JOIN rp;
END;

Read: PROCEDURE =
BEGIN
c: CHARACTER;
eatByte: BOOLEAN ← FALSE;
UNTIL pleaseStop DO
ENABLE BEGIN
Stream.SSTChange =>
BEGIN
IF sst=5 THEN
--WARNING! This is dangerous!!
BEGIN
Stream.SetSST[myStream,6];
Stream.SendNow[myStream];
END;
IF sst=1 THEN
BEGIN
WriteChar[CR];WriteLine["!Synch!"];
END;
IF sst=6 THEN
BEGIN
WriteChar[CR];WriteLine["!TimingMarkReply!"];
END;
IF sst IN [2..4] THEN
BEGIN
WriteChar[CR];WriteString["Mark Type "];
WriteDecimal[sst];WriteString[", Argument = "];
eatByte ← TRUE;
END;
RESUME;
END;
PupStream.StreamClosing =>
BEGIN
pleaseStop ← closed ← TRUE;
connected ← FALSE;
myWhy ← why;
EXIT
;
END
;
Stream.TimeOut => IF pleaseStop THEN EXIT ELSE RESUME;
END;
c ← LOOPHOLE[Stream.GetByte[myStream]];
IF eatByte THEN
BEGIN
WriteDecimal[LOOPHOLE[c]];WriteChar[CR];
eatByte ← FALSE;
END
ELSE IF c#LF THEN WriteChar[c];
ENDLOOP;
END;

Write: PROCEDURE =
BEGIN

c: CHARACTER;
UNTIL pleaseStop DO ENABLE PupStream.StreamClosing =>
BEGIN
closed ← pleaseStop ← TRUE;
connected ← FALSE;
myWhy ← why;
EXIT
;
END
;
IF NOT keyStream.endof[keyStream] THEN
BEGIN
c ← ReadChar[];
IF c=escapeChar THEN pleaseStop ← TRUE
ELSE
BEGIN
Stream.PutByte[myStream,LOOPHOLE[c]];
IF c=CR AND echoLF THEN Stream.PutByte[myStream,LOOPHOLE[LF]];
Stream.SendNow[myStream];
END;
END;
ProcessDefs.Yield[];
ENDLOOP;
END;

Echo: PROCEDURE [bs: Stream.Handle, remote: PupAddress] =
BEGIN
errstr: STRING ← [80];
c: CHARACTER;
i: CARDINAL;
eatByte: BOOLEAN ← FALSE;
-- Mainline of server
WriteString["Connection from "];
AppendPupAddress[errstr,@remote];
WriteString[errstr];
WriteLine[" accepted"];
BEGIN ENABLE PupStream.StreamClosing =>
BEGIN
WriteString["Connection with "];
AppendPupAddress[errstr,@remote];
WriteString["closed because ... "];
WriteLine[whyText[why]];
bs.delete[bs];
GOTO ShortLife
;
END
;
FOR i IN [0..herald.length)
DO
Stream.PutByte[bs,LOOPHOLE[herald.text[i]]];
ENDLOOP;
Stream.PutByte[bs,LOOPHOLE[CR]];
IF echoLF THEN Stream.PutByte[bs,LOOPHOLE[LF]];
Stream.SendNow[bs];
END
;

UNTIL serverStop DO
ENABLE BEGIN
PupStream.StreamClosing =>
BEGIN
WriteString["Connection with "];
AppendPupAddress[errstr,@remote];
WriteString["closed because ... "];
WriteLine[whyText[why]];
bs.delete[bs];
EXIT
;
END
;
Stream.SSTChange =>
BEGIN
IF sst=5 THEN
--WARNING! This is dangerous!!
BEGIN
Stream.SetSST[bs,6];
Stream.SendNow[bs];
END;
IF sst=1 THEN
BEGIN
WriteChar[CR];WriteLine["!Synch!"];
END;
IF sst=6 THEN
BEGIN
WriteChar[CR];WriteLine["!TimingMarkReply!"];
END;
IF sst IN [2..4] THEN
BEGIN
WriteChar[CR];WriteString["Mark Type "];
WriteDecimal[sst];WriteString[", Argument = "];
eatByte ← TRUE;
END;
IF serverStop THEN EXIT ELSE RESUME;
END
;
Stream.TimeOut => IF serverStop THEN EXIT ELSE RESUME;
END;
c ← LOOPHOLE[Stream.GetByte[bs]];
IF eatByte THEN
BEGIN
WriteDecimal[LOOPHOLE[c]];WriteChar[CR];
eatByte ← FALSE;
END
ELSE
BEGIN
IF c#LF THEN
BEGIN
WriteChar[c];
Stream.PutByte[bs,LOOPHOLE[c]];
END;
IF c=CR AND echoLF THEN Stream.PutByte[bs,LOOPHOLE[LF]];
Stream.SendNow[bs];
END;
IF listener=NIL THEN EXIT;
ENDLOOP;
WriteLine["Server dying..."];
bs.delete[bs];
EXITS
ShortLife => NULL;
END;

--
Mainline code

DisplayDefs.SetSystemDisplaySize[40,40];
AdjustBufferParms[30,266];
connected ← FALSE;
PupPackageMake[];
WriteChar[CR]; WriteLine["Alto Mesa Telnet"];
DO
-- loop until stopped by user typing q or Q (last case below).
ENABLE PupNameTrouble =>
BEGIN
WriteString[" ... Error: "];
WriteLine[e];
LOOP;
END;
WriteChar[CR]; WriteString["# "];
ch ← ReadChar[];
SELECT ch FROM
’c, ’C =>
BEGIN
IF connected THEN
BEGIN
WriteString["Connection already open to: "];
s.length ← 0;
AppendPupAddress[s,@address];
WriteString[s];
GOTO Reject;
END;
WriteString["Connection to "];
ReadID[s ! Rubout => GOTO Reject];
GetPupAddress[@address,s];
s.length ← 0;
AppendPupAddress[s,@address];
WriteString[" (...= "];
WriteString[s];
WriteString[" ) is "];
myStream ← PupByteStreamCreate[mySocket,address,SecondsToTocks[1]
! StreamClosing =>
BEGIN
WriteLine["incomplete"];
WriteString[" because:"];
WriteString[whyText[why]];
LOOP
;
END
];
WriteLine["complete"];WriteChar[CR];
connected ← TRUE;
SendMark[myStream,4,10]; --terminal type
SendMark[myStream,2,80]; --line width
SendMark[myStream,3,39]; --screen height
EXITS
Reject => NULL;
END;
’d, ’D =>
BEGIN
WriteString["Disconnect... "];
myStream.delete[myStream];
connected ← FALSE;
WriteString["Connection Closed"];
END;
’e, ’E =>
BEGIN
WriteString["Escape Character is "];
escapeChar ← ReadChar[];
WriteChar[escapeChar];
END;
’l, ’L =>
BEGIN
WriteString["Linefeed Echo is "];
IF echoLF THEN
BEGIN
WriteString["Off"];
echoLF ← FALSE;
END
ELSE
BEGIN
WriteString["On"];
echoLF ← TRUE;
END
;
END;
’n, ’N =>
BEGIN
address: PupAddress;
s: STRING ← [80];
WriteString["Name lookup of "];
ReadID[s! Rubout => GOTO Reject];
GetPupAddress[@address,s];
s.length ← 0;
AppendPupAddress[s,@address];
WriteString[" ...= "];
WriteString[s];
EXITS
Reject => NULL;
END;
’q, ’Q =>
BEGIN
PupPackageDestroy[];
WriteLine["Quit"]; WriteChar[CR];
STOP;
PupPackageMake[];
END;
’s, ’S =>
BEGIN
WriteString["Server Telnet "];
IF listener=NIL THEN
BEGIN
serverStop ← FALSE;
listener ← CreatePupByteStreamListener [socNum, Echo, SecondsToTocks[3]];
WriteString["On"];
END
ELSE
BEGIN
serverStop ← TRUE;
DestroyPupListener[listener];
listener←NIL;
WriteString["Off"];
END;
END;
’? =>
BEGIN
WriteLine["C(onnect), Q(uit), L(inefeed Echo On/Off)"];
WriteLine["N(ame lookup), S(erver On/Off),"];
WriteLine["D(isconnect), E(scape Char is)"];
END;
ENDCASE => NULL;
IF connected THEN
BEGIN
WriteLine[" #"];
Talk[];
END;
ProcessDefs.Yield[];
ENDLOOP;
END.