<> <> <> DIRECTORY Atom USING [ GetPName, MakeAtom ], Commander USING [ CommandProc, Register ], CommandTool USING [ NextArgument ], IO, LupineRuntime USING [ BindingError ], MBQueue USING [ Create, Flush ], NamesGV USING [ GVGetAttribute ], NamesRPC USING [ StartConversation ], Nice, RefID USING [ ID, Release, Reseal, Seal ], Rope USING [ Concat, Cat, Length, Substr ], RPC USING [ AuthenticateFailed, EncryptionKey, ExportFailed, ImportFailed ], ThNet USING [ CloseWhitePagesDatabase, HowToDial, InitWhitePagesDatabase, WhitePagesEntry, WPListing, WPState ], ThParty USING [ Credentials, NameReq, SmartsInterfaceName, SmartsInterfaceRecord, SmartsProperties ], ThPartyPrivate USING [ DoAdvance, ConversationData, ConvState, MakeSubstitution, PartyBody, PartyData, SmartsBody, SmartsData, UnsealParty, UnsealSmarts ], ThPartyRpcControl, ThPartyMonitorImpl, Thrush USING [ ConversationID, NB, NetAddress, noAddress, notReallyInConv, nullID, PartyID, PartyType, ROPE, SHHH, SmartsID, unencrypted ], ThSmartsRpcControl USING [ ImportNewInterface ], ThVersions USING [ ThrushVR ], Triples USING [ Any, Erase, Foreach, ForeachProc, Item, Make, Select ], TU USING [ MakeUnique, RefAddr ], VoiceUtils USING [ CmdOrToken, CurrentPasskey, InstanceFromNetAddress, MakeAtom, MakeRName, Registrize, FindWhere, Problem, RegisterWhereToReport, Report, ReportFR, WhereProc ] ; ThPartyInitImpl: CEDAR MONITOR LOCKS root IMPORTS Atom, IO, Commander, CommandTool, LupineRuntime, MBQueue, NamesGV, NamesRPC, Nice, root: ThPartyMonitorImpl, RefID, Rope, RPC, SmartsRpc: ThSmartsRpcControl, ThNet, ThPartyPrivate, ThPartyRpcControl, ThVersions, Triples, TU, VoiceUtils EXPORTS ThParty, ThPartyPrivate SHARES ThPartyMonitorImpl = { OPEN IO; <> NB: TYPE = Thrush.NB; PartyData: TYPE = ThPartyPrivate.PartyData; -- REF Concrete PartyID: TYPE = Thrush.PartyID; -- ID nullID: PartyID = Thrush.nullID; ROPE: TYPE = Thrush.ROPE; SmartsData: TYPE = ThPartyPrivate.SmartsData; -- REF Concrete SmartsID: TYPE = Thrush.SmartsID; -- ID SHHH: TYPE = Thrush.SHHH; none: SHHH = Thrush.unencrypted; Reseal: PROC[r: REF] RETURNS[RefID.ID] = INLINE {RETURN[RefID.Reseal[r]]; }; Any: Triples.Item = Triples.Any; larkRegistry: ROPE=".Lark"; wpState: ThNet.WPState; <> GetParty: PUBLIC ENTRY PROC[shh: SHHH_NIL, partyID: PartyID, rName: Thrush.ROPE, type: Thrush.PartyType_NIL] RETURNS [nb: NB, newPartyID: PartyID] = { ENABLE UNWIND=>NULL; newParty: PartyData; [nb, newParty] _ GetActiveParty[partyID, rName, type]; newPartyID _ Reseal[newParty]; }; GetPartyFromFeepNum: PUBLIC ENTRY PROC[ shh: SHHH_none, partyID: PartyID, feepNum: Thrush.ROPE_NIL] RETURNS [nb: NB_$success, newPartyID: PartyID_nullID] = { ENABLE UNWIND=>NULL; party: PartyData _ NIL; rName: ROPE _ ThNet.WhitePagesEntry [ wpState: wpState, name: feepNum, feep: TRUE, key: $officeNumber].fullRName; IF rName=NIL THEN RETURN[nb: $noEntryFound]; [nb, party] _ GetActiveParty[partyID, rName, NIL]; newPartyID _ Reseal[party]; }; GetPartyFromNumber: PUBLIC ENTRY PROC[ shh: SHHH, partyID: PartyID, phoneNumber: Thrush.ROPE, description: ROPE] RETURNS [nb: NB, newPartyID: PartyID] = { ENABLE UNWIND => NULL; [nb, newPartyID] _ GetPartyFromNumberInt[partyID, phoneNumber, description, FALSE]; }; GetNumbersForRName: PUBLIC PROC[shh: SHHH_none, rName: Thrush.ROPE] 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; }; <<>> GetActiveParty: INTERNAL PROC[partyID: PartyID, rName: Thrush.ROPE, type: Thrush.PartyType] RETURNS [nb: NB_$success, newParty: PartyData_NIL] = { <> party: PartyData _ ThPartyPrivate.UnsealParty[partyID]; [nb, newParty] _ GetActivePartyDo[party, rName, type]; IF nb = $success AND VoiceParty[newParty] = VoiceParty[party] THEN nb_$narcissism; }; VoiceParty: INTERNAL PROC[party: PartyData] RETURNS [voiceParty: PartyData ] = { IF party.type#$individual OR (voiceParty _ NARROW[Triples.Select[$Poaching, party, -- poachee --]]) = NIL THEN voiceParty _ party; }; PartyAvailable: PUBLIC INTERNAL PROC[ownParty: PartyData_NIL, party: PartyData] RETURNS [nb: NB] = { <<$voiceTerminalBusy if party is a $telephone or $individual and corresponding $trunk is in use, or party is a $trunk and the corresponding $telephone is in use.>> <> <> <> relatedParty: PartyData; party _ VoiceParty[party]; IF party=NIL THEN ERROR; SELECT party.type FROM $telephone, $trunk => NULL; ENDCASE => RETURN[$sucess]; [nb, relatedParty] _ GetRelatedParty[party]; -- trunk or telephone corresp. to voice party. IF nb=$convStillActive THEN nb _ IF ownParty#NIL AND relatedParty = VoiceParty[ownParty] THEN $success ELSE $voiceTerminalBusy; }; GetActivePartyDo: INTERNAL PROC[party: PartyData, rName: Thrush.ROPE, type: Thrush.PartyType] RETURNS [nb: NB_$success, newParty: PartyData_NIL] = { number: ROPE; listing: ThNet.WPListing; wpRname: ROPE; partyID: PartyID; partyID _ Reseal[party]; IF rName=NIL THEN RETURN[$noIdentSupplied, NIL]; IF type = NIL THEN { -- request for $individual or $telephone [nb, newParty] _ GetActiveParty[partyID, rName, $individual]; IF nb # $success THEN [nb, newParty] _ GetActiveParty[partyID, rName, $telephone]; RETURN; }; SELECT type FROM $service => { [nb, newParty] _ GetIdleParty[partyID, rName]; RETURN; }; $individual, $telephone => NULL; -- go on $trunk => ERROR; -- until further notice ENDCASE => ERROR; newParty _ NARROW[ Triples.Select[type, VoiceUtils.MakeAtom[VoiceUtils.Registrize[rName]], --party-- ] ]; IF newParty#NIL AND newParty.enabled THEN { SetPoaching[newParty]; nb _ PartyAvailable[party, newParty]; RETURN; }; IF type # $telephone THEN RETURN[nb: $noSuchParty2]; <> [wpRname, number, listing] _ ThNet.WhitePagesEntry [ wpState: wpState, name: rName, key: $officeNumber]; IF wpRname=NIL OR listing=NIL THEN RETURN[nb: $noSuchParty2]; IF number=NIL THEN number _ ThNet.WhitePagesEntry [ wpState: wpState, name: rName, key: $homeNumber, listing: listing].entry; IF number=NIL THEN RETURN[nb: $noSuchParty2]; [nb, partyID] _ GetPartyFromNumberInt[Reseal[party], number, wpRname, TRUE]; IF nb=$success THEN newParty _ ThPartyPrivate.UnsealParty[partyID]; }; GetIdleParty: INTERNAL PROC[partyID: PartyID, serviceName: ROPE] RETURNS [nb: NB_$success, newParty: PartyData _ NIL] = { <> <<<>>> ENABLE UNWIND=>NULL; party: PartyData_ ThPartyPrivate.UnsealParty[partyID]; myName: ROPE; rAtom: ATOM; serviceNameAtom: ATOM = MakeServiceRname[serviceName].serviceRnameAtom; <> IF party = NIL THEN RETURN[nb: $noSuchParty]; [nb, myName,] _ GetRnameFromParty[party]; <> IF nb # $success THEN RETURN[nb: nb, newParty: NIL]; rAtom _ VoiceUtils.MakeAtom[Rope.Cat[myName, ".", serviceName]]; <> newParty _ NARROW[Triples.Select[$service, serviceNameAtom, --party--]]; IF newParty = NIL OR ~newParty.enabled THEN nb_$noSuchParty2 -- e.g., all channels busy ELSE TU.MakeUnique[$service, rAtom, newParty]; -- $service[$"myself.pa.t..."] = }; GetPartyFromNumberInt: INTERNAL PROC[ partyID: PartyID, phoneNumber: Thrush.ROPE, description: ROPE, trunkRequired: BOOL] RETURNS [nb: NB_$success, newPartyID: PartyID_nullID] = { <> isExt: BOOLEAN _ FALSE; num: ROPE _ NIL; party: PartyData _ ThPartyPrivate.UnsealParty[partyID]; trunkParty: PartyData; myExtAtom: ATOM; myExt: ROPE; <> IF party=NIL THEN RETURN[$noSuchParty, nullID]; myExtAtom _ GetRnameFromParty[party, $current].rAtom; -- rName for party. myExtAtom _ IF myExtAtom=NIL THEN NIL ELSE NARROW[Triples.Select[$Extension, myExtAtom, -- extension --]]; myExt _ IF myExtAtom=NIL THEN NIL ELSE Atom.GetPName[myExtAtom]; <> <> [num, isExt] _ ThNet.HowToDial[phoneNumber, myExt]; IF isExt AND ~trunkRequired THEN { atom: ATOM_Atom.MakeAtom[num]; -- phone extension IF atom #NIL THEN atom _ NARROW[Triples.Select[$Extension, --party--, atom]]; IF atom#NIL THEN { newParty: PartyData; [nb, newParty]_ GetActiveParty[partyID, Atom.GetPName[atom], NIL]; newPartyID _ Reseal[newParty]; IF nb = $success OR nb = $narcissism THEN RETURN; }; }; <> [nb, trunkParty] _ GetRelatedParty[party]; -- trunk if telephone/individual, or vice/versa IF nb # $success THEN { party _ NARROW[Triples.Select[$Poaching, party, -- poachee--]]; IF party#NIL THEN [nb, trunkParty] _ GetRelatedParty[party]; }; IF nb # $success THEN RETURN; trunkParty.outgoing _ num; trunkParty.reservedBy _ partyID; trunkParty.name _ description; -- starts out as name of trunk owner, changes on first use newPartyID _ Reseal[trunkParty]; }; GetRelatedParty: INTERNAL PROC[party: PartyData] RETURNS [nb: NB, relatedParty: PartyData_NIL] = { rAtom: ATOM; [nb,,rAtom]_GetRnameFromParty[party, $owner]; IF nb # $success THEN RETURN; -- VERY strange SELECT party.type FROM $individual, $telephone => relatedParty _ NARROW[Triples.Select[$trunk, rAtom, -- trunk party --]]; $trunk => relatedParty _ NARROW[Triples.Select[$telephone, rAtom, -- telephone party --]]; ENDCASE; IF relatedParty = NIL THEN nb _ $noRelatedParty ELSE IF relatedParty.numConvs#0 THEN nb _ $convStillActive -- busy ELSE IF ~relatedParty.enabled THEN nb _ $noSuchParty2; -- not available yet }; <> <<>> Register: PUBLIC PROC[ shh: SHHH_none, rName: ROPE_NIL, -- party identification type: Thrush.PartyType _ $individual, clonePartyID: PartyID, interface: ThParty.SmartsInterfaceName, -- interface properties: ThParty.SmartsProperties ] RETURNS [ nb: NB, credentials: ThParty.Credentials_[] ] = { [nb, credentials] _ DoRegister[rName, type, clonePartyID, interface, NIL, properties]; }; RegisterLocal: PUBLIC PROC[ shh: SHHH_none, rName: ROPE_NIL, -- party identification type: Thrush.PartyType _ $individual, clonePartyID: PartyID, interfaceRecord: ThParty.SmartsInterfaceRecord _ NIL, properties: ThParty.SmartsProperties ] RETURNS [ nb: NB, credentials: ThParty.Credentials_[] ] = { [nb, credentials] _ DoRegister[rName, type, clonePartyID, [ ], interfaceRecord, properties]; }; DoRegister: PROC[ rName: ROPE_NIL, -- party identification type: Thrush.PartyType _ $individual, clonePartyID: PartyID, interface: ThParty.SmartsInterfaceName, -- interface interfaceRecord: ThParty.SmartsInterfaceRecord, properties: ThParty.SmartsProperties ] RETURNS [ nb: NB, credentials: ThParty.Credentials_[] ] = { hostAtom: ATOM = VoiceUtils.MakeAtom[ VoiceUtils.InstanceFromNetAddress[properties.netAddress, Atom.GetPName[type]]]; smarts: SmartsData_NARROW[Triples.Select[$SmartsForHost, hostAtom, -- smarts --]]; party: PartyData; partyToSmartsShh: SHHH _ none; IF clonePartyID#nullID THEN [nb, credentials] _ RegisterClone[clonePartyID]; IF smarts#NIL THEN { <> <> nb_Deregister[none, Reseal[smarts]]; IF nb # $success THEN RETURN; }; IF rName=NIL THEN RETURN[nb: $noIdentSupplied]; IF interfaceRecord=NIL THEN { partyToSmartsShh _ NamesRPC.StartConversation[ caller: serverInterfaceName.instance, callee: rName, key: serverPassword, level: --<>--CBCCheck ! RPC.AuthenticateFailed => { VoiceUtils.Problem["Authenticate failed", $System]; CONTINUE}]; IF partyToSmartsShh=NIL THEN RETURN[nb: $couldntAuthenticate]; interfaceRecord _ SmartsRpc.ImportNewInterface[ interfaceName: interface ! RPC.ImportFailed => { VoiceUtils.Problem["Import failed", $System]; CONTINUE}]; IF interfaceRecord=NIL THEN RETURN[nb: $couldntConnect]; }; { RegisterEntry: ENTRY PROC={ [nb, party] _ CreateParty[rName, type]; IF nb#$success THEN RETURN; <> smarts_NEW[ThPartyPrivate.SmartsBody_[ properties: properties, type: type, interface: interfaceRecord, shh: partyToSmartsShh, notifications: MBQueue.Create[] ]]; TU.MakeUnique[$Smarts, party, smarts]; TU.MakeUnique[$SmartsForHost, hostAtom, smarts]; credentials.partyID _ RefID.Reseal[party]; credentials.smartsID _ RefID.Seal[smarts]; SetPoaching[party]; -- This is recomputed on every GetParty, included here for debugging ease. }; RegisterEntry[]; }; VoiceUtils.Report[IO.PutFR["Register[%g, %g, %g] -> [%g, %g]", rope[rName], atom[type], TU.RefAddr[ThPartyPrivate.UnsealParty[clonePartyID]], TU.RefAddr[party], TU.RefAddr[smarts]]]; }; CreateParty: INTERNAL PROC[rName: Thrush.ROPE, type: Thrush.PartyType] RETURNS [nb: NB_$success, party: PartyData_NIL] = { <> partyRname: Thrush.ROPE = IF type # $service THEN rName ELSE MakeServiceRname[rName].serviceRname; partyID: PartyID_nullID; rAtom: ATOM=VoiceUtils.MakeAtom[partyRname]; extension: ATOM_NIL; IF partyRname=NIL THEN RETURN[nb: $noIdentSupplied]; IF type # $service THEN party_ NARROW[Triples.Select[type, rAtom, --party--]]; IF party#NIL THEN RETURN[$success, party]; party _ NEW[ThPartyPrivate.PartyBody _ [type: type, name: rName]]; SELECT type FROM $individual, $telephone, $service => { -- Local telephone number num: ROPE_GetNumbersForRName[rName: partyRname].number; party.outgoing _ num; IF num#NIL AND ~(([num,]_ThNet.HowToDial[num]).isLocalExtension) THEN num_NIL; IF num#NIL THEN extension _ VoiceUtils.MakeAtom[num]; }; ENDCASE; partyID _ RefID.Seal[party]; TU.MakeUnique[type, rAtom, party]; IF extension#NIL THEN TU.MakeUnique[$Extension, rAtom, extension]; }; SetPoaching: INTERNAL PROC[party: PartyData, callingParty: PartyData_NIL] = { poacher, poachee: PartyData_NIL; tempParty: PartyData _ NIL; rName: ROPE _ party.name; smarts: REF; workstation: ATOM; wsName: ROPE; nb: NB; {SELECT party.type FROM $individual => { poacheeID: PartyID; poacher_party; IF (smarts _ Triples.Select[$Smarts, poacher, -- smarts --]) = NIL THEN { VoiceUtils.Problem["No smarts connection?"]; RETURN; }; IF (workstation _ NARROW[Triples.Select[$SmartsForHost,-- host--,smarts]]) = NIL THEN { VoiceUtils.Problem["No SmartsForHost?"]; RETURN; }; wsName _ Atom.GetPName[workstation]; -- $"3#456#individual" => wsName _ wsName.Substr[len: wsName.Length[]-Rope.Length["individual"]]; wsName _ wsName.Concat[larkRegistry]; -- "3#456#.lark" IF (rName _ NamesGV.GVGetAttribute[wsName, $owner, NIL]) = NIL THEN GOTO Done; poachee _ NARROW[Triples.Select[$telephone, VoiceUtils.MakeAtom[rName], --party--]]; IF poachee#NIL OR callingParty=NIL THEN GOTO Done; <> IF party.outgoing = NIL THEN GOTO Done; -- No phone number? [nb, poacheeID] _ GetPartyFromNumberInt[ partyID: Reseal[callingParty], phoneNumber: party.outgoing, description: rName, trunkRequired: TRUE ]; IF nb#$success OR poacheeID=nullID THEN GOTO Done; poachee _ ThPartyPrivate.UnsealParty[poacheeID]; }; $telephone => { wsRope: ROPE _ NamesGV.GVGetAttribute[rName.Concat[larkRegistry], $workstationhost, NIL]; workstation _ VoiceUtils.MakeAtom[wsRope.Concat["individual"]]; IF workstation = NIL THEN GOTO Done; poachee_party; IF (smarts _ Triples.Select[$SmartsForHost, workstation,-- smarts--])= NIL THEN GOTO Done; poacher _ NARROW[Triples.Select[$Smarts, -- party --, smarts]]; IF poacher = NIL THEN { VoiceUtils.Problem["No smarts connection?"]; RETURN; }; }; ENDCASE=>RETURN; EXITS Done => NULL; }; <> IF poachee#NIL THEN { tempParty _ NARROW[Triples.Select[$Poaching, Any, poachee]]; IF tempParty#NIL AND tempParty.enabled AND poacher=tempParty AND poacher.enabled THEN RETURN; -- Already set up as desired ThPartyPrivate.MakeSubstitution[oldParty: tempParty, newParty: poachee]; -- If tempParty#NIL Triples.Erase[$Poaching, Any, poachee]; }; IF poacher#NIL THEN { tempParty _ NARROW[Triples.Select[$Poaching, poacher, Any]]; ThPartyPrivate.MakeSubstitution[oldParty: poacher, newParty: tempParty]; -- See MakeSubstitution Triples.Erase[$Poaching, poacher, Any]; }; IF poacher=NIL OR poachee=NIL OR ~poacher.enabled OR ~poachee.enabled THEN RETURN; Triples.Make[$Poaching, poacher, poachee]; ThPartyPrivate.MakeSubstitution[oldParty: poachee, newParty: poacher]; }; RegisterClone: ENTRY PROC[clonePartyID: PartyID] RETURNS [nb: NB, credentials: ThParty.Credentials_[]] = { cloneParty: PartyData_ThPartyPrivate.UnsealParty[clonePartyID]; party: PartyData _ NEW[ThPartyPrivate.PartyBody _ [type: cloneParty.type, name: cloneParty.name]]; cloneSmarts, smarts: SmartsData; IF cloneParty=NIL THEN RETURN[nb: $noSuchParty]; cloneSmarts _ NARROW[Triples.Select[$Smarts, cloneParty, -- Smarts --]]; IF cloneSmarts=NIL THEN { VoiceUtils.Problem["No Smarts for party?"]; RETURN[nb: $noSuchSmarts]; }; smarts_NEW[ ThPartyPrivate.SmartsBody _ [ properties: cloneSmarts.properties, type: cloneSmarts.type, interface: cloneSmarts.interface, shh: cloneSmarts.shh ]]; Triples.Make[$Smarts, party, smarts]; credentials.partyID _ RefID.Seal[party]; credentials.smartsID _ RefID.Seal[smarts]; <> VoiceUtils.Report[IO.PutFR["RegisterClone[%g, %g] -> [%g, %g]", TU.RefAddr[party], TU.RefAddr[cloneParty], card[credentials.smartsID], TU.RefAddr[smarts] ], $Party, party]; }; Enable: PUBLIC ENTRY PROC[shh: SHHH_none, smartsID: SmartsID] RETURNS [nb: Thrush.NB] = { RETURN[Able[smartsID, TRUE]]; }; <<>> Disable: PUBLIC ENTRY PROC[shh: SHHH_none, smartsID: SmartsID] RETURNS [nb: Thrush.NB] = { RETURN[Able[smartsID, FALSE]]; }; Able: INTERNAL PROC[smartsID: SmartsID, enabling: BOOL] RETURNS[nb: Thrush.NB_$success] = { smarts: SmartsData=ThPartyPrivate.UnsealSmarts[smartsID]; party: PartyData; IF smarts=NIL THEN RETURN[$noSuchSmarts]; IF (party_NARROW[Triples.Select[$Smarts, --party--, smarts]])=NIL THEN RETURN[$noSuchParty]; party.enabled_ smarts.enablesParty_ enabling; SetPoaching[party]; }; <> <<>> Deregister: PUBLIC ENTRY PROC[shh: SHHH, smartsID: SmartsID] RETURNS [nb: NB _ $success] = { <> <> <<$Visiting implementations and hints for implementations are only suggestions, for now.>> ENABLE UNWIND => NULL; party: PartyData; smarts: SmartsData _ ThPartyPrivate.UnsealSmarts[smartsID]; IF smarts=NIL THEN RETURN[$noSuchSmarts]; party _ NARROW[Triples.Select[$Smarts, --party--, smarts]]; IF party#NIL THEN { IF party.type # $individual THEN IdleConversationsForParty[party, smartsID] ELSE { newParty: PartyData; SetPoaching[party]; newParty _ NARROW[Triples.Select[$Poaching, party, Triples.Any]]; IF newParty#NIL AND newParty.type=$telephone THEN ThPartyPrivate.MakeSubstitution[party, newParty]; }; <> EraseAsObjOrVal[party]; VoiceUtils.ReportFR[ "DeleteParty[%g, %g]", $System, NIL, card[Reseal[party]], TU.RefAddr[party]]; IF ~RefID.Release[Reseal[party]] THEN nb _ $noSuchParty; -- ?? } ELSE nb _ $noSuchParty; EraseAsObjOrVal[smarts]; smarts.failed _ TRUE; smarts.notifications.Flush[]; -- Abandon progress-report queue VoiceUtils.ReportFR[ "UnregisterSmarts[%g, %g]", $System, NIL, card[smartsID], TU.RefAddr[smarts]]; IF ~RefID.Release[smartsID] THEN ERROR; -- Having successfully dehandled above! }; IdleConversationsForParty: INTERNAL PROC[party: PartyData, smartsID: SmartsID] = { convState: ThPartyPrivate.ConvState_NIL; IdleOneConv: Triples.ForeachProc -- [trip: TripleRec] -- RETURNS [continue: BOOLEAN _ TRUE] -- ={ WITH trip.att SELECT FROM r: ThPartyPrivate.ConvState => convState _ r; ENDCASE => RETURN[TRUE]; IF convState.state<= Thrush.notReallyInConv THEN { convState _ NIL; RETURN[FALSE]; }; [--nb, convEvent; do your best, I guess.--] _ ThPartyPrivate.DoAdvance[ credentials: [ partyID: Reseal[party], smartsID: smartsID, -- This is very questionable convID: NARROW[trip.obj, ThPartyPrivate.ConversationData].convID, state: convState.state, stateID: convState.stateID ], state: $idle, reportToAll: TRUE, reason: $terminating, newInConv: FALSE ]; -- Idle party in conversation!! RETURN[FALSE]; }; IdleRelated: INTERNAL Triples.ForeachProc -- [trip: TripleRec] -- RETURNS [continue: BOOLEAN _ TRUE] -- = { IdleConversationsForParty[NARROW[trip.obj], smartsID]; }; <> DO convState_NIL; Triples.Foreach[Any, Any, party, IdleOneConv]; IF convState = NIL THEN EXIT; ENDLOOP; <> <<This is still bogus. It won't work as well as older systems at dealing properly with Finch dropping out. >> Triples.Foreach[$Poaching, Any, party, IdleRelated]; Triples.Foreach[$Visiting, Any, party, IdleRelated]; }; DescribeParty: PUBLIC PROC[partyID: Thrush.PartyID, nameReq: ThParty.NameReq] RETURNS[nb: NB, description: Thrush.ROPE] = { a: ATOM; [nb, description, a] _ GetRnameFromParty[ThPartyPrivate.UnsealParty[partyID], nameReq]; }; <> <<>> DoDescribeParty: PUBLIC PROC[ party: PartyData, nameReq: ThParty.NameReq ] RETURNS[ description: Thrush.ROPE_NIL] = { type: Thrush.PartyType _ party.type; DescribeTrunk: PROC RETURNS[des: ROPE] = INLINE { more: ROPE=IF party.outgoing#NIL THEN party.outgoing ELSE "outside line"; des _ IF party.name=NIL THEN more ELSE IO.PutFR["%s (%s)", IO.rope[party.name], IO.rope[more]]; }; Sel: PROC[type: Thrush.PartyType, party: PartyData] RETURNS [name: Thrush.ROPE] = { a: ATOM _ NARROW[Triples.Select[$trunk, -- owner --, party]]; RETURN[IF a=NIL THEN NIL ELSE Atom.GetPName[a]]; }; IF nameReq=$none THEN RETURN; description _ SELECT type FROM $individual, $telephone => party.name, $trunk => (SELECT nameReq FROM $owner => Sel[$trunk, party], $description => DescribeTrunk[], $current => party.name, $address => party.outgoing, ENDCASE=>ERROR), $service => (SELECT nameReq FROM $owner => party.name.Concat[larkRegistry], $description => IO.PutFR["%g service", rope[party.name]], $current, $address => Sel[$service, party], ENDCASE=>ERROR), ENDCASE => ERROR; }; <<>> GetRnameFromParty: PUBLIC PROC[party: PartyData, nameReq: ThParty.NameReq_$current] RETURNS [nb: NB_$success, rName: Thrush.ROPE_NIL, rAtom: ATOM_NIL] = { <> IF party=NIL THEN RETURN[nb: $noSuchParty]; rName _ DoDescribeParty[party, nameReq]; IF rName=NIL THEN nb _ $noNameAvailable ELSE rAtom _ VoiceUtils.MakeAtom[rName]; }; MakeServiceRname: PUBLIC PROC[serviceName: Thrush.ROPE] RETURNS [serviceRname: Thrush.ROPE, serviceRnameAtom: ATOM] = { serviceRname _ Rope.Cat[serviceName, larkRegistry]; serviceRnameAtom _ VoiceUtils.MakeAtom[serviceRname]; }; <> GetCurrentParty: PUBLIC ENTRY PROC[shh: Thrush.SHHH_none, smartsID: Thrush.SmartsID] RETURNS [nb: NB_$success, partyID: Thrush.PartyID_Thrush.nullID] = { smarts: REF _ ThPartyPrivate.UnsealSmarts[smartsID]; party: PartyData; p: PartyData; IF smarts=NIL THEN RETURN[nb: $noSuchSmarts]; party _ NARROW[Triples.Select[$Smarts, --party--, smarts]]; IF party#NIL AND ~party.enabled THEN RETURN[nb: $noSuchParty]; IF party=NIL THEN { VoiceUtils.Problem["No party?"]; RETURN[nb: $noSuchParty]; }; SetPoaching[party]; -- make sure $Poaching link is correct IF (p_NARROW[Triples.Select[$Poaching, -- poacher --, party]])#NIL AND p.enabled THEN party _ p; partyID _ Reseal[party]; }; EraseAsObjOrVal: INTERNAL PROC[ref: REF] = { Triples.Erase[Any, ref, Any]; Triples.Erase[Any, Any, ref]; }; <> <> <<>> ReportSystem: VoiceUtils.WhereProc = { s_NIL; }; ReportParty: VoiceUtils.WhereProc = { party: PartyData = NARROW[whereData]; smarts: SmartsData; IF party=NIL OR ( smarts _ NARROW[Triples.Select[$VoiceTerminal, party, Any]] ) = NIL THEN RETURN; SELECT smarts.properties.role FROM $voiceTerminal => s_Nice.LarkConLogStream[smarts.properties.netAddress]; ENDCASE; IF s=NIL OR s=Nice.LarkConLogStream[Thrush.noAddress] THEN s_VoiceUtils.FindWhere[$System, NIL]; }; WhitePagesInit: Commander.CommandProc = { treeName, intExtName: ROPE; IF wpState#NIL AND ThNet.CloseWhitePagesDatabase[wpState] THEN wpState_NIL; treeName _ CommandTool.NextArgument[cmd]; intExtName _ CommandTool.NextArgument[cmd]; IF wpState=NIL THEN wpState _ ThNet.InitWhitePagesDatabase[ treeName, -- Optional, defaults supplied by WP impl., intExtName, -- so NILs are OK here $write]; }; serverInterfaceName: ThPartyRpcControl.InterfaceName; serverPassword: RPC.EncryptionKey; ThPartyInit: Commander.CommandProc = { ENABLE RPC.ExportFailed => { VoiceUtils.Problem["ThParty export failed", $System]; GOTO Failed; }; instance: ROPE = VoiceUtils.MakeRName[style: rName, name: VoiceUtils.CmdOrToken[cmd: cmd, key: "ThrushServerInstance", default: "Strowger.Lark"]]; serverInterfaceName _ [ type: "ThParty.Lark", instance: instance, version: ThVersions.ThrushVR]; serverPassword _ VoiceUtils.CurrentPasskey[VoiceUtils.CmdOrToken[ cmd: cmd, key: "ThrushServerPassword", default: "MFLFLX"]]; VoiceUtils.RegisterWhereToReport[ReportSystem, $System]; VoiceUtils.RegisterWhereToReport[ReportParty, $Party]; ThPartyRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE]; ThPartyRpcControl.ExportInterface[ interfaceName: serverInterfaceName, user: instance, password: serverPassword]; VoiceUtils.ReportFR["Export[ThParty.Lark, %s]", $System, NIL, rope[serverInterfaceName.instance]]; EXITS Failed => ThPartyRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE]; }; Commander.Register["WhitePages", WhitePagesInit, "WhitePages > -- Initialize and Open White Pages Database"]; Commander.Register["ThParty", ThPartyInit, "ThParty \nInitialize and Export ThParty"]; }. <<>> <> <> <> <> <> <> <> <> < service>> < serviceName, to generalize>> <> <> <> <> <> <> < ID, NamesAndLog => VoiceUtils>> <> <<>> <<>> <> <> <> <<>> <<>> <<>> <> <> <> <<>> <> <> <> <<>>