Thrush.mesa
Last modified by D. Swinehart, January 13, 1985 12:44:00 pm PST
Basic Thrush Types
DIRECTORY
BasicTime USING [ GMT --, nullGMT-- ],
DESFace USING [ Key, nullKey ],
GVBasics USING [ Password ],
Lark USING [ ConnectionSpec, KeyTable, Machine, noMachine, VoiceSocket ],
LarkPlay USING [ ToneSpec ],
RPC USING [ Conversation, ShortROPE, unencrypted ],
SafeStorage USING [ Type, unspecType ],
Triples USING [ Any, Item ]
;
Thrush: CEDAR DEFINITIONS = {
Parties, Smarts, Conversations
PartyHandle: TYPE = ThHandle;
ConversationHandle: TYPE = Epoch;
nullConvHandle: ConversationHandle = LOOPHOLE[LONG[0]];
SmartsHandle: TYPE = ThHandle;
Scalars
VoiceSocket: TYPE = Lark.VoiceSocket;
Machine: TYPE = Lark.Machine;
noMachine: Machine = Lark.noMachine;
Epoch: TYPE = BasicTime.GMT;
epoch: Epoch; -- things with this epoch in them were created during this incarnation
ROPE: TYPE = RPC.ShortROPE;
Rname: TYPE = ROPE;
Password: TYPE = GVBasics.Password;
nullPassword: Password = ALL[0];
NetAddress: TYPE = Machine;
TBD: TYPE=CARDINAL; -- <<used to be the most important type in the system.>>
Time: TYPE = BasicTime.GMT;
Priorities: TYPE = LIST OF REF ANY;
pERROR: -- PROGRAMMING -- ERROR;
ServerError: ERROR[code: ServerProblem←unknown];
ServerProblem: TYPE = { unknown, inconsistentStructures, hiLevFault };
Conversation State Values
A party is a member of a conversation in one of the following states:
StateInConv: TYPE = {
idle,   -- Not really in the conversation (ever, or any more.)
reserved,  -- TBD at party level; restrict some operations pending outgoing conn.
parsing,  -- TBD at party level; may restrict additional operations.
reserved and parsing states are for Smarts benefit. Treat more or less like idle.
initiating, -- You are the calling party; attempt to contact the other party is in underway.
pending,  -- You are the called party; you are deciding whether to bother your user.
maybe,  -- You are the calling party; an attempt to arouse the other user is in progress.
ringing,  -- You are the called party; you are attempting to arouse your user.
canActivate, -- You may become active in this conversation whenever you can get out of the one you may already be active in.
active,  -- You are active in this conversation.
inactive,  -- You have put this conversation on "hold."
any   -- Used in queries only
};
Sequence number of state transition within conversation. Used as an index into the conversation log, and as a unique id to control Smarts->Party interactions.
StateID: TYPE = NAT;
The basic Smarts->Party informational packet.
Credentials: TYPE = RECORD [
partyID: PartyHandle,
smartsID: SmartsHandle,
convID: ConversationHandle←nullConvHandle,
stateID: StateID𡤀
];
ConvEvents describe the progress of parties in conversations. They are used as entries in the log of events for a conversation, labels on the arcs describing the current state of parties in a conversation, and informational values provided to Smarts in Progress reports to describe situations.
ConvEvent: TYPE = REF ConvEventBody;
ConvEventBody: TYPE = RECORD [
credentials: Credentials, -- of the initiator of the event; smartsID may be null
state: StateInConv ← idle, -- the state of this party in this conversation.
reason: Reason ← wontSay,  -- for rejection, acceptance, or conditional acceptance
urgency: CallUrgency←normal, -- urgency supplied in connection attempt during this event.
alertKind: AlertKind ← standard, -- connection type hint
spec: Lark.ConnectionSpec ← NIL, -- if StatInConv is active or canActivate.
keyTable: Lark.KeyTable ← NIL, -- whenever there's a spec
intervalSpecs: IntervalSpecs ← NIL, -- if non-NIL, a SetInterval is being specified.
ringTune: LarkPlay.ToneSpec ← NIL, -- if non-NIL, the ringing tune to use (to voiceTerminal smarts only)
address: ROPENIL,   -- calling trunks and the like: external addressing information.
time: Time ← NULL,
comment: ROPE NIL  -- any human-sensible comment associated with the event.
];
EventSequence: TYPE = REF EventSequenceBody;
EventSequenceBody: TYPE = RECORD [
s: SEQUENCE size: NAT OF ConvEvent ];
Reason: TYPE = {
(Why things happened)
wontSay, -- no reason needed.
Non-rejections, ongoing
terminating, -- there was a reason for this connection, but it's over now, by me.
withdrawing, -- would like to leave, with right to return.
noAnswer, -- Alert only: we tried, honest.
Rejections, of various degrees of severity
notFound, -- called party not found
busy, -- called party is active in another conversation and/or doesn't wish to accept this one.
absent, -- called party is known to be unavailable for extended period
notImportantEnough, -- connection rejected because claimed urgency was too low.
noCircuits, -- call rejected due to system resource overload
noParticular, -- rejected for good reason, but can't say what it is.
error -- System problem caused rejection. --
};
Report success of Smarts->Party calls
NB: TYPE = {
success,   -- call succeeded, party may be in new state.
stateMismatch, -- the most common problem; your information's out of date.
invalidTransition, -- you can't go from the state you're in to the one you're requesting.
notInConv,  -- you're not a party to this conversation, and call requires it.
noSuchConv, -- named conversation doesn't exist.
noSuchParty, -- named (own) party doesn't exist.
partyNotEnabled, -- named (own) party does not have a voice path yet.
noSuchSmarts, -- get the drift?
noSuchParty2, -- second named (called) party doesn't exist.
narcissism,  -- attempt to connect to self rejected <<The right way to complain?>>
convNotActive, -- activity requested that is only satisfiable if requesting party active
convStillActive -- can't destroy it if remaining connections are not orphans.
};
Used in Party->Smarts calls to control "distribution".
Disposition: TYPE = {actedAndStop, actedAndPass--<<??>>--, pass, willAlwaysPassThisRequest};
actedAndStop: I did it. Don't consult any other Smarts.
actedAndPass: I did it. Consult others, but they should take no action, and you should pay no attention to their results, if any.
pass: I can't do it this time, keep trying.
willAlwaysPassThisRequest: I can't ever do this one.
If all Smarts pass, let the caller know; that may or may not be OK.
Conversation Guidance Values
How important is this call?
CallUrgency: TYPE= {junk, ifConvenient, normal, important, urgent, fire};
AlertKind: TYPE = { queryOnly, standard, intercom, whoKnows };
As parameters to ThParty.Alert and ThSmarts.Alert:
queryOnly: is it likely that Alert would succeed? conversation argument can be null.
standard: ring the phone, or whatever recipient would like.
intercom: try to get through without ringing.
whoKnows: TBD . . . it's early innings, yet.
Party type identification, back door stuff
NumberClass: TYPE = {public, intelnet};
PartyType: TYPE = {individual, trunk, recording};
PhoneNumber: TYPE = --.--ROPE--REF PhoneNumberBody--; -- rope for now
PhoneNumberBody: TYPE = RECORD [
extension: ROPE,
office: ROPE,
region: SELECT numberClass: NumberClass FROM
public => [ area: ROPE ],
intelnet => NULL,
ENDCASE ];
Tunes and tones: control of recording and playback, ring tone generation, and so on
Tune: TYPE = INT; -- the index of a "tune" or similar utterance identification.
nullTune: Tune = -1;
newTune: Tune = -2;
VoiceTime: TYPE = INT; -- A sample number or sample count.
VoiceInterval: TYPE = RECORD [
start: VoiceTime𡤀, -- first sample within tune to play or record.
length: VoiceTime←-1 -- number of samples: -1 to play to the end. -- ];
VoiceDirection: TYPE = { play, record };
IntSpecType: TYPE = { request, started, finished };
IntID: TYPE = RECORD [
stateID: StateID ← 0, -- supplied by ThParty as interval is accepted
reqID: CARDINAL ← 0 -- supplied by requester to disambiguate intervals in the same rqst
];
nullIntID: IntID = [];
IntervalSpec: TYPE = REF IntervalSpecBody;
IntervalSpecBody: TYPE = RECORD [
tune: Tune←newTune,
interval: VoiceInterval←[],
keyIndex: [0..17B] ← 0,
type: IntSpecType ← request,
direction: VoiceDirection,
intID: IntID ← nullIntID,
queueIt: BOOLEANTRUE,
changeNoted: BOOLEANFALSE -- For use by some clients.
];
IntervalSpecs: TYPE = LIST OF IntervalSpec;
RingEnable: TYPE = {
off,  -- Incoming calls do not make noise.
offTimed, -- Incoming calls will not make noise until a specified later time.
subdued, -- Incoming calls will make less of a racket
subduedTimed, -- Incoming calls will make less of a racket until a specified later time.
on,   -- Incoming calls make noise.
noChange -- for use as procedure parameter
};
Utility Types
A ThHandle is a sanitized REF, which can be safely stored in other address spaces.
It must be "Dehandled" before it can refer to the storage it designates.
Enhandle assures that the REF survives. KillHandle removes the association between the handle and the target REF, and reduces the reference count to the target by 1.
Rehandle is a semi-safe Enhandle; for it to work, the caller must know that the REF arg was obtained by a Dehandle of a still-valid ThHandle. If it doesn't work, the next Dehandle fails.
ThHandle: TYPE=LONG CARDINAL;
Clients should define various handle types equal to Thrush.ThHandle. For legibility.
Enhandle: PROC[r: REF] RETURNS [ThHandle]; -- handle valid until killed.
If r is a REF to some concrete type, a runtime version of that type will have to be supplied to Dehandle to get the ref back.
Rehandle, H: PROC[r: REF] RETURNS [ThHandle] = INLINE { RETURN[LOOPHOLE[r]]; };
Can be used if one obtained r from Dehandle, or knows it was obtained that way. The next Dehandle will check the handle's validity again.
Dehandle: PROC[h: ThHandle, type: SafeStorage.Type←SafeStorage.unspecType,
insist: BOOLEANFALSE]
RETURNS [LONG UNSPECIFIED];
Client can present virtually any value as a candidate handle. If it is not a currently valid handle, or if the target does not satisfy the handle's concrete type, the operation fails.
Failure is indicated by returning NIL if insist is FALSE, otherwise by raising Thrush.HandleFault.
KillHandle: PROC[h: ThHandle, type: SafeStorage.Type←SafeStorage.unspecType];
Handle is no longer valid.
nullHandle: ThHandle = LOOPHOLE[NIL[REF], LONG CARDINAL];
HandleFault: ERROR[h: ThHandle];
Orphan procedure.
MakeUnique: PROC[att, obj, val: Triples.Item ← Triples.Any];
Encryption types
SHHH: TYPE = RPC.Conversation;
unencrypted, none: SHHH = RPC.unencrypted;
EncryptionKey: TYPE = DESFace.Key;
nullKey: EncryptionKey = DESFace.nullKey;
}.