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:	--<<ECB>>--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];


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] = {
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 <ExportInstance(opt.) <ServerPassword (opt)>> -- Initialize and Export LarkSmarts"];


Commander.Register["KillLark", KillLark, "KillLark 110 -- deregisters lark 110"];


}.
���	Œ��LarkSmartsInitImpl.mesa
Copyright c 1985, 1986 by Xerox Corporation.  All rights reserved.
Last modified by D. Swinehart, May 19, 1986 10:33:00 am PDT
Last Edited by: Pier, May 3, 1984 2:52:59 pm PDT
Copies
Registration/Deregistration/Initialization
Develop partyRname: the actual RName to be used to represent this party; and dbRname: the name under which database items are stored.  The rName obtained from the conversation handle may have either form initially, since Finches will supply the former and Larks will supply the latter.  Also, obtain the name of the service represented by this Rname, if any, from the database.
Above converts from, say, Swinehart.pa.lark to Swinehart.pa.
Also, from Swinehart.pa to Swinehart.pa.  Strips one registry if there are two or more.

The LarkSmarts interface definition suggests that a Lark could present enough information during registration to be simply re-validated (kind of like a hand stamp at a dance) without any great effort.  That turns out not to be worth it.  If a Lark registers when already registered, we get rid of any old information about it first. 
Produce a Party object for this RName, if none exists yet.

Get encryption taken care of 
Make sure we can talk to the Lark
<< No way to deal with resumption of calls in progress, as yet. >>
larkInterface.Reset[larkSh, NIL];
No further bad things are expected to happen.
<< Inefficient.  Also knows too much about party linkages.
Consider additional structure relating net addresses to smarts, or the equivalent, in next redesign. May 22, 1985 5:16:18 pm PDT>>
Unimport the Lark interface (automatic, via finalization.)
Other Utilities
Initialization, export "LarkSmarts"
Same as $Lark, except doesn't print at all if debugging viewer not found.
Swinehart, May 22, 1985 5:03:50 pm PDT
Cedar 6.0
New ways of defining service parties.  autoAnswer (formerly hotLine), radio, and textToSpeech attributes obtained from data base.  Text-To-Speech service contemplated.
Deregistration works in the face of duplicate service names, etc.
changes to: DIRECTORY, Register, DO
changes to: DIRECTORY, Register, DO, DeregisterIfRegistered, ConsiderOne (local of DeregisterIfRegistered), Deregister
Swinehart, May 16, 1986 4:09:27 pm PDT
Cedar 6.1
changes to: DIRECTORY, LarkSmartsInitImpl, Register, level, interfaceName, EnableSmarts, Deregister, WhereIsSmartsLog, WhereIsLarkLog, WhereIsLarkLogFerSherr, FerSherrDefault, LarkSmartsInit

�Ê ��˜�šœ™Icodešœ
Ïmœ7™BJšœ;™;J™0J˜�—šÏk	œ˜
Jšœ
žœ˜*Jšœžœ˜#Jšœžœ˜Jšžœ˜šœÏc
˜JšŸ_œ˜`—Jšœžœ)˜=J˜J˜Jšœžœ5˜OJ˜Jšœžœ˜!Jšœ	žœ˜%Jšœžœ˜ Jšœžœ˜J˜JšžœžœN˜WJšœžœ˜-Jšœžœ˜JšœžœQ˜eJšœ2˜2Jšœžœ‚žœ)˜¼Jšœ	žœ
˜šœžœ˜Jšœ¬˜¬—J˜J˜Jšœžœ,˜9Jšž˜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˜�Jšœ
žœ˜'Jšœžœ˜)Jšœžœ˜5Jšžœžœžœžœžœžœžœ˜JJšœžœ˜J˜0Jšœ
žœ˜'Jšžœžœ
žœ˜šžœžœžœŸ*˜CJšœ>žœ˜_—Jšœžœ˜)Jšœžœ˜.Jšœžœ"˜6Jšœžœ˜'—˜�Jšœžœžœ"žœ˜=Jšœžœ	˜J˜�Jšœžœžœ˜J˜�—™*J˜�šÏnœžœžœ˜JšœžœŸ˜!J˜!J˜JšœŸ'˜>J˜Jšœžœžœ˜Jšœžœ˜JšžœS˜ZJšžœžœžœ˜Jšœ
žœ˜J˜J˜1J˜Jšœ.žœ˜2J˜"Jšœžœžœ˜%Jšœžœ
˜Jšœ	žœ˜Jšœ
žœ˜J˜)Jšœžœ˜J˜LJ˜�J™ùšžœ)ž˜.Jšžœ)žœ˜MJ™<J™W—J˜*Jšœ8žœ˜=Jšžœ
žœžœ˜,J™�J™ÍJ˜#J˜�Jšœ:™:šœ.˜.Jšœžœžœžœ˜A—šžœžœž˜Jšœ?žœ˜VJšžœ˜!Jšœ˜—J™�Jšœ™Jšœ	žœžœžœ˜Dšžœ˜!J˜J˜J˜šœŸœžœ˜7šœ=žœ˜AJšœ)žœ˜;—J˜�——Jšœ!™!˜2šœ?žœ˜SJšœEžœžœ˜s——šœžœ ˜5J˜�—JšœB™BJšœžœ™!J˜�Jšœ6˜6J˜>šœ&˜&Jšœ˜J˜JšœM˜MJšœ˜šžœžœ=žœ˜\Jšœ(žœ
˜9——Jšœ-™-Jšœ0žœ˜6šœžœ˜Jšœ˜J˜+J˜)šœ
žœ!˜.J˜J˜J˜J˜
šœ˜JšœDžœ˜K—JšœFžœ˜MJšœ8žœ˜>J˜——Jšœžœ ˜=J˜(šœ1˜1Jšœ8˜8—šœ0˜0Jšœ/˜/—JšœŸ+˜@šž˜Jšœžœ˜—Jšœ˜—J˜�Jš 
œžœžœ0˜Iš œžœžœžœžœ
žœ˜OJšžœžœžœ˜8šžœž˜#Jšœžœ˜!Jšžœžœžœ˜—Jš
žœ6žœžœžœžœ˜QJšžœžœžœžœžœŸ˜]šžœžœž˜>Jšœ0˜0—Jšœ=Ÿ˜[Jšœ=Ÿ˜NJšžœžœ˜
šž˜Jšœ
žœžœ˜—J˜J˜�—š œžœ#˜?J™:J™‚Jšžœžœžœ+˜9˜$Jšœ(žœ˜9J˜>šžœžœžœžœžœž˜CJšœžœžœžœ/˜dJšžœ˜—J˜—J˜IJ˜JJ˜GJ˜J˜�—š 
œžœžœžœ˜6Jšžœžœžœ1žœžœžœ˜OJšœ?Ÿ˜YJ˜JJ˜J™:šœ<˜<Jšœžœžœ˜/—J˜—J˜�š œžœžœ˜5Jšœžœ˜-J˜.J˜—J˜�š œžœžœžœ)žœžœ˜VJ˜�——™J˜�•StartOfExpansionO -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM _ NIL] -- šœ&ÐckNœžœ˜Jšœžœ˜#Jšžœžœ3˜CJšžœžœžœ+žœžœŸ6˜yJ˜—J˜�–O -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM _ NIL] -- šœ$¡Nœžœ˜Jšœžœ˜1Jšžœžœžœ*˜:Jšžœžœžœ+žœžœŸ$˜gJ˜J˜�—J–O -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM _ NIL] -- šœ>˜>šœ$žœžœ!˜TJ˜�——šœ#™#J˜�J˜+Jšœ"˜"J˜�š œ˜#J˜iJ˜J˜�—š œ˜)šžœ˜JšžœLžœ˜^J˜—˜
J˜Jšœ_˜_J˜—šœA˜AJ˜;—Jšžœžœžœ˜ JšœE˜Ešœy˜yJ™I—JšœI˜I˜%J˜J˜J˜—Jšœ<žœ˜XJšœžœ˜šž˜˜	JšœDžœ˜N——J˜——˜�J˜�—šœ‘˜‘J˜�J˜�—šœQ˜QJ˜�J˜�—J˜™&K™	K™§K™AKšœÏr™#Kšœ¢<œ"¢™v—™&K™	Kšœ¢²™¾—K™�—�…—����*��>¾��