<> <> <> <<>> <> <> <<>> DIRECTORY FinchSmarts USING [ FinchInfo, pd, Problem, ReportSystemStateProc ], GVBasics USING [ Password ], IO, MBQueue USING [ QueueClientAction ], NameDB USING [ Error, GetAttribute ], ThPartyRpcControl, RefID USING [ ID ], Rope USING [ ROPE ], RPC, RPCLupine, ThParty, Thrush USING [ ActionReport, AlertKind, CallUrgency, ConvEvent, ConversationID, EncryptionKey, KeyTable, InterfaceSpec, PartyID, PartyType, SmartsID, nullID, Credentials, NB, Reason, ROPE, SHHH, StateInConv, unencrypted ], ThVersions USING [ GetThrushVR, ThrushVersion ], VoiceUtils USING [ NetAddress, NetAddressFromRope, OwnNetAddress, Problem ] ; ThPartyClientImpl: CEDAR MONITOR IMPORTS FinchSmarts, IO, MBQueue, NameDB, RealControl: ThPartyRpcControl, RealThParty: ThParty, RPC, ThVersions, VoiceUtils EXPORTS FinchSmarts, ThParty = { OPEN IO, pd: FinchSmarts.pd, ThParty; <> <<>> ConversationID: TYPE = Thrush.ConversationID; PartyID: TYPE = Thrush.PartyID; SmartsID: TYPE = Thrush.SmartsID; nullID: RefID.ID = Thrush.nullID; Credentials: TYPE = Thrush.Credentials; NB: TYPE = Thrush.NB; ROPE: TYPE = Thrush.ROPE; SHHH: TYPE = Thrush.SHHH; none: SHHH = Thrush.unencrypted; SmartsInterfaceName: TYPE = RPC.InterfaceName; SmartsProperties: TYPE=ThParty.SmartsProperties; <<>> SmartsRole: TYPE= ThParty.SmartsRole; -- { $voiceTerminal, $controller, ? }; myInfo: FinchSmarts.FinchInfo _ NIL; unexpected: ROPE _ "Unexpected server failure"; <> CreateConversation: PUBLIC ENTRY PROC[ shhh: SHHH, credentials: Credentials, state: Thrush.StateInConv, urgency: Thrush.CallUrgency, alertKind: Thrush.AlertKind, reason: Thrush.Reason, comment: ROPE, subject: Thrush.ROPE, checkConflict: BOOL ] RETURNS [ nb: NB, convEvent: Thrush.ConvEvent ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb, convEvent] _ RealThParty.CreateConversation[shhh, credentials, state, urgency, alertKind, reason, comment, subject, checkConflict]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <>> <> <> Alert: PUBLIC ENTRY PROC[ shhh: SHHH, credentials: Credentials, calledPartyID: PartyID, comment: ROPE ] RETURNS [nb: NB ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; nb _ RealThParty.Alert[shhh, credentials, calledPartyID, comment]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <> <> <> <>> <> <> Advance: PUBLIC ENTRY PROC[ shhh: SHHH, credentials: Credentials, state: Thrush.StateInConv, reportToAll: BOOL, reason: Thrush.Reason, comment: ROPE, bilateral: BOOL, checkConflict: BOOL ] RETURNS [nb: NB, convEvent: Thrush.ConvEvent ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb, convEvent] _ RealThParty.Advance[shhh, credentials, state, reportToAll, reason, comment, bilateral, checkConflict]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> ReportAction: PUBLIC ENTRY PROC[ shhh: SHHH, report: Thrush.ActionReport, reportToAll: BOOL, selfOnCompletion: BOOL ] RETURNS [nb: NB, numReportsIssued: NAT] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; report.other.partyID _ myInfo.partyID; report.other.smartsID _ myInfo.smartsID; [nb, numReportsIssued] _ RealThParty.ReportAction[shhh, report, reportToAll, selfOnCompletion]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <> GetConversationInfo: PUBLIC ENTRY PROC [ shh: SHHH, convID: ConversationID ] RETURNS [ nb: NB, cInfo: ConversationInfo ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; [nb, cInfo] _ RealThParty.GetConversationInfo[shh, convID]; }; <> <> <> <> GetPartyInfo: PUBLIC ENTRY PROC [ shh: SHHH_none, credentials: Credentials, nameReq: NameReq, allParties: BOOL_FALSE ] RETURNS [nb: NB, pInfo: PartyInfo] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb, pInfo] _ RealThParty.GetPartyInfo[shh, credentials, nameReq, allParties]; }; <> <> <> <> <> <> DescribeParty: PUBLIC ENTRY PROC[partyID: Thrush.PartyID, nameReq: NameReq] RETURNS[nb: NB, description: Thrush.ROPE, type: Thrush.PartyType, partner: Thrush.PartyID, visitee: Thrush.PartyID, visitors: LIST OF Thrush.PartyID ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; [nb, description, type, partner, visitee, visitors] _ RealThParty.DescribeParty[partyID, nameReq]; }; <> <> <> <> <> RegisterServiceInterface: PUBLIC ENTRY PROC[ shhh: SHHH, credentials: Credentials, interfaceSpecPattern: Thrush.InterfaceSpec ] RETURNS[nb: NB, interfaceSpec: Thrush.InterfaceSpec] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb, interfaceSpec] _ RealThParty.RegisterServiceInterface[shhh, credentials, interfaceSpecPattern]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> LookupServiceInterface: PUBLIC ENTRY PROC[ shhh: SHHH, credentials: Credentials, serviceParty: PartyID, type: RPC.ShortROPE ] RETURNS[nb: NB, interfaceSpec: Thrush.InterfaceSpec] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb, interfaceSpec] _ RealThParty.LookupServiceInterface[shhh, credentials, serviceParty, type]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> RegisterKey: PUBLIC ENTRY PROC[ shh: SHHH, credentials: Credentials, key: Thrush.EncryptionKey, reportNewKeys: BOOL ] RETURNS [ nb: NB, keyIndex: [0..17B] ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb, keyIndex] _ RealThParty.RegisterKey[shh, credentials, key, reportNewKeys]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <> GetKeyTable: PUBLIC ENTRY PROC [ shh: SHHH, credentials: Credentials ] RETURNS [ nb: NB, keyTable: Thrush.KeyTable ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb, keyTable] _ RealThParty.GetKeyTable[shh, credentials]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> UnregisterKey: PUBLIC ENTRY PROC[ shh: SHHH, credentials: Credentials, key: Thrush.EncryptionKey ] RETURNS [ nb: NB ] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; [nb] _ RealThParty.UnregisterKey[shh, credentials, key]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> GetParty: PUBLIC ENTRY PROC[ shh: SHHH, partyID: PartyID, rName: ROPE, type: Thrush.PartyType ] RETURNS [nb: NB, newPartyID: PartyID] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; partyID _ myInfo.partyID; [nb, newPartyID] _ RealThParty.GetParty[shh, partyID, rName, type]; SELECT nb FROM $noSuchParty => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <> GetPartyFromNumber: PUBLIC ENTRY PROC[ shh: SHHH, partyID: PartyID, phoneNumber: Thrush.ROPE, description: ROPE ] RETURNS [nb: NB, newPartyID: PartyID] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; partyID _ myInfo.partyID; [nb, newPartyID] _ RealThParty.GetPartyFromNumber[shh, partyID, phoneNumber]; SELECT nb FROM $noSuchParty => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> GetPartyFromFeepNum: PUBLIC ENTRY PROC[ shh: SHHH, partyID: PartyID, feepNum: Thrush.ROPE ] RETURNS [nb: NB, newPartyID: PartyID] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; partyID _ myInfo.partyID; [nb, newPartyID] _ RealThParty.GetPartyFromFeepNum[shh, partyID, feepNum]; SELECT nb FROM $noSuchParty => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <> <> GetCurrentParty: PUBLIC ENTRY PROC[shh: SHHH, smartsID: SmartsID] RETURNS [nb: NB, partyID: Thrush.PartyID] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; smartsID _ myInfo.smartsID; [nb, partyID] _ RealThParty.GetCurrentParty[shh, smartsID]; SELECT nb FROM $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> ReleaseParty: PUBLIC ENTRY PROC[shh: SHHH, partyID: PartyID, targetPartyID: PartyID] RETURNS [nb: NB] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; partyID _ myInfo.partyID; [nb] _ RealThParty.ReleaseParty[shh, partyID, targetPartyID]; }; <> <> <> GetNumbersForRName: PUBLIC ENTRY PROC[shh: SHHH_none, rName: ROPE] RETURNS [fullRName: ROPE_NIL, number: ROPE_NIL, homeNumber: ROPE_NIL] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF PostError[why]=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND PostError[$unbound]#$success THEN RETURN; [fullRName, number, homeNumber] _ RealThParty.GetNumbersForRName[shh, rName]; }; <> <> <> <> <> <> <> <<] RETURNS [ nb: NB, credentials: Credentials ] = {>> <> < NULL;>> < IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE;>> <<};>> <> <<[nb, credentials] _ RealThParty.Register[shh, rName, type, clonePartyID, interface, properties];>> <<};>> <> <> <> <> <> <> <> <> <> <> CheckIn: PUBLIC ENTRY PROC[shh: SHHH, credentials: Credentials] RETURNS [nb: NB] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; credentials.partyID _ myInfo.partyID; credentials.smartsID _ myInfo.smartsID; nb _ RealThParty.CheckIn[shh, credentials]; SELECT nb FROM $noSuchSmarts, $noSuchParty => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> < NULL;>> < IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE;>> <<};>> <> <> <> < nb _ Quit[nb, unexpected]; ENDCASE;>> <<};>> <> <> <> <> <> Disable: PUBLIC ENTRY PROC[shh: SHHH, smartsID: SmartsID] RETURNS [nb: Thrush.NB] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; smartsID _ myInfo.smartsID; nb _ RealThParty.Disable[shh, smartsID]; SELECT nb FROM $noSuchParty, $noSuchSmarts => nb _ Quit[nb, unexpected]; ENDCASE; }; <> Visit: PUBLIC ENTRY PROC[shh: SHHH, visitedParty: PartyID, visitingParty: PartyID, visitingPassword: GVBasics.Password] RETURNS [nb: Thrush.NB] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; visitedParty _ myInfo.partyID; nb _ RealThParty.Visit[shh, visitedParty, visitingParty, visitingPassword]; SELECT nb FROM $noSuchParty => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <<>> Unvisit: PUBLIC ENTRY PROC[shh: SHHH, visitedParty: PartyID, visitingParty: PartyID, visitingPassword: GVBasics.Password] RETURNS [nb: NB] = { ENABLE { UNWIND => NULL; RPC.CallFailed => IF (nb_PostError[why])=$success THEN RETRY ELSE CONTINUE; }; IF (~pd.connected) AND (nb_PostError[$unbound])#$success THEN RETURN; visitedParty _ myInfo.partyID; nb _ RealThParty.Unvisit[shh, visitedParty, visitingParty, visitingPassword]; SELECT nb FROM $noSuchParty => nb _ Quit[nb, unexpected]; ENDCASE; }; <> <> <> <> <> <> <> <> <> <<>> FinchRegister: PUBLIC ENTRY PROC[ info: FinchSmarts.FinchInfo, interfaceName: RPC.InterfaceName] RETURNS[nb: NB] = { ENABLE UNWIND => NULL; pd.enabled _ TRUE; -- Whether successful or not, a connection is now the desired thing. myInfo _ info; pd.connected _ FALSE; pd.interfaceName _ interfaceName; nb _ PostError[$unbound]; }; FinchDeregister: PUBLIC ENTRY PROC[info: FinchSmarts.FinchInfo, disable: BOOL] RETURNS [nb: NB_$success] = { ENABLE UNWIND => NULL; IF disable THEN pd.enabled _ FALSE; IF pd.connected AND myInfo=info THEN nb _ RealThParty.Deregister[myInfo.shh, myInfo.smartsID!RPC.CallFailed=>CONTINUE]; <> IF ~disable THEN []_Quit[$serverDown]; }; <> PostError: INTERNAL PROC[why: RPC.CallFailure] RETURNS [nb: NB_$success] = { ENABLE { RPC.ImportFailed => { IF why=$wrongVersion THEN { pd.enabled _ FALSE; nb _ Quit[$serverDown, IO.PutFR["Finch version %d too old; import failed", card[ThVersions.ThrushVersion]]]; } ELSE nb _ Quit[$serverDown, IO.PutFR["Could not import ThParty (%g)", rope[pd.interfaceName.instance]]]; CONTINUE; }; RPC.CallFailed => { nb _ Quit[$serverDown, IO.PutFR["Could not import ThParty (%g)", rope[pd.interfaceName.instance]]]; CONTINUE; }; NameDB.Error => { nb _ Quit[$serverDown, IO.PutFR["ThParty import db query failed (%g): %g", atom[ec], rope[explanation]]]; CONTINUE; }; }; hostHint: RPCLupine.RPCHost; credentials: Thrush.Credentials; IF ~pd.enabled THEN RETURN[$notEnabled]; SELECT why FROM $timeout, $busy => VoiceUtils.Problem[IO.PutFR["No response from ThParty (%g)", rope[pd.interfaceName.instance]], $Finch]; $runtimeProtocol, $stubProtocol => VoiceUtils.Problem[ "Protocol violation in communications with ThParty database", $Finch]; $unbound => NULL; ENDCASE=>ERROR; pd.connected _ FALSE; hostHint _ VoiceUtils.NetAddressFromRope[ NameDB.GetAttribute[pd.interfaceName.instance, $connect]]; pd.interfaceName.version _ ThVersions.GetThrushVR; RealControl.ImportInterface[interfaceName: pd.interfaceName, hostHint: hostHint]; [nb, credentials]_RealThParty.Register[ shh: myInfo.shh, rName: myInfo.myRName, type: $individual, interface: myInfo.myName, properties: [$controller, VoiceUtils.OwnNetAddress[]] ]; IF nb=$success THEN nb _ RealThParty.Enable[shh: myInfo.shh, smartsID: credentials.smartsID]; IF nb#$success THEN { nb _ Quit[nb, "Can't register with server"]; RETURN; }; myInfo.smartsID _ credentials.smartsID; myInfo.partyID _ credentials.partyID; pd.connected _ TRUE; ReportSystemState[]; }; <> <<>> ReportSystemState: INTERNAL PROC ~ { IF myInfo=NIL THEN RETURN; pd.requests.QueueClientAction[ReallyReportSystemState, myInfo]; }; ReallyReportSystemState: PROC [r: REF] ~ { info: FinchSmarts.FinchInfo _ NARROW[r]; IF info=NIL THEN RETURN; FOR l: LIST OF FinchSmarts.ReportSystemStateProc _ info.systemStateSubscribers, l.rest UNTIL l=NIL DO l.first[pd.enabled, pd.connected]; ENDLOOP; }; QUit: PUBLIC ENTRY PROC[proposedNB: NB, problem: Rope.ROPE_NIL] RETURNS[nb: NB] = { RETURN[Quit[proposedNB, problem]]; }; Quit: INTERNAL PROC[proposedNB: NB, problem: Rope.ROPE_NIL] RETURNS[nb: NB] = { pd.connected _ proposedNB=$success; ReportSystemState[]; IF problem#NIL THEN FinchSmarts.Problem[problem, nb]; RETURN[proposedNB]; }; }. <> <> <<>>