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 ] = {
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;
s: Names.Rspec ← NIL;
gvDetails: Names.GVDetails;
ringEnable: ThSmartsPrivate.RingEnable ← on;
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.
DO
ENABLE
UNWIND=>
NULL;
Loop is for restart when had to deregister first.
Produce a Party object for this RName, if none exists yet.
partyID ← ThParty.CreateParty[
type: (SELECT model.genre FROM --<<>>-- ENDCASE=> individual),
rName: partyRname];
IF partyID=nullHandle
THEN
{
Log.Report[IO.PutFR["Registering party %s not found", rope[partyRname]], $System];
RETURN[nullHandle, Thrush.epoch];
};
This reregistration should be a no-op, if all of the supplied parameters make sense.
Otherwise, if there is a previous smartsID for this Lark, it must be eliminated.
<< This may all cause trouble later when users log in at Larks -- WAIL.>>
smartsID ← ThPartyPrivate.GetPartySmarts[partyID, $VoiceTerminal];
IF smartsID#nullHandle
THEN {
DR:
ENTRY
PROC = {
ENABLE UNWIND=>NULL;
Deregister[ThSmartsPrivate.GetSmartsInfo[smarts: smarts]];
};
smarts ← ThPartyPrivate.DehandleSmarts[smartsID];
IF oldSmartsID=smartsID
AND epoch = Thrush.epoch
AND smarts#
NIL
THEN
WITH smarts.properties
SELECT
FROM
voiceTerminal, manager =>
IF machine = netAddress THEN RETURN[oldSmartsID, Thrush.epoch];
ENDCASE; -- oldHandle is a strange beast indeed.
IF smarts#NIL THEN DR[];
smartsID←nullHandle; partyID ← nullHandle; LOOP;
There are no old Lark Smarts for this Lark. New ones are needed.
Get encryption taken care of
larkSh ← IF NOT ThNet.pd.encryptionRequested THEN Thrush.unencrypted
ELSE Names.StartConversation [
caller: myName.instance,
callee: fullRname,
key: serverPassword,
level:
--<<ECB>>--CBCCheck !
RPC.AuthenticateFailed=>{ Log.Problem["Can't authenticate"]; GOTO NotSmart; }];
Make sure we can talk to the Lark
larkInterface ← LarkRpcControl.ImportNewInterface[
interfaceName: [type: "Lark.Lark", instance: clientInstance] !
RPC.ImportFailed=> { Log.Problem["Can't import Lark interface"]; 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.Progress ← ThSmartsPrivate.LarkProgress;
smartsID←ThPartyPrivate.RegisterLocal[
partyID: partyID,
interface: localSmarts,
properties: [x: voiceTerminal[machine: netAddress]] !
-- << If decide to return error code to caller, problem tells the story. >> --
Names.NetError=> { smartsID ← nullHandle; CONTINUE; }];
IF smartsID = nullHandle THEN { Log.Problem["Can't register Lark"]; 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]] ]];
info.larkInfo.scratchEv ← NEW[Lark.CommandEventSequence[15]];
IF ([,gvDetails] ← Names.GetDefaultDetails[info.larkInfo.netAddress]).results = ok AND
gvDetails#
NIL
AND gvDetails.larkSpec
THEN
ringEnable ←
SELECT gvDetails.ringEnable
FROM
'R => on,
'S => subdued,
'O => off,
ENDCASE => on;
ThSmartsPrivate.SetRingingParameters[
info: info.larkInfo, ringEnable: ringEnable, ringTune: gvDetails.ringTune]; -- set to current defaults
Triples.Make[$SmartsData, smarts, info];
info.otherSmarts ← ThPartyPrivate.DehandleSmarts[
ThSmartsPrivate.RegisterTrunk[ partyID, smarts, info ]];
Log.Report[IO.PutFR[" (%g = %g)",
rope[clientInstance], TU.RefAddr[info.smarts]], $Smarts, info];
EnableSmartsE[info]; -- Ready to go, as long as phone is on hook
EXIT;
REPEAT
NotSmart => RETURN;
ENDLOOP;
};
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];
};
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];
Unimport the Lark interface (automatic, via finalization.)
Log.Report[IO.PutFR["Smarts %d (%g) is dead", card[H[info.smarts]], TU.RefAddr[info.smarts]], $Smarts, info];
};