Register:
PUBLIC
PROC[
shh: SHHH, -- encrypts connection
oldSmartsID: Thrush.SmartsHandle,
oldEpoch: Thrush.Epoch,
netAddress: Thrush.NetAddress, -- 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: Names.Rspec ← NIL;
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.
IF (s←Names.RnameToRspec[partyRname])#
NIL
AND Names.RnameToRspec[s.simpleName] # NIL THEN partyRname←s.simpleName;
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.
dbRname ← partyRname.Concat[larkRegistry];
serviceName ← NamesGV.GVGetAttribute[dbRname, $service, NIL];
IF serviceName#NIL THEN partyType ← service;
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.
DeregisterIfRegistered[netAddress];
Produce a Party object for this RName, if none exists yet.
partyID ← ThParty.CreateParty[type: partyType,
rName: IF partyType=individual THEN partyRname ELSE serviceName];
IF partyID=nullHandle
THEN
{
Log.ReportFR["Registering party %s not found", $System, NIL, rope[partyRname]];
RETURN[nullHandle, Thrush.epoch];
};
Get encryption taken care of
larkSh ← IF NOT ThNet.pd.encryptionRequested THEN Thrush.unencrypted
ELSE NamesRPC.StartConversation [
caller: myName.instance,
callee: fullRname,
key: serverPassword,
level:
--<<ECB>>--CBCCheck !
RPC.AuthenticateFailed=> {
Log.ProblemFR["Can't authenticate %g to %g", $System,
NIL,
rope[myName.instance], rope[fullRname]]; GOTO NotSmart; }];
Make sure we can talk to the Lark
larkInterface ← LarkRpcControl.ImportNewInterface[
interfaceName: [type: "Lark.Lark", instance: clientInstance] !
RPC.ImportFailed=> {
Log.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. >>
larkInterface.Reset[larkSh, NIL];
localSmarts ← ThSmartsRpcControl.NewInterfaceRecord[];
localSmarts.clientStubProgress ← ThSmartsPrivate.LarkProgress;
smartsID←ThPartyPrivate.RegisterLocal[
partyID: partyID,
interface: localSmarts,
properties: [x: voiceTerminal[machine: netAddress]]
];
IF smartsID=nullHandle
THEN {Log.ProblemFR["Can't register Lark: %g, %g",$System,
NIL,
rope[fullRname], rope[clientInstance]]; GOTO NotSmart; };
No further bad things are expected to happen.
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 ]];
Log.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;
};
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
Log.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.
Consider additional structure relating net addresses to smarts, or the equivalent, in next redesign. May 22, 1985 5:16:18 pm PDT>>
DR: ENTRY PROC[info: SmartsInfo] = { Deregister[info]; };
ConsiderOne: Triples.ForeachProc = {
smartsData: ThPartyPrivate.SmartsData ← NARROW[trip.val];
IF smartsData#
NIL
THEN
WITH prop: smartsData.properties
SELECT
FROM
voiceTerminal => IF netAddress = prop.machine 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];
};