-- Laurel subsystem - chat program -- -- chat.mesa -- Mike Schroeder, March 30, 1982 2:33 PM -- Edited by Brotz, January 16, 1981 11:56 AM DIRECTORY ImageDefs, InlineDefs, IODefs, LaurelExecDefs, NameInfoDefs, ProcessDefs, PupDefs, PupStream, PupTypes, Stream, StreamDefs, TimeDefs; Chat: MONITOR IMPORTS ImageDefs, InlineDefs, IODefs, LaurelExecDefs, NameInfoDefs, ProcessDefs, PupStream, Stream, StreamDefs, TimeDefs = BEGIN OPEN IODefs; ServerToUser: PROCEDURE = BEGIN char: CHARACTER; serverName: STRING _ [64]; connect: STRING _ [64]; 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 [c: CHARACTER] = 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 c='l OR c='x THEN BEGIN credential: STRING _ [64]; SendStringToServer["Login "]; LaurelExecDefs.GetUserCredentials[name: credential]; --gets name-- SendStringToServer[credential]; IF c='l THEN BEGIN SendStringToServer["."L]; credential.length _ 0; LaurelExecDefs.GetUserCredentials[registry: credential]; --gets registry-- SendStringToServer[credential] END; 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[c: CHARACTER, serverStream: Stream.Handle] = BEGIN userToServer: PROCESS = FORK UserToServer[c]; 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 WriteChar[CR]; WriteString[" C(onnect to), L(ogin to), or Q(uit)? "L]; char _ InlineDefs.BITOR[40B, ReadChar[]]; SELECT char FROM 'c => WriteHostPrompt["Connect"L]; 'l => WriteHostPrompt["Login"L]; 'x => WriteHostPrompt["Login without registry"L]; 'q => {WriteChar[CR]; WriteChar[CR]}; ENDCASE => {keyStream.reset[keyStream]; LOOP}; EXIT; ENDLOOP; IF char = 'q THEN EXIT; ReadID[serverName ! Rubout => {WriteString[" ... XXX"L]; LOOP}; LineOverflow => {WriteString[" ... name too long!"L]; keyStream.reset[keyStream]; LOOP} ]; NotifyState[running]; WriteString[" ... "L]; connect.length _ 0; FOR i:CARDINAL DECREASING IN [0 .. serverName.length) DO IF serverName[i] = '. THEN GOTO gvName; REPEAT gvName => BEGIN SELECT NameInfoDefs.GetConnect[serverName, connect] FROM individual => BEGIN hashSeen: BOOLEAN _ FALSE; IF connect.length=0 THEN BEGIN NotifyState[starting]; WriteString["No connect site in Grapevine data base."L]; keyStream.reset[keyStream]; LOOP; END; FOR j: CARDINAL IN [0 .. connect.length) DO IF connect[j] = '# THEN {IF hashSeen THEN {connect.length _ j+1; EXIT} ELSE hashSeen _ TRUE}; ENDLOOP; END; group, notFound => BEGIN NotifyState[starting]; WriteString["Invalid RName."L]; keyStream.reset[keyStream]; LOOP; END; allDown => BEGIN NotifyState[starting]; WriteString["Can't find RName: no RServer available."L]; keyStream.reset[keyStream]; LOOP; END; ENDCASE => ERROR; END; ENDLOOP; addr.socket _ PupTypes.telnetSoc; -- default value PupStream.GetPupAddress [@addr, IF connect.length=0 THEN serverName ELSE connect ! PupStream.PupNameTrouble => BEGIN NotifyState[starting]; WriteString["PUP name error"L]; FinishStringWithErrorMsg[e]; keyStream.reset[keyStream]; LOOP END]; serverStream _ PupStream.PupByteStreamCreate [addr, PupDefs.veryLongWait ! PupStream.StreamClosing => BEGIN NotifyState[starting]; WriteString["Can't connect"L]; FinishStringWithErrorMsg[text]; keyStream.reset[keyStream]; LOOP; END]; Stream.SetInputOptions [serverStream, Stream.InputOptions[TRUE,FALSE,FALSE,FALSE,FALSE]]; WriteLine["open."L]; AcceptFromServer[char, 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. e12(635)\f1