DIRECTORY
IO,
Lark
-- USING [
-- CommandEvents, ConnectionSpec, Event, LarkModel, Passel, SHHH, StatusEvent, StatusEvents ]--,
LarkRpcControl USING [ ImportNewInterface, InterfaceRecord ],
LarkSmarts,
LarkSmartsMonitorImpl,
LarkSmartsRpcControl USING [ExportInterface, InterfaceName, UnexportInterface],
Log USING [ DNFProc, RegisterWhereToReport, ReportFR, Problem, ProblemFR, WhereProc ],
LupineRuntime,
Names USING [CurrentPasskey, RnameToRspec, Rspec ],
NamesRPC USING [ StartConversation ],
Nice USING [ LarkConLogStream ],
RPC USING [ AuthenticateFailed, EncryptionKey, ExportFailed, GetCaller, ImportFailed ],
SafeStorage USING [ GetCanonicalType, Type ],
ThNet USING [ pd ],
ThPartyPrivate USING [ DehandleSmarts, LocalSmartsInterface, RegisterLocal, SmartsBody, SmartsData, GetPartySmarts ],
ThParty USING [ CreateParty, Deregister, Enable ],
Thrush USING [
CallUrgency, ConversationHandle, Disposition, epoch, Epoch, H, NetAddress, none, nullHandle, PartyHandle, ROPE, SmartsHandle, ThHandle, unencrypted ],
ThSmartsPrivate
USING [
CheckHookState, EnterLarkState, GetSmartsInfo, LarkFailed, LarkInfo, LarkInfoBody, LarkParseEvent, LarkProgress, LarkSupervise, RegisterTrunk, SmartsInfo, SmartsInfoBody ],
ThSmartsRpcControl,
Triples USING [ Erase, Make ],
TU,
UserProfile USING [ Token ]
;
Copies
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;
Registration/Deregistration/Initialization
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;
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.ReportFR["Registering party %s not found", $System, NIL, rope[partyRname]];
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 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.Progress ← 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]] ]];
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
EXIT;
REPEAT
NotSmart => RETURN;
ENDLOOP;
};
EnableSmartsE: ENTRY PROC[info: SmartsInfo] = { []𡤎nableSmarts[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
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.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 };
Other Utilities
WhereIsSmartsLog: Log.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[[[0],[0]]] THEN s←NIL; -- use default stream unless debug viewer stream open.
};
WhereIsLarkLog: Log.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[[[0],[0]]] THEN s←NIL; -- only want the debug viewer stream
};
WhereIsLarkLogFerSherr: Log.WhereProc ← WhereIsLarkLog;
FerSherrDefault: Log.DNFProc=
TRUSTED{
RETURN[ThNet.pd.defaultLarkReports]; };
}.