FinchSmartsImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last Edited by: Swinehart, January 5, 1986 11:40:10 pm PST
Polle Zellweger (PTZ) October 24, 1985 4:55:57 pm PDT
DIRECTORY
BasicTime USING [ Now, nullGMT, OutOfRange, Update ],
Commander USING [ CommandProc, Register ],
FinchSmarts,
IO,
Lark USING [ SHHH ],
LupineRuntime USING [ BindingError ],
MBQueue USING [ Create, QueueClientAction ],
NamesGV USING [ GVGetAttribute ],
NamesGVImpExp USING [ GVImport, UnGVImport ],
NamesRPC USING [ StartConversation ],
Nice,
PrincOpsUtils USING [ IsBound ],
Process USING [ SecondsToTicks, SetTimeout, Ticks ],
RefID USING [ ID ],
RefQ USING [ Dequeue, Enqueue, Map, MapType, Queue ],
Rope,
RPC USING [ AuthenticateFailed, CallFailed, EncryptionKey, ImportFailed, VersionRange ],
ThParty USING [ Advance, Alert, ConversationInfo, CreateConversation, Deregister, Enable, GetConversationInfo, GetParty, GetPartyFromNumber, GetPartyInfo, Register ],
ThPartyRpcControl,
Thrush
USING[
ConversationID, ConvEvent, Credentials, NB, none, nullConvID, nullID, PartyID, Reason, ROPE, SmartsID, StateInConv, unencrypted ],
ThSmarts,
ThSmartsRpcControl,
ThVersions USING [ GetThrushVR, FinchVersion, FinchVR ],
UserProfile USING [ Token],
VoiceUtils USING [ CurrentPasskey, CurrentRName, InstanceFromNetAddress, OwnNetAddress, Problem, ProblemFR, Report ]
;
FinchSmartsImpl:
CEDAR
MONITOR
IMPORTS BasicTime, Commander, IO, FinchSmarts, LupineRuntime, MBQueue, NamesGV, NamesGVImpExp, NamesRPC, Nice, PrincOpsUtils, Process, RefQ, RPC, ThParty, ThPartyRpcControl, ThSmartsRpcControl, ThVersions, UserProfile, VoiceUtils
EXPORTS FinchSmarts, ThSmarts = {
OPEN IO;
Declarations
ConvDesc: TYPE = FinchSmarts.ConvDesc;
ConversationID:
TYPE = Thrush.ConversationID;
nullConvID: ConversationID = Thrush.nullConvID;
FinchInfo: TYPE = FinchSmarts.FinchInfo;
NB: TYPE = Thrush.NB;
none: SHHH = Thrush.none;
nullID: RefID.ID = Thrush.nullID;
PartyID: TYPE = Thrush.PartyID;
ROPE: TYPE = Thrush.ROPE;
SHHH: TYPE = Lark.SHHH;
SmartsID: TYPE = Thrush.SmartsID;
StateInConv: TYPE = Thrush.StateInConv;
PD:
TYPE =
RECORD [
doReports: BOOL←FALSE,
doNice: BOOL←FALSE,
timeoutNoAction: INTEGER ← 30,
timeoutJayConnect: INTEGER ← 1,
noJayTicks: Process.Ticks ← Process.SecondsToTicks[1],
encryptionRequested: BOOLEAN←TRUE,
interfacesAreImported: BOOLEAN←FALSE,
smartsIsExported: BOOLEAN←FALSE,
waitsForConnect: NAT𡤆,
queueIt: BOOL←FALSE,
finchOn: BOOLEAN←FALSE,
maxProseLength: INT
];
info: FinchInfo;
pd: REF PD ← NEW[PD←[]];
Report:
PROC[what:
ROPE] = {
IF NOT pd.doReports THEN RETURN;
VoiceUtils.Report[what, $Finch];
};
BeNice:
PROC[r:
REF, d:
INT] = {
IF NOT pd.doNice THEN RETURN;
Nice.BeNice[r, d, $Finch, NIL];
};
Supervision
Progress:
PUBLIC
ENTRY
PROC[
shh: SHHH,
convEvent: Thrush.ConvEvent
] = {
ENABLE UNWIND => NULL; -- RestoreInvariant;
Some party has changed state in a conversation we know about (or should).
IF convEvent.self.partyID = convEvent.other.partyID
THEN
-- See below
info.requests.QueueClientAction[QdProgress, convEvent];
};
QdProgress:
ENTRY
PROC[r:
REF] = {
Two cases:
Our party has changed state in a conversation, whether or not we're going to deal with it (at present, LarkSmarts makes all such decisions)
Another party changed state in a conversation we know about (at present, we don't need to know that; again, LarkSmarts does all the work.) That case is filtered out in Progress, above.
It is our duty to obtain all relevant information about the call when the information becomes available, and to notify any Finch Clients.
ENABLE UNWIND => NULL; -- RestoreInvariant;
[] ← NoteNewState[ NARROW[r] ];
};
Client Functions
CallInfo: TYPE = REF CallInfoBody; -- needed because MBQueue requires a REF
CallInfoBody:
TYPE =
RECORD [
convID: Thrush.ConversationID,
calledPartyID: Thrush.PartyID←nullID,
reason: Thrush.Reason←NIL,
comment: ROPE←NIL
];
DisconnectCall:
PUBLIC
ENTRY
PROC[
convID: Thrush.ConversationID,
reason: Thrush.Reason ← $terminating,
comment: ROPE←NIL] = {
ENABLE UNWIND => NULL; -- RestoreInvariant;
info.requests.QueueClientAction[QdDisconnect,
NEW[CallInfoBody ← [convID: convID, reason: reason, comment: comment]]];
};
QdDisconnect:
ENTRY
PROC[r:
REF] = {
ENABLE UNWIND => NULL; -- RestoreInvariant;
callInfo: CallInfo = NARROW[r];
cDesc: ConvDesc; state: StateInConv;
IF NOT(([,cDesc, state]𡤏inchOn[callInfo.convID]).on) THEN RETURN;
SELECT state
FROM
$idle, $failed, $neverWas => {
info.ReportConversationState[$convNotActive, NIL, "No conversation to disconnect"];
RETURN;
};
ENDCASE;
Request[cDesc, $idle, callInfo.reason, callInfo.comment];
};
AnswerCall:
PUBLIC
ENTRY
PROC[convID: Thrush.ConversationID] = {
ENABLE UNWIND => NULL; -- RestoreInvariant;
info.requests.QueueClientAction[QdAnswerCall, NEW[CallInfoBody ← [convID: convID]]];
};
QdAnswerCall:
ENTRY
PROC[r:
REF] = {
ENABLE UNWIND => NULL; -- RestoreInvariant;
callInfo: CallInfo = NARROW[r];
cDesc: ConvDesc; state: StateInConv;
IF NOT(([,cDesc, state]𡤏inchOn[callInfo.convID]).on) THEN RETURN;
SELECT state
FROM
$ringing, $notified => NULL;
ENDCASE=>RETURN;
Request[cDesc, $active];
};
PlaceCall:
PUBLIC
ENTRY
PROC [
convID: Thrush.ConversationID←nullConvID,
rName: ROPE, -- rName or description
number: ROPE, -- telephone number, if present
useNumber: BOOL←FALSE
] = {
ENABLE UNWIND => NULL; -- RestoreInvariant;
calledPartyID: PartyID;
nb: NB;
IF NOT (FinchOn[].on) THEN RETURN;
IF ~useNumber
THEN {
[nb, calledPartyID] ←ThParty.GetParty[shh:info.shh, partyID:info.partyID, rName:rName];
IF nb = $noSuchParty2 THEN useNumber ← TRUE;
};
IF useNumber
THEN [nb, calledPartyID] ← ThParty.GetPartyFromNumber[
shh: info.shh, partyID: info.partyID, phoneNumber: number, description: rName];
IF nb # $success THEN { info.ReportConversationState[nb, NIL, NIL]; RETURN; };
info.requests.QueueClientAction[QdPlaceCall,
NEW[CallInfoBody ← [convID: convID, calledPartyID: calledPartyID]]];
};
QdPlaceCall:
ENTRY
PROC [r:
REF] = {
ENABLE {
UNWIND=>NULL; -- RestoreInvariant;
RPC.CallFailed => { UninitFinchSmarts["Communication Failure"]; CONTINUE; };
};
callInfo: CallInfo = NARROW[r];
IF NOT (FinchOn[].on) THEN RETURN;
[--cDesc--]𡤌onnect[callInfo.calledPartyID, callInfo.convID];
};
Utilities
GetConv:
PUBLIC
PROC[convID: ConversationID, createOK:
BOOL←
FALSE]
RETURNS [ cDesc: ConvDesc←NIL ] = --INLINE-- {
IsConv: RefQ.MapType = {
cDesc ← NARROW[subqueue.first];
IF cDesc.situation.self.convID = convID THEN RETURN[TRUE];
};
IF convID#nullConvID AND RefQ.Map[info.conversations, IsConv] THEN RETURN;
IF ~createOK THEN RETURN;
New conversation
cDesc ←
NEW[FinchSmarts.ConvDescBody←[
situation: [ self: [ convID: convID, smartsID: info.smartsID, partyID: info.partyID ]]]];
info.conversations ← RefQ.Enqueue[info.conversations, cDesc];
};
FinchOn:
INTERNAL
PROC[convID: ConversationID←nullConvID]
RETURNS [
on: BOOL←FALSE, cDesc: ConvDesc←NIL, state: StateInConv←$idle] = {
IF ~pd.finchOn
OR info=
NIL
THEN {
VoiceUtils.Report["Your Finch is not running", $Finch]; RETURN; };
on←TRUE;
IF convID=nullConvID THEN RETURN;
cDesc ← GetConv[convID, FALSE];
statesc.situation.self.state;
};
NoteNewState:
INTERNAL
PROC[convEvent: Thrush.ConvEvent]
RETURNS[cDesc: ConvDesc]= {
cInfo: ThParty.ConversationInfo;
nb: NB;
cDesc ← GetConv[convEvent.self.convID, TRUE];
cDesc.situation ← convEvent^;
[nb, cInfo] ← ThParty.GetConversationInfo[shh: info.shh, convID: convEvent.self.convID];
Now gather up additional information that we might not know yet:
Who started this?
Who the other party(s) is (are)
SELECT
TRUE
FROM
nb # $success => Problem["Can't obtain conversation information"];
cDesc.numParties#cInfo.numParties, cDesc.numActive#cInfo.numActive,
cDesc.numIdle#cInfo.numIdle => {
State information guaranteed correct only as of last time one of these numbers changed.
cDesc.subject ← cInfo.subject;
cDesc.startTime ← cInfo.startTime;
cDesc.numParties ← cInfo.numParties;
cDesc.numActive ← cInfo.numActive;
cDesc.numIdle ← cInfo.numIdle;
[nb, cDesc.partyInfo] ←
ThParty.GetPartyInfo[shh: info.shh, credentials: cDesc.situation.self,
nameReq: $description, allParties: TRUE];
IF nb#$success THEN Problem["Can't obtain conversation information"]
ELSE
IF cDesc.numParties>=1
THEN
cDesc.whoOriginated ←
IF cDesc.partyInfo[0].partyID=cInfo.originator THEN $us ELSE $them;
};
ENDCASE;
SELECT cDesc.situation.self.state
FROM
$idle, $neverWas => info.conversations ← RefQ.Dequeue[info.conversations, cDesc];
ENDCASE => cDesc.ultimateState ← cDesc.situation.self.state;
info.ReportConversationState[$success, cDesc, NIL];
};
Request:
INTERNAL
PROC[
cDesc: ConvDesc,
state: StateInConv,
reason: Thrush.Reason←NIL,
comment: ROPE←NIL
] = {
DO
nb: NB;
convEvent: Thrush.ConvEvent;
reportToAll:
BOOL =
SELECT state
FROM
$idle, $active, $inactive, $ringing => TRUE, ENDCASE=>FALSE;
[nb, convEvent] ←
ThParty.Advance[shhh: info.shh, credentials: cDesc.situation.self, state: state,
reportToAll: reportToAll, reason: reason, comment: comment];
SELECT nb
FROM
$success => []←NoteNewState[convEvent];
$stateMismatch => {
cDesc←NoteNewState[convEvent];
IF state=$idle AND cDesc.situation.self.state # $idle THEN LOOP;
};
ENDCASE =>
-- Some cases are fatal, requiring re-registration! --
info.ReportConversationState[nb, cDesc, "Telephone server action failed"];
Real confused about Problem (typeout only) reporting vs. client reporting. The responsibilities are unconvincingly distributed among Smarts and client.
EXIT;
ENDLOOP;
};
Connect:
INTERNAL
PROC [calledPartyID: PartyID, convID: ConversationID←nullConvID]
RETURNS [ cDesc: ConvDesc ] = {
state: StateInConv;
nb: NB;
convEvent: Thrush.ConvEvent;
[,cDesc, state]𡤏inchOn[convID];
SELECT state
FROM
$idle => {
[nb, convEvent] ← ThParty.CreateConversation[
shhh: info.shh,
credentials: [partyID: info.partyID, smartsID: info.smartsID],
state: $initiating
];
IF nb # $success THEN { -- Do something interesting -- ERROR; };
cDesc ← NoteNewState[convEvent];
};
$reserved, $parsing => NULL;
ENDCASE => {
info.ReportConversationState[$convStillActive, NIL, "Conversation already in progress"];
RETURN;
};
cDesc.originatorRecorded ← TRUE;
nb←ThParty.Alert[shhh: info.shh,
credentials: cDesc.situation.self, calledPartyID: calledPartyID];
SELECT nb
FROM
$success => NULL;
$stateMismatch => {
Request[cDesc, $failed, $error, "Conversation already in progress"];
Some smarts don't do this. They probably should.
RETURN;
};
ENDCASE => {
-- Do something interesting — see other smarts for more confusion -- ERROR; };
};
WaitForActive:
INTERNAL
PROC[cDesc: ConvDesc] = {
For use in Recording, and so on, where client needs to wait for setup.
FOR i:
NAT
IN [0..pd.waitsForConnect)
DO
TRUSTED { Process.SetTimeout[@info.stateChange, pd.noJayTicks]; };
WAIT info.stateChange; -- <<The supervisor condition vbl; will this work?>>
SELECT cDesc.situation.self.state
FROM
$active => RETURN;
$idle, $neverWas, $failed => EXIT;
ENDCASE;
ENDLOOP;
This isn't queued; does it have to be?
Request[cDesc, $failed, $error, "Finch failed to connect to voice service."];
};
Problem:
PROC[remark:
ROPE←
NIL, nb:
NB←
NIL] = {
IF nb=
NIL
THEN VoiceUtils.Problem[remark, $Finch]
ELSE VoiceUtils.ProblemFR["%g, reason: %g", $Finch, NIL, rope[remark], atom[nb]];
};
PutFTime:
PROC[convID: ConversationID]
RETURNS [
IO.Value] = {
ehsMemorialBool: BOOL←FALSE; -- wouldn't need if could return from catch phrase.
IF convID=nullConvID
OR convID=BasicTime.nullGMT
THEN RETURN[rope["(not assigned)"]];
[]sicTime.Update[convID, 0!BasicTime.OutOfRange=> {
ehsMemorialBool←TRUE; CONTINUE; }];
IF ehsMemorialBool THEN RETURN[int[LOOPHOLE[convID, INT]]]
ELSE RETURN[time[convID]];
};
Registration
InitFinchSmarts:
PUBLIC
PROC [
thrushInstance: Thrush.ROPE←NIL,
ReportSystemState: PROC[ on: BOOL ],
ReportConversationState: PROC[ nb: NB, cDesc: ConvDesc, remark: Rope.ROPE ]
] = {
problem: ROPE←NIL; nb: NB; {
ENABLE RPC.CallFailed => { problem ← "Communication Failure"; GOTO InitFailed; };
credentials: Thrush.Credentials;
thVR: RPC.VersionRange = ThVersions.GetThrushVR;
problem: Thrush.ROPE ← NIL;
namesGVInstance: Thrush.ROPE←NIL;
UninitFinchSmarts[NIL];
info ← NEW[FinchSmarts.FinchInfoBody]; -- Dump any old one!
info.requests ← MBQueue.Create[];
info.conversations ← NIL;
info.ReportSystemState←ReportSystemState;
info.ReportConversationState←ReportConversationState;
IF thrushInstance =
NIL
THEN thrushInstance ← UserProfile.Token[
key: "ThrushClientServerInstance", default: "Strowger.Lark"];
info.myName ← [
type: "ThSmarts.Lark",
instance: VoiceUtils.InstanceFromNetAddress[netAddress: VoiceUtils.OwnNetAddress[], suffix: "0"],
version: ThVersions.FinchVR];
info.myRName ← VoiceUtils.CurrentRName[];
info.myPassword ← VoiceUtils.CurrentPasskey[];
info.serverInstanceName ← thrushInstance;
ThSmartsRpcControl.ExportInterface[
interfaceName: info.myName,
user: info.myRName,
password: info.myPassword];
pd.smartsIsExported←
TRUE;
For the purpose of importing NamesGV, use prior binding of serverInstance if there is one and the server name is the same as before.
namesGVInstance ← UserProfile.Token[key: "NamesGVInstance", default: "Strowger.lark"];
IF ~(PrincOpsUtils.IsBound[
LOOPHOLE[NamesGVImpExp.GVImport]]
AND NamesGVImpExp.GVImport[namesGVInstance])
THEN {
problem ← "Couldn't import Grapevine Package"; GOTO InitFailed; };
info.shh ← IF NOT pd.encryptionRequested THEN Thrush.unencrypted
ELSE NamesRPC.StartConversation [
caller: info.myRName,
callee: thrushInstance,
key: info.myPassword,
level: --<<ECB>>--CBCCheck !
RPC.AuthenticateFailed=> { problem←"Could not authenticate"; GOTO InitFailed}];
IF (info.serverInstance ← NamesGV.GVGetAttribute[rName: info.serverInstanceName, attribute: $connect, default: NIL]) = NIL THEN { problem←"Telephone server not found"; GOTO InitFailed};
ThPartyRpcControl.ImportInterface[
interfaceName: [type: "ThParty.Lark", instance: info.serverInstance, version: thVR] ! --
RPC.ImportFailed=> {
IF why=wrongVersion THEN
problem ← IO.PutFR["Finch version %d too old; import failed",
card[ThVersions.FinchVersion]];
GOTO InitFailed;
}];
pd.interfacesAreImported←TRUE;
[nb, credentials]←ThParty.Register[
shh: info.shh,
rName: info.myRName,
type: $individual,
interface: info.myName,
properties: [$controller, VoiceUtils.OwnNetAddress[]]
];
IF nb=$success THEN nb ← ThParty.Enable[shh: info.shh, smartsID: credentials.smartsID];
IF nb#$success
THEN {
problem←"Can't register with server"; GOTO InitFailed; };
info.smartsID ← credentials.smartsID;
info.partyID ← credentials.partyID;
ThParty.ConversationsForParty[shh: info.shh, partyID: partyID];
pd.finchOn←TRUE;
info.ReportSystemState[pd.finchOn];
EXITS
InitFailed => UninitFinchSmarts[problem, nb];
};};
UninitFinchSmarts:
PUBLIC
PROC[problem:
ROPE←
NIL, nb:
NB←
NIL] = {
ENABLE RPC.CallFailed => GOTO Failed;
IF problem#NIL THEN Problem[problem, nb];
IF info#
NIL
THEN {
IF pd.finchOn
AND info.partyID#nullID
AND info.smartsID#nullID
THEN
[-- nb --]←ThParty.Deregister[info.shh, info.smartsID!RPC.CallFailed=>CONTINUE];
info.shh←none;
info.ReportSystemState[FALSE];
{
ClearConvs: RefQ.MapType = {
cDesc: ConvDesc=NARROW[subqueue.first];
cDesc.clientData ← NIL;
};
[]←RefQ.Map[info.conversations, ClearConvs];
info.conversations ← NIL;
};
};
pd.finchOn←FALSE;
IF PrincOpsUtils.IsBound[
LOOPHOLE[NamesGVImpExp.UnGVImport]]
THEN
NamesGVImpExp.UnGVImport[];
pd.interfacesAreImported←FALSE;
IF pd.smartsIsExported
THEN
ThSmartsRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE];
pd.smartsIsExported←FALSE;
EXITS
Failed => pd.interfacesAreImported ← pd.smartsIsExported ← FALSE;
FinchIsRunning:
PUBLIC
PROC RETURNS [finchIsRunning:
BOOL] = {
RETURN[pd.finchOn]; };
Debugging nonsense
ViewCmd: Commander.CommandProc =
TRUSTED {
Nice.View[pd, "Finch PD"];
};
Commander.Register["VuFinch", ViewCmd, "Program Management variables Finch"];
Commander.Register["FlushNoiseCache", FlushNoiseCacheCmd, "Forget cached SysNoises"];
Registration for use by arms-length systems
FinchSmarts.Register[
NEW[FinchSmarts.ProcsRecord ← [
playbackTune: PlaybackTune,
playNoise: PlayNoise,
recordTune: RecordTune,
stopTune: StopTune,
textToSpeech: TextToSpeech,
registerTranslateProc: RegisterTranslateProc,
stopSpeech: StopSpeech,
finchIsRunning: FinchIsRunning
]]];
}.
Couldn't bring myself to throw this away! Note care about info not being there yet/still.
RepRet: PROC[bool: BOOL, nb: NB, remark: Rope.ROPE]
RETURNS[sameBool: BOOL] = {
IF bool=FALSE THEN
IF info#NIL THEN info.ReportConversationState[nb, NIL, remark]
ELSE VoiceUtils.Report[remark, $Finch];
sameBool𡤋ool;
};
These responses are still maybe reasonable ones; where should they be handled? Feels like more stuff is being foisted off onto the client, or ignored. But this was never right either.
Supervise: PUBLIC ENTRY PROC[info: FinchInfo ] = {
invl, ntiy =>
Problem["FinchSmarts: Invalid state transition request. [, or not yet implemented]"];
cDesc.desiredState ← idle;
cDesc.desiredReason ← error;
cDesc.desiredComment ← "Invalid state transition", or "Unimplemented state transition"
SELECT nb FROM
success, stateMismatch =>;
noSuchParty2 => -- Have to get to error tone here. No such party.
Request[cDesc, $idle, $notFound, "Called party not found"];
narcissism => -- Have to get to error tone here. No such party.
Request[cDesc, $notFound, "Attempt to call self rejected on philosophical grounds"];
partyNotEnabled =>
info.ReportConversationState[noSuchSmarts, cDesc, "Your Etherphone is not connected to the telephone server"];
invalidTransition, convNotActive, convStillActive =>
comment: ROPE="Party-level detected invalid state transition request";
Problem[comment];
Request[cDesc, $idle, $error, comment];
notInConv, noSuchConv => -- Complain, zap, go idle and repeat.
comment: ROPE="NotInConv or NoSuchConv";
Problem[comment];
IF ours THEN info.currentConvID ← nullConvID;
cDesc.cState.credentials.convID ← nullConvID;
cDesc.cState.credentials.stateID ← 0;
Request[cDesc, $idle, $error, comment];
noSuchParty, noSuchSmarts => { -- Complain, deregister, we gone! Needs tuning.
problem ← "NoSuchParty or NoSuchSmarts reported, must try to go away";
GOTO Failing;
Failing => UninitFinchSmarts[problem]; -- now Failed
};
Swinehart, May 22, 1985 1:08:51 pm PDT
Changes to GetParty.
changes to: JayConnection
Polle Zellweger (PTZ) July 13, 1985 5:20:26 pm PDT
adding Text-to-Speech server
changes to: DIRECTORY, ProseSpec, ProseSpecs, stopIntervalSpec (was stopSpec), stopProseSpec, Progress, Supervise, DisconnectCall, PlaceCall, StopSpeech, TextToSpeech, InitFinchSmarts, GetConv, ReportProses, EnqueueProses, Complain, Connect, ProseConnection
Swinehart, August 6, 1985 5:43:08 pm PDT
Merge PTZ prose changes
changes to: DIRECTORY, NB, PD, stopIntervalSpec, stopProseSpec, Report, Progress, Supervise, DisconnectCall, PlaceCall, StopTune, NoiseSpec, PlaybackTune, TextToSpeech, InitFinchSmarts, GetConv, ReportProses, CompareIntID, EnqueueProses, Complain, Connect, JayConnection, ProseConnection, RepRet, FinchSmarts
Polle Zellweger (PTZ) August 19, 1985 4:16:40 pm PDT
Meter text in TextToSpeech so as to avoid sending large ropes all at once. Allows speech to begin sooner and flush faster. Also flushing changes.
changes to: FinchInfo, PD, Supervise, TextToSpeech, StopSpeech, ReportProses (comments only)
Polle Zellweger (PTZ) September 3, 1985 6:28:29 pm PDT
Allow registration of defaultTranslateProc.
changes to: Supervise, defaultTranslateProc, RegisterTranslateProc, TextToSpeech, FinchSmarts
Swinehart, September 16, 1985 10:00:59 am PDT
If Finch has never been initialized, info is NIL -- don't let that bother you.
changes to: GetRname, PlayNoise, FinchOn
Polle Zellweger (PTZ) October 22, 1985 5:10:44 pm PDT
changes to: Progress (add prose debugging reports), TextToSpeech (report connection failure), ReportProses (fix debugging reports), JayConnection (report connection failure), ProseConnection (report connection failure)
Polle Zellweger (PTZ) October 24, 1985 4:53:21 pm PDT
Move bluejayConnection and proseConnection from FinchInfo to ConvDesc.
changes to: Supervise, DisconnectCall, InitFinchSmarts, Connect, JayConnection, ProseConnection
Swinehart, October 28, 1985 12:31:20 pm PST
Merge Above changes with other other minor changes (RefQ and the like)
changes to: DIRECTORY, FinchSmartsImpl, Progress, Supervise, DisconnectCall, TextToSpeech, InitFinchSmarts, UninitFinchSmarts, IsConv, GetConv, IsConv (local of GetConvDesc), GetConvDesc, ReportProses, FinchOn, Connect, JayConnection, ProseConnection, PlaybackTune, ClearConvs (local of UninitFinchSmarts)
Swinehart, December 13, 1985 2:52:25 pm PST
Massive change to new Thrush, leaving out proses and intervals for the moment.
changes to: ConversationHandle, FinchInfo, Progress, Supervise, DisconnectCall, AnswerCall, PlaceCall, Apprise, Complain, Connect, Problem, FinchSmarts, Progress, QdProgress
Swinehart, December 17, 1985 10:05:46 am PST
Major revision for new Thrush. Removed all Prose and Bluejay stuff temporarily
changes to: QdProgress, NoteNewState, PutFTime, Connect, Problem, Progress, Other, Supervise