DIRECTORY IO, Process, Protocols, PupDefs, PupStream, PupTypes, Rope, UserCredentials; PupTelnet: CEDAR MONITOR LOCKS pc USING pc: PupConversation IMPORTS IO, Process, Protocols, PupDefs, PupStream, Rope, UserCredentials = {OPEN Protocols; pupTelnet: Protocol _ NEW [ProtocolRep _ [ name: "PupTelnet", Connect: Connect, Disconnect: Disconnect ]]; PupConversation: TYPE = REF PupConversationRep; PupConversationRep: TYPE = MONITORED RECORD [ serverName: ROPE, fromClient, toClient, serverStream: IO.STREAM _ NIL, charsSentSinceFlush: NAT _ 0, procs: ARRAY Who OF PROCESS, procing: ARRAY Who OF BOOL _ ALL[TRUE], looping: ARRAY Who OF BOOL _ ALL[FALSE], open: BOOL _ TRUE]; Who: TYPE = {uToS, sToU}; whoBar: ARRAY Who OF Who _ [uToS: sToU, sToU: uToS]; MarkByte: TYPE = [0..256); setLineWidth: MarkByte = 2; setPageLength: MarkByte = 3; timingMark: MarkByte = 5; timingMarkReply: MarkByte = 6; doSetLineWidth: BOOL _ TRUE; Connect: PROC [ serverName: ROPE, fromClient, toClient: IO.STREAM, noteDisconnect: PROC [clientData: REF ANY] _ NIL, clientData: REF ANY _ NIL, login: BOOL _ FALSE] RETURNS [c: Conversation] = { pc: PupConversation _ NEW [PupConversationRep _ [ serverName: serverName, fromClient: fromClient, toClient: toClient]]; addr: PupDefs.PupAddress; c _ NIL; PupDefs.PupPackageMake[]; toClient.PutF["Opening connection to %g ... ", IO.rope[serverName]]; addr _ PupStream.GetPupAddress[PupTypes.telnetSoc, serverName ! PupStream.PupNameTrouble => { toClient.PutRope["PUP name error"]; FinishStringWithErrorMsg[toClient, e]; GOTO Return; } ]; pc.serverStream _ PupStream.PupByteStreamCreate[addr, PupStream.SecondsToTocks[1] ! PupStream.StreamClosing => { toClient.PutRope["Can't connect"]; FinishStringWithErrorMsg[toClient, text]; GOTO Return; } ]; toClient.PutF["open.\015\012"]; c _ NEW [ConversationRep _ [ protocol: pupTelnet, noteDisconnect: noteDisconnect, clientData: clientData, data: pc]]; IF doSetLineWidth THEN { PupStream.SendMark[pc.serverStream, setLineWidth]; pc.serverStream.PutChar[0C]; pc.serverStream.Flush[]; }; IF login THEN { name, password: Rope.ROPE; [name: name, password: password] _ UserCredentials.Get[]; pc.serverStream.PutRope["Login "]; pc.serverStream.PutRope[name]; IF Rope.Find[s1: name, s2: "."] = -1 THEN pc.serverStream.PutRope[".PA"]; pc.serverStream.PutRope[" "]; pc.serverStream.PutRope[password]; pc.serverStream.PutRope[" \n"]; pc.serverStream.Flush[]; }; TRUSTED { Process.Detach[pc.procs[uToS] _ FORK UserToServer[c, pc]]; Process.Detach[pc.procs[sToU] _ FORK ServerToUser[c, pc]]; }; EXITS Return => NULL; }; Disconnect: PROC [c: Conversation] = { pc: PupConversation _ NARROW[c.data]; IF pc.open THEN CloseConnection[pc, TRUE]}; flushPeriod: NAT _ 50; UserToServer: PROC [c: Conversation, pc: PupConversation] = { char: CHAR; report: BOOL _ TRUE; {ENABLE UNWIND => Exit[c, pc, uToS]; SetLooping[pc, uToS, TRUE]; WHILE pc.open DO ENABLE { PupStream.StreamClosing => { IF pc.open THEN { pc.toClient.PutF["\015\012Connection being closed by %s", IO.rope[pc.serverName]]; FinishStringWithErrorMsg[pc.toClient, text, " ... "]; report _ FALSE; }; EXIT; }; IO.EndOfStream, IO.Error, ABORTED => EXIT; }; char _ pc.fromClient.GetChar[]; IF NOT pc.open THEN { pc.fromClient.Backup[char]; EXIT; }; pc.serverStream.PutChar[char]; IF pc.charsSentSinceFlush >= flushPeriod OR pc.fromClient.CharsAvail[] = 0 THEN { pc.serverStream.Flush[]; pc.charsSentSinceFlush _ 0; } ELSE pc.charsSentSinceFlush _ pc.charsSentSinceFlush + 1; ENDLOOP; SetLooping[pc, uToS, FALSE]; IF pc.open THEN CloseConnection[pc, report]; }; Exit[c, pc, uToS]; }; ServerToUser: PROC [c: Conversation, pc: PupConversation] = { char: CHAR; report: BOOL _ TRUE; {ENABLE UNWIND => Exit[c, pc, sToU]; SetLooping[pc, sToU, TRUE]; WHILE pc.open DO ENABLE { PupStream.StreamClosing => { IF pc.open THEN { pc.toClient.PutF["\015\012Connection being closed by %s", IO.rope[pc.serverName]]; FinishStringWithErrorMsg[pc.toClient, text, " ... "]; report _ FALSE; }; EXIT; }; IO.EndOfStream, IO.Error, ABORTED => EXIT; }; IF pc.serverStream.EndOf[] THEN { mySST: MarkByte; mySST _ PupStream.ConsumeMark[pc.serverStream]; IF mySST = timingMark THEN PupStream.SendMark[pc.serverStream, timingMarkReply]; }; char _ pc.serverStream.GetChar[! PupStream.TimeOut => RESUME; IO.EndOfStream => LOOP; ]; IF NOT pc.open THEN EXIT; pc.toClient.PutChar[char]; ENDLOOP; SetLooping[pc, sToU, FALSE]; IF pc.open THEN CloseConnection[pc, report]; }; Exit[c, pc, sToU]; }; SetLooping: ENTRY PROC [pc: PupConversation, who: Who, ing: BOOL] = {pc.looping[who] _ ing}; Exit: PROC [c: Conversation, pc: PupConversation, who: Who] = { whoElse: Who _ whoBar[who]; LastOneOut: ENTRY PROC [pc: PupConversation] RETURNS [last: BOOL] = { pc.procing[who] _ FALSE; pc.looping[who] _ FALSE; last _ NOT pc.procing[whoElse]; }; IF whoElse = who THEN ERROR; IF NOT LastOneOut[pc] THEN RETURN; pc.toClient.PutRope[" ... closed\015\012" !IO.Error => CONTINUE]; IF c.noteDisconnect # NIL THEN c.noteDisconnect[c.clientData]; pc.serverStream.Close[!IO.Error => CONTINUE]; pc.serverStream _ NIL; -- could cause pointer faults! PupDefs.PupPackageDestroy[]; }; FinishStringWithErrorMsg: PROC [toClient: IO.STREAM, errorMsg: ROPE, ending: ROPE _ ".\015\012"] = { IF errorMsg # NIL THEN toClient.PutF[":\t%s", IO.rope[errorMsg]]; toClient.PutRope[ending]; }; CloseConnection: PROC [pc: PupConversation, report: BOOL] = { rawSelf: UNSAFE PROCESS; self: PROCESS; AbortEm: ENTRY PROC [pc: PupConversation] = TRUSTED { IF pc.procs[uToS] # self AND pc.looping[uToS] THEN Process.Abort[pc.procs[uToS] !Process.InvalidProcess => CONTINUE]; IF pc.procs[sToU] # self AND pc.looping[sToU] THEN Process.Abort[pc.procs[sToU] !Process.InvalidProcess => CONTINUE]; }; TRUSTED { rawSelf _ Process.GetCurrent[]; self _ LOOPHOLE[rawSelf]}; IF report THEN pc.toClient.PutF["\015\012Closing connection to %s ...", IO.rope[pc.serverName] ! IO.Error => CONTINUE]; pc.open _ FALSE; pc.serverStream.Close[TRUE !IO.Error => CONTINUE]; AbortEm[pc]; }; Protocols.RegProtocol[pupTelnet]; }. PPupTelnet.Mesa Last Edited by: Spreitzer, March 20, 1985 11:42:17 am PST Κ"– "cedar" style˜Icode™K™9K˜KšΟk œœJ˜VK˜šΠbx œœ˜Kšœœ˜"Kšœœ?˜IK˜Kšœœ ˜K˜šœœ˜*K˜Kšœ˜Kšœ˜K˜—K˜Kšœœœ˜/šœœ œœ˜-Kšœ œ˜Kšœ$œœœ˜4Kšœœ˜Kšœœœœ˜Kš œ œœœœœ˜'Kš œ œœœœœ˜(Kšœœœ˜—K˜Kšœœ˜Kšœœœ ˜4K˜Kšœ œ ˜K˜K˜K˜K˜K˜Kšœœœ˜K˜šΟnœ˜ šœ˜Kšœ œ˜Kšœœœ˜ Kš œœœœœ˜1Kšœ œœœ˜Kšœœœ˜—Kšœ˜Kšœ˜šœœ˜1Kšœ˜Kšœ˜Kšœ˜—K˜Kšœœ˜K˜Kšœ/œ˜D˜=˜˜Kšœ#˜#Kšœ&˜&Kšœ˜ —K˜—K˜—˜Q˜˜Kšœ"˜"Kšœ)˜)Kšœ˜ —K˜—K˜—Kšœ˜šœœ˜Kšœ˜Kšœ7˜7Kšœ ˜ —šœœ˜Kšœ3˜3Kšœ˜Kšœ˜K˜—šœœ˜Kšœœ˜J˜9Jšœ"˜"Jšœ˜Jšœ#œ ˜IJšœ˜Jšœ"˜"Jšœ˜Jšœ˜J˜—šœ˜ Kšœ œ˜:Kšœ œ˜:Kšœ˜—š˜Kšœ œ˜—K˜—K˜šŸ œœ˜&Kšœœ ˜%Kšœ œœ˜+—K˜Kšœ œ˜K˜šŸ œœ+˜=Kšœœ˜ šœœœ˜Kšœœœ˜$Kšœœ˜šœ ˜šœ˜šœ˜šœ œ˜Kšœ:œ˜RK˜5Kšœ œ˜K˜—Kšœ˜K˜—Kšœœœœ˜*K˜—K˜šœœ œ˜Kšœ˜Kšœ˜K˜—K˜šœ'œ œ˜QJ˜Jšœ˜J˜—Jšœ5˜9Kšœ˜—Kšœœ˜Kšœ œ˜,K˜—K˜K˜—K˜šŸ œœ+˜=Kšœœ˜ šœœœ˜Kšœœœ˜$Kšœœ˜šœ ˜šœ˜˜šœ œ˜Kšœ:œ˜RK˜5Kšœ œ˜K˜—Kšœ˜J˜—Kšœœœœ˜*J˜—šœœ˜!K˜K˜/Kšœœ6˜PK˜—˜ Jšœœ˜Jšœœ˜Jšœ˜—Jšœœ œœ˜J˜Jšœ˜—Kšœœ˜Kšœ œ˜,K˜—K˜K˜—K˜šŸ œœœ&œ˜CK˜—K˜šŸœœ5˜?K˜š Ÿ œœœœœ˜EKšœœ˜Kšœœ˜Kšœœ˜K˜—Jšœœœ˜Jšœœœœ˜"Jšœ+œ œ˜AJšœœœ ˜>Kšœœ œ˜-JšœœΟc˜5J˜K˜—K˜š Ÿœœ œœ œ œ˜dKšœ œœœ˜AKšœ˜K˜—K˜šŸœœœ˜=Kšœ œœ˜Kšœœ˜šŸœœœœ˜5šœœ˜-Kšœ9œ˜G—šœœ˜-Kšœ9œ˜G—K˜K˜—šœ˜ Kšœ˜Kšœœ ˜—Kš œœ:œœ œ˜wKšœ œ˜Kšœœœ œ˜2Kšœ ˜ K˜—K˜K˜!K˜K˜——…—ž