ThParty.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last modified by Swinehart, May 22, 1985 12:18:34 pm PDT
Parties and Conversations
DIRECTORY
Basics USING [ LongNumber, BITAND ],
Lark,
Thrush USING [
AlertKind, CallUrgency, ConversationHandle, ConvEventBody, Credentials, EncryptionKey, IntervalSpec, IntervalSpecs, NB, nullHandle, PartyHandle, PartyType, ProseSpecs, Reason, RingEnable, Rname, ROPE, SHHH, SmartsHandle, StateID, StateInConv, ThHandle, unencrypted, VoiceTime ],
ThSmarts USING [
SmartsInterface, SmartsProperties ]
;
ThParty: CEDAR DEFINITIONS IMPORTS Basics = {
Redefinitions, Obligatory Concrete, simple types
PartyHandle: TYPE = Thrush.PartyHandle;
ConversationHandle: TYPE = Thrush.ConversationHandle;
SmartsHandle: TYPE = Thrush.SmartsHandle;
nullHandle: Thrush.ThHandle = Thrush.nullHandle;
AlertKind: TYPE = Thrush.AlertKind;
CallUrgency: TYPE = Thrush.CallUrgency;
ConvEventBody: TYPE = Thrush.ConvEventBody;
Credentials: TYPE = Thrush.Credentials;
NB: TYPE = Thrush.NB;
Reason: TYPE = Thrush.Reason;
Rname: TYPE = Thrush.Rname;
ROPE: TYPE = Thrush.ROPE;
SHHH: TYPE = Thrush.SHHH;
none: SHHH = Thrush.unencrypted;
SmartsInterface: TYPE = ThSmarts.SmartsInterface;
StateID: TYPE = Thrush.StateID;
StateInConv: TYPE = Thrush.StateInConv;
convClassMask: CARDINAL = 377B;
Conversation Management
A Smarts must relay all call-placement requests through a Party it is associated with. This is because we don't trust all Smarts as much as we trust all Parties; the Parties should validate the requests.
Alert can either perform a feasibility study, or an actual attempt to connect. In either case, it provokes an answer indicating how likely it is that the connection would (will) be made. To perform the feasibility study, the alertKind parameter should be queryOnly (the conversation argument need not be supplied for this call.) This allows the calling client to determine whether the callee is busy, filtered out, missing in action, etc., before attempting to make the call. It also allows the calling client to obtain this information for some reason other than to place the call. If the call fails, perhaps it will succeed if the priority is increased.
When the call has been accepted or rejected, the result will be reported back to the caller of Alert via a call to ThSmarts.Progress. Alert the end client or user associated with EACH "PENDING" PARTY of the attempted connection.
Alert[..., calledPartyID: nullHandle, ... state: reserved, ...] reserves presence in conv. without attempting a connection (state reserved).
Alert: PROC[
shhh: SHHH ← none,
credentials: Credentials,
state: StateInConv←initiating,  -- IF reserved, reason specifies reason for cancelling prev.
reason: Reason←wontSay,
calledPartyID: PartyHandle←nullHandle,
urgency: CallUrgency←normal,
alertKind: AlertKind←standard,
newConv: BOOLFALSE,
comment: ROPENIL
] RETURNS [nb: NB, convID: ConversationHandle ];
Called by Smarts to progress through a call; answer, indicate "ringing", reject, "hold", . . .   
Advance: PROC[
shhh: SHHH ← none,
credentials: Credentials,
state: StateInConv,
reason: Reason←wontSay,
comment: ROPENIL
] RETURNS [nb: NB];
Conversations
Create a conversation with nobody in it, state empty or something. Scavengers may reclaim it after a time if no Party joins it. conv, stateID fields of Credentials are ignored.
CreateConversation: PROC[
shhh: SHHH ← none,
credentials: Credentials,
urgency: CallUrgency←normal,
alertKind: AlertKind←standard
] RETURNS [ nb: NB, convID: ConversationHandle ];
SameConvClass: PROC[convID1: ConversationHandle, convID2: ConversationHandle]
RETURNS [sameClass: BOOL] = INLINE {
ln1: Basics.LongNumber=LOOPHOLE[convID1];
ln2: Basics.LongNumber=LOOPHOLE[convID2];
IF ln1.lowbits#ln2.lowbits THEN RETURN[FALSE];
RETURN[
Basics.BITAND[ln1.highbits,convClassMask]=Basics.BITAND[ln2.highbits,convClassMask]];
};
MergeConversations: PROC[
shhh: SHHH ← none,
credentials: Credentials, -- of surviving conversation
otherStateID: StateID, -- of dissolving conversation
otherConvID: ConversationHandle
] RETURNS [ nb: NB ];
OtherParty: PROC[
shhh: SHHH←none,
credentials: Credentials
] RETURNS[ nb: NB, partyID: PartyHandle, description: Thrush.ROPE, conference: BOOL ];
Produces ID of one other party, + description. If # parties > 2, description is best efforts description of who's in it with credentials.partyID, conference is TRUE.
DescribeParty: PROC[
shh: SHHH←none,
partyID: PartyHandle]
RETURNS[ description: Thrush.ROPE
];
Like GetRName.... but produces best available user-oriented description.
Enumerations, queries
ConversationsForParty: PROC [ shh: SHHH←none, partyID: PartyHandle ];
Caller should expect to be informed of all conversations currently in progress for this party. So should all of the other Smartses connected to the party. Thus, a Smarts must be prepared to hear about the same event twice. <<Could cause trouble when interval specs, connection specs, and conversation keys are being distributed.>>
Recorded voice management.
SetIntervals: PROC[
shhh: SHHH ← none,
credentials: Credentials,
intervalSpecs: Thrush.IntervalSpecs -- a list allows some queueing at request site.
]
RETURNS [ nb: NB ];
This is provided as a convenience. It simply calls a similar procedure in the currently connected Jukebox service to describe the loud and silence intervals within the specified interval. Implementation tries to keep things unlocked; nonexistence of an interval might arise due to tunes in transition.
DescribeInterval: PROC[
shhh: SHHH ← none,
credentials: Credentials,
targetInterval: Thrush.IntervalSpec,
minSilence: Thrush.VoiceTime ← 1 -- Smallest silent interval that will be considered silence.
]
RETURNS [ nb: NB, exists: BOOL, intervals: Thrush.IntervalSpecs ];
RegisterKey: PROC[
shh: SHHH ← none,
credentials: Credentials,
key: Thrush.EncryptionKey
]
RETURNS [ nb: NB, keyIndex: [0..17B] ];
Synthesized-voice management (intend to fold into voice-rope-style design next round)
SetProse: PROC[
shhh: SHHH ← none,
credentials: Credentials,
proseSpecs: Thrush.ProseSpecs -- a list allows some queueing at request site.
]
RETURNS [ nb: NB ];
Party Initialization
The PartyHandle is used by local or remote Smarts and other Parties to invoke the Party's functions. The Party is the dynamic representative of its Rname; most of the system functions traffic in PartyHandles. Clients should convert from Rname to Party as early as possible.
Returns NIL if no valid name found.
Owning Smarts identify (and authenticate) themselves to Parties using Register*[]. That's where the password action is. GetParty assumes that a Party for the specified party already exists, returning NIL if none can be found. The self argument is the caller's own Party; it's used to obtain the corresponding trunk, or "back door", Party when the callee must be reached via the public network.
CreateParty also returns an existing Party if there is one. If there isn't, it creates one instead, as long as the Rname is valid. This is for use by the Smarts registration procedures.
For parties of type "service", only the service name is provided (e.g., "Jay") as rName. The Create procedure adds the needed frippery.
CreateParty: PROC[
shh: SHHH←none, rName: Rname←NIL, type: Thrush.PartyType
] RETURNS [partyID: PartyHandle];
GetParty: PROC[
shh: SHHH←none, partyID: PartyHandle, rName: Rname←NIL,
type: Thrush.PartyType←individual
] RETURNS [newPartyID: PartyHandle];
Raises Thrush.ServerError if fatal confusion arises.
For other troubles ~~ no such name, no network response ~~ returns NIL
Replaces GetJayParty: if type is "service", then rName will be a serviceName, and we need to obtain an idle party supporting the named service (named "idle.serviceName.Lark") and assigns it to self. When conversations involving such parties end, they are idled. <<If errors occur before the conversations are established, possibly these end up not being idled?>> Typical service names are "Recording", "Text-to-Speech", etc.
phoneNumber is a valid extension or outside telephone number. Description is probably a name, but may not be an RName; we can use it to help the user, but not to look up anything.
Unless trunkOK, number must be an internal extension representing an Etherphone user.
GetPartyFromNumber: PROC[
shh: SHHH←none,
partyID: PartyHandle,
phoneNumber: Thrush.ROPENIL, description: ROPENIL, trunkOK: BOOLTRUE
] RETURNS [newPartyID: PartyHandle];
FeepNum is a string of the form "*nnnnn", where "nnnnn" is a prefix of some rName, mapped with information loss into the corresponding DTMF buttons. The prefix should be long enough to be guaranteed unique within the system. This isn't at all good yet.
GetPartyFromFeepNum: PROC[
shh: SHHH←none,
partyID: PartyHandle,
feepNum: Thrush.ROPENIL
] RETURNS [newPartyID: PartyHandle];
Return the Rname for a given fone
GetRname: PROC[shh: SHHH←none, partyID: PartyHandle] RETURNS [Rname: Thrush.Rname];
A Smarts uses one of these Register* functions to identify itself as the owner (implementor) of the specified Party, and to supply the Party with necessary attribute information. If a password is provided (and is OK), the smarts will be an authenticated smarts. This will carry additional privileges. At present, the attributes comprise a role that will determine the order in which multiple Smarts for a Party will be polled, when polling is necessary. The idea is that first workstations, then Larks, will get the oportunity to deal with each action. When the role is "voiceTerminal", the attributes also include a Thrush.Machine value identifying the machine that can carry out a voice conversation.
Since there can be more than one Smarts implementation per Party, the Smarts must also supply its interface as an RPC-style interface record.
A Thrush-based Smarts uses RegisterLocal to supply the interface record directly (type LocalSmartsInterface). A remote Smarts uses Register to supply an RPC InterfaceName that can be used to import the proper implementation (type SmartsInterface).
A Smarts re-registers when it wants to supply a new/different password, when the Lark or workstation it represents is reinitialized, or at any other time it chooses to. When re-registering, a Smarts should include its current handle, but be willing to believe the returned one if it's different. This is the Party-level analog of the LarkSmarts.Register[] approach to resiliency.
Register: PROC[shh: SHHH←none, partyID: PartyHandle, interface: SmartsInterface,
properties: ThSmarts.SmartsProperties, oldSmartsID: SmartsHandle←nullHandle]
RETURNS [smartsID: SmartsHandle];
RegisterClone: PROC[shh: SHHH←none, partyID: PartyHandle,
clonePartyID: PartyHandle, oldSmartsID: SmartsHandle←nullHandle]
RETURNS [smartsID: SmartsHandle];
Deregister: PROC[shh: SHHH←none, smartsID: SmartsHandle];
Enable: PROC[shh: SHHH←none, smartsID: SmartsHandle]
RETURNS [nb: Thrush.NB];
nb=success unless something went wrong. Any parties connected to this smarts will now be available to GetParty; this smarts is an active voice smarts.
Disable: PROC[shh: SHHH←none, smartsID: SmartsHandle]
RETURNS [nb: Thrush.NB];
This smarts can no longer supply a voice connection to its parties.
GetNumbersForRName: PROC[shh: SHHH←none, rName: ROPE]
RETURNS [fullRName: ROPE, number: ROPE, homeNumber: ROPE];
fullRName is NIL if nothing found.
SetRingEnable: PROC[shh: SHHH←none, partyID: PartyHandle, ringEnable: Thrush.RingEnable←noChange, ringInterval: INT𡤀, update: BOOLFALSE];
}.
Swinehart, May 15, 1985 10:01:11 am PDT
Cedar 6.0
changes to: GetParty stuff simplified (from client standpoint), Prose functions added, some unused procedures removed.