FingerCmd.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by: Donahue, June 20, 1986 9:56:06 am PDT
Kornfeld, July 19, 1985 5:06:20 pm PDT
Gifford, July 22, 1985 8:54:35 am PDT
Ewan Tempero August 28, 1986 1:56:50 pm PDT
Carl Hauser, March 16, 1987 10:06:16 pm PST
DIRECTORY
BasicTime USING [GMT, Now],
Commander USING [CommandProc, Handle, Register],
Convert USING [RopeFromCard],
FingerOps,
IO,
RemoteFingerOpsRpcControl,
Rope,
SymTab USING [Create, Store, Ref];
FingerCmd: CEDAR MONITOR
IMPORTS
BasicTime, Commander, Convert, FingerOps, IO, RemoteFingerOpsRpcControl, Rope, SymTab =
BEGIN
fingerErrorCode: FingerOps.Reason;
SetifyList: PROC [list: LIST OF Rope.ROPE] RETURNS [LIST OF Rope.ROPE]
Removes duplicate entries of list ( ie makes it a "set" ). Does so by entering everything into a symbol table. If it isn't already in the symbol table then add it to the list, otherwise forget it.
~ {
table: SymTab.Ref ← SymTab.Create[];
newList: LIST OF Rope.ROPENIL;
FOR ropeList: LIST OF Rope.ROPE ← list, ropeList.rest UNTIL ropeList = NIL DO
IF SymTab.Store[table, ropeList.first, NIL] THEN newList ← CONS[ropeList.first, newList]
ENDLOOP;
RETURN[newList]
}; -- SetifyList
PerformFingerAtExec: ENTRY Commander.CommandProc =
BEGIN
The nothingToDo flag is used to determine if someone tried to do a finger on nothing. However the way this thing works is it blasts along the command line and exits when IO.EndOfStream is raised and you can't tell if there was anything there or not! Hence the extra scoping level and nothingToDo. (hack hack hack... )
nothingToDo:BOOLEAN ← TRUE;
BEGIN
ENABLE
BEGIN
IO.EndOfStream => { IF nothingToDo THEN IO.Put[cmd.out, IO.rope["Usage: Finger usernamePattern-list\n"]]; CONTINUE };
FingerOps.FingerError => {
fingerErrorCode ← reason; GOTO FingerProblem };
END;
Break: IO.BreakProc =
BEGIN
RETURN[IF char IN [IO.NUL..IO.SP] THEN sepr ELSE other]
END;
stream: IO.STREAMIO.RIS[cmd.commandLine];
WHILE TRUE DO -- stop when command line is exhausted and IO.EndOfStream is raised
userNamePattern: Rope.ROPEIO.GetTokenRope[stream, Break].token;
fingerResult: LIST OF Rope.ROPE ← FingerOps.GetMatchingPersons[pattern: userNamePattern];
matches: CARDINAL ← 0;
nothingToDo ← FALSE;
FOR list: LIST OF Rope.ROPE ← fingerResult, list.rest WHILE list # NIL DO
matches ← matches + 1
ENDLOOP;
SELECT matches FROM
0 => IO.PutRope[cmd.out, Rope.Cat["\nThere were no matches on the pattern \"", userNamePattern, "\".\n"]];
1 => IO.PutRope[cmd.out, Rope.Cat["\nThere was 1 match on the pattern \"", userNamePattern, "\":\n"]];
ENDCASE => IO.PutRope[cmd.out, Rope.Cat["\nThere were ", Convert.RopeFromCard[matches], " matches on the pattern \"", userNamePattern, "\":\n"]];
UNTIL fingerResult = NIL DO
propList: LIST OF FingerOps.PropPair = FingerOps.GetUserProps[fingerResult.first];
output results
IO.PutRope[cmd.out, Rope.Cat["\n\"", fingerResult.first, "\""]];
FOR p: LIST OF FingerOps.PropPair ← propList, p.rest UNTIL p = NIL DO
IO.Put[cmd.out, IO.rope["\n "], IO.atom[p.first.prop]];
IO.Put[cmd.out, IO.rope[": "], IO.rope[p.first.val]]
ENDLOOP;
fingerResult ← fingerResult.rest;
IO.PutRope[cmd.out, "\n"]
ENDLOOP;
ENDLOOP;
EXITS FingerProblem => {
IO.PutRope[cmd.out,
SELECT fingerErrorCode FROM
Aborted => "\n... Transaction Aborted; Retry Finger Operation",
Error => "\n... Internal Finger Error; Contact Implementor",
Failure => "\n... Connection with server broken; try again later",
ENDCASE => NIL ] };
END
END;
GetActiveUsers: ENTRY Commander.CommandProc = {
ENABLE FingerOps.FingerError => { fingerErrorCode ← reason; GOTO FingerProblem };
users: LIST OF Rope.ROPE = SetifyList[FingerOps.CurrentUsers[]];
now: BasicTime.GMT = BasicTime.Now[];
IO.PutF[cmd.out, "Login TTY When\n"];
IF users = NIL THEN RETURN;
FOR u: LIST OF Rope.ROPE ← users, u.rest UNTIL u = NIL DO
machines: LIST OF Rope.ROPE = FingerOps.GetUserData[u.first];
FOR m: LIST OF Rope.ROPE ← machines, m.rest UNTIL m = NIL DO
lastChange: FingerOps.StateChange;
time: BasicTime.GMT;
[lastChange ~ lastChange, time ~ time ] ← FingerOps.GetMachineData[m.first];
IO.PutF[cmd.out, "%-20g %-20g %g\n", IO.rope[u.first], IO.rope[m.first], IO.time[time]];
ENDLOOP;
ENDLOOP;
EXITS FingerProblem => {
IO.PutRope[cmd.out,
SELECT fingerErrorCode FROM
Aborted => "\n... Transaction Aborted; Retry Finger Operation",
Error => "\n... Internal Finger Error; Contact Implementor",
Failure => "\n... Connection with server broken; try again later",
ENDCASE => NIL ] };
};
FindUser: ENTRY Commander.CommandProc = {
ENABLE {
FingerOps.FingerError => { fingerErrorCode ← reason; GOTO FingerProblem };
IO.EndOfStream => { IO.Put[cmd.out, IO.rope["Usage: WhereIs username\n"]]; CONTINUE }
};
who: Rope.ROPE = IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc].token;
users: LIST OF Rope.ROPE = FingerOps.CurrentUsers[];
FOR u: LIST OF Rope.ROPE ← users, u.rest UNTIL u = NIL DO
IF Rope.Equal[u.first, who, FALSE] THEN {
machines: LIST OF Rope.ROPE = FingerOps.GetUserData[u.first];
FOR m: LIST OF Rope.ROPE ← machines, m.rest UNTIL m = NIL DO
lastChange: FingerOps.StateChange;
time: BasicTime.GMT;
[lastChange ~ lastChange, time ~ time ] ← FingerOps.GetMachineData[m.first];
IF lastChange = logout THEN LOOP;
IO.Put[cmd.out, IO.rope[u.first]];
IO.Put[cmd.out, IO.rope[" on machine: "], IO.rope[m.first]];
IO.Put[cmd.out, IO.rope[" \n logged in at: "], IO.time[time], IO.rope["\n"]]
ENDLOOP;
RETURN }
ENDLOOP;
IO.Put[cmd.out, IO.rope["\n"], IO.rope[who], IO.rope[" is not logged in on any machine\n"]];
EXITS FingerProblem => {
IO.PutRope[cmd.out,
SELECT fingerErrorCode FROM
Aborted => "\n... Transaction Aborted; Retry Finger Operation",
Error => "\n... Internal Finger Error; Contact Implementor",
Failure => "\n... Connection with server broken; try again later",
ENDCASE => NIL ] };
};
FindMachine: ENTRY Commander.CommandProc = {
ENABLE {
FingerOps.FingerError => { fingerErrorCode ← reason; GOTO FingerProblem };
IO.EndOfStream => { IO.Put[cmd.out, IO.rope["Usage: Host machinename\n"]]; CONTINUE }
};
machine: Rope.ROPE = IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc].token;
data: LIST OF FingerOps.PropPair ← FingerOps.GetMachineProps[machine];
IO.Put[cmd.out, IO.rope[machine]];
FOR lp: LIST OF FingerOps.PropPair ← data, lp.rest UNTIL lp = NIL DO
p: FingerOps.PropPair ← lp.first;
IF p.prop = $Owner THEN IO.Put[cmd.out, IO.rope[" Owner: "], IO.rope[p.val]];
IF p.prop = $Location THEN IO.Put[cmd.out, IO.rope[" Location: "], IO.rope[p.val]];
IF p.prop = $Gateway AND Rope.Equal[p.val, "TRUE"] THEN
IO.PutF[cmd.out, " GATEWAY"];
IF p.prop = $Network AND Rope.Equal[p.val, "TRUE"] THEN
IO.PutF[cmd.out, " NETWORK"];
ENDLOOP;
IO.Put[cmd.out, IO.rope["\n"]];
EXITS FingerProblem => {
IO.PutRope[cmd.out,
SELECT fingerErrorCode FROM
Aborted => "\n... Transaction Aborted; Retry Finger Operation\n",
Error => "\n... Internal Finger Error; Contact Implementor\n",
Failure => "\n... Connection with server broken; try again later\n",
ENDCASE => NIL ] };
};
FreeMachines: ENTRY Commander.CommandProc = {
ENABLE FingerOps.FingerError => { fingerErrorCode ← reason; GOTO FingerProblem };
machines: LIST OF Rope.ROPE = FingerOps.FreeMachines[];
FOR u: LIST OF Rope.ROPE ← machines, u.rest UNTIL u = NIL DO
time: BasicTime.GMT = FingerOps.GetMachineData[u.first].time;
IO.PutF[cmd.out, "%-20g last used at: %g\n", IO.rope[u.first], IO.time[time]];
ENDLOOP;
IO.Put[cmd.out, IO.rope["\n"]];
EXITS FingerProblem => {
IO.PutRope[cmd.out,
SELECT fingerErrorCode FROM
Aborted => "\n... Transaction Aborted; Retry Finger Operation\n",
Error => "\n... Internal Finger Error; Contact Implementor\n",
Failure => "\n... Connection with server broken; try again later\n",
ENDCASE => NIL ] };
};
FingerServer: ENTRY Commander.CommandProc = {
ENABLE UNWIND => NULL;
action: Rope.ROPE = IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc].token;
SELECT TRUE FROM
Rope.Equal[action, "on", FALSE] => RemoteFingerOpsRpcControl.ExportInterface[interfaceName: [type: "RemoteFingerOps"], user: NIL, password: [0,0,0,0]];
Kludge: if exported with "FingerServer old" the interface type matches the needs of CedarChest6.1 Finger, rather than CedarChest7.0 Cedar.
Rope.Equal[action, "old", FALSE] => RemoteFingerOpsRpcControl.ExportInterface[interfaceName: [type: "RemoteFingerOps~210#207#22632575164"], user: NIL, password: [0,0,0,0]];
Rope.Equal[action, "off", FALSE] => RemoteFingerOpsRpcControl.UnexportInterface[];
ENDCASE => IO.PutRope[cmd.out, "FingerServer on to export the RemoteFingerOps interface, FingerServer off to unexport"];
};
Register commands with the Exec to perform finger and create an instance of the Finger Tool.
Commander.Register[key: "Finger", proc: PerformFingerAtExec, doc: "Perform a finger." ];
Commander.Register[key: "Who", proc: GetActiveUsers, doc: "lists all of the active machines and who's using each one"];
Commander.Register[key: "WhereIs", proc: FindUser, doc: "gives all of the machines currently used by the given user"];
Commander.Register[key: "Host", proc: FindMachine, doc: "provides information on a host"];
Commander.Register[key: "FreeMachines", proc: FreeMachines, doc: "list all of the currently unused Cedar machines"];
Commander.Register[key: "FingerServer", proc: FingerServer, doc: "FingerServer on to export the RemoteFingerOps interface, FingerServer off to unexport"];
END.
Ewan Tempero July 31, 1986 6:03:29 pm PDT
Fixed bug in GetActiveUsers which listed current users on more that one machine more than once.
changes to: DIRECTORY added SymTab. Added SetifyList. GetActiveUsers added call to SetifyList
Ewan Tempero August 13, 1986 4:26:44 pm PDT
Added a usage message to the "Finger" command.