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] ~ { table: SymTab.Ref _ SymTab.Create[]; newList: LIST OF Rope.ROPE _ NIL; 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 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.STREAM _ IO.RIS[cmd.commandLine]; WHILE TRUE DO -- stop when command line is exhausted and IO.EndOfStream is raised userNamePattern: Rope.ROPE _ IO.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]; 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[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"]; }; 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. ζFingerCmd.mesa Copyright c 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, September 13, 1986 3:57:27 pm PDT 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. 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... ) output results Register commands with the Exec to perform finger and create an instance of the Finger Tool. 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. Κ Τ– "cedar" style˜code– "Cedar" style™K– "Cedar" stylešœ Οmœ1™˜@š žœžœžœ'žœžœž˜EKšžœžœžœ˜8Kšžœžœ žœ˜4Kšžœ˜—Kšœ!˜!Kšžœ˜Kšžœ˜——Kšžœ˜šžœ˜šžœ˜Kšžœž˜Kšœ?˜?Kšœ<˜˜>KšœD˜DKšžœžœ˜——Kšœ˜—K˜šŸ œžœ˜-Kšžœ6žœ˜QKšœ žœžœžœ˜7š žœžœžœžœžœžœž˜˜>KšœD˜DKšžœžœ˜——Kšœ˜K˜—šŸ œžœ˜-Kšžœžœžœ˜Kš œ žœžœžœžœžœ˜Nšžœžœž˜Kšœžœ5žœ˜mKšœžœ3˜RKšžœžœk˜x—Kšœ˜—K˜Kšœ\™\KšœX˜XK˜wK˜vK˜ZK˜tK˜šK˜—Kšžœ˜—™)Kšœ  œD™_Kšœ Οr œ €œ€œ™]—™+K™.K™—K™—…—¬.f