<> <> <> <> DIRECTORY Commander USING [ CommandProc, Register ], CommandTool USING [ NextArgument ], Convert USING [ IntFromRope ], IO, Lark -- USING [ -- CommandEvents, ConnectionSpec, Event, LarkModel, Passel, SHHH, StatusEvent, StatusEvents ]--, LarkRpcControl USING [ ImportNewInterface, InterfaceRecord ], LarkSmarts, LarkSmartsMonitorImpl, LarkSmartsRpcControl USING [ExportInterface, InterfaceName, UnexportInterface], LupineRuntime, NamesGV USING [ GVGetAttribute ], NamesRPC USING [ StartConversation ], Nice USING [ LarkConLogStream ], Pup USING [ nullSocket ], Rope USING [Concat, Equal], RPC USING [ AuthenticateFailed, EncryptionKey, ExportFailed, GetCaller, ImportFailed ], SafeStorage USING [ GetCanonicalType, Type ], ThNet USING [ pd ], ThPartyPrivate USING [ DehandleSmarts, LocalSmartsInterface, RegisterLocal, SmartsBody, SmartsData ], ThParty USING [ CreateParty, Deregister, Enable ], Thrush USING [ CallUrgency, ConversationHandle, Disposition, epoch, Epoch, H, NetAddress, none, nullHandle, noMachine, PartyHandle, PartyType, ROPE, SmartsHandle, ThHandle, unencrypted ], ThSmarts USING [ Machine ], ThSmartsPrivate USING [ CheckHookState, EnterLarkState, GetSmartsInfo, LarkFailed, LarkInfo, LarkInfoBody, LarkParseEvent, LarkProgress, LarkSupervise, RegisterTrunk, SmartsInfo, SmartsInfoBody ], ThSmartsRpcControl, ThVersions, Triples USING [ Any, Erase, Foreach, ForeachProc, Make ], TU, VoiceUtils USING [ CmdOrToken, CurrentPasskey, RnameToRspec, Rspec, DNFProc, RegisterWhereToReport, ReportFR, Problem, ProblemFR, WhereProc ] ; LarkSmartsInitImpl: CEDAR MONITOR LOCKS root IMPORTS IO, Commander, CommandTool, Convert, LarkRpcControl, LarkSmartsRpcControl, NamesGV, NamesRPC, root: LarkSmartsMonitorImpl, LupineRuntime, Nice, Rope, RPC, SafeStorage, ThNet, ThPartyPrivate, ThParty, Thrush, ThSmartsPrivate, ThSmartsRpcControl, ThVersions, Triples, TU, VoiceUtils EXPORTS LarkSmarts, ThSmartsPrivate SHARES LarkSmartsMonitorImpl = { OPEN IO; <> CallUrgency: TYPE = Thrush.CallUrgency; CommandEvents: TYPE = Lark.CommandEvents; ConversationHandle: TYPE = Thrush.ConversationHandle; H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; }; none: SHHH = Thrush.none; nullHandle: Thrush.ThHandle = Thrush.nullHandle; PartyHandle: TYPE = Thrush.PartyHandle; ROPE: TYPE = Thrush.ROPE; SHHH: TYPE = Lark.SHHH; -- Encrypts conv. if first arg to RPC PROC RTSmartsType: SafeStorage.Type = SafeStorage.GetCanonicalType[CODE[ThPartyPrivate.SmartsBody]]; SmartsHandle: TYPE = Thrush.SmartsHandle; SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; SmartsInfoBody: TYPE = ThSmartsPrivate.SmartsInfoBody; StatusEvents: TYPE = Lark.StatusEvents; larkInterfaces: LIST OF LarkRpcControl.InterfaceRecord _ NIL; larkRegistry: ROPE_".lark"; thSmartsExported: BOOL_FALSE; <> Register: PUBLIC PROC[ shh: SHHH, -- encrypts connection oldSmartsID: Thrush.SmartsHandle, oldEpoch: Thrush.Epoch, machine: Lark.Machine, -- machine name for registering Lark -- model: Lark.LarkModel, authenticated: BOOL_FALSE, clientInstance: ROPE ] RETURNS [ smartsID: Thrush.SmartsHandle_nullHandle, epoch: Thrush.Epoch_Thrush.epoch ] = { ENABLE UNWIND => NULL; larkSh: Lark.SHHH; partyID: PartyHandle; localSmarts: ThPartyPrivate.LocalSmartsInterface; info: SmartsInfo; larkInterface: LarkRpcControl.InterfaceRecord_NIL; smarts: ThPartyPrivate.SmartsData; fullRname: ROPE = RPC.GetCaller[shh]; partyRname: ROPE _ fullRname; dbRname: ROPE; serviceName: ROPE; partyType: Thrush.PartyType _ individual; s: VoiceUtils.Rspec _ NIL; netAddress: Thrush.NetAddress _ [machine.net, machine.host, Pup.nullSocket]; <> IF (s_VoiceUtils.RnameToRspec[partyRname])#NIL AND VoiceUtils.RnameToRspec[s.simpleName] # NIL THEN partyRname_s.simpleName; <> <> dbRname _ partyRname.Concat[larkRegistry]; serviceName _ NamesGV.GVGetAttribute[dbRname, $service, NIL]; IF serviceName#NIL THEN partyType _ service; <<>> <> DeregisterIfRegistered[netAddress]; <> partyID _ ThParty.CreateParty[type: partyType, rName: IF partyType=individual THEN partyRname ELSE serviceName]; IF partyID=nullHandle THEN { VoiceUtils.ReportFR["Registering party %s not found", $System, NIL, rope[partyRname]]; RETURN[nullHandle, Thrush.epoch]; }; <<>> <> larkSh _ IF NOT ThNet.pd.encryptionRequested THEN Thrush.unencrypted ELSE NamesRPC.StartConversation [ caller: myName.instance, callee: fullRname, key: serverPassword, level: --<>--CBCCheck ! RPC.AuthenticateFailed=> { VoiceUtils.ProblemFR["Can't authenticate %g to %g", $System, NIL, rope[myName.instance], rope[fullRname]]; GOTO NotSmart; }]; <> larkInterface _ LarkRpcControl.ImportNewInterface[ interfaceName: [type: "Lark.Lark", instance: clientInstance] ! RPC.ImportFailed=> { VoiceUtils.ProblemFR["Can't import Lark interface from %g", $System, NIL, rope[clientInstance]]; GOTO NotSmart; }]; larkInterfaces _ CONS[larkInterface, larkInterfaces]; <<<< No way to deal with resumption of calls in progress, as yet. >>>> <> localSmarts _ ThSmartsRpcControl.NewInterfaceRecord[]; localSmarts.clientStubProgress _ ThSmartsPrivate.LarkProgress; smartsID_ThPartyPrivate.RegisterLocal[ partyID: partyID, interface: localSmarts, properties: [x: voiceTerminal[netAddress: [netAddress.net, netAddress.host]]] ]; IF smartsID=nullHandle THEN {VoiceUtils.ProblemFR["Can't register Lark: %g, %g",$System,NIL, rope[fullRname], rope[clientInstance]]; GOTO NotSmart; }; <> smarts _ ThPartyPrivate.DehandleSmarts[smartsID,TRUE]; info _ NEW[SmartsInfoBody_ [ smarts: smarts, ParseEvent: ThSmartsPrivate.LarkParseEvent, Supervise: ThSmartsPrivate.LarkSupervise, larkInfo: NEW[ThSmartsPrivate.LarkInfoBody _ [ interface: larkInterface, shh: larkSh, netAddress: netAddress, model: model, autoAnswer: NamesGV.GVGetAttribute[dbRname, $autoanswer, "FALSE"].Equal["TRUE", FALSE], radio: NamesGV.GVGetAttribute[dbRname, $radio, "FALSE"].Equal["TRUE", FALSE], textToSpeech: Rope.Equal[serviceName, "Text-to-Speech", FALSE] ]] ]]; info.larkInfo.scratchEv _ NEW[Lark.CommandEventSequence[15]]; Triples.Make[$SmartsData, smarts, info]; info.otherSmarts _ ThPartyPrivate.DehandleSmarts[ ThSmartsPrivate.RegisterTrunk[ partyID, smarts, info ]]; VoiceUtils.ReportFR[" (%g = %g)", $Smarts, info, rope[clientInstance], TU.RefAddr[info.smarts]]; EnableSmartsE[info]; -- Ready to go, as long as phone is on hook EXITS NotSmart => RETURN; }; EnableSmartsE: ENTRY PROC[info: SmartsInfo] = { []_EnableSmarts[info]; }; EnableSmarts: PUBLIC INTERNAL PROC[info: SmartsInfo] RETURNS[enabled: BOOL] = { ENABLE UNWIND, ThSmartsPrivate.LarkFailed =>GOTO Failed; SELECT info.larkInfo.larkState FROM none, failed, recovering => NULL; ENDCASE=> RETURN[TRUE]; IF ThSmartsPrivate.CheckHookState[info.larkInfo].onHook=FALSE THEN RETURN[FALSE]; IF ThParty.Enable[ smartsID: H[info.smarts]]#success THEN RETURN[FALSE]; -- << REPORT!! >> -- IF ThParty.Enable[ smartsID: H[info.otherSmarts]]#success THEN VoiceUtils.Problem["Impossible", $Smarts, info]; ThSmartsPrivate.EnterLarkState[ info.larkInfo, none, info ]; -- Clear any previous failure. ThSmartsPrivate.EnterLarkState[ info.larkInfo, idle, info ]; -- Reset the Lark RETURN[TRUE]; EXITS Failed => RETURN[FALSE]; }; DeregisterIfRegistered: PROC[netAddress: Thrush.NetAddress] = { <<<< Inefficient. Also knows too much about party linkages.>> <>>> DR: ENTRY PROC[info: SmartsInfo] = { Deregister[info]; }; ConsiderOne: Triples.ForeachProc = { smartsData: ThPartyPrivate.SmartsData _ NARROW[trip.val]; machine: ThSmarts.Machine = [netAddress.net, netAddress.host]; IF smartsData#NIL THEN WITH prop: smartsData.properties SELECT FROM voiceTerminal => IF machine = prop.netAddress THEN DR[ThSmartsPrivate.GetSmartsInfo[H[smartsData]]]; ENDCASE; }; Triples.Foreach[$LocatedTerminal, Triples.Any, Triples.Any, ConsiderOne]; Triples.Foreach[$AdjacentTerminal, Triples.Any, Triples.Any, ConsiderOne]; Triples.Foreach[$VoiceTerminal, Triples.Any, Triples.Any, ConsiderOne]; }; Deregister: PUBLIC INTERNAL PROC[info: SmartsInfo] = { IF info=NIL OR ThPartyPrivate.DehandleSmarts[H[info.smarts]] = NIL THEN RETURN; ThSmartsPrivate.EnterLarkState[ info.larkInfo, failed, info ]; -- prevent further action. SimpleDeregister[ThSmartsPrivate.GetSmartsInfo[smarts: info.otherSmarts]]; SimpleDeregister[info]; <> VoiceUtils.ReportFR["Smarts %d (%g) is dead", $Smarts, info, card[H[info.smarts]], TU.RefAddr[info.smarts]]; }; SimpleDeregister: INTERNAL PROC[info: SmartsInfo] = { ThParty.Deregister[smartsID: H[info.smarts]]; Triples.Erase[$SmartsData, info.smarts, info]; }; Login: PUBLIC PROC[shh: SHHH, smartsID: SmartsHandle, authenticated: BOOL] = { NULL }; <> WhereIsSmartsLog: VoiceUtils.WhereProc -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM _ NIL] -- = CHECKED { info: SmartsInfo=NARROW[whereData]; IF info#NIL THEN s_Nice.LarkConLogStream[info.larkInfo.netAddress]; IF s#NIL AND s=Nice.LarkConLogStream[Thrush.noMachine] 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.noMachine] THEN s_NIL; -- only want the debug viewer stream }; WhereIsLarkLogFerSherr: VoiceUtils.WhereProc _ WhereIsLarkLog; FerSherrDefault: VoiceUtils.DNFProc=TRUSTED{ RETURN[ThNet.pd.defaultLarkReports]; }; <> myName: LarkSmartsRpcControl.InterfaceName; serverPassword: RPC.EncryptionKey; KillLark: Commander.CommandProc = { DeregisterIfRegistered[[[173B],[Convert.IntFromRope[CommandTool.NextArgument[cmd], 8]], Pup.nullSocket]]; }; LarkSmartsInit: Commander.CommandProc = { ENABLE { RPC.ExportFailed => { VoiceUtils.Problem["LarkSmarts export failed", $System]; GOTO Failed; }; }; myName _ [ type: "LarkSmarts.Lark", instance: VoiceUtils.CmdOrToken[cmd: cmd, key: "ThrushServerInstance", default: "Morley.Lark"], version: ThVersions.ThrushVR]; serverPassword _ VoiceUtils.CurrentPasskey[VoiceUtils.CmdOrToken[ cmd: cmd, key: "ThrushServerPassword", default: "MFLFLX"]]; IF thSmartsExported THEN RETURN; VoiceUtils.RegisterWhereToReport[proc: WhereIsLarkLog, where: $Lark]; VoiceUtils.RegisterWhereToReport[proc: WhereIsLarkLogFerSherr, where: $LarkDetailed, defaultIfNotFound: FerSherrDefault]; <> VoiceUtils.RegisterWhereToReport[proc: WhereIsSmartsLog, where: $Smarts]; LarkSmartsRpcControl.ExportInterface[ interfaceName: myName, user: myName.instance, password: serverPassword]; VoiceUtils.ReportFR["Export[LarkSmarts.Lark, %s]", $System, NIL, rope[myName.instance]]; thSmartsExported _ TRUE; EXITS Failed => LarkSmartsRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE]; }; Commander.Register["LarkSmarts", LarkSmartsInit, "LarkSmarts > -- Initialize and Export LarkSmarts"]; Commander.Register["KillLark", KillLark, "KillLark 110 -- deregisters lark 110"]; }. <> <> <> <> <> <> <> <> <> <<>>