-- Laurel subsystem - chat program -- -- chat.mesa -- Mike Schroeder, 3-Mar-81 12:19:07 -- Edited by Brotz, January 16, 1981 11:56 AM DIRECTORY ImageDefs, InlineDefs, IODefs, LaurelExecDefs, ProcessDefs, PupDefs, PupStream, PupTypes, Stream, StreamDefs, TimeDefs; Chat: MONITOR IMPORTS ImageDefs, InlineDefs, IODefs, LaurelExecDefs, ProcessDefs, PupStream, Stream, StreamDefs, TimeDefs = BEGIN OPEN IODefs; ServerToUser: PROCEDURE = BEGIN char: CHARACTER; serverName: STRING _ [32]; addr: PupDefs.PupAddress; serverStream: Stream.Handle _ NIL; keyStream: StreamDefs.StreamHandle = GetInputStream[]; displayStream: StreamDefs.StreamHandle = GetOutputStream[]; setPageLength: Stream.SubSequenceType = 3; timingMark: Stream.SubSequenceType = 5; timingMarkReply: Stream.SubSequenceType = 6; UserToServer: PROCEDURE [login: BOOLEAN] = BEGIN char: CHARACTER; BEGIN ENABLE ABORTED, PupStream.StreamClosing => GOTO return; --Stream.SetSST[serverStream, setPageLength]; --Stream.PutByte[serverStream, 255]; kludge to minimize BELLS from Juniper IF login THEN BEGIN credential: STRING _ [40]; SendStringToServer["Login "]; LaurelExecDefs.GetUserCredentials[name: credential]; --gets name-- SendStringToServer[credential]; SendStringToServer[" "L]; credential.length _ 0; LaurelExecDefs.GetUserCredentials[password: credential]; --gets password-- SendStringToServer[credential]; SendStringToServer[" "L]; END; DO char _ ReadChar[]; DO Stream.PutChar[serverStream, char]; IF keyStream.endof[keyStream] THEN EXIT; char _ ReadChar[]; ENDLOOP; Stream.SendNow[serverStream]; ENDLOOP; EXITS return => NULL; END; END; AcceptFromServer: PROC[login: BOOLEAN, serverStream: Stream.Handle] = BEGIN userToServer: PROCESS = FORK UserToServer[login]; DO ENABLE BEGIN ABORTED, PupStream.StreamClosing => { NotifyState[starting]; ProcessDefs.Abort[userToServer] }; UNWIND => JOIN userToServer-- join outside the Pup pkg monitor! --; END; buffer: STRING _ [200]; why: Stream.CompletionCode; mySST: Stream.SubSequenceType; [buffer.length, why, mySST] _ Stream.GetBlock[serverStream, [@buffer.text, 0, buffer.maxlength]]; WriteString[buffer]; IF why = sstChange AND mySST = timingMark THEN Stream.SetSST[serverStream, timingMarkReply]; ENDLOOP; END; SendStringToServer: PROCEDURE[s: STRING] = BEGIN i: CARDINAL; FOR i IN [0 .. s.length) DO Stream.PutChar[serverStream, s[i]]; ENDLOOP; Stream.SendNow[serverStream]; END; WriteHostPrompt: PROCEDURE[c: STRING] = BEGIN WriteChar[CR]; WriteString[c]; WriteString[" to host: "L]; END; WriteCRStringHost: PROCEDURE[s: STRING] = BEGIN WriteChar[CR]; WriteString[s]; WriteString[serverName]; END; FinishStringWithErrorMsg: PROCEDURE[errorMsg: STRING] = BEGIN IF errorMsg # NIL THEN BEGIN WriteString[": "L]; WriteString[errorMsg]; END; WriteChar['.]; END; WriteHerald: PROCEDURE = BEGIN time: STRING _ [25]; TimeDefs.AppendDayTime[time, TimeDefs.UnpackDT[ImageDefs.BcdVersion[].time]]; WriteChar[CR]; WriteString["Laurel Chat of "L]; WriteLine[time]; WriteString["(CTRL DEL closes connection and returns to Chat command level.)"L]; END; -- of WriteHerald -- LaurelExecDefs.MakeMenuCommandCallable[newMail]; LaurelExecDefs.MakeMenuCommandCallable[user]; LaurelExecDefs.MakeMenuCommandCallable[mailFile]; LaurelExecDefs.MakeMenuCommandCallable[display]; LaurelExecDefs.MakeMenuCommandCallable[delete]; LaurelExecDefs.MakeMenuCommandCallable[undelete]; LaurelExecDefs.MakeMenuCommandCallable[moveTo]; LaurelExecDefs.MakeMenuCommandCallable[copy]; WriteHerald[]; DO ENABLE BEGIN ABORTED => BEGIN NotifyState[starting]; IF serverStream # NIL THEN BEGIN WriteCRStringHost["Closing connection to "L]; WriteChar['.]; END; LOOP; END; PupStream.StreamClosing => BEGIN NotifyState[starting]; IF serverStream # NIL THEN BEGIN WriteCRStringHost["Connection closed by "L]; FinishStringWithErrorMsg[text]; END; keyStream.reset[keyStream]; LOOP; END; END; IF serverStream # NIL THEN BEGIN serverStream.delete[serverStream]; serverStream _ NIL; END; DO WriteString[" C(onnect to), L(ogin to), or Q(uit)? "L]; char _ InlineDefs.BITOR[40B, ReadChar[]]; WriteChar[char]; SELECT char FROM 'c => WriteHostPrompt["Connect"L]; 'l => WriteHostPrompt["Login"L]; 'q => {WriteChar[CR]; WriteChar[CR]}; ENDCASE => LOOP; EXIT; ENDLOOP; IF char = 'q THEN EXIT; ReadID[serverName ! Rubout => BEGIN WriteString[" ... XXX"L]; LOOP; END; LineOverflow => BEGIN WriteString[" ... name too long!"L]; keyStream.reset[keyStream]; LOOP; END ]; NotifyState[running]; WriteString[" ... "L]; addr.socket _ PupTypes.telnetSoc; -- default value PupStream.GetPupAddress[@addr, serverName ! PupStream.PupNameTrouble => BEGIN NotifyState[starting]; WriteString["Can't find host name"L]; FinishStringWithErrorMsg[e]; keyStream.reset[keyStream]; LOOP; END]; serverStream _ PupStream.PupByteStreamCreate [addr, PupDefs.veryLongWait ! PupStream.StreamClosing => BEGIN NotifyState[starting]; WriteString["Can't connect to host"L]; FinishStringWithErrorMsg[text]; keyStream.reset[keyStream]; LOOP; END]; Stream.SetInputOptions [serverStream, Stream.InputOptions[TRUE,FALSE,FALSE,FALSE,FALSE]]; WriteLine["open."L]; AcceptFromServer[char = 'l, serverStream]; ENDLOOP; NotifyState[quitTyped]; RETURN; END; State: TYPE = {starting, running, quitTyped}; serverToUserState: State _ starting; NotifyState: ENTRY PROCEDURE [s: State] = BEGIN IF s = running AND serverToUserState # running THEN StreamDefs.ResetControlDEL[]; serverToUserState _ s; NOTIFY pause; END; WaitForQuit: ENTRY PROCEDURE = BEGIN UNTIL serverToUserState = quitTyped DO IF StreamDefs.ControlDELtyped[] AND serverToUserState = running THEN BEGIN StreamDefs.ResetControlDEL[]; ProcessDefs.Abort[serverToUser]; END; WAIT pause; ENDLOOP; END; -- main program for chat pause: CONDITION; serverToUser: PROCESS; ProcessDefs.SetTimeout[@pause, ProcessDefs.MsecToTicks[250]]; serverToUser _ FORK ServerToUser[]; WaitForQuit[]; JOIN serverToUser; END.