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
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;
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 ...
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;
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.";
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];
IF password = NIL AND useGV THEN {
password ¬ UserCredentials.Get[].password;
};
};
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 ~ "<host> [-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[" <del>\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 ~ {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
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 ~ {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
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 ~ {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
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 ~ {
PROC [sessionName: ROPE, userName: ROPE, class: ATOM] RETURNS [quit: BOOLFALSE]
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 ~ "<host> [ <user> ]\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];
}...