<> <> <> <> DIRECTORY CardTab USING [ Create, Fetch, Ref, Store ], Commander USING [ CommandProc, Register ], CommandTool USING [ NextArgument ], Convert USING [ IntFromRope ], IO, Lark USING [ CommandEventSequence, LarkModel, Machine, SHHH ], LarkControl USING [ GetLark, SetApplicationMode ], LarkOpsRpcControl USING [ ImportNewInterface, InterfaceRecord ], LarkSmarts, LarkSmartsMonitorImpl, LarkSmartsRpcControl USING [ExportInterface, InterfaceName, UnexportInterface], LupineRuntime, MBQueue USING [ Create, Flush, Queue, QueueClientAction ], NameDB USING [ GetAttribute ], NamesRPC USING [ StartConversation ], Nice USING [ LarkConLogStream ], Pup USING [ nullSocket ], RefID USING [ ID, Reseal, Unseal ], Rope USING [Equal], RPC USING [ AuthenticateFailed, EncryptionKey, ExportFailed, GetCaller, ImportFailed ], ThNet USING [ pd ], ThPartyPrivate USING [ AssignSmartsID, RegisterLocal, UnsealSmarts ], ThParty USING [ Deregister, Enable, SmartsInterfaceRecord ], Thrush USING [ ActionClass, Credentials, epoch, Epoch, NB, NetAddress, noAddress, nullID, PartyID, PartyType, ROPE, SmartsID, unencrypted ], ThSmartsPrivate USING [ CheckHookState, EnterLarkState, Fail, LarkCheckIn, LarkInfo, LarkInfoBody, LarkParseEvent, LarkProgress, LarkReportAction, LarkSubstitution, NoteNewState, RegisterTrunk, SetupTimeouts, SmartsInfo, SmartsInfoBody ], ThSmartsRpcControl, ThVersions, Triples USING [ Make ], TU, VoiceUtils USING [ CmdOrToken, CurrentPasskey, DNFProc, InstanceFromNetAddress, MakeRName, Problem, ProblemFR, RegisterWhereToReport, ReportFR, RnameToRspec, Rspec, WhereProc ] ; LarkSmartsInitImpl: CEDAR MONITOR LOCKS root IMPORTS IO, CardTab, Commander, CommandTool, Convert, LarkOpsRpcControl, LarkControl, LarkSmartsRpcControl, NameDB, NamesRPC, root: LarkSmartsMonitorImpl, LupineRuntime, MBQueue, Nice, RefID, Rope, RPC, ThNet, ThPartyPrivate, ThParty, Thrush, ThSmartsPrivate, ThSmartsRpcControl, ThVersions, Triples, TU, VoiceUtils EXPORTS LarkSmarts, ThSmartsPrivate SHARES LarkSmartsMonitorImpl = { OPEN IO; larkInfos: CardTab.Ref _ NIL; -- Locate current or previous LarkInfos directly. <> Reseal: PROC[r: REF] RETURNS[RefID.ID] = INLINE {RETURN[RefID.Reseal[r]]; }; nullID: RefID.ID = Thrush.nullID; PartyID: TYPE = Thrush.PartyID; ROPE: TYPE = Thrush.ROPE; SHHH: TYPE = Lark.SHHH; -- Encrypts conv. if first arg to RPC PROC LarkInfo: TYPE = ThSmartsPrivate.LarkInfo; SmartsID: TYPE = Thrush.SmartsID; SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; SmartsInfoBody: TYPE = ThSmartsPrivate.SmartsInfoBody; <> <> potentialServiceProviders: ServiceProvidersList; ServiceProvidersList: TYPE = LIST OF ServiceProviderRecord; ServiceProviderRecord: TYPE = RECORD [ actionClass: Thrush.ActionClass, potentialServiceProvider: PROC[credentials: Thrush.Credentials, smartsInfo: SmartsInfo] ]; <> Register: PUBLIC PROC[ shh: SHHH, -- encrypts connection oldSmartsID: Thrush.SmartsID, oldEpoch: Thrush.Epoch, machine: Lark.Machine, -- machine name for registering Lark -- model: Lark.LarkModel, authenticated: BOOL_FALSE, clientInstance: ROPE ] RETURNS [ smartsID: Thrush.SmartsID_nullID, epoch: Thrush.Epoch_Thrush.epoch ] = { <> larkSh: Lark.SHHH; smartsInfo: SmartsInfo; larkInfo: LarkInfo; inputQueue: MBQueue.Queue; larkInterface: LarkOpsRpcControl.InterfaceRecord_NIL; rName: ROPE _ RPC.GetCaller[shh]; serviceName: ROPE; partyType: Thrush.PartyType _ $telephone; s: VoiceUtils.Rspec _ NIL; netAddress: Thrush.NetAddress = [machine.net, machine.host, Pup.nullSocket]; <> larkInfo _ LarkInfoForNetAddress[netAddress].info; IF larkInfo#NIL AND ~larkInfo.failed THEN { inputQueue _ larkInfo.inputQueue; ThSmartsPrivate.Fail[larkInfo, "Lark is reregistering", FALSE]; -- already rebooted } ELSE inputQueue _ MBQueue.Create[]; <> IF (s_VoiceUtils.RnameToRspec[rName])#NIL AND VoiceUtils.RnameToRspec[s.simpleName] # NIL THEN rName_s.simpleName; <> <> serviceName _ NameDB.GetAttribute[rName, $service]; IF serviceName#NIL THEN partyType _ $service; <<>> <> larkSh _ IF NOT ThNet.pd.encryptionRequested THEN Thrush.unencrypted ELSE NamesRPC.StartConversation [ caller: myName.instance, callee: rName, key: serverPassword, level: --<>--CBCCheck ! RPC.AuthenticateFailed=> { VoiceUtils.ProblemFR["Can't authenticate %g to %g", $System, NIL, rope[myName.instance], rope[rName]]; GOTO NotSmart; }]; <> larkInterface _ LarkOpsRpcControl.ImportNewInterface[ interfaceName: [type: "Lark.Lark", instance: clientInstance] ! RPC.ImportFailed=> { VoiceUtils.ProblemFR["Can't import Lark interface from %g", $System, NIL, rope[clientInstance]]; GOTO NotSmart; }]; larkInfo _ NEW[ThSmartsPrivate.LarkInfoBody _ [ interface: larkInterface, shh: larkSh, netAddress: netAddress, model: model, inputQueue: inputQueue, textToSpeech: Rope.Equal[serviceName, "Text-to-Speech", FALSE], scratchEv: NEW[Lark.CommandEventSequence[15]] ]]; smartsID _ ThPartyPrivate.AssignSmartsID[]; smartsInfo _ NEW[SmartsInfoBody_ [ smartsID: smartsID, partyType: partyType, ParseEvent: ThSmartsPrivate.LarkParseEvent, NoteNewStateP: ThSmartsPrivate.NoteNewState, requests: MBQueue.Create[], larkInfo: larkInfo ]]; inputQueue.QueueClientAction[ QdLarkRegistration, NEW[RegistrationInfoSpec _ [smartsInfo, rName, serviceName, clientInstance]]]; EXITS NotSmart => RETURN; }; RegistrationInfo: TYPE = REF RegistrationInfoSpec; RegistrationInfoSpec: TYPE = RECORD [ smartsInfo: SmartsInfo, rName: ROPE, serviceName: ROPE, clientInstance: ROPE ]; QdLarkRegistration: ENTRY PROC[r:REF] = { ENABLE UNWIND => NULL; nb: Thrush.NB; registrationInfo: RegistrationInfo _ NARROW[r]; smartsInfo: SmartsInfo _ registrationInfo.smartsInfo; larkInfo: LarkInfo _ smartsInfo.larkInfo; credentials: Thrush.Credentials; smartsID: Thrush.SmartsID; smarts: REF; localSmarts: ThParty.SmartsInterfaceRecord; localSmarts _ ThSmartsRpcControl.NewInterfaceRecord[]; localSmarts.clientStubProgress _ ThSmartsPrivate.LarkProgress; localSmarts.clientStubSubstitution _ ThSmartsPrivate.LarkSubstitution; localSmarts.clientStubReportAction _ ThSmartsPrivate.LarkReportAction; localSmarts.clientStubCheckIn _ ThSmartsPrivate.LarkCheckIn; [nb, credentials] _ ThPartyPrivate.RegisterLocal[ rName: (SELECT smartsInfo.partyType FROM $telephone => registrationInfo.rName, ENDCASE=> registrationInfo.serviceName), type: smartsInfo.partyType, interfaceRecord: localSmarts, smartsID: smartsInfo.smartsID, -- pre-allocated so Lark could know. properties: [role: $voiceTerminal, netAddress: larkInfo.netAddress] ]; IF nb # $success OR (smartsID_credentials.smartsID) = nullID THEN { VoiceUtils.ProblemFR["Can't register Lark: %g, %g",$System,NIL, rope[registrationInfo.rName], rope[registrationInfo.clientInstance]]; GOTO NotSmart; }; <> larkInfo.larkSmartsInfo _ smartsInfo; smarts _ RefID.Unseal[smartsID]; IF smarts=NIL THEN ERROR; Triples.Make[$SmartsData, smarts, smartsInfo]; IF smartsInfo.partyType # $service THEN [--nb--, smartsInfo.otherSmartsID]_ ThSmartsPrivate.RegisterTrunk[ smartsID, smartsInfo, registrationInfo.rName ]; VoiceUtils.ReportFR[" (%g = %g)", $Smarts, smartsInfo, rope[registrationInfo.clientInstance], TU.RefAddr[smarts]]; FOR pSP: ServiceProvidersList _ potentialServiceProviders, pSP.rest WHILE pSP#NIL DO pSP.first.potentialServiceProvider[credentials, smartsInfo]; <> ENDLOOP; RegisterLarkInfo[larkInfo]; <> NoteApplicationState[larkInfo, 'r]; []_ThSmartsPrivate.CheckHookState[larkInfo]; <> EXITS NotSmart => RETURN; }; EnableSmarts: PUBLIC ENTRY PROC[r: REF] = { ENABLE UNWIND => NULL; larkInfo: LarkInfo _ NARROW[r]; debugging: BOOL; smartsInfo: SmartsInfo _ larkInfo.larkSmartsInfo; IF larkInfo.failed THEN RETURN; -- Lost a race IF ThParty.Enable[ smartsID: smartsInfo.smartsID] # $success OR (smartsInfo.otherSmartsID # nullID AND ThParty.Enable[smartsID: smartsInfo.otherSmartsID] # $success) THEN { VoiceUtils.Problem["Could not enable", $Smarts, smartsInfo]; ThSmartsPrivate.Fail[larkInfo, "Lark failure due to failure to enable party", FALSE]; <> }; ThSmartsPrivate.EnterLarkState[ larkInfo, idle ]; -- Reset the Lark <> debugging _ Rope.Equal[case: FALSE, s2: "D", s1: NameDB.GetAttribute[ VoiceUtils.InstanceFromNetAddress[larkInfo.netAddress, NIL], $mode, "O", $larkhost]]; larkInfo.debugging _ debugging; ThSmartsPrivate.SetupTimeouts[ larkInfo, debugging ]; -- Reset the Lark NoteApplicationState[larkInfo, 'R]; }; Deregister: PUBLIC ENTRY PROC[r: REF] = { <> larkInfo: LarkInfo _ NARROW[r]; smartsID: SmartsID _ nullID; otherSmartsID: SmartsID _ nullID; smartsInfo: SmartsInfo _ IF larkInfo#NIL THEN larkInfo.larkSmartsInfo ELSE NIL; smarts: REF; IF smartsInfo = NIL THEN { VoiceUtils.Problem["No Smarts to Deregister", $System]; RETURN; }; NoteApplicationState[larkInfo, 'U]; smartsID _ smartsInfo.smartsID; smarts _ ThPartyPrivate.UnsealSmarts[smartsID]; VoiceUtils.ReportFR["Smarts %d (%g) is dead", $Smarts, smartsInfo, card[Reseal[smarts]], TU.RefAddr[smarts]]; smartsInfo.failed _ TRUE; smartsInfo.larkInfo.larkSmartsInfo _ NIL; IF smartsInfo.larkInfo.larkTrunkSmartsInfo#NIL THEN { smartsInfo.larkInfo.larkTrunkSmartsInfo.failed _ TRUE; smartsInfo.larkInfo.larkTrunkSmartsInfo.larkInfo _ NIL; }; smartsInfo.larkInfo.larkTrunkSmartsInfo _ NIL; smartsInfo.larkInfo _ NIL; otherSmartsID _ smartsInfo.otherSmartsID; IF otherSmartsID # nullID THEN [--nb--]_ThParty.Deregister[smartsID: otherSmartsID]; [--nb--]_ThParty.Deregister[smartsID: smartsID]; smartsInfo.requests.Flush[]; -- Abandon progress-notification queue }; NoteApplicationState: INTERNAL PROC[info: LarkInfo, state: CHAR] = { LarkControl.SetApplicationMode[LarkControl.GetLark[info.netAddress], state]; }; Login: PUBLIC PROC[shh: SHHH_, smartsID: SmartsID_, authenticated: BOOL_TRUE] = { NULL;}; <> <> WhereIsSmartsLog: VoiceUtils.WhereProc -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM _ NIL] -- = CHECKED { info: SmartsInfo=NARROW[whereData]; larkInfo: LarkInfo = IF info#NIL THEN info.larkInfo ELSE NIL; IF larkInfo#NIL THEN s_Nice.LarkConLogStream[larkInfo.netAddress]; IF s#NIL AND s=Nice.LarkConLogStream[Thrush.noAddress] THEN s_NIL; -- use default stream unless debug viewer stream open. }; WhereIsLarkLog: VoiceUtils.WhereProc -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM _ NIL] -- = CHECKED { info: ThSmartsPrivate.LarkInfo=NARROW[whereData]; IF info#NIL THEN s_Nice.LarkConLogStream[info.netAddress]; IF s#NIL AND s=Nice.LarkConLogStream[Thrush.noAddress] THEN s_NIL; -- only want the debug viewer stream }; WhereIsLarkLogFerSherr: VoiceUtils.WhereProc _ WhereIsLarkLog; FerSherrDefault: VoiceUtils.DNFProc=TRUSTED{ RETURN[ThNet.pd.defaultLarkReports]; }; <> KillLark: Commander.CommandProc = { netAddress: Thrush.NetAddress = [[173B],[Convert.IntFromRope[CommandTool.NextArgument[cmd], 8]], Pup.nullSocket]; larkInfo: LarkInfo _ LarkInfoForNetAddress[netAddress].info; IF larkInfo=NIL THEN RETURN; ThSmartsPrivate.Fail[larkInfo, "Lark failed through operator request", TRUE]; }; myName: LarkSmartsRpcControl.InterfaceName; serverPassword: RPC.EncryptionKey; LarkSmartsInit: Commander.CommandProc = { ENABLE { RPC.ExportFailed => { VoiceUtils.Problem["LarkSmarts export failed", $System]; GOTO Failed; }; }; instance: ROPE = VoiceUtils.MakeRName[style: rName, name: VoiceUtils.CmdOrToken[cmd: cmd, key: "ThrushServerInstance", default: "Strowger.Lark"]]; serverPassword _ VoiceUtils.CurrentPasskey[VoiceUtils.CmdOrToken[ cmd: cmd, key: "ThrushServerPassword", default: "MFLFLX"]]; myName _ [ type: "LarkSmarts.Lark", instance: instance, version: ThVersions.ThrushVR ]; VoiceUtils.RegisterWhereToReport[proc: WhereIsLarkLog, where: $Lark]; VoiceUtils.RegisterWhereToReport[proc: WhereIsLarkLogFerSherr, where: $LarkDetailed, defaultIfNotFound: FerSherrDefault]; <> VoiceUtils.RegisterWhereToReport[proc: WhereIsSmartsLog, where: $Smarts]; LarkSmartsRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE]; LarkSmartsRpcControl.ExportInterface[ interfaceName: myName, user: instance, password: serverPassword ]; VoiceUtils.ReportFR["Export[LarkSmarts.Lark, %s]", $System, NIL, rope[myName.instance]]; EXITS Failed => LarkSmartsRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE]; }; RegisterServiceProvider: PUBLIC PROC[ actionClass: Thrush.ActionClass, -- to prevent duplicates serviceProvider: PROC[credentials: Thrush.Credentials, smartsInfo: SmartsInfo] ] = { <> RemoveServiceProvider[actionClass]; potentialServiceProviders _ CONS[[actionClass, serviceProvider], potentialServiceProviders]; }; RemoveServiceProvider: PROC[actionClass: Thrush.ActionClass] = { IF potentialServiceProviders = NIL THEN RETURN; IF potentialServiceProviders.first.actionClass=actionClass THEN { potentialServiceProviders _ potentialServiceProviders.rest; RETURN; }; FOR pSP: ServiceProvidersList _ potentialServiceProviders, pSP.rest WHILE pSP.rest#NIL DO IF pSP.rest.first.actionClass = actionClass THEN { pSP.rest _ pSP.rest.rest; RETURN; }; ENDLOOP; }; RegisterLarkInfo: PROC[info: LarkInfo] = { index: CARD _ LarkInfoForNetAddress[info.netAddress].index; [] _ larkInfos.Store[index, info]; }; LarkInfoForNetAddress: PROC[netAddress: Thrush.NetAddress] RETURNS[info: LarkInfo, index: CARD] = TRUSTED { netAddress.socket _ Pup.nullSocket; -- only interested in host values index _ LOOPHOLE[LONG[@netAddress], LONG POINTER TO CARD]^; IF larkInfos=NIL THEN { larkInfos _ CardTab.Create[mod: 59]; <> }; info _ NARROW[larkInfos.Fetch[index].val]; }; <> <> <> <<[key: CardTab.Key, val: CardTab.Val] RETURNS [quit: BOOLEAN]>> <> <> <> <> <> <> <> <<};>> <> <> <> <> <<};>> Commander.Register["LarkSmarts", LarkSmartsInit, "LarkSmarts \nInitialize and Export LarkSmarts"]; Commander.Register["KillLark", KillLark, "KillLark 110 -- deregisters lark 110"]; }. <> <> <> <> <> <> <> < VoiceUtils, Handle => ID>> <> <> <> <> <> <> <> <> < LarkOps>> <> <> <> <> <<>>