DIRECTORY BasicTime USING [GMT, Now], Booting, FingerLog, FingerOps, FingerSimpleOps, Idle USING [IdleReason, IdleHandler, RegisterIdleHandler], Process USING [Detach], RemoteFingerOps, RemoteFingerOpsRpcControl, Rope USING [ROPE], RPC, RPCLupineExtras, ThisMachine USING [Address, Name], UserCredentials USING [Get], UserProfile; FingerSimpleOpsImpl: CEDAR MONITOR IMPORTS BasicTime, Booting, FingerLog, Idle, Process, RemoteFingerOps, RemoteFingerOpsRpcControl, RPC, ThisMachine, UserCredentials, UserProfile EXPORTS FingerOps, FingerSimpleOps = BEGIN OPEN FingerOps, FingerLog; idle: BOOL _ FALSE; thisMachine: Rope.ROPE _ ThisMachine.Name[$Pup]; serverMachine: Rope.ROPE; stateLog: LIST OF LogEntry _ NIL; bound: BOOL _ FALSE; ImportPlayProc: PROC [host: Rope.ROPE _ NIL] ~ { success: BOOL _ TRUE; RemoteFingerOpsRpcControl.ImportInterface[interfaceName: [instance: IF host = NIL THEN serverMachine ELSE host] ! RPC.ImportFailed => { success _ FALSE; CONTINUE }]; bound _ success; }; PlayLog: INTERNAL PROC[] ~ { IF (stateLog # NIL) THEN { IF NOT bound THEN ImportPlayProc[]; IF bound THEN { ENABLE RPC.CallFailed => {bound _ FALSE; CONTINUE}; IF RemoteFingerOps.PlayLog[stateLog] THEN { stateLog _ NIL; FingerLog.FlushLog[] }; }; }; }; AttemptToPlayLog: PUBLIC ENTRY PROC[] = { ENABLE UNWIND => NULL; PlayLog[] }; RegisterLoginOrLogout: ENTRY Idle.IdleHandler = TRUSTED BEGIN ENABLE UNWIND => NULL; idle _ reason = becomingIdle; InternalPutStateChange[IF idle THEN $logout ELSE $login, BasicTime.Now[]]; Process.Detach[FORK AttemptToPlayLog[]] END; PutStateChange: PUBLIC ENTRY PROC [change: FingerOps.StateChange, time: BasicTime.GMT] ~ { ENABLE UNWIND => NULL; InternalPutStateChange[change, time]; IF NOT idle THEN PlayLog[] }; InternalPutStateChange: INTERNAL PROC [change: FingerOps.StateChange, time: BasicTime.GMT] ~ { name: Rope.ROPE = UserCredentials.Get[].name; DoLog[logEntry: NEW[StateChange LogEntryObject _ [StateChange[event: change, user: name, time: time, machine: thisMachine]]]]; }; DoLog: INTERNAL PROC[ logEntry: LogEntry ] = TRUSTED { FingerLog.Log[ logEntry ]; IF stateLog = NIL THEN stateLog _ LIST[logEntry] ELSE { log: LIST OF LogEntry _ stateLog; WHILE log.rest # NIL DO log _ log.rest ENDLOOP; log.rest _ LIST[logEntry] } }; Log: PUBLIC ENTRY PROC [logEntry: LogEntry] ~ { DoLog[logEntry]; }; ParseLog: INTERNAL PROC[] ~ { stateLog _ FingerLog.ParseLog[] }; GetLogAndLoginUser: ENTRY PROC[] ~ { ENABLE UNWIND => NULL; ParseLog[]; InternalPutStateChange[$login, BasicTime.Now[]]; TRUSTED { Process.Detach[FORK AttemptToPlayLog[]] } }; OpenUp: Booting.RollbackProc = TRUSTED { bound _ FALSE; Process.Detach[FORK GetLogAndLoginUser[]] }; ProfileChanged: UserProfile.ProfileChangedProc = { serverMachine _ UserProfile.Token["Finger.RemoteHost", "Ebbetts"]; }; IF thisMachine = NIL THEN thisMachine _ ThisMachine.Address[$Pup]; IF thisMachine = NIL THEN thisMachine _ "Unknown"; UserProfile.CallWhenProfileChanges[proc: ProfileChanged]; ImportPlayProc[]; Booting.RegisterProcs[r: OpenUp]; GetLogAndLoginUser[]; [] _ Idle.RegisterIdleHandler[handler: RegisterLoginOrLogout] END. ΜFingerSimpleOpsImpl.mesa Carl Hauser, January 9, 1987 11:16:18 am PST is the machine in the idle state; if so, don't bother connecting to the database to save any log entries made (just collect them and replay them when you come out of idle) The name of the machine currently running Finger The name of the machine to look for a Finger server on being careful not to make bound TRUE until it really is true. if this succeeds, then the contents of the log file can be thrown away, since they have all been played to the database record that the current user has logged off of this machine (entries are changed for both the user and the machine) Write the entry on the log file and also on the internal log list Κΰ˜™Icode™,—šΟk ˜ Kšœ œœ˜K˜K˜ Kšœ ˜ K˜Kšœœ0˜:Kšœœ ˜K˜K˜Kšœœœ˜K˜Kšœ˜Kšœ œ˜"Kšœœ˜Kšœ ˜ K˜—KšΟnœœ˜"˜š˜Kšœˆ˜ˆ—K˜š˜Kšœ˜K˜—š˜Kšœ˜K˜Jšœœœ˜Jšœ«™«J˜šœ0™0Kšœœ˜0K˜—šœ6™6Kšœœ˜K˜—Jšœ œœ œ˜!J˜Jšœœœ˜J˜šžœœ œœ˜0Kšœ œœ˜Kšœ=™=Kšœo˜oKšœ"œœ˜5Kšœ˜K˜—J˜šžœœœ˜šœ œœ˜Kšœœœ˜#šœœ˜Kšœœœ œ˜4šœ#œ˜+Kšœw™wKšœ ˜Kšœ˜K˜—K˜—K˜—Kšœ˜K˜—šžœ œœ˜)Kšœœœ˜Kšœ ˜ —K˜šžœœ˜/šœ˜ Kšœœœ˜Kšœ˜Kšœœœ œ˜JKšœœ˜'—Kšœ˜—K˜š žœœœœ1œ˜ZKšœs™sKšœœœ˜K˜%Kšœœœ ˜—K˜šžœœœ1œ˜^Kšœ œ˜-Kšœœk˜~K˜—K˜šžœœœœ˜6JšœA™AK˜Kšœ œœ œ ˜0šœ˜Kšœœœ˜!Kšœ œœœ˜/Kšœ œ ˜K˜—Jšœ˜J˜—šžœœ˜/Kšœ˜K˜—J˜Jšžœœœ)˜@J˜šžœœœ˜$Jšœœœ˜Jšœ ˜ Jšœ0˜0Kšœœ˜3Jšœ˜—J˜šžœœ˜)Jšœœ˜Jšœœ˜*Jšœ˜—J˜šžœ$˜2JšœB˜BJšœ˜—J˜Jšœœœ)˜BJšœœœ˜2Jšœ9˜9J˜Jšœ!˜!Kšœ˜Kšœ=˜=—šœ˜J˜J˜K˜J˜K˜—K˜K˜—J˜—…— Jφ