// DLSTelnet.bcpl -- Telnet server providing dial-out capability // Last modified October 20, 1983 2:14 PM by Diebert get "DLSDriver.decl" get "Pup.decl" get "DLSControl.decl" external [ // Outgoing procedures DLSSocketNotFound; TelnetRendezvousServer; DialOutTop; SendAbort; GetNumber GenerateLongSpace; TelnetGets; InnerGets; TelnetEndofs; TelnetResets TelnetPuts; SendTelnetProtocol // Incoming procedures HangUp; Echo; Confirm; Error; GetString; LeaveRemoteMode; DialOut; OpenPortForCtx ControlOut; SetDLSLineSpeed; DLSOutput7; DLSResetInput; DLSResetOutput DLSInputIdle; WaitForBitTimes; PrintLogLine ExchangePorts; AppendStringToPup; CompletePup; ReleasePBI; PupError OpenRTPSocket; CreateBSPStream; BSPGetMark; BSPPutMark; BSPForceOutput InitializeContext; Block; Dismiss Enqueue; Dequeue; Unqueue; SetTimer; TimerHasExpired; MultEq Gets; Puts; Endofs; Errors; Wss; PutTemplate MoveBlock; SetBlock; SysErr; ReturnFrom; MyFrame; DialOutBSPError DLSInput; DLSInput7; DLSOutput; ControlIn Login; DialOutDialIn; Free; StatusToLog; CallSwat // Outgoing statics strayPupQ // Incoming statics dlsName; dlsRegistry; dlsAuthorizationList; dlsGVhasnotInit @lbTable; ctxTable; mainCtx; CtxRunning; postedNotice; crlf; ndbQ; sysZone logstream ] manifest [ // Telnet mark types markSync = 1 markLineWidth = 2 markPageLength = 3 markTerminalType = 4 markTiming = 5 markTimingReply = 6 ] structure AuxCtx: // Auxiliary (DialOutLineToNet) context [ blank word 3 // usual Ctx stuff mainCtx word // -> main context for line active word // true if recent activity in net -> line direction ] // --------------------------------------------------------------------------- let GenerateLongSpace(dlb, bitTimes) be // --------------------------------------------------------------------------- [ while dlb>>DLB.outActive do Block() dlsOutBase!(dlb>>DLB.oLCB.line) = 0 // space = EIA high Dismiss((bitTimes*(dlb>>DLB.oLCB.interval+1))/((dlsTicksPerSecond+50)/100)) dlsOutBase!(dlb>>DLB.oLCB.line) = 1 // mark = EIA low ] // --------------------------------------------------------------------------- and TelnetGets(tstr, remoteMode; numargs na) = valof // --------------------------------------------------------------------------- // The Gets procedure for the Telnet stream. It interprets Telnet protocol. // If remoteMode is false or omitted, times out after 2 minutes (at which point // Errors is called), and also forces BSP output periodically. // If remoteMode is true, no timeout or forcing occurs. [ if na ls 2 then remoteMode = false let ctx = tstr>>ST.par1 let soc = lv ctx>>CTX.socket let str = lv soc>>BSPSoc.bspStr let char = InnerGets(str, remoteMode) if char ge 0 resultis char // Encountered a mark. Interpret Telnet protocol. switchon BSPGetMark(soc) into [ case markTiming: // Should really await DLSOutputEmpty, but not easy! [ BSPPutMark(soc, markTimingReply); endcase ] case markLineWidth: case markPageLength: case markTerminalType: // For now, ignore terminal parameters [ InnerGets(str, remoteMode); endcase ] // Just ignore other mark types. // Shouldn't ever receive markTimingReply because we never send markTiming. // Ignore markSync since it isn't typically generated by user Telnet. ] ] repeat // --------------------------------------------------------------------------- and InnerGets(str, remoteMode) = valof // --------------------------------------------------------------------------- // Returns the next byte from BSP stream str, or -1 if a mark is encountered. // remoteMode is as for TelnetGets, except that it is not defaulted. [ if remoteMode resultis Gets(str) let soc = str - offset BSPSoc.bspStr/16 let timer = nil SetTimer(lv timer, 12000) // 2-minute timeout for local mode until TimerHasExpired(lv timer) do [ if soc>>BSPSoc.state ne stateOpen then Errors(str, ecBadStateForGets) unless Endofs(str) resultis Gets(str) if soc>>BSPSoc.markPending resultis -1 // Force Telnet output every 40 ms while we are waiting for input BSPForceOutput(soc) Dismiss(4) ] Errors(str, ecGetsTimeout) ] // --------------------------------------------------------------------------- and TelnetEndofs(tstr) = Endofs(lv tstr>>ST.par1>>CTX.socket.bspStr) // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- and TelnetResets(tstr) be until Endofs(tstr) do Gets(tstr) // --------------------------------------------------------------------------- // Reset Telnet input. // Should really use Telnet timing mark to flush input stream. // --------------------------------------------------------------------------- and TelnetPuts(tstr, char) be Puts(lv tstr>>ST.par1>>CTX.socket.bspStr, char) // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- and SendTelnetProtocol(soc, markByte, argByte) be // --------------------------------------------------------------------------- [ BSPPutMark(soc, markByte) Puts(lv soc>>BSPSoc.bspStr, argByte, 3000) BSPForceOutput(soc) ]