DIRECTORY IO, Lark, LarkSmartsMonitorImpl, Rope USING [ Concat, Equal, Fetch, FromChar, Substr ], Log USING [ Problem, ProblemHandle, SLOG ], ThParty USING [ GetPartyFromNumber, GetPartyFromFeepNum ], Thrush USING [ ConversationHandle, H, IntervalSpec, PartyHandle, nullConvHandle, nullHandle, ROPE, StateInConv, ThHandle ], ThSmartsPrivate USING [ Apprise, ChangeState, ConvDesc, Deregister, EnableSmarts, EnterLarkState, GetConv, InterpretHookState, LarkFailed, OpenConversations, ParseState, SetRingingParameters, SmartsInfo ] ; LarkSmartsImpl: CEDAR MONITOR LOCKS root IMPORTS IO, root: LarkSmartsMonitorImpl, Rope, Log, ThParty, Thrush, ThSmartsPrivate EXPORTS ThSmartsPrivate SHARES LarkSmartsMonitorImpl = { OPEN IO; CommandEvents: TYPE = Lark.CommandEvents; ConversationHandle: TYPE = Thrush.ConversationHandle; nullConvHandle: ConversationHandle=Thrush.nullConvHandle; ConvDesc: TYPE = ThSmartsPrivate.ConvDesc; disabled: Lark.Event = Lark.disabled; enabled: Lark.Event = Lark.enabled; endNum: Lark.Event = Lark.endNum; H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; }; IntervalSpec: TYPE = Thrush.IntervalSpec; nullHandle: Thrush.ThHandle = Thrush.nullHandle; OpenConversations: TYPE = ThSmartsPrivate.OpenConversations; PartyHandle: TYPE = Thrush.PartyHandle; ROPE: TYPE = Thrush.ROPE; SHHH: TYPE = Lark.SHHH; -- Encrypts conv. if first arg to RPC PROC SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; StateInConv: TYPE = Thrush.StateInConv; StatusEvents: TYPE = Lark.StatusEvents; defaultRecordLength: INT _ -1; LarkParseEvent: PUBLIC ENTRY PROC[ smartsInfo: SmartsInfo, sEvent: Lark.StatusEvent] = { ENABLE { UNWIND=>NULL; ThSmartsPrivate.LarkFailed => { Log.Problem["Lark Failed", $Smarts, smartsInfo]; GOTO Failed; }; ANY => { Log.Problem[NIL, $Smarts, smartsInfo]; GOTO Failed; }; }; cDesc: ConvDesc; IF ~LarkEnabled[smartsInfo] THEN RETURN; -- don't interfere with reverted call! sEvent _ ThSmartsPrivate.InterpretHookState[smartsInfo.larkInfo, sEvent]; IF sEvent.device=nothing THEN RETURN; Log.SLOG[]; DoParse[smartsInfo, sEvent.event]; IF smartsInfo.haveArguments THEN { val: INT_0; IF smartsInfo.Command=NIL THEN smartsInfo.Command _ CmdCall; SELECT smartsInfo.parseState FROM inNum => val _ IO.GetInt[IO.RIS[smartsInfo.arguments]]; ENDCASE; smartsInfo.Command[smartsInfo, val]; []_SetParserIdle[smartsInfo, TRUE]; }; cDesc _ GetCDesc[smartsInfo]; IF cDesc#NIL THEN { SELECT cDesc.cState.state FROM # cDesc.desiredState => RETURN; -- some request already in the works. reserved => IF smartsInfo.haveOne THEN cDesc.desiredState_parsing ELSE RETURN; parsing => IF ~smartsInfo.haveOne THEN cDesc.desiredState_reserved ELSE RETURN; ENDCASE=>RETURN; ThSmartsPrivate.Apprise[smartsInfo]; }; EXITS Failed => ThSmartsPrivate.Deregister[smartsInfo]; }; LarkEnabled: INTERNAL PROC[info: SmartsInfo] RETURNS [enabled: BOOL] = INLINE { RETURN[SELECT info.larkInfo.larkState FROM none => ThSmartsPrivate.EnableSmarts[info], failed, recovering => FALSE, ENDCASE => TRUE]; }; DoParse: INTERNAL PROC[info: SmartsInfo, event: Lark.Event] = { info.haveOne _ TRUE; SELECT event FROM disabled => { info.haveArguments _ TRUE; info.Command _ CmdOnhook; }; enabled => { info.haveArguments _ TRUE; info.Command _ CmdOffhook; }; endNum => { info.haveArguments _ TRUE; }; IO.DEL, IO.ESC => []_SetParserIdle[info, TRUE]; '* => { IF info.cmdOrRecip THEN info.offset_10; info.cmdOrRecip _ TRUE; info.parseState _ idle; }; ENDCASE => { IF info.cmdOrRecip THEN { info.cmdOrRecip _ FALSE; event_event+info.offset; info.offset_0; IF event = '0 THEN { []_SetParserIdle[info, FALSE]; info.parseState _ getFeep; RETURN;}; []_SetParserIdle[info, TRUE]; SELECT event FROM '1, 'H, 'h => -- hold << for now, toggle "radio" state >> { info.Command _ CmdRadio; info.haveArguments _ TRUE; }; '3, 'C, 'c => -- conference << for now, toggle "hot line" state >> { info.Command _ CmdHotline; info.haveArguments _ TRUE; }; '7, 'F, 'f => -- forward << for now, toggle "monitored" state >> { info.Command _ CmdMonitor; info.haveArguments _ TRUE; }; '*, -- esc endNum -- del -- => []_SetParserIdle[info, TRUE]; '0+10, 'T, 't => { info.Command _ CmdBackDoor; info.haveArguments _ TRUE; }; '1+10, 'O, 'o => { info.Command _ CmdRingOff; info.haveArguments _ TRUE; }; '2+10, 'N, 'n => { info.Command _ CmdRingOn; info.haveArguments _ TRUE; }; '3+10, 'L, 'l => { info.Command _ CmdRingOffTimed; info.parseState _ getNum; }; '4+10, 'A, 'a => { info.Command _ CmdRingOnce; info.haveArguments _ TRUE; }; '5+10, 'B, 'b => { info.Command_CmdRingOnceTimed; info.parseState _ getNum; }; '9+10, 'R, 'r => info.Command _ CmdFlash; ENDCASE => -- unassigned same as DEL -- NULL; RETURN; }; ParseArgument[info, event]; }; }; ParseArgument: INTERNAL PROC[info: SmartsInfo, event: Lark.Event] = { AppendEvent[info, event]; info.parseState _ SELECT event FROM IN ['0..'9] => SELECT info.parseState FROM idle => inSeq, getFeep => inFeep, getNum => inNum, getStr => inStr, ENDCASE => info.parseState, ENDCASE => SELECT info.parseState FROM idle, getStr => inStr, getFeep, getNum, inFeep, inNum => inTossStr, inSeq => SetParserIdle[info, TRUE], ENDCASE => info.parseState; IF info.parseState = inSeq THEN info.haveArguments _ SELECT info.argLength FROM 1 => event='0, 2 => info.arguments.Fetch[0]='9 AND info.arguments.Fetch[1]='0, 4 => (SELECT info.arguments.Fetch[0] FROM '9 => info.arguments.Substr[start: 2, len: 2].Equal["11"], '8 => info.arguments.Fetch[1] = '1, ENDCASE => TRUE), 8 => info.arguments.Fetch[2] > '1, 11 => TRUE, ENDCASE=>FALSE; }; AppendEvent: INTERNAL PROC[info: SmartsInfo, event: Lark.Event] = { info.arguments _ Rope.Concat[info.arguments, Rope.FromChar[event]]; info.argLength _ info.argLength + 1; }; SetParserIdle: INTERNAL PROC[info: SmartsInfo, clearCmd: BOOL] RETURNS [ ThSmartsPrivate.ParseState ] = { info.haveArguments _ info.haveOne _ FALSE; info.parseState _ idle; info.arguments _ NIL; info.offset _ 0; info.cmdOrRecip _ FALSE; info.argLength _ 0; IF clearCmd THEN info.Command _ NIL; RETURN[idle]; }; CmdCall: INTERNAL PROC[info: SmartsInfo, val: INT] = { partyID: PartyHandle; cDesc: ConvDesc; IF info.argLength=0 OR info.parseState=inTossStr THEN RETURN; SELECT GetSIC[info] FROM reserved, parsing => NULL; ENDCASE => RETURN; cDesc _ ThSmartsPrivate.GetConv[info, info.currentConvID, TRUE]; partyID _ cDesc.cState.credentials.partyID; cDesc.desiredPartyID _ GetPartiesForCall[info, partyID, info.parseState, info.arguments, TRUE]; ThSmartsPrivate.ChangeState[info, cDesc, active]; }; CmdBackDoor: INTERNAL PROC[info: SmartsInfo, val: INT] = { IF GetSIC[info]=active AND info.larkInfo.larkState = trunkTalking THEN { -- Hack ThSmartsPrivate.EnterLarkState[info.larkInfo, trunkFlashing, info]; RETURN; }; info.arguments _ NIL; info.parseState _ inSeq; info.argLength _ 1; CmdCall[info, val]; }; CmdOnhook: INTERNAL PROC[info: SmartsInfo, val: INT] = { ThSmartsPrivate.ChangeState[info, GetCDesc[info], idle, terminating]; }; CmdOffhook: INTERNAL PROC[info: SmartsInfo, val: INT] = { cDesc: ConvDesc; desiredState: StateInConv_active; Log.SLOG[]; SELECT GetSIC[info] FROM idle => { cDesc _ ThSmartsPrivate.GetConv[info, nullConvHandle, TRUE]; desiredState _ reserved; }; ringing => cDesc _ GetCDesc[info]; ENDCASE => RETURN; ThSmartsPrivate.ChangeState[info, cDesc, desiredState]; }; CmdRingOff: INTERNAL PROC[info: SmartsInfo, val: INT] = { ThSmartsPrivate.SetRingingParameters[info: info.larkInfo, ringEnable: off, ringTune: info.larkInfo.ringTune]; }; CmdRingOn: INTERNAL PROC[info: SmartsInfo, val: INT] = { ThSmartsPrivate.SetRingingParameters[info: info.larkInfo, ringEnable: on, ringTune: info.larkInfo.ringTune]; }; CmdRingOffTimed: INTERNAL PROC[info: SmartsInfo, val: INT] = { ThSmartsPrivate.SetRingingParameters[info: info.larkInfo, ringEnable: offTimed, ringInterval: (IF val#0 THEN val ELSE 30)*60, ringTune: info.larkInfo.ringTune]; }; CmdRingOnce: INTERNAL PROC[info: SmartsInfo, val: INT] = { ThSmartsPrivate.SetRingingParameters[info: info.larkInfo, ringEnable: subdued, ringTune: info.larkInfo.ringTune]; }; CmdRingOnceTimed: INTERNAL PROC[info: SmartsInfo, val: INT] = { ThSmartsPrivate.SetRingingParameters[info: info.larkInfo, ringEnable: subduedTimed, ringInterval: (IF val#0 THEN val ELSE 30)*60, ringTune: info.larkInfo.ringTune]; }; CmdFlash: INTERNAL PROC[info: SmartsInfo, val: INT] = { NULL; }; CmdRadio: INTERNAL PROC[info: SmartsInfo, val: INT] = { info.larkInfo.radio _ NOT info.larkInfo.radio; }; CmdHotline: INTERNAL PROC[info: SmartsInfo, val: INT] = { info.larkInfo.hotLine _ NOT info.larkInfo.hotLine; }; CmdMonitor: INTERNAL PROC[info: SmartsInfo, val: INT] = { info.larkInfo.monitor _ NOT info.larkInfo.monitor; }; GetConvDesc: PUBLIC PROC[info: SmartsInfo] RETURNS [ cDesc: ConvDesc_NIL ] = { RETURN[GetCDesc[info]]; }; GetCDesc: PROC[info: SmartsInfo] RETURNS [ cDesc: ConvDesc_NIL ] = { convID: ConversationHandle=info.currentConvID; IF convID=nullConvHandle THEN RETURN; FOR convs: OpenConversations _ info.conversations, convs.rest WHILE convs#NIL DO IF convs.first.cState.credentials.convID = convID THEN { cDesc _ convs.first; EXIT; }; ENDLOOP; RETURN[IF cDesc#NIL AND cDesc.descValid THEN cDesc ELSE NIL]; }; GetSIC: PUBLIC INTERNAL PROC[info: SmartsInfo] RETURNS [ state: StateInConv ] = { cDesc: ConvDesc = GetCDesc[info]; RETURN[IF cDesc=NIL THEN idle ELSE cDesc.cState.state]; }; GetPartiesForCall: PROC[info: SmartsInfo, partyID: PartyHandle, parseState: ThSmartsPrivate.ParseState, args: ROPE, trunkOK: BOOL] RETURNS[calledPartyID: PartyHandle _ nullHandle ] = { IF partyID = nullHandle THEN RETURN; calledPartyID _ SELECT parseState FROM inSeq, inNum => ThParty.GetPartyFromNumber[ partyID: partyID, phoneNumber: args, trunkOK: trunkOK], inFeep => ThParty.GetPartyFromFeepNum[partyID: partyID, feepNum: args], inStr => Log.ProblemHandle[NIL, $Smarts, nullHandle, info], -- not these days! ENDCASE => Log.ProblemHandle[NIL, $Smarts, nullHandle, info]; }; }. ���N��LarkSmartsImpl.mesa Last modified by D. Swinehart, November 27, 1983 12:53 am Last Edited by: Pier, May 3, 1984 3:00:22 pm PDT Copies Parsing ParseEvent handles events from the EtherPhone Be sure state of conv. and tones agree with state of parsing. <<This feels like in the wrong place. Oughta be done by a command proc of some sort? Or get rid of the command procs?>> In the name of unexcess generality, this procedure parses all of the commands: call placement, message handling, call management, and so on. Could change to call sequential registered procedures and like that, if more flexibility is needed. The biggies. Termination of arguments, DEL IF info.parseState=idle AND info.Command=NIL THEN info.Command _ CmdQuietJay; Command or recipient initiation Valid argument event Here are the commands Message system commands '2, 'R, 'r => { info.Command _ CmdRecord; info.haveArguments _ TRUE; }; '4, 'P, 'p => { info.Command _ CmdPlayOwn; info.haveArguments _ TRUE; }; '5, 'D, 'd => { info.Command _ CmdDelete; info.haveArguments _ TRUE; }; '6, 'G, 'g => { info.Command _ CmdPlayRecd; info.parseState _ getNum; }; '8, 'M, 'm => info.Command _ CmdMail; **0 A letter, digit, or other non-activation character. User-invoked actions Connection Management Utilities Not at present protected by monitor -- LarkStateImpl back-pointer problem. �ÊF��˜�Jšœ™šœ9™9J™0J™�—šÏk œ˜ Jšœ˜Jšœ˜J˜Jšœœ,˜6Jšœœœ˜+Jšœœ-˜:šœœ˜Jšœœ9œ˜l—šœœ˜Jšœ´˜´—J˜J˜�—šœœœœ˜(šœœ˜J˜J˜J˜J˜J˜J˜—Jšœ˜Jšœ˜ Jšœœ˜J˜�—šœ™J˜�Jšœœ˜)šœœ˜5Jšœ9˜9—Jšœ œ˜*Jšœ%˜%Jšœ#˜#Jšœ!˜!Jšœœœœœœœ˜JJšœœ˜)J˜0Jšœœ%˜<Jšœ œ˜'Jšœœ œ˜JšœœœÏc*˜CJšœœ˜.J˜'Jšœœ˜'J™�Jšœœ˜—J™�šž™J™�Jšœ-™-šÏnœœœœ˜"Jšœ5˜5šœ˜Jšœœ˜ JšœQœ˜`Jšœœœ˜?J˜—J˜Jšœœœž&˜OJšœI˜IJšœœœ˜%Jšœœ˜Jšœ"˜"šœœ˜"Jšœœ˜Jšœœœ˜<šœ˜!Jš œœœœœ˜@—Jšœ$˜$Jšœœ˜&—Jšœ=™=J™UJ™"J˜šœœœ˜šœ˜Jšœœž%˜EJš œœœœœ˜NJš œœœœœ˜OJšœœ˜—J˜$J˜—š˜Jšœ1˜1—Jšœ˜J˜�—šŸœœœœœœ˜Ošœœ˜*J˜+Jšœœ˜Jšœœ˜—J˜J˜�—šŸœœœ)˜?J™ñJšœœ˜šœ˜J™�J™Jšœ#œ˜EJšœ"œ˜EJ˜�J™šœ˜Jšœœ˜Jšœœœœ™MJšœ˜—Jš œœœœœ˜/J˜�J™šœ˜Jšœœ˜'Jšœœ˜2—J˜�J™šœ˜šœœ˜Jšœœ˜J˜J˜šœœ˜Jšœœœ˜C—Jšœœ˜šœ˜J™šœž+˜9Jšœ0œ˜8—šœž4˜BJšœ2œ˜:—šœž2˜@Jšœ2œ˜:—Jšœž˜Jšœž œœ˜1J˜�J™Jšœ?œ™GJšœ@œ™HJšœ?œ™GJ™HJ™%šœDœ˜LJ™—JšœCœ˜KJšœBœ˜JJšœO˜OJšœL˜LJšœN˜NJ˜)Jšœžœœ˜-—Jšœ˜ —J˜�J™3J˜!——J˜�—šŸ œœœ)˜EJšœ˜šœœ˜#šœ œ˜*J˜J˜J˜J˜Jšœ˜—šœœ˜&J˜J˜,Jšœœ˜#Jšœ˜——šœ˜šœœ˜/J˜Jšœ œ˜?˜šœœ˜$Jšœ:˜:J˜#Jšœœ˜——J˜"Jšœœ˜Jšœœ˜——Jšœ˜—J˜�šŸœœœ)˜CJšœC˜CJ˜(—J˜�šŸ œœœœ˜>Jšœ#˜*Jšœ$œ˜*Jšœ)œ˜-Jšœ#œ˜)Jšœœ œœ˜8Jšœ ˜J˜�——™J™�J˜�šŸœœœœ˜6J˜J˜Jšœœœœ˜=Jš œœœœœ˜FJšœ:œ˜@J˜+JšœYœ˜_J˜1Jšœ˜—J˜�šŸœœœœ˜:šœœ(œž˜PJšœDœ˜N—Jšœœ˜J˜J˜J˜J˜J˜�—šŸ œ œœ˜8J˜EJšœ˜—J˜�šŸ œœœœ˜9J˜J˜!Jšœœ˜šœ˜šœ ˜ Jšœ6œ˜<J˜Jšœ˜—J˜"Jšœ˜—Jšœ7˜7Jšœ˜—J˜�šŸ œ œœ˜9Jšœm˜mJ˜—J˜�šŸ œ œœ˜8J˜lJ˜—J˜�šŸœœœœ˜>˜OJšœœœœ+˜P—J˜—J˜�šŸœ œœ˜:Jšœq˜qJ˜—J˜�šŸœ œœ˜?˜SJšœœœœ+˜P—J˜—J˜�šŸœ œœ˜7Jšœ˜J˜—J˜�šŸœ œœ˜7Jšœœ˜.J˜—J˜�šŸ œ œœ˜9Jšœœ˜2J˜J˜�—šŸ œ œœ˜9Jšœœ˜2J˜—J˜�—™J˜�šŸœœœœ˜NJšœ˜J˜J˜�—šŸœœœœ˜DJ™JJšœ.˜.Jšœœœ˜%šœ;œœ˜Pšœ0œ˜8Jšœœ˜—Jšœ˜—Jšœœœœœœœ˜=J˜J˜�—šŸœœœ˜QJ˜!Jš œœœœœ˜7Jšœ˜—J˜�šŸœœP˜gJšœœœ˜Jšœ.˜5Jšœœœ˜$šœœ˜&šœ+˜+Jšœ7˜7—˜ Jšœ=˜=—Jšœœž˜NJšœœ˜=—Jšœ˜——J˜—�…—����&è��7|��