DIRECTORY BasicTime USING [ GMT ], IV, RefID USING [ ID ], RPC USING [ InterfaceName, ShortROPE ], Thrush USING [ ActionReport, AlertKind, CallUrgency, ConversationID, ConvEvent, Credentials, EncryptionKey, InterfaceSpec, KeyTable, NetAddress, NB, nullID, noAddress, PartyID, PartyType, Reason, ROPE, SHHH, SmartsID, StateInConv, unencrypted, VoiceSocket ], ThSmartsRpcControl ; ThParty: CEDAR DEFINITIONS = { 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; SmartsInterfaceRecord: TYPE = ThSmartsRpcControl.InterfaceRecord; SmartsProperties: TYPE=RECORD[ role: SmartsRole_NIL, netAddress: Thrush.NetAddress_Thrush.noAddress ]; SmartsRole: TYPE= ATOM; -- { $voiceTerminal, $controller, ? }; CreateConversation: PROC[ shhh: SHHH _ none, credentials: Credentials, state: Thrush.StateInConv_$initiating, urgency: Thrush.CallUrgency_NIL, -- $normal alertKind: Thrush.AlertKind_NIL, -- $standard reason: Thrush.Reason _ NIL, -- if present, state is probably $failed (to get error signals when no conversation was ever established.) comment: ROPE _ NIL, subject: Thrush.ROPE_NIL ] RETURNS [ nb: NB, convEvent: Thrush.ConvEvent ]; Alert: PROC[ shhh: SHHH _ none, credentials: Credentials, calledPartyID: PartyID_nullID, comment: ROPE_NIL ] RETURNS [nb: NB ]; Advance: PROC[ shhh: SHHH _ none, credentials: Credentials, state: Thrush.StateInConv, reportToAll: BOOL_FALSE, reason: Thrush.Reason_NIL, -- wontSay comment: ROPE_NIL ] RETURNS [nb: NB, convEvent: Thrush.ConvEvent ]; ReportAction: PROC[ shhh: SHHH _ none, report: Thrush.ActionReport, -- includes credentials (in other field) identifying the service party. reportToAll: BOOL _ FALSE, selfOnCompletion: BOOL_FALSE ] RETURNS [nb: NB, numReportsIssued: NAT_0]; ConversationInfo: TYPE = RECORD [ subject: ROPE_NIL, urgency: Thrush.CallUrgency_NIL, alertKind: Thrush.AlertKind_NIL, startTime: BasicTime.GMT_TRASH, conferenceHost: Thrush.NetAddress_TRASH, numParties: NAT_TRASH, numActive: NAT_TRASH, numIdle: NAT_TRASH, originator: Thrush.PartyID _ TRASH ]; GetConversationInfo: PROC [ shh: SHHH_none, convID: ConversationID ] RETURNS [ nb: NB, -- one of $success, $noSuchConv cInfo: ConversationInfo ]; PartyInfo: TYPE = REF PartyInfoSeq; PartyInfoSeq: TYPE = RECORD [ numParties: NAT_0, -- number of valid entries in this sequence conferenceHost: Thrush.NetAddress_TRASH, -- needed for connection spec. stuff. parties: SEQUENCE len: NAT OF PartyInfoSpec ]; PartyInfoSpec: TYPE = RECORD [ partyID: PartyID_nullID, type: Thrush.PartyType_NIL, state: Thrush.StateInConv_$neverWas, -- of this party in the conversation name: Thrush.ROPE_NIL, -- owner, current name, or description, see below numConvs: NAT_TRASH, enabled: BOOL_TRASH, partyActive: BOOL_TRASH, socket: Thrush.VoiceSocket_TRASH -- in1 (tx1) socket template for voice terminal for this party ]; NameReq: TYPE = ATOM; -- { $owner, $current, $description, $address, $none }; GetPartyInfo: PROC [ shh: SHHH_none, credentials: Credentials, nameReq: NameReq_$current, allParties: BOOL_FALSE -- IF FALSE, just calling party; else all parties, calling party first ] RETURNS [ nb: NB, -- one of $success, $noSuchConv, $noSuchParty, $notInConv pInfo: PartyInfo ]; DescribeParty: PROC[partyID: Thrush.PartyID, nameReq: NameReq] RETURNS[nb: NB, description: Thrush.ROPE]; RegisterServiceInterface: PROC[ shhh: SHHH _ none, credentials: Credentials, interfaceSpecPattern: Thrush.InterfaceSpec ] RETURNS[nb: NB, interfaceSpec: Thrush.InterfaceSpec]; LookupServiceInterface: PROC[ shhh: SHHH _ none, credentials: Credentials, serviceParty: PartyID, type: RPC.ShortROPE ] RETURNS[nb: NB, interfaceSpec: Thrush.InterfaceSpec]; RegisterKey: PROC[ shh: SHHH _ none, credentials: Credentials, key: Thrush.EncryptionKey, reportNewKeys: BOOL_FALSE ] RETURNS [ nb: NB, keyIndex: [0..17B] ]; GetKeyTable: PROC [ shh: SHHH_none, credentials: Credentials ] RETURNS [ nb: NB, -- one of $success, $noSuchConv, $noSuchParty, $notInConv keyTable: Thrush.KeyTable ]; GetParty: PROC[ shh: SHHH_none, partyID: PartyID, rName: ROPE_NIL, type: Thrush.PartyType_NIL ] RETURNS [nb: NB, newPartyID: PartyID]; GetPartyFromNumber: PROC[ shh: SHHH_none, partyID: PartyID, phoneNumber: Thrush.ROPE_NIL, description: ROPE_NIL ] RETURNS [nb: NB, newPartyID: PartyID]; GetPartyFromFeepNum: PROC[ shh: SHHH_none, partyID: PartyID, feepNum: Thrush.ROPE_NIL ] RETURNS [nb: NB, newPartyID: PartyID]; GetCurrentParty: PROC[shh: SHHH_none, smartsID: SmartsID] RETURNS [nb: NB, partyID: Thrush.PartyID]; GetNumbersForRName: PROC[shh: SHHH_none, rName: ROPE] RETURNS [fullRName: ROPE, number: ROPE, homeNumber: ROPE]; Register: PROC[ shh: SHHH_none, rName: ROPE_NIL, type: Thrush.PartyType_ $individual, clonePartyID: PartyID _ nullID, interface: SmartsInterfaceName, properties: SmartsProperties ] RETURNS [ nb: NB, credentials: Credentials ]; CheckIn: PROC[shh: SHHH_none, credentials: Credentials] RETURNS [nb: NB]; Deregister: PROC[shh: SHHH_none, smartsID: SmartsID] RETURNS [nb: NB]; Enable: PROC[shh: SHHH_none, smartsID: SmartsID] RETURNS [nb: Thrush.NB]; Disable: PROC[shh: SHHH_none, smartsID: SmartsID] RETURNS [nb: Thrush.NB]; }. 3hThParty.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Last modified by Swinehart, June 3, 1986 11:47:22 pm PDT Parties and Conversations Definitions The netAddress is the address to use for establishing voice connections, including a socket number that does not change for the life of the Smarts. A smarts must not be active in more than one conversation at a time, so this unique assignment works. voiceTerminal represents a role corresponding to Lark Smarts, front or back door, or BluejaySmarts; an actual source/sink of audio information, as well as the smarts control functions. controller represents an entity that can perform control functions, but cannot supply or accept the voice transmission protocol. Standard and only present example: FinchSmarts. Controllers generally get to hear about changes in conversations before their associated voice terminals do. Conversation Management Discussion 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. The party level, however, only concerns itself with maintaining the "truth" about the current state of all parties in a conversation, reporting state transitions to interested smarts, and storing/computing some values that smarts may be interested in. Smarts are responsible for initiating their own state transitions and in interpreting the meaning of being in one state or another. Exceptions: 1) One smarts may advance another party into the $notified state in order to initiate a call. 2) When all parties in a conversation are in the $idle state, the party code can eliminate all the data structures associated with the conversation. CreateConversation produces a new conversation and puts the calling party in it, in the indicated state; one can destroy the conversation only by idling onesself with respect to it, and expecting others to do the same. CreateConversation accepts other call parameters as a convenience. The conversation's creator is henceforth known to the system as the $originator of the conversation. Alert adds another party to the conversation, in $notified state -- this is always legal, assuming the party's not in the conversation already! The notified party is expected to advance to a further state and report it to the $originator (caller of Alert). The originator can not subsequently influence the behavior of the notified party, except by suggestion. Advance is called by smarts to progress its own party through a call. See Thrush.StateInConv for a description of the states and their meanings. The reason/comment fields are most useful when going idle, to indicate whether it was due to some problem or just because the call is over. Most ThParty functions return an NB (nota bene) code. If this value is not $success, usually any other return values will be NIL, nullID, or meaningless, and the requested operation will not have been performed. The NB values indicate generally what went wrong. $stateMismatch means that some other party has changed state and the caller has not yet been informed of that. This will only be returned from functions that operate on the conversation state. ConvEvent will be reported to alerted party, not us; if this fails, give up on the call. IF TRUE, advance is reported to all parties; if FALSE, to calling party only (smarts other than the calling smarts; in no case is an advance reported back to the caller). See discussion with the definition of Thrush.ActionReport. See also Register/ LookupServiceInterface, below, and ThSmarts.ReportAction. ActionReport's other field should be the credentials of the caller; self will be filled in during the reporting process. IF TRUE, a copy of the report is delivered to all parties (except the caller); if FALSE, to originating party only (and its poachee, if any). IF TRUE, a copy of the report is delivered to the reporting party, after all other progress reports have been delivered (no such copy is delivered if numReportsIssued is 0). See the discusson in RegisterKey for use of this feature. This could lead back to Finch-caused delays and such, but at least does not prevent anybody from hanging up. Conversations MergeConversations: PROC[ shhh: SHHH _ none, credentials: Credentials, -- of surviving conversation otherStateID: Thrush.StateID, -- of dissolving conversation otherConvID: ConversationID ] RETURNS [ nb: NB ]; Enumerations, queries Information about the conversation as a whole lastTime: BasicTime.GMT_TRASH, -- Time of last state transition, any party Readily-available (and not too big) information about the conversation Socket numbers and host names for each of the voice terminals in this conversation; own entry, if any, comes first. stateID: Thrush.StateID_TRASH, -- last transition. lastTime: BasicTime.GMT_TRASH, -- of last transition $owner: RName of creator of this party; same as $current for telephone and individual parties; RName of trunk's owner for trunks; Idle service RName for services. $current: Current assignment; identity of party on the other end of a $trunk, or modified service name identifying user. $address: meaningless but same as $current for all but $trunk, where it's the phone number $description: dolled-up version of $current, suitable for framing, including all known names and numbers, for Finch and so on. Information about the parties (or just one party) in a conversation Credentials should have either a ConversationID or PartyID or both; other fields irrelevant. GetPartyInfo[nameReq: $current, allParties: FALSE] replaces GetRname. GetPartyInfo[nameReq: $description, allParties: FALSE] replaces DescribeParty Service action registration, lookup. See also ReportAction, above. Having registered it, the caller (service provider) must also XXXRpcControl.ExportInterface[...] the interface, under the specified instance name. interfaceSpecPattern.type should be a simple rope, not a Grapevine RName, since we don't really want Grapevine involved at all. The client can either supply an instance value or let RegisterService invent one (present BluejaySmarts produces 5 parties, but each has the same behavior, so it could use the instance invented during the registration of the first one for the rest of them.) There can/will be only one instance/version of an interface with a given type name registered for a party at a time. New ones override old ones. Caller should supply interfaceSpecPattern.hostHint. If it's null, an attempt will be made to produce a decent value, no guarantees (shhh=none implies call is from own host.) NB can complain about the credentials. The client can now import the interface directly. Interface procedures should traffic in Thrush.Credentials and the like, providing enough information to identify the relevant conversation and so on. The implementations are responsible for issuing the necessary progress reports, and dealing with the other ThParty rules. NB is $noSuchInterface if one cannot be found. NB can also complain about caller's credentials or the validity of the serviceParty (see Thrush.NB). LookupService tries the identified serviceParty and its poachee, if there is one, in that order. Version checking is not done by this function; if the versions don't match the Import attempt will discover it. Encryption key registration. The voice protocol requires each voice terminal to maintain a table of active encryption keys, whose indices appear in individual voice packets. RegisterKey enters a new key, possibly displacing an old one. Management in overflow situations is not completely solved. The result is the key's index location. If reportNewKeys, a Thrush.ActionReport is issued to all but the originator of the request (see ReportAction, above), with actionClass=$KeyDistribution and actionType=$newKeys, uniqueID=(high order half of key). Once all these reports have been delivered, the originator gets one, too. At this point, it is certain that all participants have been given an opportunity to call GetKeyTable and record the new keys. RegisterKey returns nb=$newKeys if reports are being generated. Thus ends the infamous and long-standing key synchronization problem. GetParty and friends Discussion Parties represent participants in conversations. Depending on type, they represent: service: a recording service, synthesizer, and the like. trunk: the party at the other end of a "back door" telephone line. telephone: the user of a Lark (Etherphone) in an office. individual: an authenticated user of a Lark and/or a client program registered with the server. GetParty and friends map names into parties. (Register creates new parties.) The rName is either the name of an individual (including registry), a service (e.g., "recording"), or (in the case of trunks) NIL. partyID is the ID for one's own party -- the "self" of object-style references. This form is followed throughout this interface. IF nb#success, it gives some idea of what went wrong. Thrush.NB can be extended with specialized error values in cases where the caller is expected to understand more about it (when obtaining services, for instance) IF type=NIL, it's a request for an $individual (preferably) or $telephone (otherwise). GetParty will return one's own trunk, properly configured, if type=$telephone and no Etherphone party can be found. 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. 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. Who do we represent when we initiate an outgoing call? After obtaining this party, it may become invalid (due to the party dropping out), so be prepared for $noSuchParty problems all along the line. Information about people and parties fullRName is NIL if nothing found. Party and Smarts creation, initialization Discussion A Smarts implementation uses Register to create the server's identifier for the Smarts, to create the corresponding party, and to establish the necessary links between these objects and the reset of the system. Since the server needs to be able to deal with more than one Smarts implementation, they are implemented as objects and must use RPC's object-oriented option. Options include: Local or remote registration: in the local case, the Smarts implementation is on the same machine and can supply the interface record directly. Cloning: a service can request additional registrations based on an initial prototype. This allows the service to support a number of simultaneous conversations. Calling Register with identical party identification results in the immediate destruction (via Deregister) of the previous version of the party and creation of a new one. CheckIn can be used to determine whether such a step is necessary. Identification of party -- requires either: Description of party Or ID of party to replicate (used to provide multiple instances of services) Identification of smarts implementation -- requires either: RPC Interface allowing an instance to be imported Or Local Interface record matching that produced by RPC -- see ThPartyPrivate.RegisterLocal Kind of Smarts being registered, and from what host nb will indicate something about what went wrong if anything did; if nb=$success, credentials contains the resulting PartyID and SmartsID. Verifies that the credentials are still valid, (conv can be null), or if not, which problem is the most pronounced. Can be used as basis for occasional Smarts to party polling. nb will be noSuchSmarts or success, or something else (which implies things are confused) 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. This smarts can no longer supply a voice connection to its parties. 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. Swinehart, October 31, 1985 5:18:48 pm PST Major changes to argument structure, Smarts/Party structure changes to: Alert, Advance, CreateConversation, GetParty, SetRingEnable, DIRECTORY, LocalSmartsInterface, SmartsProperties, SmartsRole, Register, GetPartyFromFeepNum Swinehart, November 7, 1985 9:50:41 am PST Revamping ThParty, (lean, mean Thrush) changes to: CreateConversation, Alert, Advance Swinehart, May 30, 1986 10:45:17 am PDT Cedar 6.1. Add Action Registration, Lookup, Reporting. Clean out some old Interval/Prose stuff. changes to: DIRECTORY, RegisterServiceInterface Ê ù˜Jšœ ™ Jšœ Ïmœ7™BJšœ8™8J˜Jšœ™J˜šÏk ˜ Jšœ žœžœ˜J˜Jšœžœžœ˜Jšžœžœ˜'šœžœ˜Jšœ‚žœ1žœžœ4˜ó—J˜Jšœ˜J˜—Jšœ žœ˜J˜™ J˜Jšœžœ˜-Jšœ žœ˜šœ žœ˜!J˜!—Jšœ žœ˜'Jšžœžœ žœ˜Jšžœžœ žœ˜šžœžœ žœ˜Jšœžœ˜ —Jšœžœžœ˜.Jšœžœ&˜AJ˜šœžœžœ˜Jšœžœ˜˜.J™û—J˜—J™šœ žœžœÏc&˜>JšÏb œ«™¸Jš  œ•™ŸJ™—J˜—™™ JšœÍ™ÍJ™€J™Jš œÊ œv  œ™„J™Jš œ,  œ©  œ|™êJ™Jš œ—™žJ™Jš œ!žœ[žœYžœ- œ³™ÊJ˜—šÏnœžœ˜Jšœžœ˜J˜J˜&JšœžœŸ ˜+JšœžœŸ ˜-JšœžœŸj˜‡Jšœ žœžœ˜Jšœžœž˜Jšœžœžœ ˜2J˜—š¡œžœ˜ Jšœžœ˜J˜J˜Jšœ žœž˜šœžœžœ˜JšœX™X—J˜—š¡œžœ˜Jšœžœ˜J˜J˜šœ žœžœ˜Jšœžœ)žœu™ª—J˜JšœžœŸ ˜%Jšœ žœž˜Jšœžœžœ ˜1J˜—Icodešœ‚™‚š¡ œžœ˜Jšœžœ˜JšœŸG˜dšœ žœž˜JšœžœKžœ6™—šœžœž˜JšœžœÏoœCÏtœl£™×—Kšœžœžœžœ˜,—K˜—šœ ™ š¡œžœ™Jšœžœ™JšœŸ™6JšœŸ™;J™Jšœžœ ™J™——šœ™J™šœžœžœ˜!J™-Jšœ žœžœ˜Jšœžœ˜ Jšœžœ˜ Jšœž œ˜Jšœ"žœ˜(Jšœ žœžœ˜Jšœ žœžœ˜Jšœ žœžœ˜Jšœž˜"JšœžœžœŸ+™JJ˜J˜—š¡œžœžœ˜Dšžœ˜ J™FJšœžœŸ˜(Jšœ˜J˜J˜——šœ žœžœ˜#J™s—šœžœžœ˜Jšœ žœŸ+˜>Jšœ"žœŸ%˜NJšœ žœžœžœ˜+J˜—šœžœžœ˜Jšœ˜Jšœžœ˜Jšœž œŸ$˜IJšœžœŸ™2JšœžœžœŸ™4Jšœ žœžœŸ1˜HJšœ ž œ˜Jšœ ž œ˜Jšœ ž ˜JšœžœŸ>˜_J˜—šœ žœžœŸ7˜MJ™¢J™xJšœZ™ZJ™~J˜—š¡ œžœ˜Jšœžœ˜Jšœ˜Jšœ˜Jšœ žœžœŸF˜]Jšœ˜šžœ˜ J™CJ™\JšœžœŸ9˜BJšœ˜J˜—J™Ešœ0žœ™MJ˜——š¡ œžœ+˜>Jšžœžœžœ˜*J˜——™CJ™š¡œžœ˜Kšœžœ˜K˜Kšœ*˜*Kšœžœžœ'˜7Kšœ>¢"œ4¢œŸ¢œ»™—K™‘Kšœ®™®Kš¢œ$™&—K˜š¡œžœ˜Kšœžœ˜K˜K˜Kšœžœ ˜Kšœžœžœ'˜7—KšœZ¢œÉ¢œ™ÃKš¢œ¢œ¢œd¢ œÄ™çK™—J™™JšœÑ£œ;£*™·Jš œ¢ œ¢œT¢œ¢9œÉ™žJš¢ œ ¢ œ ™?J™EJ™š¡ œžœ˜Jšœžœ˜Jšœ˜J˜Jšœžœž˜J˜Jšžœžœ˜'J˜—š¡ œžœžœ!˜>šžœ˜ JšœžœŸ9˜BJšœ˜J˜——J™—™J˜™ ™TJ™8J™BJ™8J™_—J™ÑJ™—J˜š¡œžœ˜Jšœžœ žœžœ˜2Jšœž˜Jšœžœžœ˜(J™ØJšžœžœK™VJ™s—J˜š¡œžœ˜Jšœžœ˜Jšœ˜Jšœžœžœžœž˜3Jšœžœžœ˜(J™‹J˜—š¡œžœ˜Jšœžœ˜Jšœ˜Jšœžœž˜Jšœžœžœ˜(Jšœþ™þJ˜—š¡œžœžœ˜9Jšžœžœ˜*J™ÇJ˜——™$J™š¡œžœžœžœ˜5Jšžœ žœ žœžœ˜:Jšœ žœ™"—J™—™)J™™ JšœÕ™ÕJšœž™ž™J™J™¢J™î——J˜š¡œžœ˜Jšœžœ˜™+™Jšœžœžœ˜J˜$—™LJ˜——™;™1Jšœ˜—J™[—™3J˜—Jšœžœ˜ šœžœ˜#J™QJ™8——J˜š ¡œžœžœ!žœžœ˜IJ™±J˜—š ¡ œžœžœžœžœ˜FJ™Y—J˜š¡œžœžœ˜0Jšžœ žœ˜J™——J˜š¡œžœžœ˜1Jšžœ žœ˜J™C—J˜—J˜J˜J˜™'K™ K™v—™*K™;Kšœ Ïr™™¥—K™K™™*K™&Kšœ ¤"™.—™'K™aKšœ ¤#™/—K™—…—4S•