<> <> <> <> <> DIRECTORY Booting USING [switches], Convert USING [IntFromRope], File USING [SystemVolume], FileBackdoor USING [IsDebugger], FS USING [Error, GetName, OpenFileFromStream, StreamOpen], IO USING [Backup, BreakProc, Close, CR, EndOfStream, Error, GetChar, GetIndex, GetRopeLiteral, GetTokenRope, int, PeekChar, PutF, PutFR, rope, SP, STREAM, TAB, time], Rope USING [Cat, Concat, Equal, ROPE, SkipTo, Substr], RuntimeError USING [UNCAUGHT], ThisMachine USING [Name], UserCredentials USING [Get], UserProfile USING [ProfileChangeReason, ProfileChangedProc], UserProfileBackdoor USING [GuestProcsRec]; UserProfileImpl: CEDAR MONITOR IMPORTS Booting, Convert, File, FileBackdoor, FS, IO, Rope, RuntimeError, ThisMachine, UserCredentials EXPORTS UserProfile, UserProfileBackdoor = BEGIN <<>> <> <<>> ProfileList: TYPE = LIST OF ProfileEntry; ProfileEntry: TYPE = REF ProfileRecord; ProfileRecord: TYPE = RECORD[key: ROPE, tokens: LIST OF ROPE, position: INT]; ROPE: TYPE = Rope.ROPE; ProfileChangedItem: TYPE = RECORD [ proc: UserProfile.ProfileChangedProc, clientData: REF ANY ]; <<>> <> IsGuestProcess: PROC [] RETURNS [isGuest: BOOL] _ FalseProc; GuestProcs: REF UserProfileBackdoor.GuestProcsRec _ NEW[UserProfileBackdoor.GuestProcsRec _ [FalseProc]] ; <> <<>> Boolean: PUBLIC PROC [key: ROPE, default: BOOL _ FALSE] RETURNS [value: BOOL] = { entry: ProfileEntry; val: ROPE; IF IsGuestProcess[] THEN RETURN GuestProcs.Boolean[key, default]; entry _ Lookup[key]; val _ GetRope[entry]; IF val = NIL THEN RETURN[default]; IF val.Equal["TRUE", FALSE] THEN RETURN[TRUE]; IF val.Equal["FALSE", FALSE] THEN RETURN[FALSE]; Report[entry, val.Concat[" is not a Boolean"]]; RETURN[default]; }; Number: PUBLIC PROC [key: ROPE, default: INT] RETURNS [value: INT] = { entry: ProfileEntry; val: ROPE; IF IsGuestProcess[] THEN RETURN GuestProcs.Number[key, default]; entry _ Lookup[key]; val _ GetRope[entry]; IF val = NIL THEN RETURN[default]; value _ Convert.IntFromRope[val ! RuntimeError.UNCAUGHT => { value _ default; Report[entry, val.Concat[" is not an INT"]]; CONTINUE; } ]; }; Token: PUBLIC PROC [key: ROPE, default: ROPE] RETURNS [value: ROPE] = { entry: ProfileEntry; val: ROPE; IF IsGuestProcess[] THEN RETURN GuestProcs.Token[key, default]; entry _ Lookup[key]; val _ GetRope[entry]; IF val = NIL THEN RETURN[default]; value _ val; }; ListOfTokens: PUBLIC PROC [key: ROPE, default: LIST OF ROPE] RETURNS [value: LIST OF ROPE] = { entry: ProfileEntry; IF IsGuestProcess[] THEN RETURN GuestProcs.ListOfTokens[key, default]; entry _ Lookup[key]; IF entry = NIL THEN RETURN[default] ELSE RETURN[entry.tokens]; }; Line: PUBLIC PROC [key: ROPE, default: ROPE] RETURNS [value: ROPE] = { entry: ProfileEntry; IF IsGuestProcess[] THEN RETURN GuestProcs.Line[key, default]; entry _ Lookup[key]; IF entry = NIL THEN RETURN[default]; FOR l: LIST OF ROPE _ entry.tokens, l.rest UNTIL l = NIL DO IF value = NIL THEN value _ l.first ELSE value _ value.Cat[" ", l.first]; ENDLOOP; }; Lookup: ENTRY PROC [key: ROPE] RETURNS [ProfileEntry] = { ENABLE UNWIND => NULL; RETURN[LookupInternal[key]] }; LookupInternal: INTERNAL PROC [key: ROPE] RETURNS [ProfileEntry] = { IF FileBackdoor.IsDebugger[File.SystemVolume[]] THEN { s2: ROPE = Rope.Concat["Debugger.", key]; FOR l: ProfileList _ profileList, l.rest UNTIL l = NIL DO IF Rope.Equal[s1: l.first.key, s2: s2, case: FALSE] THEN RETURN[l.first]; ENDLOOP; }; FOR l: ProfileList _ profileList, l.rest UNTIL l = NIL DO IF Rope.Equal[s1: l.first.key, s2: key, case: FALSE] THEN RETURN[l.first]; ENDLOOP; RETURN[NIL]; }; GetRope: PROC [entry: ProfileEntry] RETURNS [value: ROPE] = INLINE { IF entry = NIL OR entry.tokens = NIL THEN RETURN[NIL]; value _ entry.tokens.first; IF entry.tokens.rest # NIL THEN Report[entry, "extra material on line"]; }; GetProfileName: PUBLIC PROC RETURNS [ROPE] = { IF IsGuestProcess[] THEN RETURN GuestProcs.GetProfileName[] ELSE RETURN[profileName]; }; <<>> <> profileList: ProfileList _ NIL; profileName: ROPE _ NIL; ParseProfile: ENTRY PROC [startNewErrorLog: BOOL _ FALSE] = { ENABLE UNWIND => NULL; stream: IO.STREAM _ NIL; name: ROPE _ UserCredentials.Get[].name; IF startNewErrorLog THEN errorLog _ NIL; profileList _ NIL; profileName _ NIL; IF Booting.switches[p] THEN RETURN; -- return default values for the profile name _ Rope.Cat["///", name.Substr[0, name.SkipTo[0, "."]], ".profile"]; stream _ FS.StreamOpen[fileName: Rope.Cat["///", ThisMachine.Name[], ".machineProfile"] ! FS.Error => CONTINUE ]; IF stream # NIL THEN { <> ParseProfileInternal[stream]; stream _ NIL; }; stream _ FS.StreamOpen[fileName: "///Server.profile" ! FS.Error => CONTINUE ]; IF stream # NIL THEN { <> profileName _ "///Server.profile"; ParseProfileInternal[stream]; RETURN; }; stream _ FS.StreamOpen[fileName: name ! FS.Error => CONTINUE ]; IF stream # NIL THEN { <> profileName _ name; ParseProfileInternal[stream]; RETURN; }; <> stream _ FS.StreamOpen[fileName: "///User.profile" ! FS.Error => CONTINUE ]; IF stream # NIL THEN { profileName _ "///User.profile"; ParseProfileInternal[stream]; }; }; ParseProfileInternal: INTERNAL PROC [stream: IO.STREAM] = { <> DO ENABLE { RuntimeError.UNCAUGHT => EXIT; UNWIND => IO.Close[stream]; }; SkipWhite: PROC [flushLines: BOOL _ FALSE] RETURNS [c: CHAR] = { DO ENABLE IO.Error, IO.EndOfStream => GO TO stop; c _ stream.PeekChar[]; SELECT c FROM '\n => IF NOT flushLines THEN RETURN; <= 40C => {}; '- => {-- could be a comment [] _ stream.GetChar[]; IF stream.PeekChar[] # '- THEN { <> stream.Backup[c]; RETURN [c]; }; DO <> c _ stream.GetChar[]; SELECT c FROM '\n => { <> stream.Backup[c]; IF flushLines THEN EXIT; RETURN; }; '- => IF stream.PeekChar[] = '- THEN EXIT; ENDCASE; ENDLOOP; }; ENDCASE => RETURN; [] _ stream.GetChar[]; ENDLOOP; EXITS stop => {c _ 0C}; }; LocalToken: PROC [flushLines: BOOL _ FALSE] = { stop: CHAR _ SkipWhite[flushLines]; position _ stream.GetIndex[]; token _ NIL; SELECT stop FROM 0C, '\n => RETURN; '" => token _ stream.GetRopeLiteral[]; ENDCASE => token _ stream.GetTokenRope[tokenProc].token; }; tokenProc: IO.BreakProc = { RETURN[SELECT char FROM IO.SP, IO.TAB, ', => sepr, IO.CR, ': => break, ENDCASE => other ]; }; token: ROPE _ NIL; tokens, tail: LIST OF ROPE _ NIL; position: INT; key: ROPE _ NIL; LocalToken[TRUE]; IF (key _ token) = NIL THEN EXIT; SELECT SkipWhite[] FROM ': => [] _ stream.GetChar[]; -- flush the ': ENDCASE => { <> DO IF stream.GetChar[ ! IO.EndOfStream => EXIT] = '\n THEN EXIT; ENDLOOP; ReportInternal[msg: IO.PutFR["missing : at [%d]", IO.int[position]]]; LOOP; }; DO list: LIST OF ROPE _ NIL; LocalToken[]; IF token = NIL THEN EXIT; list _ LIST[token]; IF tail = NIL THEN {tail _ tokens _ list} ELSE {tail.rest _ list; tail _ list}; ENDLOOP; IF LookupInternal[key] # NIL THEN ReportInternal[ entry: LookupInternal[key], msg: IO.PutFR["%g also appears at [%d]", IO.rope[key], IO.int[position]] ]; profileList _ CONS[NEW[ProfileRecord _ [key, tokens, position]], profileList]; ENDLOOP; IO.Close[stream]; }; <<>> <> Report: ENTRY PROC [entry: ProfileEntry _ NIL, msg: ROPE] = { ENABLE UNWIND => NULL; ReportInternal[entry, msg]; }; ReportInternal: INTERNAL PROC [entry: ProfileEntry _ NIL, msg: ROPE] = { ENABLE RuntimeError.UNCAUGHT => CONTINUE; IF errorLog = NIL THEN { errorLog _ FS.StreamOpen[fileName: "///UserProfile.log", accessOptions: $create]; errorLog.PutF["Processing %g at %t", IO.rope[profileName], IO.time[]]; }; errorLog.PutF["\n\n%g", IO.rope[msg]]; IF entry # NIL THEN errorLog.PutF[", at %g [%d]", IO.rope[entry.key], IO.int[entry.position]]; }; GetErrorLog: PUBLIC ENTRY PROC RETURNS [fileName: ROPE _ NIL] = { ENABLE UNWIND => {errorLog _ NIL; NULL}; IF errorLog # NIL THEN { fileName _ FS.GetName[FS.OpenFileFromStream[errorLog]].fullFName; errorLog.Close[]; errorLog _ NIL; }; }; errorLog: IO.STREAM _ NIL; <<>> <> <> profileChangedList: LIST OF ProfileChangedItem _ NIL; profileChangedListLast: LIST OF ProfileChangedItem _ NIL; listInUse: BOOL _ FALSE; listAvailable: CONDITION _ [timeout: 0]; CallWhenProfileChanges: PUBLIC PROC [proc: UserProfile.ProfileChangedProc] = { itemL: LIST OF ProfileChangedItem = CONS[[proc, --clientData--NIL], NIL]; IF IsGuestProcess[] THEN {GuestProcs.CallWhenProfileChanges[proc]; RETURN}; AcquireList[]; IF profileChangedList = NIL THEN profileChangedList _ itemL ELSE profileChangedListLast.rest _ itemL; profileChangedListLast _ itemL; ReleaseList[]; DoIt[itemL.first, firstTime]; }; ProfileChanged: PUBLIC PROC [reason: UserProfile.ProfileChangeReason] = { IF IsGuestProcess[] THEN {GuestProcs.ProfileChanged[reason]; RETURN}; AcquireList[]; ParseProfile[startNewErrorLog: TRUE ! RuntimeError.UNCAUGHT => CONTINUE]; FOR l: LIST OF ProfileChangedItem _ profileChangedList, l.rest UNTIL l = NIL DO DoIt[l.first, reason]; ENDLOOP; ReleaseList[]; }; DoIt: PROC [item: ProfileChangedItem, reason: UserProfile.ProfileChangeReason] = { item.proc[reason--, item.clientData-- ! RuntimeError.UNCAUGHT => { Report[msg: "Problem while executing ProfileChangedProc"]; CONTINUE } ]; }; AcquireList: ENTRY PROC = { WHILE listInUse DO WAIT listAvailable; ENDLOOP; listInUse _ TRUE; }; ReleaseList: ENTRY PROC = { listInUse _ FALSE; BROADCAST listAvailable; }; <> RegisterGuestProcs: PUBLIC PROC [newProcs: REF UserProfileBackdoor.GuestProcsRec] = { GuestProcs _ newProcs; IsGuestProcess _ newProcs.IsGuestProcess; }; <> FalseProc: PROC RETURNS [isGuest: BOOL] = { isGuest _ FALSE; }; <> END. <> <> <> <> <<>> <> <> <<>> <<>>