DIRECTORY BasicTime USING [ Now, Period ], LarkPlay USING [ MergeToneSpecs, ToneSpec, ToneSpecRec ], Process USING [ Detach, EnableAborts, SecondsToTicks, SetTimeout ], Log USING [ ProblemBool ], 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, MakeServiceRname, PartyBody, PartyData, RingMethod, outsideRingTune, Verify ], Thrush USING [ ConversationHandle, ConvEvent, Credentials, Disposition, EventSequence, EventSequenceBody, H, HandleFault, KillHandle, NB, PartyHandle, Priorities, SHHH, StateID, ThHandle ], Triples USING [ Any, Erase, Foreach, ForeachProc, Select ], ThSmartsRpcControl, TU USING [ MakeUnique] ; ThPartySupervisorImpl: CEDAR MONITOR LOCKS root IMPORTS BasicTime, LarkPlay, Log, Process, root: ThPartyMonitorImpl, RPC, SafeStorage, --SpyLog,-- ThNet, Thrush, ThParty, ThPartyPrivate, ThSmartsRpcControl, Triples, TU 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 (event.proseSpecs=NIL OR (event.proseSpecs.first.type=request AND party.type=individual)) AND (NOT yourParty) AND (event.state#initiating) THEN RETURN; 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 { SELECT party.type FROM trunk => { party.outgoing _ NIL; Triples.Erase[$RnameForTrunk, party, Triples.Any]; }; service => TU.MakeUnique[$RnameForParty, party, ThPartyPrivate.MakeServiceRname[party.serviceName].serviceRnameAtom]; 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; SELECT party.type FROM individual => { SELECT party.ringEnable FROM offTimed, subduedTimed => IF BasicTime.Period[from: party.ringTime, to: BasicTime.Now[]] > 0 THEN ThParty.SetRingEnable[partyID: partyID, ringEnable: party.defaultRingEnable]; ENDCASE; SELECT party.ringEnable FROM offTimed, off => RETURN; ENDCASE; otherParty _ ThPartyPrivate.DehandleParty[ ThPartyPrivate.FindOtherParty[partyID, ThPartyPrivate.DehandleConv[event.credentials.convID]].partyID]; IF otherParty#NIL THEN SELECT otherParty.type FROM individual => { divisor _ 2; otherMethod _ otherParty.ringDo; IF otherMethod # standard THEN otherTune _ otherParty.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 _ party.ringTune; IF party.ringDo # bothTunes OR otherMethod # bothTunes OR otherTune=NIL THEN RETURN; event.ringTune _ LarkPlay.MergeToneSpecs[event.ringTune, otherTune, divisor, ringTuneDelay]; }; ENDCASE; }; }. ThPartySupervisorImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last modified by D. Swinehart, July 21, 1985 10:41:12 pm PDT Polle Zellweger (PTZ) August 22, 1985 1:59:56 pm PDT Copies, Obligatory Concrete Types Supervision Process . . . One per party PROC[smarts: SmartsData ] RETURNS [ d: Thrush.Disposition ]; Don't report uninteresting events. Allow request proseSpecs to get to service (for speech) and/or trunk (for feeping) smarts. (Note: a proseSpec list will be either wholly requests or some combination of started and finished at this level.) Need to change if proseSpecs used to communicate with own Lark. 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 Swinehart, May 15, 1985 10:35:09 am PDT Cedar 6.0 changes to: Dissolve (new way to idle service (recording) party), proseSpecs test in Inform Swinehart, May 20, 1985 1:16:28 pm PDT PartyBody is not a variant record any more changes to: Dissolve, SetupRingTunes Swinehart, May 22, 1985 12:02:13 pm PDT ServiceName changes changes to: Dissolve Swinehart, May 22, 1985 12:08:44 pm PDT recording => service changes to: Dissolve Polle Zellweger (PTZ) August 14, 1985 4:22:41 pm PDT Don't report proseSpec transitions to the individual's party -- would have to be changed to use proseSpecs to send tunes to your own Lark. Idea is to keep traffic of large ropes down. Since Dan is using proseSpecs to make the trunk feep to his bank, have to report them to trunk parties. changes to: Inform (local of Supervisor) Polle Zellweger (PTZ) August 22, 1985 1:59:57 pm PDT changes to: Inform (local of Supervisor) Κ Ά˜šœ™Icodešœ Οmœ1™šžœžœž˜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š žœžœžœžœžœ˜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˜V˜/J˜E—Jšžœ˜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šžœ ž˜˜šžœž˜šœ˜šžœAž˜GJšœM˜M——Jšžœ˜—šžœž˜Jšœžœ˜Jšžœ˜—˜*˜&J˜@——š žœ žœžœžœž˜2šœ˜Jšœ-˜-Jšžœžœ!˜?Jšœ˜—šœ žœžœ˜&JšœD˜DJšœ˜—Jšžœ˜—šžœ ž˜˜ Jšžœ žœžœžœ˜Jšœžœ$˜8J˜/Jšœ$žœ˜)Jšžœ˜Jšœ˜—Jšœ žœ˜Jšžœžœ˜—J˜ Jš žœžœžœ žœžœžœ˜T˜J˜K—J˜——Jšžœ˜Jšœ˜—J˜—J˜™'K™ Kšœ ΟrœG™[—™&K™*Kšœ ‘™$—™'K™Kšœ ‘™—™'K™Kšœ ‘™—™4K™‘Kšœ ‘œ™(—™4Kšœ ‘œ™(—K™—…— φ6Ά