DIRECTORY Args, Ascii, BridgeExec, BridgeComm, BridgeDriver, Commander, CommanderOps, Convert, IO, NetworkName, NetworkStream, Process, RefTab, RefText, Rope, SymTab, SystemNames, TypeScript, UserProfile, ViewerIO ; BridgeDriverImpl: CEDAR MONITOR LOCKS h USING h: Handle IMPORTS Ascii, Args, BridgeExec, BridgeComm, Commander, CommanderOps, Convert, IO, NetworkName, NetworkStream, Process, RefTab, RefText, Rope, SymTab, SystemNames, TypeScript, UserProfile, ViewerIO EXPORTS BridgeDriver ~ { NetworkStreamPair: TYPE ~ BridgeExec.NetworkStreamPair; ROPE: TYPE ~ Rope.ROPE; Session: TYPE ~ BridgeExec.Session; STREAM: TYPE ~ IO.STREAM; bridgeWKSRope: ROPE ¬ "3001"; initialTransportClassRope: ROPE ~ Rope.Translate[ base: UserProfile.Token[key: "Bridge.DefaultTransport", default: "ARPA"], translator: Upper]; defaultTransportClass: ATOM ¬ Convert.AtomFromRope[initialTransportClassRope]; defaultInitialPutTimeout: NetworkStream.Milliseconds ¬ 20000; defaultInitialGetTimeout: NetworkStream.Milliseconds ¬ 40000; bridgeNetworkStreamTransportClass: ATOM ~ $SPP; Handle: TYPE ~ REF Object; Object: TYPE ~ MONITORED RECORD [ session: Session ¬ NIL, listener: NetworkStream.Listener ¬ NIL, mgrStreams: NetworkStreamPair ¬ [NIL, NIL], userName: ROPE, passwd: ROPE ]; sessionTab: SymTab.Ref ¬ SymTab.Create[]; transportTab: RefTab.Ref ¬ RefTab.Create[]; Upper: PROC [old: CHAR] RETURNS [new: CHAR] ~ { RETURN [Ascii.Upper[old]]; }; SessionNameFromHostNameEtc: PUBLIC PROC [hostName: ROPE, etc: ROPE] RETURNS [sessionName: ROPE] ~ { RETURN [Rope.Cat[hostName, "(", etc, ")"]]; }; HostNameFromSessionName: PUBLIC PROC [sessionName: ROPE] RETURNS [hostName: ROPE] ~ { pos: INT ¬ Rope.SkipTo[s~sessionName, pos~0, skip~"("]; IF (pos < Rope.Length[sessionName]) AND (pos > 0) THEN { WHILE (pos > 0) AND (Rope.Fetch[sessionName, pos-1] = ' ) DO pos ¬ pos - 1; ENDLOOP; }; RETURN [Rope.Substr[sessionName, 0, pos]] }; CloseConnectionWrapper: PROC [nsp: NetworkStreamPair] ~ { BridgeComm.CloseConnection[nsp, initiate]; }; SessionWorker: NetworkStream.ListenerWorkerProc -- [listener, in, out] -- ~ { h: Handle ~ NARROW[listener.listenerWorkerClientData]; msg: CHAR ¬ 'X; rawArg, cmdName, cookedArg: ROPE; pos: INT; nsp: NetworkStreamPair ¬ [in, out]; [msg, rawArg] ¬ BridgeComm.GetMsg[nsp ! BridgeComm.Error => CONTINUE]; IF msg # 'E THEN GOTO Bad; pos ¬ Rope.SkipTo[s~rawArg, pos~0, skip~argSeparator]; cmdName ¬ Rope.Substr[rawArg, 0, pos]; pos ¬ Rope.SkipOver[s~rawArg, pos~pos, skip~argSeparator]; pos ¬ Rope.SkipOver[s~rawArg, pos~pos, skip~" "]; cookedArg ¬ Rope.Substr[rawArg, pos]; { len: INT ~ Rope.Length[cookedArg]; IF len > 0 AND Rope.Equal[Rope.Substr[cookedArg, len-1, 1], argSeparator] THEN cookedArg ¬ Rope.Substr[cookedArg, 0, len-1]; }; IF BridgeExec.CreateInstance[cmdName, nsp, cookedArg, h.session, CloseConnectionWrapper] = NIL THEN GOTO Bad; EXITS Bad => { IO.Close[in]; IO.Close[out] } }; defaultCmd: ROPE ¬ ""; StartSession: PUBLIC PROC [sessionName: ROPE, nameAndPasswordProc: BridgeDriver.NameAndPasswordProc, cmd: ROPE ¬ NIL, transportClass: ATOM ¬ NIL] RETURNS [excuse: ROPE ¬ NIL] ~ { h: Handle; userName: ROPE; passwd: ROPE; FetchOrCreateHandle: SymTab.UpdateAction -- [found, val] RETURNS [op, new] -- ~ { handles: LIST OF Handle ¬ IF found THEN NARROW[val] ELSE NIL; FOR tail: LIST OF Handle ¬ handles, tail.rest UNTIL tail = NIL DO IF Rope.Equal[tail.first.userName, userName] THEN { h ¬ tail.first; op ¬ none; RETURN; }; ENDLOOP; h ¬ NEW[Object ¬ [userName~userName, passwd~passwd]]; handles ¬ CONS[h, handles]; -- work around compiler bug new ¬ handles; op ¬ store; RETURN; }; StartSessionInner: ENTRY PROC [h: Handle] ~ { ENABLE UNWIND => NULL; IF h.session = NIL THEN { hisName, theRemote, logonMsg, ansArg: ROPE ¬ NIL; ansChar: CHAR; hisName ¬ HostNameFromSessionName[sessionName]; [addr~theRemote] ¬ NetworkName.AddressFromName[transportClass, hisName, bridgeWKSRope, hostAndPort, NIL ! NetworkName.Error => {theRemote ¬ NIL; CONTINUE }]; IF Rope.IsEmpty[theRemote] THEN { excuse ¬ "name lookup failed"; GOTO CantCreate }; [h.mgrStreams.in, h.mgrStreams.out] ¬ NetworkStream.CreateStreams[ protocolFamily~transportClass, remote~theRemote, transportClass~bridgeNetworkStreamTransportClass, timeout~defaultInitialGetTimeout ! NetworkStream.Error => CONTINUE]; IF h.mgrStreams.in = NIL THEN { excuse ¬ "Can't connect"; GOTO CantCreate }; h.session ¬ BridgeExec.CreateSession[sessionName]; h.listener ¬ NetworkStream.CreateListener[ protocolFamily~transportClass, transportClass~bridgeNetworkStreamTransportClass, listenerWorkerProc~SessionWorker, listenerWorkerClientData~h]; logonMsg ¬ Rope.Cat[NetworkStream.GetListenerInfo[h.listener].local, " ", userName, " ", passwd]; { ENABLE NetworkStream.Error, IO.Error => { excuse ¬ "I/O error sending logon: "; GOTO CantCreate }; IO.PutRope[h.mgrStreams.out, logonMsg]; NetworkStream.SendEndOfMessage[h.mgrStreams.out]; }; [ansChar, ansArg] ¬ BridgeComm.GetMsg[h.mgrStreams ! BridgeComm.Error => { excuse ¬ Rope.Concat["I/O error reading logon response: ", msg]; GOTO CantCreate; } ]; excuse ¬ SELECT ansChar FROM 'Y => NIL, 'N, 'Q => ansArg, ENDCASE => "Protocol error"; IF excuse # NIL THEN GOTO CantCreate; EXITS CantCreate => { KillSessionInternal[h, sessionName]; RETURN } }; IF BridgeExec.SessionIsDead[h.session] THEN { excuse ¬ "Session is dead"; RETURN }; BridgeComm.PutMsgWithAck[h.mgrStreams, 'E, (IF Rope.IsEmpty[cmd] THEN defaultCmd ELSE cmd) ! BridgeComm.Error => { excuse ¬ "Can't send cmd"; CONTINUE }]; }; IF nameAndPasswordProc # NIL THEN [userName, passwd] ¬ nameAndPasswordProc[] ELSE [userName, passwd] ¬ GetCurrentCredentials[ HostNameFromSessionName[sessionName], TRUE ]; IF Rope.IsEmpty[userName] THEN RETURN["missing user name"]; IF transportClass = NIL THEN transportClass ¬ defaultTransportClass; SymTab.Update[sessionTab, sessionName, FetchOrCreateHandle]; -- h ¬ handle IF excuse # NIL THEN RETURN; StartSessionInner[h]; }; KillSessionInternal: INTERNAL PROC [h: Handle, sessionName: ROPE] ~ { DoDelete: SymTab.UpdateAction -- [found, val] RETURNS [op, new] -- ~ { newHandles: LIST OF Handle ¬ NIL; IF NOT found THEN RETURN [none, NIL]; FOR handles: LIST OF Handle ¬ NARROW[val], handles.rest UNTIL handles = NIL DO IF handles.first # h THEN newHandles ¬ CONS[handles.first, newHandles]; ENDLOOP; IF newHandles # NIL THEN RETURN [store, newHandles] ELSE RETURN [delete, NIL]; }; SymTab.Update[sessionTab, sessionName, DoDelete]; IF h.session # NIL THEN { BridgeExec.DestroySession[h.session]; h.session ¬ NIL; }; IF h.listener # NIL THEN { NetworkStream.DestroyListener[h.listener]; h.listener ¬ NIL; }; IF h.mgrStreams # [NIL, NIL] THEN { NetworkStream.SetTimeout[h.mgrStreams.in, 7500, FALSE ! NetworkStream.Error => CONTINUE]; NetworkStream.SetTimeout[h.mgrStreams.out, 7500, FALSE ! NetworkStream.Error => CONTINUE]; BridgeComm.PutMsg[h.mgrStreams, 'Q, "" ! BridgeComm.Error => CONTINUE]; BridgeComm.CloseConnection[h.mgrStreams]; h.mgrStreams ¬ [NIL, NIL]; } }; EntryKillSession: ENTRY PROC [h: Handle, sessionName: ROPE] ~ { ENABLE UNWIND => NULL; KillSessionInternal[h, sessionName]; }; KillSession: PUBLIC PROC [sessionName: ROPE, userName: ROPE ¬ NIL] RETURNS [excuse: ROPE] ~ { handles: LIST OF Handle; h: Handle; excuse ¬ "No session with that name."; DO handles ¬ NARROW[SymTab.Fetch[sessionTab, sessionName].val]; WHILE handles # NIL DO IF (h ¬ handles.first) = NIL THEN ERROR; IF userName = NIL OR Rope.Equal[userName, h.userName] THEN EXIT; handles ¬ handles.rest; ENDLOOP; IF handles = NIL THEN EXIT; excuse ¬ NIL; EntryKillSession[h, sessionName]; ENDLOOP; }; EnumerateSessions: PUBLIC PROC [procToApply: BridgeDriver.EachSession] ~ { EachSession: SymTab.EachPairAction -- [key, val] RETURNS [quit] -- ~ { FOR handles: LIST OF Handle ¬ NARROW[val], handles.rest UNTIL handles = NIL DO h: Handle ~ handles.first; listener: NetworkStream.Listener ~ h.listener; class: ATOM ¬ IF listener # NIL THEN NetworkStream.GetListenerInfo[listener].protocolFamily ELSE $NONE; IF procToApply[sessionName: key, userName: h.userName, class: class] THEN RETURN[quit: TRUE]; ENDLOOP; }; [] ¬ SymTab.Pairs[sessionTab, EachSession]; }; UpdateDefaultTransportClass: PUBLIC PROC [newClass: ATOM ¬ NIL] RETURNS [oldClass: ATOM] ~ { oldClass ¬ defaultTransportClass; IF newClass # NIL THEN defaultTransportClass ¬ newClass; }; secondsBetweenKeepalives: INT ¬ 300; Daemon: PROC ~ { EachSessionInner: ENTRY PROC [h: Handle] ~ { ENABLE UNWIND => NULL; IF h.mgrStreams # [NIL, NIL] THEN BridgeComm.PutMsgWithAck[h.mgrStreams, 'Z, Convert.RopeFromCard[2*secondsBetweenKeepalives] ! BridgeComm.Error => CONTINUE]; }; EachSession: SymTab.EachPairAction ~ { FOR handles: LIST OF Handle ¬ NARROW[val], handles.rest UNTIL handles = NIL DO EachSessionInner[handles.first]; ENDLOOP; }; DO Process.PauseMsec[INT[1000]*secondsBetweenKeepalives]; [] ¬ SymTab.Pairs[sessionTab, EachSession]; ENDLOOP; }; FixUserNameForUnix: PUBLIC PROC [name: ROPE] RETURNS [fixedName: ROPE] ~ { len: INT ~ MIN [8, Rope.Length[name], name.Index[pos1: 0, s2: "."]]; text: REF TEXT ~ RefText.ObtainScratch[len]; FOR i: INT IN [0..len) DO text[i] ¬ name.Fetch[i]; ENDLOOP; text.length ¬ len; fixedName ¬ Rope.FromRefText[text]; RefText.ReleaseScratch[text]; }; argSeparator: ROPE ~ "\r"; CmdFromRopes: PROC [r1, r2, r3, r4, r5: ROPE ¬ NIL] RETURNS [cmd: ROPE] ~ { list: LIST OF ROPE ¬ NIL; IF r5 # NIL THEN list ¬ CONS[r5, list]; IF r4 # NIL THEN list ¬ CONS[r4, list]; IF r3 # NIL THEN list ¬ CONS[r3, list]; IF r2 # NIL THEN list ¬ CONS[r2, list]; IF r1 # NIL THEN list ¬ CONS[r1, list]; RETURN [CmdFromListOfRope[list]]; }; CmdFromListOfRope: PUBLIC PROC [list: LIST OF ROPE] RETURNS [cmd: ROPE ¬ NIL] ~ { FOR each: LIST OF ROPE ¬ list, each.rest WHILE each # NIL DO IF cmd = NIL THEN cmd ¬ each.first ELSE cmd ¬ Rope.Cat[cmd, argSeparator, each.first]; ENDLOOP; }; ListOfRopeFromCmd: PUBLIC PROC [cmd: ROPE] RETURNS [list: LIST OF ROPE ¬ NIL] ~ { separatorIndex: INT; temp: ROPE ¬ cmd; len: INT ¬ Rope.Length[cmd]; IF len > 0 THEN { IF Rope.EqualSubstrs[s1~temp, start1~len-1, len1~1, s2~argSeparator] THEN { temp ¬ Rope.Substr[base~temp, len~len-1]; }; }; WHILE (separatorIndex ¬ Rope.FindBackward[temp, argSeparator]) >= 0 DO list ¬ CONS[ Rope.Substr[base~temp, start~separatorIndex+1], list ]; temp ¬ Rope.Substr[base~temp, len~separatorIndex]; ENDLOOP; IF NOT Rope.IsEmpty[temp] THEN list ¬ CONS[ temp, list ]; }; CredsEntry: TYPE ~ REF CredsEntryObject; CredsEntryObject: TYPE ~ RECORD [ name: ROPE, password: ROPE ]; credsTab: SymTab.Ref ¬ SymTab.Create[case~FALSE]; GetCurrentCredentials: PUBLIC PROC [machineName: ROPE, useGV: BOOL] RETURNS [name: ROPE ¬ NIL, password: ROPE ¬ NIL] ~ { credsEntry: CredsEntry; key: ROPE; IF Rope.IsEmpty[machineName] THEN machineName ¬ "*"; WITH SymTab.Fetch[credsTab, machineName].val SELECT FROM it: CredsEntry => {name ¬ it.name; password ¬ it.password}; ENDCASE => WITH SymTab.Fetch[credsTab, "*"].val SELECT FROM it: CredsEntry => {name ¬ it.name; password ¬ it.password}; ENDCASE; IF name = NIL AND useGV THEN { remoteMachine: ROPE ~ HostNameFromSessionName[sessionName~machineName]; userProfileKey: ROPE ~ Rope.Cat["Bridge.", machineName, ".userName"]; name ¬ SystemNames.UserName[]; name ¬ UserProfile.Token[key~userProfileKey, default~name]; }; name ¬ FixUserNameForUnix[name]; }; SetCurrentCredentials: PUBLIC PROC [machineName: ROPE, name: ROPE, password: ROPE] ~ { credsEntry: CredsEntry; key: ROPE; SELECT TRUE FROM Rope.IsEmpty[machineName] => key ¬ "*"; ENDCASE => key ¬ machineName; credsEntry ¬ NEW[CredsEntryObject ¬ [name, password]]; [] ¬ SymTab.Store[credsTab, key, credsEntry]; }; SmashBridgeCredentialsIfUserChanged: UserProfile.ProfileChangedProc ~ { IF reason = newUser THEN credsTab ¬ SymTab.Create[case~FALSE]; }; BridgeStart: ROPE ~ "BridgeStart"; BridgeStartShort: ROPE ~ "Bridge"; BridgeStartDoc: ROPE ~ " [-i]\nStart a Cornell Unix Bridge Session.\n-i => prompt for username and password.\n"; BridgeStartUsage: ROPE ~ Rope.Concat["Usage: BridgeStart ", BridgeStartDoc]; PromptForLine: PROC [ stdin: STREAM, stdout: STREAM, prompt: ROPE, echo: BOOL ¬ TRUE] RETURNS [line: ROPE ¬ NIL] ~ { lookHidden: IO.Value ~ IO.rope["h"]; lookShiftHidden: IO.Value ~ IO.rope["H"]; IO.PutF1[stdout, " %g: ", [rope[prompt]]]; IF NOT echo THEN { IO.PutF1[stdout, "%l", lookHidden]; }; BEGIN ENABLE UNWIND => IF NOT echo THEN stdout.PutF1["%l", lookShiftHidden]; BEGIN ENABLE BEGIN IO.EndOfStream => CONTINUE; IO.Rubout => { IF NOT echo THEN stdout.PutF1["%l", lookShiftHidden]; stdout.PutRope[" \n"]; stdin.Reset[]; CONTINUE; }; END; line ¬ IO.GetLineRope[stdin]; END; IF line = NIL THEN { IF NOT echo THEN stdout.PutF1["%l", lookShiftHidden]; RETURN; }; IF NOT echo THEN { viewer: ViewerIO.Viewer ~ ViewerIO.GetViewerFromStream[stdout]; IO.PutF1[stdout, "%l", lookShiftHidden]; IF TypeScript.IsATypeScript[viewer] THEN { TypeScript.BackSpace[viewer, line.Length[] + 1]; IO.PutRope[stdout, "****\n"]; stdin.Reset[]; }; }; END; }; DoBridgeStart: Commander.CommandProc ~ { sessionName, iFlag: Args.Arg; bridgeCmd, name, password: ROPE; SupplyNameAndPassword: BridgeDriver.NameAndPasswordProc -- RETURNS [userName, passwd] -- ~ { RETURN [name, password]; }; IF Args.NArgs[cmd] = 0 THEN RETURN [$Failure, BridgeStartUsage]; [sessionName, iFlag] ¬ Args.ArgsGet[cmd: cmd, format: "%s-i%b", caseSensitive: FALSE ! Args.Error => {msg ¬ reason; CONTINUE}]; IF msg # NIL THEN RETURN [result~$Failure, msg~msg]; IF NOT iFlag.bool THEN { [name, password] ¬ GetCurrentCredentials[sessionName.rope, TRUE]; }; IF Rope.IsEmpty[name] THEN { name ¬ PromptForLine[stdin~cmd.in, stdout~cmd.out, prompt~"user name", echo~TRUE]; password ¬ NIL; }; name ¬ FixUserNameForUnix[name]; IF Rope.IsEmpty[password] THEN { password ¬ PromptForLine[stdin~cmd.in, stdout~cmd.out, prompt~"password", echo~FALSE]; }; bridgeCmd ¬ CmdFromListOfRope[LIST["RTTY", "LoginSh"]]; msg ¬ StartSession[sessionName.rope, SupplyNameAndPassword, bridgeCmd, NIL]; IF msg # NIL THEN RETURN[result~$Failure, msg~msg]; }; BridgeChangeTransport: ROPE ~ "BridgeChangeTransport"; BridgeChangeTransportDoc: ROPE ~ "\nChange the transport used by bridge."; BridgeChangeTransportUsage: ROPE ~ Rope.Concat["Usage: BridgeChangeTransport [XNS|TCP]", BridgeChangeTransportDoc]; TransportIsRegistered: PROC [desiredFamily: ATOM] RETURNS [isRegistered: BOOL ¬ FALSE] ~ { EachClass: NetworkStream.EnumerateCallbackProc -- [protocolFamily, transportClass] RETURNS [continue] -- ~ { IF transportClass # bridgeNetworkStreamTransportClass THEN ERROR; IF protocolFamily = desiredFamily THEN { isRegistered ¬ TRUE; continue ¬ FALSE; } ELSE { continue ¬ TRUE; } }; NetworkStream.Enumerate[families~NIL, classes~bridgeNetworkStreamTransportClass, proc~EachClass]; }; DoBridgeChangeTransport: Commander.CommandProc ~ { transportClassArg: Args.Arg; oldTransportClass, newTransportClass: ATOM; IF Args.NArgs[cmd] # 1 THEN RETURN[$Failure, BridgeChangeTransportUsage]; [transportClassArg] ¬ Args.ArgsGet[cmd~cmd, format~"%s", caseSensitive~FALSE ! Args.Error => {result ¬ $Failure; msg ¬ reason; GOTO Out }]; newTransportClass ¬ Convert.AtomFromRope[transportClassArg.rope]; IF NOT TransportIsRegistered[newTransportClass] THEN { result ¬ $Failure; msg ¬ "Transport not registered"; GOTO Out }; oldTransportClass ¬ UpdateDefaultTransportClass[newTransportClass]; msg ¬ Rope.Concat["transport was ", Convert.RopeFromAtom[oldTransportClass]]; EXITS Out => NULL; }; BridgeCredentials: ROPE ~ "BridgeCredentials"; BridgeCredentialsDoc: ROPE ~ "\n[name, [machine]] Supply explicit Bridge credentials for machine"; BridgeCredentialsUsage: ROPE ~ Rope.Concat["Usage: BridgeCredentials ", BridgeCredentialsDoc]; DoBridgeCredentials: Commander.CommandProc ~ { argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd ! CommanderOps.Failed => {msg ¬ errorMsg; GO TO oops}]; argc: NAT ¬ argv.argc; name: ROPE ¬ IF argc > 1 THEN argv[1] ELSE NIL; machine: ROPE ¬ IF argc > 2 THEN argv[2] ELSE NIL; password: ROPE ¬ NIL; IF argc > 3 THEN GO TO usage; IF Rope.IsEmpty[name] THEN { name ¬ PromptForLine[stdin~cmd.in, stdout~cmd.out, prompt~"name", echo~TRUE]; }; IF Rope.IsEmpty[password] THEN { password ¬ PromptForLine[stdin~cmd.in, stdout~cmd.out, prompt~"password", echo~FALSE]; }; IF Rope.IsEmpty[machine] THEN machine ¬ "*"; SetCurrentCredentials[machine, name, password]; msg ¬ Rope.Cat["Credentials set for Bridge sessions to ", machine, ".\n"]; EXITS usage => msg ¬ BridgeCredentialsUsage; oops => result ¬ $Failure; }; BridgePrintTransport: ROPE ~ "BridgePrintTransport"; BridgePrintTransportDoc: ROPE ~ "\nPrint the default transport currently being used by bridge."; BridgePrintTransportUsage: ROPE ~ Rope.Concat["Usage: BridgePrintTransport", BridgePrintTransportDoc]; DoBridgePrintTransport: Commander.CommandProc ~ { IF Args.NArgs[cmd] # 0 THEN RETURN[$Failure, BridgePrintTransportUsage]; msg ¬ Rope.Concat["Transport is ", Convert.RopeFromAtom[defaultTransportClass]]; RETURN[result: result, msg: msg]; }; BridgeList: ROPE ~ "BridgeList"; BridgeListDoc: ROPE ~ "\nList active Bridge sessions."; BridgeListUsage: ROPE ~ Rope.Concat["Usage: BridgeList ", BridgeListDoc]; DoBridgeList: Commander.CommandProc ~ { PrintSession: BridgeDriver.EachSession ~ { IO.PutF[cmd.out, "%g on %g (%g)\n", [rope[userName]], [rope[sessionName]], [atom[class]]] }; IF Args.NArgs[cmd] # 0 THEN RETURN[$Failure, BridgeListUsage]; EnumerateSessions[PrintSession]; }; BridgeKill: ROPE ~ "BridgeKill"; BridgeKillDoc: ROPE ~ " [ ]\nKill a Bridge session."; BridgeKillUsage: ROPE ~ Rope.Concat["Usage: BridgeKill ", BridgeKillDoc]; DoBridgeKill: Commander.CommandProc ~ { sessionName, userName: Args.Arg; excuse: ROPE; [sessionName, userName] ¬ Args.ArgsGet[cmd, "%s[s" ! Args.Error => {msg ¬ reason; CONTINUE}]; IF msg # NIL THEN RETURN[$Failure, BridgeKillUsage]; excuse ¬ KillSession[sessionName.rope, IF userName.ok THEN userName.rope ELSE NIL]; IF excuse # NIL THEN RETURN[$Failure, excuse]; }; TRUSTED { Process.Detach[FORK Daemon[]] }; UserProfile.CallWhenProfileChanges[SmashBridgeCredentialsIfUserChanged]; Commander.Register[ key: BridgeChangeTransport, proc: DoBridgeChangeTransport, doc: BridgeChangeTransportDoc]; Commander.Register[ key: BridgePrintTransport, proc: DoBridgePrintTransport, doc: BridgePrintTransportDoc]; Commander.Register[ key: BridgeList, proc: DoBridgeList, doc: BridgeListDoc]; Commander.Register[ key: BridgeKill, proc: DoBridgeKill, doc: BridgeKillDoc]; Commander.Register[ key: BridgeStart, proc: DoBridgeStart, doc: BridgeStartDoc]; Commander.Register[ key: BridgeStartShort, proc: DoBridgeStart, doc: BridgeStartDoc]; Commander.Register[ key: BridgeCredentials, proc: DoBridgeCredentials, doc: BridgeCredentialsDoc]; }... ά BridgeDriverImpl.mesa Copyright Σ 1991, 1992 by Xerox Corporation. All rights reserved. Demers, May 15, 1990 8:37 am PDT Christian Le Cocq September 29, 1987 4:58:16 pm PDT Eduardo Pelegri-Llopart April 4, 1989 5:10:40 pm PDT Peter B. Kessler February 22, 1988 3:49:50 pm PST Last changed by Pavel on September 20, 1989 5:16:40 pm PDT Willie-s, January 29, 1992 6:26 pm PST Foote, August 5, 1991 9:58 am PDT Note: Bridge and NetworkStream disagree about the meaning of "transport class" . For Bridge, "transport class" denotes a protocol family like $XNS, $ARPA, etc. For NetworkStream, "transport class" denotes a kind of stream functionality like $BasicStream or in this case $SPP, while the term "protocol family" is reserved for protocols like $XNS, $ARPA, etc. This is all very confusing ... The following check is commented out because it makes it impossible to use commands like RCopy, that don't accept a password, on hosts whose password is different from the one that UserCredentials knows about. This was considered a worse bug than the fact that a user can now use connections made by other users even without knowing the correct password. Of course, since a malicious user could just invoke the interpreter to read the sessionTab, it was never a very secure stance in the first place. IF NOT Rope.Equal[tail.first.passwd, passwd] THEN excuse _ "Incorrect password given."; IF password = NIL AND useGV THEN { password ¬ UserCredentials.Get[].password; }; PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] PROC [sessionName: ROPE, userName: ROPE, class: ATOM] RETURNS [quit: BOOL _ FALSE] Κx•NewlineDelimiter –(cedarcode) style™™Jšœ Οeœ7™BIcode™ K™3K™4K™1K™:K™&K™!K˜—šΟk ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ K˜ Kšœ˜Kšžœ˜K˜ K˜Kšœ˜Kšœ˜K˜Kšœ˜Kšœ˜K˜ K˜ Kšœ ˜ K˜K˜K˜—šΟnœžœž˜Kšžœžœ ˜KšžœHžœt˜ΕKšžœ ˜Kšœ˜K˜Kšœžœ ˜7Kšžœžœžœ˜Kšœ žœ˜#Kšžœžœžœžœ˜K˜K™‡K˜Kšœžœ ˜Kšœžœp˜Kšœžœžœ1˜OK˜=K˜=K˜Kšœ#žœ˜/K˜Kšœžœžœ˜šœžœž œžœ˜!Kšœžœ˜Kšœ#žœ˜'Kšœ!žœžœ˜+Kšœ žœ˜Kšœž˜ K˜K˜—K˜)K˜+K˜š Ÿœžœžœžœžœ˜/Kšžœ˜K˜K˜—šŸœžœžœ žœžœžœžœ˜cKšžœ%˜+Kšœ˜K˜—š Ÿœžœžœžœžœ žœ˜UKšœžœ/˜7šžœ"žœ žœ˜8šžœ žœ'ž˜žœžœžœžœžœ žœžœ˜²K˜ Kšœ žœ˜Kšœžœ˜ šŸœ $œ˜QKšœ žœžœ žœžœžœžœžœ˜=K˜š žœžœžœžœžœž˜Ašžœ*žœ˜3K˜K™φšžœžœ'ž™1K™%—K˜ Kšžœ˜Kšœ˜—Kšžœ˜—K˜Kšœžœ.˜5Kšœ žœ ˜7K˜K˜ Kšžœ˜K˜K˜—šŸœžœžœ˜-Kšžœžœžœ˜šžœ žœžœ˜Kšœ&žœžœ˜1Kšœ žœ˜K˜/Kšœdžœ%žœžœ˜šžœ˜Kšžœ"žœ˜8—˜ΖKšœžœ˜#—šžœžœžœ˜Kšœžœ˜,—K˜2K˜ΊK˜ašœžœžœ2žœ˜dKšžœ%˜'Kšœ1˜1Kšœ˜—˜2šœ˜K˜@Kšžœ ˜Kšœ˜—Kšœ˜—Kš œ žœ žœžœžœ˜VKšžœ žœžœžœ ˜%šž˜Kšœ5žœ˜=—Kšœ˜—šžœ%žœ˜-Kšœžœ˜%—šœ,žœžœ žœ˜ZKšœ3žœ˜?—K˜—K˜šžœž˜Kšžœ+˜/KšžœSžœ˜^—Kšžœžœžœ˜=Kšžœžœžœ(˜DKšœ= œ ˜JKšžœ žœžœžœ˜Kšœ˜K˜K˜—šŸœžœžœžœ˜EšŸœ $œ˜FKšœ žœžœ žœ˜!K˜š žœžœžœžœžœ˜%K˜—š žœ žœžœ žœžœ žœž˜Nšžœž˜Kšœ žœ˜-—Kšžœ˜—K˜šžœž˜Kšžœžœ˜Kšžœžœ žœ˜—K˜K˜—Kšœ1˜1šžœ žœžœ˜Kšœ%˜%Kšœ žœ˜Kšœ˜—šžœžœžœ˜Kšœ*˜*Kšœ žœ˜Kšœ˜—šžœžœžœžœ˜#Kšœ0žœžœ˜YKšœ1žœžœ˜ZKšœ=žœ˜GKšœ)˜)Kšœžœžœ˜Kšœ˜—K˜—K˜šŸœžœžœžœ˜?Kšžœžœžœ˜K˜$K˜K˜—šŸ œž œžœ žœžœžœ žœ˜]Kšœ žœžœ˜K˜ K˜K˜&šž˜Kšœ žœ,˜<šžœ žœž˜Kšžœžœžœžœ˜(Kš žœ žœžœ"žœžœ˜@K˜Kšžœ˜—Kšžœ žœžœžœ˜Kšœ žœ˜ Kšœ!˜!Kšžœ˜—K˜K˜—šŸœž œ,˜JšŸ œ œ˜Fš žœ žœžœ žœžœ žœž˜NKšœ˜Kšœ žœ ˜.šœžœžœ ž˜Kšžœ7˜;Kšžœ˜ —šžœCž˜IKšžœžœ˜—Kšžœ˜—Kšœ˜—K˜+Kšœ˜K˜K˜—šŸœžœžœ žœžœžœ žœ˜\K˜!Kšžœ žœžœ"˜8K˜K˜—Kšœžœ˜$K˜šŸœžœ˜šŸœžœžœ˜,Kšžœžœžœ˜šžœžœžœžœ\˜}Kšœžœ˜ —K˜—šŸ œ˜&š žœ žœžœ žœžœ žœž˜NKšœ ˜ Kšžœ˜—K˜—K˜šž˜Kšœžœ!˜6K˜+Kšžœ˜—K˜K˜—K˜š Ÿœž œžœžœ žœ˜JK•StartOfExpansion>[s1: ROPE, pos1: INT _ 0, s2: ROPE, case: BOOL _ TRUE]šœžœžœ6˜DKšœžœžœ˜,K˜šžœžœžœ ž˜K˜Kšžœ˜—K˜K˜#Kšœ˜Kšœ˜K˜—Kšœžœ˜K˜š Ÿ œžœžœžœžœžœ˜KKš œžœžœžœžœ˜Kšžœžœžœžœ ˜'Kšžœžœžœžœ ˜'Kšžœžœžœžœ ˜'Kšžœžœžœžœ ˜'Kšžœžœžœžœ ˜'Kšžœ˜!K˜K˜—šŸœžœžœžœžœžœžœžœžœ˜Qš žœžœžœžœžœžœž˜<šžœž˜ Kšžœ˜Kšžœ/˜3—Kšžœ˜—K˜K˜—šŸœžœžœžœžœžœžœžœžœ˜QKšœžœ˜Kšœžœ˜Kšœžœ˜šžœ žœ˜šžœCžœ˜KK˜)K˜—K˜—šžœ?ž˜FKšœžœ9˜DK˜2Kšžœ˜—Kšžœžœžœžœ˜9K˜K˜—Kšœ žœžœ˜(šœžœžœ˜!Kšœžœ˜ Kšœ ž˜K˜K˜—Kšœ*žœ˜1K˜šŸœžœžœžœ žœžœžœžœ žœžœ˜xK˜Kšœžœ˜ Kšžœžœ˜4šžœ)žœž˜8K˜;šžœ˜ šžœ!žœž˜0K˜;Kšžœ˜———šžœžœžœžœ˜Kšœžœ4˜GKšœžœ1˜EK˜K˜;K˜—K˜ šžœ žœžœžœ™"K™*K™—Kšœ˜K˜—š Ÿœžœžœžœžœ žœ˜VKšœ˜Kšœžœ˜ šžœžœž˜K˜'Kšžœ˜—Kšœ žœ&˜6K˜-K˜K˜—šŸ#œ$˜GKšžœžœžœ˜>K˜K˜—KšŸ œžœ˜"KšŸœžœ ˜"KšŸœžœb˜vKšŸœžœ&Ÿœ˜LK˜šŸ œžœ žœ žœ žœ žœžœžœžœžœ˜wKšœ žœ žœ ˜$Kšœžœ žœ ˜)K˜Kšžœ)˜+šžœžœžœ˜Kšžœ!˜#Kšœ˜—š žœžœžœžœžœžœ%˜Lšžœžœž˜Kšžœžœ˜šžœ ˜Kšžœžœžœ%˜5Kšœ˜K˜Kšžœ˜ K˜—Kšžœ˜Kšœžœ˜Kšžœ˜—šžœžœžœ˜Kšžœžœžœ%˜5Kšžœ˜K˜——˜šžœžœžœ˜Kšœ?˜?Kšžœ&˜(šžœ"žœ˜*Kšœ0˜0Kšžœ˜Kšœ˜K˜—Kšœ˜—Kšžœ˜—K˜K˜—K˜šΠbn œ˜(Kšœ˜Kšœžœ˜ šŸœ#  œ˜\Kšžœ˜K˜—Kšžœžœžœ Οbœ˜@šœOž˜TKšœžœ˜*—Kšžœžœžœžœ˜4šžœžœ žœ˜Kšœ;žœ˜AK˜—šžœžœ˜KšœLžœ˜RKšœ žœ˜K˜—K˜ šžœžœ˜ KšœOžœ˜VK˜—Kšœžœ˜7KšœGžœ˜LKšžœžœžœžœ˜3Kšœ˜K˜—K˜K˜KšŸœžœ˜6KšŸœžœ,˜JKšŸœžœ9’œ˜sK˜š Ÿœžœžœžœžœžœ˜ZšŸ œ& œ œ œ˜lKšžœ4žœžœ˜Ašžœ˜!šžœ˜Kšœžœ˜Kšœ žœ˜K˜—šžœ˜Kšœ žœ˜K˜——K˜—Kšœ!žœ=˜aK˜K˜—š‘œ˜2Kš žœžœ žœžœžœžœ™?Kšœ˜Kšœ&žœ˜+Kšžœžœžœ'˜IKšœGžœ3žœ˜‹K˜Ašžœžœ)˜/Kšžœ8žœ˜G—K˜CK˜Mšž˜Kšœžœ˜ —K˜K˜—KšŸœžœ˜.KšŸœžœI˜cKšŸœžœ,Ÿœ˜^K˜šŸœ˜.Kš žœžœ žœžœžœžœ™?˜:Kšœ*žœžœ˜7—Kšœžœ ˜Kš œžœžœ žœ žœžœ˜0Kš œ žœžœ žœ žœžœ˜2Kšœ žœžœ˜Kšžœ žœžœžœ˜šžœžœ˜KšœGžœ˜MK˜—šžœžœ˜ KšœOžœ˜VK˜—Kšžœžœ˜,Kšœ/˜/K˜Jšž˜K˜&K˜—K˜—K˜K˜KšŸœžœ˜4KšŸœžœC˜`KšŸœžœ.Ÿœ˜fK˜š‘œ˜1Kš žœžœ žœžœžœžœ™?Kšžœžœžœ&˜HK˜PKšžœ˜!K˜—K˜K˜KšŸ œžœ˜ Kš’ œžœ$˜7Kš’œžœ%’ œ˜IK˜š‘ œ˜'šŸ œ˜*Kšžœžœ žœ žœžœžœžœ™RKšžœW˜YK˜—Kšžœžœžœ ’œ˜>K˜ K˜K˜—Kš‘Ÿœžœ˜ Kš’ œžœ/˜BKš’œžœ%’ œ˜IK˜š‘ œ˜'Kšœ ˜ Kšœžœ˜ KšœRžœ˜]Kš žœžœžœžœ ’œ˜4Kš œ'žœ žœžœžœ˜SKšžœ žœžœžœ˜.Kšœ˜K˜—Kšžœžœ ˜*KšœH˜Hšœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜—K˜K˜—K˜—…—Ilgΐ