DIRECTORY Atom USING [ GetPName, MakeAtom ], GVBasics USING [ RName ], GVNames USING [ Expand, RListHandle ], IO, Log USING [ FindWhere, Problem, ProblemHandle, RegisterWhereToReport, Report, WhereProc ], LupineRuntime USING [ BindingError ], Names USING [ CurrentRName, CurrentPasskey, GetDefaultDetails, GVDetails, Registrize, Results, RNameAtom, StartConversation ], Nice, Rope USING [ Concat, Fetch, Length, Substr ], RPC USING [ AuthenticateFailed, EncryptionKey, ExportFailed, ImportFailed ], SafeStorage USING [ GetCanonicalType, Type ], Thrush USING [ AlertKind, CallUrgency, ConversationHandle, Enhandle, HandleFault, KillHandle, NB, PartyHandle, PartyType, H, nullHandle, Machine, MakeUnique, pERROR, PhoneNumber, Priorities, Rname, ROPE, SHHH, SmartsHandle, TBD, ThHandle, unencrypted ], ThNet USING [ HowToDial, InitWhitePagesDatabase, WhitePagesEntry, WPListing, WPState ], ThParty, ThPartyPrivate USING [ CFRef, DehandleParty, DehandleSmarts, DoAdvance, PartyBody, PartyData, SmartsBody, SmartsData, Supervise ], ThPartyRpcControl, ThPartyMonitorImpl, ThSmarts USING [ SmartsInterface, SmartsProperties ], ThSmartsRpcControl USING [ ImportNewInterface, InterfaceRecord ], ThVersions USING [ ThrushVR ], Triples USING [ Any, Erase, Foreach, ForeachProc, Select ], TU USING [ RefAddr ], UserProfile USING [ Token ] ; ThPartyInitImpl: CEDAR MONITOR LOCKS root IMPORTS Atom, GVNames, IO, Log, LupineRuntime, Names, Nice, root: ThPartyMonitorImpl, Rope, RPC, SafeStorage, SmartsRpc: ThSmartsRpcControl, Thrush, ThNet, ThPartyPrivate, ThPartyRpcControl, ThVersions, Triples, TU, UserProfile EXPORTS ThParty, ThPartyPrivate SHARES ThPartyMonitorImpl = { OPEN IO; AlertKind: TYPE = Thrush.AlertKind; CallUrgency: TYPE = Thrush.CallUrgency; CFRef: TYPE = ThPartyPrivate.CFRef; ConversationHandle: TYPE = Thrush.ConversationHandle; PartyBody: TYPE = ThPartyPrivate.PartyBody; -- Concrete RTPartyType: SafeStorage.Type = SafeStorage.GetCanonicalType[CODE[PartyBody]]; PartyData: TYPE = ThPartyPrivate.PartyData; -- REF Concrete PartyHandle: TYPE = Thrush.PartyHandle; -- Handle ROPE: TYPE = Thrush.ROPE; SmartsBody: TYPE = ThPartyPrivate.SmartsBody; -- Concrete SmartsData: TYPE = ThPartyPrivate.SmartsData; -- REF Concrete RTSmartsType: SafeStorage.Type =SafeStorage.GetCanonicalType[CODE[SmartsBody]]; SmartsHandle: TYPE = Thrush.SmartsHandle; -- Handle SmartsInterface: TYPE = ThSmarts.SmartsInterface; LocalSmartsInterface: TYPE = SmartsRpc.InterfaceRecord; nullHandle: Thrush.PartyHandle = Thrush.nullHandle; SHHH: TYPE = Thrush.SHHH; none: SHHH = Thrush.unencrypted; TBD: TYPE = Thrush.TBD; pERROR: ERROR = Thrush.pERROR; H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; }; larkRegistry: ROPE=".Lark"; recordingRname: Thrush.Rname = "idle.jay.lark"; recordingRAtom: PUBLIC ATOM _ Atom.MakeAtom[recordingRname]; standardPriorities: Thrush.Priorities = LIST [ LIST [$Supervisor], LIST [$Manager], LIST[$LocatedTerminal], LIST [$AdjacentTerminal], LIST [$VoiceTerminal, $LabPhone], LIST [$Secretary], LIST [$Receptionist] ]; GetParty: PUBLIC ENTRY PROC[shh: SHHH_NIL, partyID: PartyHandle, rName: Thrush.Rname] RETURNS [newPartyID: PartyHandle] = { ENABLE UNWIND=>NULL; RETURN[H[GetActiveParty[rName]]]; }; GetActiveParty: INTERNAL PROC[rName: Thrush.Rname] RETURNS [newParty: PartyData] = { rAtom: ATOM; IF rName=NIL THEN RETURN[NIL]; rName _ Names.Registrize[rName]; rAtom _ Names.RNameAtom[rName]; RETURN[NARROW[Triples.Select[$RnameForParty, --party--, rAtom]]]; }; GetJayParty: PUBLIC ENTRY PROC[shh: SHHH_none, partyID: PartyHandle] RETURNS [newPartyID: PartyHandle_nullHandle] = { ENABLE UNWIND=>NULL; party: PartyData_ ThPartyPrivate.DehandleParty[partyID]; rAtom: ATOM; IF party = NIL THEN RETURN; rAtom _ NARROW[Triples.Select[$RnameForParty, party, -- rAtom --]]; rAtom _ Names.RNameAtom[Atom.GetPName[rAtom].Concat[".Jay"]]; party _ NARROW[Triples.Select[$RnameForParty, --party--, recordingRAtom]]; IF party = NIL OR party.numEnabled = 0 THEN RETURN; Thrush.MakeUnique[$RnameForParty, party, rAtom]; RETURN[H[party]]; }; GetPartyFromFeepNum: PUBLIC ENTRY PROC[ shh: SHHH_none, partyID: PartyHandle, feepNum: Thrush.ROPE_NIL] RETURNS [newPartyID: PartyHandle_nullHandle] = { ENABLE UNWIND=>NULL; party: PartyData _ NIL; rName, officeNumber: ROPE; listing: ThNet.WPListing; [rName, officeNumber, listing] _ ThNet.WhitePagesEntry [ wpState: wpState, name: feepNum, feep: TRUE, key: $officeNumber]; IF rName=NIL THEN RETURN; party _ GetActiveParty[rName]; IF party#NIL THEN RETURN[H[party]]; IF officeNumber=NIL THEN RETURN; RETURN[GetPartyFromNumberInt[partyID, officeNumber, rName, TRUE]]; }; GetPartyFromNumber: PUBLIC ENTRY PROC[ shh: SHHH, partyID: PartyHandle, phoneNumber: Thrush.ROPE, description: ROPE, trunkOK: BOOL] RETURNS [newPartyID: PartyHandle] = { ENABLE UNWIND => NULL; RETURN[GetPartyFromNumberInt[partyID, phoneNumber, description, trunkOK]]; }; GetPartyFromNumberInt: INTERNAL PROC[ partyID: PartyHandle, phoneNumber: Thrush.ROPE, description: ROPE, trunkOK: BOOL] RETURNS [newPartyID: PartyHandle] = { ENABLE ANY => { newPartyID _ Log.ProblemHandle[,$System]; CONTINUE; }; isExt: BOOLEAN _ FALSE; num: ROPE _ NIL; party: PartyData = ThPartyPrivate.DehandleParty[partyID]; myExtAtom: ATOM = IF party=NIL THEN NIL ELSE NARROW[Triples.Select[$Extension, party,]]; myExt: ROPE = IF myExtAtom=NIL THEN NIL ELSE Atom.GetPName[myExtAtom]; IF phoneNumber#NIL THEN [num, isExt] _ ThNet.HowToDial[phoneNumber, myExt]; IF isExt THEN { extAtom: ATOM=Atom.MakeAtom[num]; newPartyID _ H[NARROW[Triples.Select[$Extension, --party--, extAtom]]]; IF newPartyID#nullHandle THEN RETURN[newPartyID]; }; IF ~trunkOK THEN RETURN[nullHandle]; RETURN[H[GetTrunkParty[partyID: partyID, description: description, address: num]]]; }; GetTrunkParty: INTERNAL PROC[ partyID: PartyHandle, description: Thrush.ROPE, address: Thrush.ROPE] RETURNS[trunkParty: PartyData_NIL] = { party: PartyData = ThPartyPrivate.DehandleParty[partyID]; IF party#NIL THEN trunkParty _ NARROW[Triples.Select[$TrunkParty, party, Triples.Any]]; IF trunkParty = NIL THEN RETURN; TRUSTED { WITH tp: trunkParty SELECT FROM trunk => { IF tp.outgoing#NIL OR GetRnameFromParty[trunkParty] # NIL THEN RETURN[NIL]; tp.outgoing _ address; IF description#NIL THEN Thrush.MakeUnique[$RnameForTrunk, trunkParty, Atom.MakeAtom[description]]; }; ENDCASE => { Log.Problem["Wrong party type", $System]; RETURN[NIL]; }; }; }; GetNumbersForRName: PUBLIC PROC[shh: SHHH_none, rName: Thrush.Rname] RETURNS [fullRName: ROPE, number: ROPE, homeNumber: ROPE] = { listing: ThNet.WPListing; [fullRName, number, listing] _ ThNet.WhitePagesEntry[ wpState: wpState, name: rName, key: $officeNumber]; IF listing#NIL THEN homeNumber _ ThNet.WhitePagesEntry[ wpState: wpState, key: $outsideNumber, listing: listing].entry; }; GetRname: PUBLIC PROC[shh: SHHH_none, partyID: PartyHandle] RETURNS [rName: Thrush.Rname] = { RETURN[GetRnameFromParty[ThPartyPrivate.DehandleParty[partyID]]]; }; CreateParty: PUBLIC PROC[shh: SHHH_NIL, rName: Thrush.Rname, type: Thrush.PartyType] RETURNS [partyID: PartyHandle_nullHandle] = { ENABLE ANY => { partyID _ Log.ProblemHandle[, $System]; CONTINUE; }; party: PartyData_NIL; rn: Thrush.Rname = IF type#recording THEN rName ELSE recordingRname; larkName: ROPE=rn.Concat[larkRegistry]; nameAttr: ATOM=$RnameForParty; rAtom: ATOM=Names.RNameAtom[rn]; extension: ATOM_NIL; ExistingParty: ENTRY PROC = -- INLINE -- { ENABLE UNWIND=>NULL; party_IF type=recording THEN NIL ELSE NARROW[Triples.Select[nameAttr, --party--, rAtom]]; IF party#NIL AND ~party.partyFailed AND party.type#type THEN { Log.Problem[remark: "Same party name, new type", where: $System]; party_NIL; }; }; NewParty: ENTRY PROC = -- INLINE -- { SELECT type FROM individual => { party_NEW[PartyBody _ [v: individual []]]; IF extension#NIL THEN Thrush.MakeUnique[$Extension, party, extension]; }; recording => party_NEW[PartyBody _ [v: recording []]]; trunk => party _ NEW [ PartyBody _ [ v: trunk [ NIL, NIL ] ] ]; ENDCASE => { Log.Problem["Unknown party type", $System]; RETURN; }; party.supervisor _ NIL; IF rName#NIL THEN Thrush.MakeUnique[nameAttr, party, rAtom]; Thrush.MakeUnique[$Priorities, party, standardPriorities]; partyID _ Thrush.Enhandle[party]; }; rName_rn; IF rName=NIL AND type#trunk THEN RETURN; ExistingParty[]; IF party#NIL THEN RETURN[H[party]]; SELECT type FROM individual => TRUSTED { WITH GVNames.Expand[larkName] SELECT FROM group => { FOR entries: GVNames.RListHandle _ members, members.rest WHILE entries#NIL DO entry: GVBasics.RName=entries.first; IF entry.Length[]>2 AND entry.Fetch[0]='X AND entry.Fetch[1]='. THEN { extension _ Names.RNameAtom[entry.Substr[start: 2, len: 4]]; EXIT; }; ENDLOOP; }; ENDCASE; IF extension=NIL THEN { ext: ROPE _ GetNumbersForRName[rName: rName].number; IF ext#NIL AND ([ext,]_ThNet.HowToDial[ext]).isLocalExtension THEN extension_Names.RNameAtom[ext]; }; }; ENDCASE; NewParty[]; Log.Report[IO.PutFR["CreateParty[%s, %s] -> [ %g, %g ]", rope[rName], rope[SELECT type FROM individual => "individual", trunk=>"trunk", recording=>"recording", ENDCASE=>NIL], card[partyID], IF party=NIL THEN atom[$Unknown] ELSE TU.RefAddr[party]], $Party, party]; }; ReleaseTrunkParty: PUBLIC ENTRY PROC[shh: SHHH, partyID: PartyHandle] = TRUSTED { party: PartyData = ThPartyPrivate.DehandleParty[partyID]; IF party=NIL THEN RETURN; IF party.numConvs#0 THEN RETURN; -- ONLY do if didn't make it into a conversation WITH tp: party SELECT FROM trunk => { IF party.numConvs#0 THEN RETURN; tp.outgoing _ NIL; Triples.Erase[$RnameForTrunk, party, Triples.Any]; }; ENDCASE; }; Register: PUBLIC PROC[shh: SHHH, partyID: PartyHandle, interface: SmartsInterface, properties: ThSmarts.SmartsProperties, oldSmartsID: SmartsHandle] RETURNS [smartsID: SmartsHandle] = { RETURN[DoRegister[ThPartyPrivate.DehandleParty[partyID], NIL, interface, properties]]; }; RegisterLocal: PUBLIC PROC[partyID: PartyHandle, interface: LocalSmartsInterface, properties: ThSmarts.SmartsProperties, oldSmartsID: SmartsHandle] RETURNS [smartsID: SmartsHandle] = { RETURN[DoRegister[ThPartyPrivate.DehandleParty[partyID], interface, NIL, properties]]; }; DoRegister: PROC[party: PartyData, localInterface: LocalSmartsInterface, remoteInterface: SmartsInterface, properties: ThSmarts.SmartsProperties] RETURNS [smartsID: Thrush.SmartsHandle_nullHandle] ={ ENABLE ANY => { smartsID _ Log.ProblemHandle[,$System]; CONTINUE; }; rName: ROPE; smarts: SmartsData; shh: SHHH; interface: SmartsRpc.InterfaceRecord; IF party=NIL THEN RETURN[nullHandle]; IF properties.role = manager THEN { smarts _ NARROW[Triples.Select[$Manager, party, Triples.Any]]; IF smarts#NIL THEN Deregister[shh: none, smartsID: H[smarts]]; }; rName_GetRnameFromParty[IF party.type#trunk THEN party ELSE GetHostParty[party]]; IF rName=NIL THEN RETURN[Log.ProblemHandle["No RName for own party", $System]]; shh _ Names.StartConversation[caller: Names.CurrentRName[], callee: rName, key: Names.CurrentPasskey[], level: --<<ECB>>--CBCCheck ! RPC.AuthenticateFailed => { smartsID _ Log.ProblemHandle["Authenticate failed", $System]; GOTO Failed}]; interface _ IF remoteInterface=NIL THEN localInterface ELSE SmartsRpc.ImportNewInterface[interfaceName: remoteInterface^ ! RPC.ImportFailed => { smartsID _ Log.ProblemHandle["Import failed", $System]; GOTO Failed}]; smarts_NEW[ThPartyPrivate.SmartsBody_[interface: interface, properties: properties, type: party.type, shh: shh, authenticated: FALSE--, remote: remoteInterface#NIL--]]; smartsID _ EnterSmarts[party, smarts]; Log.Report[IO.PutFR["RegisterSmarts[%g, %s] -> [%g, %g]", TU.RefAddr[party], rope[SELECT properties.role FROM voiceTerminal=>"voice", manager=>"mgr", ENDCASE=>"NIY"], card[smartsID], TU.RefAddr[smarts]], $Party, party]; EXITS Failed => smartsID_nullHandle; }; GetHostParty: PROC[party: PartyData] RETURNS [hostParty: PartyData ] = { RETURN[NARROW[Triples.Select[$TrunkParty, Triples.Any, party]]]; }; RegisterClone: PUBLIC PROC[ shh: SHHH_none, partyID: PartyHandle, clonePartyID: PartyHandle, oldSmartsID: SmartsHandle_nullHandle ] RETURNS [smartsID: SmartsHandle] = { cloneParty: PartyData_ThPartyPrivate.DehandleParty[clonePartyID]; party: PartyData _ ThPartyPrivate.DehandleParty[partyID]; cloneSmarts: SmartsData; smData: SmartsData; IF party=NIL OR cloneParty=NIL THEN RETURN[nullHandle]; cloneSmarts _ NARROW[Triples.Select[$VoiceTerminal, cloneParty, -- Smarts --]]; IF cloneSmarts=NIL THEN RETURN[nullHandle]; smData_NEW[ ThPartyPrivate.SmartsBody _ [ interface: cloneSmarts.interface, properties: cloneSmarts.properties, shh: cloneSmarts.shh, authenticated: cloneSmarts.authenticated--, remote: cloneSmarts.remote--]]; smartsID _ EnterSmarts[party, smData]; Log.Report[IO.PutFR["RegisterClone[%g, %g] -> [%g, %g]", TU.RefAddr[party], TU.RefAddr[cloneParty], card[smartsID], TU.RefAddr[smData]], $Party, party]; }; Deregister: PUBLIC ENTRY PROC[shh: SHHH, smartsID: SmartsHandle] = { OPEN Triples; ENABLE { UNWIND => NULL; ANY => { Log.Problem[, $System]; CONTINUE; }; }; party: PartyData; cfRef: CFRef; smarts: SmartsData; CleanupParty: INTERNAL ForeachProc -- [trip: Triples.TripleRec] -- RETURNS [continue: BOOLEAN _ TRUE] -- = { WITH trip.att SELECT FROM r: CFRef => IF (party.numEnabled=0 OR r.voiceSmartsID = smartsID) AND r.event.state#idle THEN { cfRef _ r; [] _ ThPartyPrivate.DoAdvance[ smartsID: smartsID, party: party, conv: NARROW[trip.obj], cfRef: cfRef, state: idle, reason: terminating]; -- Idle party in conversation!! RETURN[FALSE]; }; ENDCASE; }; DeregisterOneParty: INTERNAL ForeachProc -- [trip: TripleRec] -- RETURNS [continue: BOOLEAN _ TRUE] -- = { WITH trip.obj SELECT FROM p: PartyData => party _ p; ENDCASE => RETURN; -- not a party to smarts connection Erase[trip.att, party, smarts -- (trip.val) --]; party.numSmarts _ party.numSmarts - 1; IF smarts.enablesParty THEN party.numEnabled _ party.numEnabled - 1; SELECT NARROW[trip.att, ATOM] FROM $Manager => { adjSmarts: SmartsData=NARROW[Select[$AdjacentTerminal, party, Any]]; Erase[$ManagerOwner, trip.val, Any]; IF adjSmarts#NIL THEN { Erase[$AdjacentTerminal, party, Any]; party.numSmarts _ party.numSmarts - 1; IF adjSmarts.enablesParty THEN party.numEnabled _ party.numEnabled - 1; }; }; ENDCASE; DO cfRef_NIL; Foreach[Any, Any, party, CleanupParty]; IF cfRef = NIL THEN EXIT; ENDLOOP; IF party.numSmarts = 0 THEN { party.partyFailed_TRUE; ThPartyPrivate.Supervise[party]; Log.Report[IO.PutFR["DeleteParty[%g, %g]", card[H[party]], TU.RefAddr[party]], $System]; }; RETURN[FALSE]; }; smarts _ ThPartyPrivate.DehandleSmarts[smartsID]; IF smarts=NIL THEN RETURN; DO -- Outside loop avoids conflict when Deregister erases things. party_NIL; Foreach[Any, Any, smarts, DeregisterOneParty]; IF party = NIL THEN EXIT; ENDLOOP; Log.Report[IO.PutFR["UnregisterSmarts[%g, %g]", card[smartsID], TU.RefAddr[smarts]], $System]; Thrush.KillHandle[smartsID, RTSmartsType! Thrush.HandleFault=>{Log.Problem["Problem killing smarts handle", $System]; CONTINUE}]; }; EnterSmarts: PROC[party: PartyData, smarts: SmartsData] RETURNS[smartsID: SmartsHandle] = { managerOwnerRAtom: ATOM_NIL; EnterSmartsE: ENTRY PROC RETURNS[smartsID: SmartsHandle] = -- INLINE -- { attr: ATOM=WITH props: smarts.properties SELECT FROM backstop=> $BackStop, manager=> $Manager, supervisor=> $Supervisor, voiceTerminal=> $VoiceTerminal, ENDCASE=>ERROR pERROR; smartsID _ Thrush.Enhandle[smarts]; Thrush.MakeUnique[attr, party, smarts]; party.numSmarts _ party.numSmarts + 1; IF smarts.enablesParty THEN party.numEnabled _ party.numEnabled + 1; WITH props: smarts.properties SELECT FROM manager => { OPEN Triples; Thrush.MakeUnique[$ManagerOwner, smarts, managerOwnerRAtom]; WITH Select[$RnameForParty, --party--, managerOwnerRAtom] SELECT FROM managerOwnerParty: PartyData => { mgrOwnSmarts: SmartsData _ NARROW[Select[$VoiceTerminal, managerOwnerParty, --smarts--]]; IF mgrOwnSmarts#NIL THEN { Thrush.MakeUnique[$AdjacentTerminal, party, mgrOwnSmarts]; party.numSmarts _ party.numSmarts + 1; IF mgrOwnSmarts.enablesParty THEN party.numEnabled _ party.numEnabled + 1; }; }; ENDCASE; }; voiceTerminal => IF party.type=individual THEN { OPEN Triples; managerOwnerSmarts: REF; managerOwnerParty: PartyData; managerOwnerRAtom _ NARROW[Select[$RnameForParty, party, -- rAtom --]]; IF managerOwnerRAtom=NIL THEN RETURN; -- This is really an Error, though. managerOwnerSmarts _ Select[$ManagerOwner, --smarts--, managerOwnerRAtom]; IF managerOwnerSmarts=NIL THEN RETURN; managerOwnerParty _ NARROW[Select[$Manager, -- party--, managerOwnerSmarts]]; IF managerOwnerParty=NIL THEN RETURN; Thrush.MakeUnique[$AdjacentTerminal, managerOwnerParty, smarts]; managerOwnerParty.numSmarts _ managerOwnerParty.numSmarts + 1; IF smarts.enablesParty THEN managerOwnerParty.numEnabled _ managerOwnerParty.numEnabled + 1; }; ENDCASE; }; WITH props: smarts.properties SELECT FROM manager => { managerDetails: Names.GVDetails; results: Names.Results; managerOwner: Thrush.Rname; [results,managerDetails]_Names.GetDefaultDetails[props.machine]; IF results=ok AND managerDetails.valid THEN managerOwner _ managerDetails.connect; IF managerOwner#NIL THEN managerOwnerRAtom _ Names.RNameAtom[managerOwner]; }; ENDCASE; RETURN[EnterSmartsE[]]; }; Enable: PUBLIC ENTRY PROC[shh: SHHH_none, smartsID: SmartsHandle] RETURNS [nb: Thrush.NB] = { smarts: SmartsData=ThPartyPrivate.DehandleSmarts[smartsID]; IF smarts=NIL THEN RETURN[noSuchSmarts]; IF smarts.enablesParty THEN RETURN[success]; smarts.enablesParty_TRUE; RETURN[Able[smarts, 1]]; }; Disable: PUBLIC ENTRY PROC[shh: SHHH_none, smartsID: SmartsHandle] RETURNS [nb: Thrush.NB] = { smarts: SmartsData=ThPartyPrivate.DehandleSmarts[smartsID]; IF smarts=NIL THEN RETURN[noSuchSmarts]; IF ~smarts.enablesParty THEN RETURN[success]; smarts.enablesParty_FALSE; RETURN[Able[smarts, -1]]; }; Able: INTERNAL PROC[smarts: SmartsData, direction: INT] RETURNS[nb: Thrush.NB_success] = { AbleOne: Triples.ForeachProc -- [trip: TripleRec] -- RETURNS [continue: BOOLEAN _ TRUE] -- ={ WITH trip.obj SELECT FROM party: PartyData => { res: INT=party.numEnabled+direction; IF res<0 THEN nb_invalidTransition ELSE party.numEnabled _ res; }; ENDCASE; }; Triples.Foreach[Triples.Any, Triples.Any, smarts, AbleOne]; }; DescribeParty: PUBLIC ENTRY PROC[shh: SHHH_none, partyID: PartyHandle] RETURNS[ description: Thrush.ROPE] = { ENABLE UNWIND=>NULL; RETURN[DoDescribeParty[partyID]]; }; DoDescribeParty: PUBLIC INTERNAL PROC[ partyID: PartyHandle ] RETURNS[ description: Thrush.ROPE] = TRUSTED { party: PartyData = ThPartyPrivate.DehandleParty[partyID]; IF party=NIL THEN RETURN[NIL]; description _ GetRnameFromParty[party]; WITH p: party SELECT FROM individual => RETURN[description]; trunk => { more: ROPE=IF p.outgoing#NIL THEN p.outgoing ELSE "outside line"; IF description=NIL THEN description _ more ELSE description _ IO.PutFR["%s (%s)", IO.rope[description], IO.rope[more]]; RETURN[description]; }; recording => RETURN["Recording service"]; ENDCASE; }; GetRnameFromParty: PROC[party: PartyData] RETURNS [rName: Thrush.Rname] = { rRef: REF ANY; IF party=NIL THEN RETURN[NIL]; rRef _ Triples.Select[$RnameForParty, party, --rRef--]; IF rRef=NIL THEN rRef_Triples.Select[$RnameForTrunk, party, --rRef--]; IF rRef=NIL THEN RETURN[NIL]; RETURN[Atom.GetPName[NARROW[rRef]]]; }; GetCurrentParty: PUBLIC ENTRY PROC[shh: Thrush.SHHH_none, smartsID: Thrush.SmartsHandle] RETURNS [partyID: Thrush.PartyHandle_Thrush.nullHandle] = { ENABLE UNWIND=>NULL; smarts: REF _ ThPartyPrivate.DehandleSmarts[smartsID]; IF smarts=NIL THEN RETURN; FOR p: Thrush.Priorities _ standardPriorities, p.rest WHILE p#NIL DO FOR s: Thrush.Priorities _ NARROW[p.first], s.rest WHILE s#NIL DO att: ATOM_NARROW[s.first]; party: REF_Triples.Select[att, Triples.Any, smarts]; IF party#NIL THEN RETURN[H[party]]; ENDLOOP; ENDLOOP; }; GetPartySmarts: PUBLIC ENTRY PROC[partyID: Thrush.PartyHandle, kind: ATOM ] RETURNS [smartsID: Thrush.SmartsHandle]={ ENABLE UNWIND=>NULL; party: PartyData_ThPartyPrivate.DehandleParty[partyID]; IF party=NIL THEN RETURN [Thrush.nullHandle]; RETURN[H[Triples.Select[kind, party, --smarts--]]]; }; ReportSystem: Log.WhereProc = CHECKED { s_Nice.LarkConLogStream[[[0],[0]]]; }; ReportParty: Log.WhereProc = TRUSTED { party: PartyData = NARROW[whereData]; IF party#NIL THEN { smarts: SmartsData = NARROW[Triples.Select[$VoiceTerminal, party, Triples.Any]]; IF smarts#NIL THEN WITH props: smarts.properties SELECT FROM voiceTerminal => s_Nice.LarkConLogStream[props.machine]; ENDCASE; }; IF s=NIL THEN s _ Log.FindWhere[$System, NIL]; }; myName: ThPartyRpcControl.InterfaceName_ [ type: "ThParty.Lark", instance: UserProfile.Token[key: "ThrushServerInstance", default: "Morley.Lark"], version: ThVersions.ThrushVR]; serverPassword: RPC.EncryptionKey = Names.CurrentPasskey[UserProfile.Token[ key: "ThrushServerPassword", default: "MFLFLX"]]; wpState: ThNet.WPState; ThPartyInit: PROC = { ENABLE { RPC.ExportFailed => GOTO Failed; ANY => { Log.Problem["ThParty export failed", $System]; GOTO Failed; }; }; Log.RegisterWhereToReport[ReportSystem, $System]; Log.RegisterWhereToReport[ReportParty, $Party]; wpState _ ThNet.InitWhitePagesDatabase[ UserProfile.Token[key: "ThrushWPTreeName", default: "///Strowger/WPTree"]]; ThPartyRpcControl.ExportInterface[ interfaceName: myName, user: myName.instance, password: serverPassword]; Log.Report[IO.PutFR["Export[ThParty.Lark, %s]", rope[myName.instance]], $System]; EXITS Failed => ThPartyRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE]; }; ThPartyInit[]; }. ��†��ThPartyInitImpl.mesa Last modified by D. Swinehart, May 14, 1984 9:34:47 am PDT Copies Implementation of ThParty |Need an NB return on failure| myExt is used as Intelnet authorization code. Return the Rname for a given party |Need NB indicating why null handle returned.| Party does not already exist. Make one if possible. Get data base information By this time, assume upstream processes have validated, authenticated the rName Telephone system extension Party does not already exist. Make one if possible. Doesn't handle oldHandle (ReRegister) yet. Implementation of ThPartyPrivate |Need NB why failed| Doesn't handle oldHandle (ReRegister) yet. |Need NB why failed| Allow only one Manager. Allow it to be the new one. Take care of encryption, and talking to calling smarts Create Smarts body, link with Party; we're rolling. Remove party from each conversation in which smarts is the voiceSmarts, or to which no enabled smarts remain connected. Outside loop avoids Foreach/Erase conflicts. Party is serving no smarts; destroy the party itself. Discussion: The idea is that as Smarts register with a Party they are connected by links whose attributes are derived from their properties and degree of authentication. When Parties initiate actions that involve Smarts they will select the Smarts to respond in an order determined by the attributes, including SmartsRole, authentication (maybe, see notes), etc. Each kind of Smarts has its own link name to its Party A Manager also needs to know the party to whom the physical workstation belongs, as an aid to locating the corresponding voice terminal. Set up the relationship, then locate the adjacent terminal, if one already exists. When the Manager registers first, the $Adjacent link must be sent when the Lark smarts arrives or dies and revives. A Manager also needs to know the party to whom the physical workstation belongs, as an aid to locating the corresponding voice terminal. Set up the relationship, then locate the adjacent terminal, if one already exists. See if it works just to get the first instance of the highest priority connection that exists, using standardPriorities. | Should have an NB | �Ê[��˜�Jšœ™Jšœ:™:J˜�šÏk ˜ Jšœœ˜"Jšœ œ˜Jšœœ˜&J˜JšœœœN˜ZJ˜%Jšœœs˜~J˜Jšœœ#˜-JšœœC˜LJšœœ˜-šœœ˜JšœOœœKœœœ˜î—JšœœœI˜WJ˜Jšœœn˜‚Jšœ˜J˜Jšœ œ'˜5Jšœœ)˜AJ˜Jšœœ.˜;Jšœœ ˜Jšœœ ˜J˜J˜�—šœ œœ˜)šœ˜ J˜J˜J˜J˜J˜J˜J˜J˜Jšœ˜J˜J˜Jšœ˜J˜J˜J˜J˜J˜Jšœ˜J˜—Jšœ˜šœ˜Jšœœ˜—J˜�—šœ™Jšœœ˜#Jšœ œ˜'Jšœœ˜#Jšœœ˜5šœœÏc˜7Jšœ=œ ˜N—Jšœœž˜;Jšœ œž ˜1Jšœœ œ˜Jšœœž˜9šœœž˜=Jšœ=œ˜O—Jšœœž ˜3Jšœœ˜1Jšœœ˜7J˜3Jšœœ œ˜Jšœœ˜ Jšœœ œ˜Jšœœ˜Jšœœœœœœœ˜JJ˜�Jšœœ ˜J˜/Jšœœœ!˜<J˜�—Jšœ™J˜�šœ(œ˜.Jšœœ œœ˜VJšœœœ˜LJ˜�—š Ïnœœ œœœ,˜UJšœ˜%Jšœœœ˜J™Jšœœ˜$J˜�—šŸœ œ˜2Jšœ˜!Jšœœ˜Jš œœœœœ˜J˜ J˜Jšœœ ž œ˜AJ˜J˜�—š Ÿœœœœœ˜DJšœ)˜0Jš œœ˜Jšœ8˜8Jšœœ˜Jšœ œœœ˜Jšœœ'žœ˜CJ˜=Jšœœ ž œ˜JJš œ œœœœ˜3J˜0Jšœœ˜J˜�—šŸœœ œ˜'Jšœœ-œœ˜?Jšœ)˜0Jšœœœ˜Jšœœ˜Jšœœ˜Jšœ˜šœ8˜8Jšœ'œ˜A—Jšœœœœ˜J˜Jš œœœœœ ˜#Jšœœœœ˜ Jšœ5œ˜BJšœ˜J˜�—šŸœœœœ˜&Jšœœ,œ˜:Jšœ œœ˜!Jšœ˜%Jšœœœ˜JšœD˜JJ˜—J˜�šŸœ œ˜%Jšœ*œ˜/Jšœ œœ˜!Jšœ˜%Jšœœ0œ˜FJšœœœ˜Jšœœœ˜J˜9J™-Jšœœœœœœœœ%˜XJš œœœœœœœ˜FJšœ œœ4˜Kšœœ˜Jšœ œ˜!Jšœ œœž œ ˜GJšœœœ˜4—Jšœ œœ ˜$JšœœK˜SJšœ˜J˜�—šŸ œ œ˜Jšœ*œœ˜EJšœœ˜&Jšœ9˜9Jšœœœœ2˜WJšœœœœ˜ šœœœ˜)šœ ˜ Jšœ œœ!œœœœ˜KJ˜šœ œ˜JšœM˜M——Jšœ0œœ˜FJ˜—J˜J˜�—šŸœœœœ˜DJšœ œ œœ˜=J˜šœ5˜5Jšœ3˜3—šœ œœ$˜7J˜?—J˜J™�—šœ"™"šŸœœœœ˜<Jšœ˜!šœ>˜DJ˜�———š Ÿœœœœœ.˜TJšœ&˜-J™.Jšœœ.œ˜DJšœœ˜Jšœœœœ˜DJšœ œ˜'Jšœ œ˜Jšœœ˜ Jšœœœ˜šŸ œœœžœ˜*Jšœœœ˜Jš œœœœœœž œ ˜Yš œœœœœ˜>JšœHœ˜O—J˜—šŸœœœžœ˜%Jšœ4™4šœ˜˜Jšœœ!˜*J˜FJ˜—Jšœœ ˜6Jšœœœœ˜?Jšœ2œ˜C—Jšœœ˜Jšœœœ+˜<J˜:J˜!šœ˜J˜�——J˜ Jš œœœœœ˜(J˜Jš œœœœœ ˜#J™šœ˜šœ œ˜J™OJšœ™šœœ˜)˜ šœ6œ œ˜M˜$šœœœœ˜FJ˜<Jšœ˜Jšœ˜——Jšœ˜—Jšœ˜—Jšœ˜—šœœœ˜Jšœœ+˜4šœœœ0˜BJšœ˜—J˜—J˜—Jšœ˜—Jšœ4™4Jšœ˜šœœ+˜8šœœ˜"JšœDœœ˜R—Jšœœœœœœ!˜X—šœ˜J˜�——šŸœœœœœœ˜QJšœ9˜9Jšœœœœ˜Jšœœœž0˜Qšœœ˜˜ Jšœœœ˜ Jšœœ4˜EJ˜—Jšœ˜—J˜J˜�—šŸœœœœ3˜RJ˜AJšœ˜$Jšœ*™*Jšœ3œ˜YJ˜�—Jšœ ™ J˜�šŸ œœœ7˜QJ˜AJšœ˜$J™Jšœ*™*Jšœ>œ˜YJ˜�—šŸ œœ8˜HJ˜HJšœ.˜5J™Jšœœ.œ˜DJšœœ˜J˜Jšœœ˜ J˜%Jšœœœœ ˜%šœœ˜#J™3Jšœ œ/˜>Jšœœœ!œ ˜>J˜—Jšœœœœ˜QJšœœœœ7˜OJ˜�Jšœ6™6šœJ˜JJšœ$žœœ˜SJšœ@œ ˜N—šœœœœ˜6šœ@œ˜WJšœ:œ ˜H—J˜�—Jšœ3™3šœœJ˜TJšœ+œœ˜T—Jšœ&˜&˜9J˜Jšœœœ)œ ˜YJšœ4˜4—š˜J˜—Jšœ˜J˜�—šŸœœœ˜HJšœœ6˜CJ˜�—šŸ œœœ˜Jšœœ˜%Jšœ?˜?Jšœœ˜&JšœA˜AJšœ9˜9J˜J˜Jšœœœœœœ ˜7Jšœœ,žœ˜OJšœ œœœ ˜+šœœ˜)˜FJ˜a——Jšœ&˜&˜8JšœO˜OJšœ˜—Jšœ˜J˜�—š Ÿ œœœœœ˜DJšœ ˜ šœ˜Jšœœ˜Jšœœ˜-J˜—J˜J˜ J˜J•StartOfExpansionD -- [trip: Triples.TripleRec] RETURNS [continue: BOOLEAN _ TRUE] -- ˜�šŸœœÐck˜?Jšž(œ˜-šœ œ˜šœ˜šœœœœ˜SJ˜ šœ˜Jšœ˜Jšœ ˜ Jšœœ˜Jšœ ˜ J˜Jšœž˜5—Jšœœ˜J˜——Jšœ˜—J˜J˜�—–D -- [trip: Triples.TripleRec] RETURNS [continue: BOOLEAN _ TRUE] -- šŸœœ ˜=Jš (œ˜-šœ œ˜J˜Jšœœž#˜6—J˜1J˜&Jšœœ)˜Dšœœœ˜"˜ Jšœœ(˜DJ˜$šœœœ˜J˜%J˜&Jšœœ)˜GJ˜—J˜—Jšœ˜—š˜J™¥Jšœœ˜ J˜'Jšœ œœœ˜Jšœ˜—šœœ˜J™5Jšœœ˜Jšœ ˜ Jšœœ#œ'˜XJ˜—Jšœœ˜J˜—J˜�J˜1Jšœœœœ˜šœž>˜AJšœœ˜ Jšœ.˜.Jšœ œœœ˜Jšœ˜—J˜^šœ)˜)JšœLœ˜W—J˜J™�—šŸœœ'œ˜[Jšœ™Jšœ™JšœÀ™ÀJšœœœ˜š Ÿœœœœžœ˜IJ™6šœœœœ˜4J˜Jšœ˜J˜J˜Jšœœ˜—J˜#J˜'Jšœ&˜&Jšœœ)˜DJ˜�šœœ˜)J™Ü˜Jšœ ˜ Jšœ<˜<šœž œœ˜Ešœ!˜!šœ˜Jšœ+ž œ˜>—šœœœ˜Jšœ:˜:J˜&Jšœœ)˜JJ˜—J˜—Jšœ˜—J˜—J™sšœœœ˜0Jšœ ˜ Jšœœ˜Jšœ˜Jšœœžœ˜GJš œœœœž#˜IJšœ+ž œ˜JJšœœœœ˜&Jšœœž œ˜MJšœœœœ˜%Jšœ@˜@Jšœ>˜>šœ˜Jšœ@˜@—J˜—Jšœ˜—J˜J˜�—šœœ˜)J™Ü˜J˜ J˜Jšœ˜J˜@Jšœœœ'˜Ršœœ˜Jšœ2˜2—J˜—Jšœ˜—Jšœ˜J˜—J˜�š Ÿœœœœœ˜AJšœ œ˜J˜;Jšœœœœ˜(Jšœœœ ˜,Jšœœ˜Jšœ˜J˜J™�—š Ÿœœœœœ˜BJšœ œ˜J˜;Jšœœœœ˜(Jšœœœ ˜-Jšœœ˜Jšœ˜J˜—J˜�šŸœœœ œ˜7Jšœœ ˜"šŸœ ˜1Jš (œ˜,šœ œ˜˜Jšœœ˜$Jšœœ˜"Jšœ˜J˜—Jšœ˜—J˜—J˜;J˜—J˜�š Ÿ œœœœœ˜0J˜Jšœœ˜&Jšœœœ˜Jšœ˜!J˜—J˜�šŸœœœœ˜=Jšœœœ˜.J˜9Jš œœœœœ˜Jšœ'˜'šœ œ˜Jšœœ˜"šœ ˜ Jšœœœœœœ˜AJšœ œœ˜*Jšœœœœ ˜LJšœ˜J˜—Jšœ)˜)Jšœ˜—J˜J™�—šŸœœœ˜KJšœœœ˜Jš œœœœœ˜Jšœ-žœ˜7Jšœœœ,žœ˜FJš œœœœœ˜Jšœœ˜'—J˜�J™xšŸœœ œ œ%˜XJšœ4˜;J™Jšœœœ˜Jšœœ+˜6Jšœœœœ˜šœ3œœ˜Dš œœœœ˜AJšœœœ ˜Jšœœ*˜4Jšœœœœ˜#Jšœ˜—Jšœ˜J˜�——š Ÿœœœœ$˜IJšœœ"˜+Jšœœœ˜Jšœ7˜7Jšœœœœ˜-Jšœœž œ˜6J˜�—šœœ˜'Jšœ#˜#J˜J˜�—šœœ˜&Jšœœ˜%šœœœ˜Jšœœ5˜Pšœœœœœ˜<Jšœ8˜8Jšœ˜—J˜—Jšœœœ!˜.J˜J˜�—˜*J˜J˜QJ˜—šœœ8˜KJ˜1J˜�—J˜J˜�šŸœœ˜šœ˜Jšœœ˜ Jšœ5œ˜GJ˜—Jšœ1˜1Jšœ/˜/˜'J˜K—˜"J˜J˜J˜—J˜Qš˜JšœKœ˜U—J˜—J˜�J˜J˜J˜�—�…—����T*��v��