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] = { 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] = { 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; 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"]; }. œThPartyInitImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Last modified by D. Swinehart, May 31, 1986 4:28:36 pm PDT Definitions Functions for obtaining existing parties, or phone numbers Obtains a $service, $individual, or $telephone party, if available $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. Except $success when ownParty is present and equals the corresponding party. This represents an attempt to call one's own front door from the back or vice/versa, and is legal. nb can take on other values if problems occur in obtaining the related party. This is an Etherphone implementation-dependent thing -- front and back doors cannot be in use for independent reasons at simultaneously -- and we are sore ashamed. No active party; try to get a trunk line for that individual Locates an idle $service party, if available <> e.g., $"text-to-speech.lark" e.g., $"myself.pa" e.g., $"myself.pa.text-to-speech" Party description has not yielded a party, so phone number will have to do. Perhaps the phone number is an extension of an active $individual; if not, try to find an idle outgoing trunk. myExt is used as Intelnet authorization code. IF phoneNumber = NIL THEN RETURN[$noIdentSupplied, nullID]; A null phoneNumber is a request for a direct outside line connection. Get Trunk Party Making new parties and smartses Deregister any previous smarts from this machine. When cloning to produce multiple smarts and parties for a multi-channel service, obviously don't want to do this. Multi-channel services must deregister explicitly, since this won't handle it. Includes setting RName access, poaching and visiting designations. rName is a misnomer; it's the name of a service, without registry, if type is service. There's no voice path for this individual. Try to create one using calling party's trunk. Splice in poachees for poachers in any relationships that are ending, poachers for poachees in any that are beginning. No HostForSmarts entry is made for clones. What should happen here anyhow? Deregister Smarts from Party, destroy both There's but one party per smarts, these days. When the Smarts goes, so goes the party. For the most part, we can (after idling all the conversations in which the party participates) merely erase all the interconnections between the party and smarts and other objects, and release their ID's. Don't hang up calls for $individual parties with valid poachees, since a poachee can carry on a conversation by itself. $Visiting implementations and hints for implementations are only suggestions, for now. Transfer $Visitors from authenticated to assumed. Idle any conversations in which the party is involved. Outside loop avoids Foreach/Erase conflicts. Apply the process recursively to poachers and visitors: if a poacher is in a conversation, the poachee is not recorded as being in the same one; similarly for visitors, at least at present. But the poachee or visitee is always vital to the conversation's existence, so out it goes. This is still bogus. It won't work as well as older systems at dealing properly with Finch dropping out.  ThPartyPrivate Implementations Returns (bogus) service name if type = $service Which party should we be when initiating calls? Service Action Registration Initialization Log Swinehart, May 15, 1985 10:24:49 am PDT Cedar 6.0 changes to: larkRegistry, GetParty, GetActiveParty, GeIdleParty, CreateParty, NewParty Swinehart, May 16, 1985 9:18:28 am PDT CommandToolExtras zapped. Swinehart, May 22, 1985 12:01:41 pm PDT ServiceName changes recording => service Jay => serviceName, to generalize individual and service treated similarly in places changes to: GetIdleParty, CreateParty, NewParty, DoDescribeParty, MakeServiceRname changes to: CreateParty, ExistingParty, NewParty, DoDescribeParty changes to: GetIdleParty changes to: CreateParty, ExistingParty, NewParty Swinehart, October 25, 1985 6:45:23 pm PDT Handle => ID, NamesAndLog => VoiceUtils changes to: DIRECTORY, ThPartyInitImpl, GetActiveParty, GetIdleParty, CreateParty, ExistingParty, DoRegister, RegisterClone, Deregister, EnterSmarts, MakeServiceRname, GetStdRingInfo, ReportSystem, ReportParty, ThPartyInit, ConversationID, PartyID, SmartsID, nullID, Reseal, GetParty, GetPartyFromFeepNum, GetPartyFromNumber, GetPartyFromNumberInt, GetTrunkParty, GetRname, Register, RegisterLocal, EnterSmartsE (local of EnterSmarts), Enable, Disable, DescribeParty, DoDescribeParty, GetCurrentParty, GetPartySmarts, SetStdRingInfo, SetRingEnable, NewParty Swinehart, October 29, 1985 5:55:37 pm PST Major revisions for visiting and poaching. See design document. changes to: CreateParty, Register, RegisterLocal, DoRegister, EnterSmarts, Able, Deregister, PrepareRingTune, GetPartyFromNumber, GetRname, DescribeParty, GetActiveParty, GetIdleParty, GetPartyFromNumberInt, GetTrunkParty, Deregister, Deregister, EraseAsObj, Deregister Swinehart, December 11, 1985 3:29:30 pm PST Just improve comments changes to: GetRelatedParty, SetPoaching Swinehart, May 17, 1986 5:38:13 pm PDT Cedar 6.1 changes to: DIRECTORY, DoRegister, ReportParty Κˆ˜Jšœ™šœ Οmœ7™BJšœ:™:J˜—šΟk ˜ Jšœžœ˜"Jšœ žœ˜*Jšœ žœ˜#J˜Jšœžœ˜%Jšœžœ˜ Jšœžœ˜!Jšœ žœ˜%J˜Jšœžœžœ˜*Jšœžœ!˜+JšžœžœC˜LJšœžœžœb˜pJšœe˜eJšœžœ‡˜›Jšœ˜J˜šœžœ˜JšœžœFžœžœ˜|—Jšœžœ˜0J˜Jšœžœ:˜GJšžœžœ˜!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šœ žœΟc˜;šœ žœŸ˜%J˜ —Jšžœžœ žœ˜Jšœ žœŸ˜=Jšœ žœŸ˜'šžœžœ žœ˜Jšœžœ˜ —JšΟnœžœžœžœžœžœžœ˜LJ˜ J˜Jšœžœ ˜J˜J˜J˜—™:J˜š  œžœž œžœžœ˜šœ/˜/Jšœžœ˜.Jšœ0žœ˜;—Jšžœžœžœžœ˜8J˜—JšΟbΠbn ‘Πbk‘£‘˜Jšœ'˜'šžœ žœžœ˜JšœB™B—šœžœ˜&Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšžœ$˜&Jšžœ.˜0J˜*J˜*JšœŸJ˜_Jš‘˜šœ>˜>J˜NJ˜(—J˜J˜—š  œžœžœžœ˜FJšžœžœžœ˜3J™VJš œžœžœžœžœ&˜bJ˜Jšœžœ!˜,Jšœ žœžœ˜Jšžœ žœžœžœ˜4JšžœžœžœŸ œ˜NJšžœžœžœžœ˜*Jšœžœ7˜Bšžœž˜šœ'Ÿ˜@Jšœžœ.˜7Jšœ˜Jš žœžœžœ3žœžœ˜NJšžœžœžœ&˜5J˜—Jšžœ˜—J˜Jšžœ ˜"Jšžœ žœžœžœ*˜BJšœ˜J˜—š  œžœžœ+žœ˜MJšœžœ˜ Jšœžœ˜Jšœžœ˜Jšœžœ˜ Jšœ žœ˜Jšœžœ˜ Jšœžœ˜š‘žœ ž˜˜J˜J˜šžœ,Ÿ œžœžœ˜IJšœ-žœ˜7—š žœžœŸ œ žœžœ˜WJšœ)žœ˜3—Jšœ%Ÿ˜>J˜GJšœ(Ÿ˜8Jš žœ1žœžœžœžœ˜NJšœ žœ8Ÿ œ˜TJš žœ žœžœ žœžœ˜2JšΟtZ™ZJš žœžœžœžœŸ˜=˜(J˜J˜J˜Jšœž˜Jšœ˜—Jšžœ žœžœžœ˜2J˜0J˜—˜šœ˜JšœEžœ˜J—J˜?Jšžœžœžœžœ˜$J˜Jš žœ6Ÿ œžœžœžœ˜ZJšœ žœ/˜?Jšžœ žœžœ0žœ˜OJ˜—Jšžœžœ˜—Jšžœ‘œžœ‘œ˜™všžœ žœžœ˜Jšœ žœ*˜<š žœ žœžœžœžœ˜PJšžœžœŸ˜)—JšœIŸ˜\J˜'J˜—šžœ žœžœ˜Jšœ žœ*˜Jšžœ žœžœžœ˜=—J˜š œžœžœžœ˜7Jšžœ žœ˜#J˜9J˜Jšžœžœžœžœ˜)šžœžœŸ œ ž˜AJšžœžœ˜—Jšœ-˜-Jšœ˜J˜J˜——™*J™š   œžœžœžœžœ˜J˜—Jšžœ˜Jšœ˜Jšœžœ˜JšœŸ ˜>šœ˜Jšœ%žœžœ˜N—JšžœžœžœŸ'˜OJ˜J˜—š œžœžœ*˜RJšœ$žœ˜(š  œΠck˜5Jš₯(œ˜,Jš žœ žœžœ/žœžœžœ˜`Jš žœ*žœžœžœžœ˜UšœŸ+œ˜J˜J˜JšœŸ ΡbceŸ œ˜2Jšœžœ3˜AJ˜J˜J˜—J˜ Jšœ žœ˜Jšœ˜Jšœ ž˜JšœŸ˜"—Jšžœžœ˜J˜—š  œžœ₯˜>Jš₯(œ˜.Jšœžœ˜6J˜—J™dšž˜Jšœ žœ˜J˜.Jšžœ žœžœžœ˜Jšžœ˜—J™šJ™lJšœ4˜4Jšœ4˜4J˜J˜—š  œž œ3˜MJšžœžœžœ˜-Jšœžœ˜J˜WJ˜J˜——™J™š œžœžœ.˜JJšžœžœžœ˜*J˜$š   œžœžœžœžœ˜1Jš œžœžœžœžœžœ˜Išœžœ žœžœ˜!Jšžœžœžœžœ ˜=—J˜—š œžœ+žœžœ˜SJšœžœžœŸ œ ˜=Jš žœžœžœžœžœžœ˜0J˜—Jšžœžœžœ˜šœžœž˜J˜&šœ žœ ž˜Jšœ˜J˜ Jšœ˜J˜Jšžœžœ˜—šœ žœ ž˜ J˜*Jšœžœ'˜9Jšœ+˜+Jšžœžœ˜—Jšžœžœ˜—J˜J™—š œž œ5˜SJš žœžœžœžœ žœžœ˜FJ™/Jšžœžœžœžœ˜+J˜(Jšžœžœžœ˜'Jšžœ$˜(Jšœ˜—J˜š œžœžœžœ˜7Jšžœžœžœ˜?Jšœ3˜3Jšœ5˜5Jšœ˜—J˜J™/š œžœž œ žœ!˜TJšžœžœ5˜DJšœžœ)˜4J˜Jšœ ˜ Jšžœžœžœžœ˜-JšœžœŸ œ ˜;Jš žœžœžœžœžœ˜>Jšžœžœžœ$žœ˜QJšœŸ&˜:šžœžœŸ œ ž˜BJšžœ žœ ˜—J˜J˜—J˜š œžœžœžœ˜,J˜J˜J˜J˜——™J˜—™J™š  œžœ˜0J˜—š  œ˜%Jšœžœ ˜%Jšœ˜šžœžœž˜Jš œ žœ1žœžœžœ˜R—šžœž˜"JšœHžœ˜Q—Jš žœžœžœ+žœ!žœ˜`J˜—J˜š œ˜)Jšœžœ˜Jš žœ žœžœ(žœ žœ˜KJšœ)˜)Jšœ+˜+šžœ žœžœ(˜;Jšœ Ÿ+˜5Jšœ Ÿ˜#J˜—J˜—J˜Jšœ5˜5Jšœžœ˜"J˜š  œ˜&šž˜JšžœIžœ ˜[—šœ žœ+˜9JšœX˜X—šœ˜J˜Jšœ˜J˜—šœA˜AJ˜;—Jšœ8˜8Jšœ6˜6JšœAžœ˜Kšœ"˜"Jšœ#˜#Jšœ˜J˜—Jšœ9žœ&˜bšž˜JšœKžœ˜U—J˜—J˜Jšœ—˜—šœ*˜*Jšœ[˜[—J˜Icode™—™™'K™ Kšœ ΟrJ™V—™&K™—™'K™K™K™!K™2Kšœ §F™RKšœ §5™AKšœ § ™Kšœ §$™0—™*K™'Kšœ §œ§{™­K™K™—™*K™@Kšœ §™—K™K™—K™™+K™Kšœ §™(—K™™&K™ Kšœ §"™.—K™—…—^jŽŽ