DIRECTORY BasicTime USING [ Now, Period ], LarkPlay USING [ MergeToneSpecs, ToneSpec, ToneSpecRec ], Process USING [ Detach, EnableAborts, SecondsToTicks, SetTimeout ], Log USING [ ProblemBool, SLOG ], RPC USING [ CallFailed ], SafeStorage USING [ GetCanonicalType, Type ], ThNet USING [ pd ], ThParty USING [ Deregister, SetRingEnable ], ThPartyMonitorImpl, ThPartyPrivate USING [ CFRef, ConversationBody, ConversationData, DehandleConv, DehandleParty, DestroyConversation, Distribute, DistributionProc, FindOtherParty, GetEvent, PartyBody, PartyData, RingMethod, outsideRingTune, recordingRAtom, Verify ], Thrush USING [ ConversationHandle, ConvEvent, Credentials, Disposition, EventSequence, EventSequenceBody, H, HandleFault, KillHandle, MakeUnique, NB, PartyHandle, Priorities, SHHH, StateID, ThHandle ], Triples USING [ Any, Erase, Foreach, ForeachProc, Select ] ; ThPartySupervisorImpl: CEDAR MONITOR LOCKS root IMPORTS BasicTime, LarkPlay, Log, Process, root: ThPartyMonitorImpl, RPC, SafeStorage, --SpyLog,-- ThNet, Thrush, ThParty, ThPartyPrivate, Triples EXPORTS ThPartyPrivate SHARES ThPartyMonitorImpl = { CFRef: TYPE = ThPartyPrivate.CFRef; ConversationData: TYPE = ThPartyPrivate.ConversationData; RTConvType: SafeStorage.Type = SafeStorage.GetCanonicalType[CODE[ThPartyPrivate.ConversationBody]]; ConvEvent: TYPE = Thrush.ConvEvent; Credentials: TYPE = Thrush.Credentials; H: PROC[r: REF] RETURNS [Thrush.ThHandle] = INLINE { RETURN[LOOPHOLE[Thrush.H[r]]]; }; NB: TYPE = Thrush.NB; PartyData: TYPE = ThPartyPrivate.PartyData; RTPartyType: SafeStorage.Type = SafeStorage.GetCanonicalType[CODE[ThPartyPrivate.PartyBody]]; StateID: TYPE = Thrush.StateID; maxSpvrInterval: NAT _ 10; ringTuneDelay: NAT _ 2400; -- ms. delay between tune starts. Supervisor: PUBLIC PROC[ party: PartyData ] = { event: ConvEvent; toDo, failing, latest: BOOL_FALSE; informationOnly: BOOLEAN_FALSE; Inform: ThPartyPrivate.DistributionProc = { ENABLE RPC.CallFailed => { smarts.canProgress_FALSE; ThParty.Deregister[smartsID: H[smarts]]; RETRY; }; yourParty: BOOL = event.credentials.partyID=H[party]; d_pass; IF ~smarts.canProgress THEN RETURN; IF event.keyTable=NIL AND event.intervalSpecs=NIL AND (NOT yourParty) AND (event.state#initiating) THEN RETURN; -- don't report uninteresting events IF yourParty AND smarts.properties.role=voiceTerminal THEN SetupRingTunes[event]; SELECT (d _ smarts.interface.Progress[shh: smarts.shh, smartsID: H[smarts], informationOnly: informationOnly, yourParty: yourParty, event: event, latestEvent: latest ]) FROM actedAndPass => informationOnly_TRUE; willAlwaysPassThisRequest => smarts.canProgress_FALSE; ENDCASE; event.ringTune _ NIL; }; TRUSTED { Process.EnableAborts[@party.actionNeeded]; Process.SetTimeout[@party.actionNeeded, Process.SecondsToTicks[maxSpvrInterval]]; }; DO ENABLE ABORTED => CONTINUE; [ event, toDo, latest ] _ ScanPostOrWait[party]; informationOnly _ FALSE; IF toDo THEN []_ThPartyPrivate.Distribute[party: party, proc: Inform] ELSE IF failing THEN EXIT ELSE IF party.partyFailed THEN failing_TRUE -- one more pass to clean up! ELSE IF party.supervisor=NIL THEN RETURN; -- vanish to keep local frames to minimum. ENDLOOP; EndParty[party]; }; Supervise: PUBLIC INTERNAL PROC[party: PartyData] = TRUSTED { IF party.supervisor=NIL THEN Process.Detach[party.supervisor _ FORK Supervisor[party]]; NOTIFY party.actionNeeded; -- Spurious if process just spawned? }; ScanPostOrWait: ENTRY PROC[ party: PartyData ] RETURNS [ event: ConvEvent, toDo: BOOL_FALSE, latest: BOOL ] = { ENABLE UNWIND => NULL; Scanner: INTERNAL Triples.ForeachProc = TRUSTED { conv: ConversationData; WITH trip.att SELECT FROM r: CFRef => { cfRef: CFRef_NIL; conv _ NARROW[trip.obj]; IF r.lastNotedID RETURN[FALSE]; actedAndPass, pass, willAlwaysPassThisRequest => RETURN[TRUE]; ENDCASE=> RETURN[Log.ProblemBool[ remark: "Invalid distribute return code", where: $System, bool: TRUE]]; }; Triples.Foreach[priority, party, Triples.Any, DistOne]; IF d=actedAndStop THEN RETURN; ENDLOOP; ENDLOOP; }; Dissolve: INTERNAL PROC[cfRef: CFRef, conv: ConversationData, party: PartyData] = { IF cfRef.event.state#idle THEN RETURN; Triples.Erase[cfRef, conv, party]; conv.numParties _ conv.numParties-1; party.numConvs _ party.numConvs-1; IF conv.numParties=0 THEN ThPartyPrivate.DestroyConversation[conv]; TRUSTED { WITH p: party SELECT FROM trunk => { p.outgoing _ NIL; Triples.Erase[$RnameForTrunk, party, Triples.Any]; }; recording => Thrush.MakeUnique[$RnameForParty, party, ThPartyPrivate.recordingRAtom]; ENDCASE; }; }; EndParty: ENTRY PROC[party: PartyData] = { Thrush.KillHandle[H[party], RTPartyType!Thrush.HandleFault=>CONTINUE]; Triples.Erase[Triples.Any, party, Triples.Any]; party.supervisor _ NIL; }; GetHistory: PUBLIC ENTRY PROC[ shhh: Thrush.SHHH, credentials: Credentials, firstState: StateID, lastState: StateID -- default: get latest ] RETURNS [ nb: Thrush.NB, events: Thrush.EventSequence_NIL ] = { ENABLE UNWIND => NULL; conv: ConversationData; numStates: NAT; [conv, , , nb] _ ThPartyPrivate.Verify[credentials]; IF nb#success OR conv=NIL OR conv.currentStateID=0 THEN RETURN; IF lastState=0 OR lastState>conv.currentStateID THEN lastState_conv.currentStateID; SELECT firstState FROM <1 => firstState_1; >conv.currentStateID => RETURN; ENDCASE; IF lastState NULL; ENDCASE => RETURN; WITH iParty: party^ SELECT FROM individual => { SELECT iParty.ringEnable FROM offTimed, subduedTimed => IF BasicTime.Period[from: iParty.ringTime, to: BasicTime.Now[]] > 0 THEN ThParty.SetRingEnable[partyID: partyID, ringEnable: iParty.defaultRingEnable]; ENDCASE; SELECT iParty.ringEnable FROM offTimed, off => RETURN; ENDCASE; otherParty _ ThPartyPrivate.DehandleParty[ ThPartyPrivate.FindOtherParty[partyID, ThPartyPrivate.DehandleConv[event.credentials.convID]].partyID]; IF otherParty#NIL THEN WITH oParty: otherParty^ SELECT FROM individual => { divisor _ 2; otherMethod _ oParty.ringDo; IF otherMethod # standard THEN otherTune _ oParty.ringTune; }; trunk => IF event.state=ringing THEN { otherTune _ ThPartyPrivate.outsideRingTune; otherMethod _ bothTunes; }; ENDCASE; SELECT event.state FROM maybe => { IF otherTune=NIL THEN RETURN; event.ringTune _ NEW[LarkPlay.ToneSpecRec _ otherTune^]; event.ringTune.volume _ ThNet.pd.tonesVolume+2; event.ringTune.repeatIndefinitely _ TRUE; RETURN; }; ringing => NULL; ENDCASE => RETURN; event.ringTune _ iParty.ringTune; IF iParty.ringDo # bothTunes OR otherMethod # bothTunes OR otherTune=NIL THEN RETURN; event.ringTune _ LarkPlay.MergeToneSpecs[event.ringTune, otherTune, divisor, ringTuneDelay]; }; ENDCASE; }; }. ÞThPartySupervisorImpl.mesa Last modified by D. Swinehart, January 13, 1985 2:35:36 pm PST Copies, Obligatory Concrete Types Supervision Process . . . One per party PROC[smarts: SmartsData ] RETURNS [ d: Thrush.Disposition ]; I think this is a hack. July 23, 1984 3:06 pm PDT Tell only voiceTerminals about the ring or ringback tune More hack. July 23, 1984 3:06 pm PDT <> { party.partyFailed _ TRUE; CONTINUE; }; Have discovered a change in state that our Smarts should know about. The Smarts will now learn about it, even if the state changes again before they can act on the change. PROC[trip: TripleRec] RETURNS [continue: BOOLEAN_TRUE] Distribution utility. Basic Party distribution function << At last!! >> Perform distribution in order of this Party's priorities <> Distribute to all Smarts at this priority level. If Post generates new work to do, stop and do it, then cycle again. Post is probably the wrong word for this activity, now. But the work needs doing. When a trunk party leaves a conversation, it loses its identity (<< something wrong here? >>) When a recording party leaves, it reverts to available. If timed, see if time has expired. If so, switch back to default ring tune Ê ˜Jšœ™Jšœ>™>J˜šÏk ˜ J˜ Jšœ œ+˜9Jšœœ6˜CJšœœœ˜ Jšœœ˜J˜-Jšœœ˜Jšœœ˜,Jšœ˜šœœ˜Jšœá˜á—Jš œœ^œ'œœ˜ÉJšœœ-˜:J˜J˜—šœ œœ˜/š˜J˜ J˜ J˜Jšœ˜J˜Jšœ˜J˜ JšÏc ˜ Jšœ˜Jšœ˜J˜Jšœ˜Jšœ˜—Jšœ˜Jšœ˜J˜—J™™Jšœœ˜#šœœ#˜9Jšœ<œ#˜c—Jšœ œ˜#Jšœ œ˜'Jšœœœœœœœœ ˜VJšœœ œ˜šœ œ˜+Jšœ=œ˜]—J˜J˜—™J™Jšœœ˜Jšœœ ž!˜šœœ˜Jšœ"œ˜:—Jšœž$˜?J˜J˜—šŸœœœ˜.Jšœœœ œ˜@Jšœœœ˜šœ œœ˜1Jšœœ ™6J˜šœ œ˜šœ ˜ Jšœ œ˜Jšœœ ˜Jšœ#œ ˜3Jšœœœ˜9šœœœ˜Jšœ(˜(Jšœœ˜ šœ˜Jšœ(œ(˜R—Jšœ9˜9Jšœœ˜ Jšœœ˜Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜—Jšœ:˜:šœœ˜$Jš œœœœœ˜K—Jšœ˜J˜—šœH™HšŸ œœœ;˜RJšœ#˜*J˜Jšœ œœœ˜!Jšœ œ$žœ˜KJšœ8™8š œ!œ$žœœ œ˜‡J™(š œ$œ'œœ˜nJšœ œœ˜-šŸœ˜ Jšœœ ˜#šœ˜ Jšœœ˜Jšœ1 œ˜>šœœ˜!Jšœ@œ˜G——Jšœ˜—Jšœ0™0Jšœ7˜7Jš œœœœœ˜3——J˜—J˜—šŸœœœ<˜SJ™CJ™RJšœœœ˜&J˜"J˜$J˜"Jšœœ*˜CJ™]J™7šœœ œ˜#Jšœœ7˜RJ˜UJšœ˜J˜—Jšœ˜—J˜šŸœœœ˜*Jšœœ)œ˜FJ˜/Jšœœ˜Jšœ˜J˜—šŸ œœœœ˜Jšœ œ˜Jšœ˜J˜Jšœž˜)Jšœœœœ˜AJšœœœ˜J˜Jšœ œ˜Jšœ4˜4Jš œ œœœœœ˜?Jšœ œœ˜Sšœ ˜J˜Jšœœ˜Jšœ˜—Jšœœœ˜$J˜#Jšœœ&˜0Jš œœœœ%œ˜O—J˜šŸœœœ˜9J˜8J˜9J˜Jšœ˜Jšœ2˜2Jšœ œ˜J™KJš œ œœœœ˜Bšœ ˜˜šœ˜šœ˜šœB˜HJšœN˜N——Jšœ˜—šœ˜Jšœœ˜Jšœ˜—˜*˜&J˜@——š œ œ œœ˜;šœ˜Jšœ)˜)Jšœœ˜;Jšœ˜—šœ œœ˜&JšœD˜DJšœ˜—Jšœ˜—šœ ˜˜ Jšœ œœœ˜Jšœœ$˜8J˜/Jšœ$œ˜)Jšœ˜Jšœ˜—Jšœ œ˜Jšœœ˜—J˜!Jš œœœ œœœ˜U˜J˜K—J˜——Jšœ˜Jšœ˜—J˜—J˜—…— „0u