(FILECREATED "15-Feb-85 15:49:30" {ERIS}<SPEECH>MAILREADER>PROSE-CONTROLLER.;8 15506  

      previous date: "15-Feb-85 10:40:33" {ERIS}<SPEECH>MAILREADER>PROSE-CONTROLLER.;7)


(* Copyright (c) 1984, 1985 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT PROSE-CONTROLLERCOMS)

(RPAQQ PROSE-CONTROLLERCOMS ((VARS (P.PASSWORD NIL)
				   (P.HELP.FLG T)
				   (ALL.NUMERIC.PASSWORD NIL)
				   P.TOUCHTONE.LIST)
			     (CONSTANTS P.TOUCHTONE.LIST)
			     (FNS P.CONTROLLER P.SET.PASSWORD P.SET.USERNAME P.USER.INIT 
				  P.DECIPHER.TOUCHTONES P.INVALID.TOUCHTONES P.CONTROLLER.RESET)))

(RPAQQ P.PASSWORD NIL)

(RPAQQ P.HELP.FLG T)

(RPAQQ ALL.NUMERIC.PASSWORD NIL)

(RPAQQ P.TOUCHTONE.LIST ((2 A B C)
			 (3 D E F)
			 (4 G H I)
			 (5 J K L)
			 (6 M N O)
			 (7 P R S)
			 (8 T U V)
			 (9 W X Y)))
(DECLARE: EVAL@COMPILE 

(RPAQQ P.TOUCHTONE.LIST ((2 A B C)
			 (3 D E F)
			 (4 G H I)
			 (5 J K L)
			 (6 M N O)
			 (7 P R S)
			 (8 T U V)
			 (9 W X Y)))

(CONSTANTS P.TOUCHTONE.LIST)
)
(DEFINEQ

(P.CONTROLLER
  [LAMBDA NIL                                                (* BBB "15-Feb-85 10:36")
                                                             (* Top level control of the PROSE through the phone)

          (* The structure of this function is one big COND; what branch is to be taken depends on the settings of the global 
	  variables: P.USER P.PASSWORD P.QUIT and P.READING.MAIL)



          (* Trigger button is the button which caused P.PROCESS to wake up and thus P.CONTROLLER to be called, i.e. the last 
	  key pushed on the phone)


    (IGNORETIMER T)
    TRIGGERBUTTON←STATE:PHONEINPUT:1                         (* Should the PROSESTATUS window be updated?)
    (DEBUGOUTPUT?)

          (* Parse the input to make sure it is well-formed; may be better to do this at various places in the code where we 
	  know more about what the input ought to be)


    (VERIFYINPUT STATE:STATE.PHONEINPUT)                     (* Set the COMMAND field)
    (MAKECOMMAND)
    (if STATE:QUIT=T and (STATE:STATE.COMMAND or TRIGGERBUTTON=(QUOTE #))
	then                                                 (* A quit command was given but it was not immediately 
							     followed by a quit command so we should reset the quit 
							     flag)
	     (STATE:QUIT←NIL))                               (* Main control of operations)
    (if TRIGGERBUTTON=(QUOTE #) and (EQUAL STATE:STATE.COMMAND (QUOTE (0)))
	then                                                 (* No user logged in; log the new user 
							     (in; help is wanted))
	     (P.HELP (QUOTE LOGIN.HELP))
      elseif TRIGGERBUTTON=(QUOTE *) and STATE:STATE.COMMAND=NIL
	then                                                 (* If we get a * when STATE:QUIT is T then we want to 
							     log out)
	     (if STATE:STATE.MESSAGEQUERY?=(QUOTE T)
		 then STATE:STATE.MESSAGEQUERY?←NIL
		      (P.CHUNK "Specify another message. ")
	       elseif STATE:QUIT=T
		 then (P.BYE)
	       elseif STATE:TALKING=(QUOTE HALTED)
		 then (PROSE.STOP)
		      STATE:STATE.TALKING←NIL
		      STATE:STATE.HALTSPEECH←NIL
		      STATE:MESSAGEQUERY?←NIL
		      (P.CHUNK " Message aborted. Ready to read another message. ")
	       else                                          (* Prepare to quit)
		    STATE:STATE.QUIT←T
		    (PROSE.STOP)
		    (P.CHUNK 
	       " You gave a command to quit.  If you really want to quit type another asterisk. "))
      elseif STATE:STATE.USERINFO.USER=NIL
	then                                                 (* No user logged in; log the new user in)
	     (P.SET.USERNAME)
      elseif STATE:STATE.USERINFO.PASSWORD=NIL
	then                                                 (* Password not yet obtained;
							     obtain it)
	     (if ~ALL.NUMERIC.PASSWORD and ((EQUAL TRIGGERBUTTON (QUOTE #)) and STATE:COMMAND=NIL)
		 then ALL.NUMERIC.PASSWORD←T
	       elseif (P.SET.PASSWORD)
		 then                                        (* Login was successfull so we start LAFITE up for the 
							     new user)
		      (P.USER.INIT STATE:STATE.USER)
		      (P.LAFITE.START.NEW.USER))
      elseif STATE:STATE.STATEINFO.QUIT
	then                                                 (* Maybe quit from Lafite; or read old mail)

          (* !!! It is hard to decide where in the hierarchy of states to put this is; It is here mainly because if there is 
	  no new mail QUIT is T in order to allow the user to get out right away !!!)


	     (P.QUIT.OR.READ.OLD.MAIL TRIGGERBUTTON)
      elseif (EQUAL STATE:STATE.STATEINFO.TALKING (QUOTE HALTED))
	then                                                 (* Speech output has been halted 
							     (during the utterance of a msg body))
	     (if (EQUAL TRIGGERBUTTON (QUOTE #))
		 then                                        (* The user specified a number of sentences to back up)
		      (BACK.SENTENCE TRIGGERBUTTON STATE:STATE.COMMAND)
		      STATE:STATE.STATEINFO.HALTSPEECH←NIL
		      (COPYMSGBYTES STATE:STATE.PROSEINPUT.TEMPFILE (GETSTREAM (QUOTE {RS232})))
	       elseif (EQUAL TRIGGERBUTTON (QUOTE *))
		 then                                        (* The user specified a number of sentences to back up)
		      (BACK.SENTENCE TRIGGERBUTTON STATE:STATE.COMMAND)
		      STATE:STATE.STATEINFO.HALTSPEECH←NIL
		      (COPYMSGBYTES STATE:STATE.PROSEINPUT.TEMPFILE (GETSTREAM (QUOTE {RS232})))
	       else                                          (* The user simply wanted to quit out of reading the 
							     msg alltogether)
		    (P.FINISHED.ACTIONS))
      elseif ~(STATE:STATE.LAFITEINFO.FOLDEROPEN)
	then                                                 (* No browser open so open one)
	     (if STATE:STATE.LAFITEINFO.NEWMAIL
		 then                                        (* Both open it and get new mail)
		      (P.OPEN.FOLDER.AND.GET.NEW.MAIL STATE:STATE.USERINFO.USER)
	       elseif STATE:STATE.LAFITEINFO.NONEWMAIL
		 then                                        (* No new mail, so we just open the browser on the 
							     mailfile associated with USER)
		      (P.READ.OLD.MAIL (P.MAILFILE STATE:STATE.USERINFO.USER T))
	       else (SHOULDNT))
      elseif STATE:STATE.STATEINFO.MESSAGEQUERY?
	then 

          (* The user has selected a message or a message has been selected for him; he has been presented with the header of 
	  the message; we now let the user decide whether or not to read the message body depeding on the button which was 
	  pushed)


	     [if TRIGGERBUTTON=(QUOTE *)
		 then                                        (* Don't read it)
                                                             (* Reset MESSAGEQUERY?; another # or MSG.NO# has to be 
							     pushed in order to hear another message)
		      STATE:STATE.MESSAGEQUERY?←NIL
	       elseif TRIGGERBUTTON=(QUOTE #)
		 then                                        (* Read it)
		      STATE:STATE.MESSAGEQUERY?←NIL
		      (P.SAY.BODY STATE:STATE.LAFITEINFO.MAILFOLDER (OR 
							     STATE:STATE.PROSEINPUT.MSGDESCRIPTOR
									(PROGN (P.SELECT.MSG 
								STATE:STATE.LAFITEINFO.MAILFOLDER)
									       
							     STATE:STATE.PROSEINPUT.MSGDESCRIPTOR]
      else                                                   (* Default case is that we are reading mail;
							     we select a message to utter from the phone input)
	   (P.SELECT.AND.SAY.MSG STATE:STATE.INPUTINFO.COMMAND))
    (P.RESET.TIMER)
    (IGNORETIMER NIL])

(P.SET.PASSWORD
  [LAMBDA NIL                                                (* pkh: "23-Jan-85 16:46")
    (USEDFREE \LAFITE.AUTHENTICATION.FAILURE)
    [SETQ PASSWORD (COND
	(ALL.NUMERIC.PASSWORD (PACK (fetch (STATE INPUTINFO COMMAND) of STATE)))
	(T (P.DECIPHER.TOUCHTONES (fetch (STATE INPUTINFO COMMAND) of STATE]
    (SETQ ALL.NUMERIC.PASSWORD NIL)                          (* printout T "PASSWORD IS " PASSWORD T)
    (COND
      ((AND PASSWORD (NEQ PASSWORD (PACK NIL)))
	(SETUSERNAME (fetch (STATE USER) of STATE))
	(SETPASSWORD NIL (fetch (STATE USER) of STATE)
		     (MKSTRING PASSWORD))
	(SETPASSWORD (QUOTE PHYLUM)
		     (fetch (STATE USER) of STATE)
		     (MKSTRING PASSWORD))
	(SETPASSWORD (QUOTE ERIS)
		     (fetch (STATE USER) of STATE)
		     (MKSTRING PASSWORD))
	(SETPASSWORD (QUOTE IVY)
		     (fetch (STATE USER) of STATE)
		     (MKSTRING PASSWORD))                    (* Indigo for fonts)
	(SETPASSWORD (QUOTE INDIGO)
		     (fetch (STATE USER) of STATE)
		     (MKSTRING PASSWORD))
	(LAFITECLEARCACHE)                                   (* Set the password)
	(SETQ \LAFITE.AUTHENTICATION.FAILURE NIL)            (* Flush any user specific info)
	(P.CHUNK "We are checking the password. ")
	(P.AUTHENTICATE)
	(SELECTQ \LAFITE.AUTHENTICATION.FAILURE
		 (BadRName (P.CHUNK " Please re-enter your name.")
			   (P.CONTROLLER.RESET)
			   NIL)
		 (BadPassword (replace (STATE USERINFO PASSWORD) of STATE with NIL)
			      (P.CHUNK " Please re-enter your password. ")
			      NIL)
		 (PROGN (replace (STATE USERINFO PASSWORD) of STATE with T)
			(P.CHUNK "You are logged in, checking for new mail.")
			T)))
      (T (replace (STATE PASSWORD) of STATE with NIL)
	 (P.CHUNK " Please re-enter your password. ")
	 NIL])

(P.SET.USERNAME
  [LAMBDA NIL                                                (* edited: "17-Jan-85 13:58")
    (PROG (POSSIBLE.NAMES NAME)
          (SETQ POSSIBLE.NAMES (FIND.CODE NAME.TREE (fetch (STATE INPUTINFO COMMAND) of STATE)))
          (COND
	    (POSSIBLE.NAMES [COND
			      ((EQ (LENGTH POSSIBLE.NAMES)
				   1)
				(SETQ NAME (CAR POSSIBLE.NAMES)))
			      (T 

          (* * The touchtone sequence is ambiguous ie. the touchtones represent more than on user name.
	  For now we will return the first one.)


				 (P.CHUNK 
		 "Sorry, the touchtones you entered represent more than one name. You could be: ")
				 (for NAME in POSSIBLE.NAMES do (P.CHUNK (CONCAT " " NAME " ")))
				 (P.CHUNK " Assuming you are " (CAR POSSIBLE.NAMES))
				 (SETQ NAME (CAR POSSIBLE.NAMES]
			    (printout MAILREADERLOGFILE "User: " NAME T)
			    (replace (STATE USERINFO USER) of STATE with NAME)
			    (P.CHUNK (CONCAT " User " (L-CASE NAME T)
					     ", Please enter your password.")))
	    (T (P.CHUNK " Please re-enter your name. ")
	       (P.CONTROLLER.RESET])

(P.USER.INIT
  [LAMBDA (USER)                                             (* pkh: "30-Jan-85 14:31")

          (* * comment)


    (COND
      ((EQ USER HALVORSEN)
	(SETQ P.HELP.FLG NIL])

(P.DECIPHER.TOUCHTONES
  [LAMBDA (TOUCHTONES)                                       (* BBB " 9-Jan-85 09:26")

          (* * This function takes an TOUCHTONES, a list of numbers representing the keys that the user has entered, and 
	  decodes them with the following rules.)



          (* * entering a key enters the first letter on the key)



          (* * 0 followed by a key enters the second letter on the key)



          (* * 1 followed by a key enters the third letter on the key)



          (* * 0 followed by a key enters the number on that key)



          (* * 0 1 enters Q)



          (* * 11 enters Z)



          (* * 10 rubouts the last encoded character)


    (PROG (LETTER.LIST TOUCHTONE.STATE)
          (SETQ TOUCHTONE.STATE (QUOTE SIMPLE))
          (RETURN (for TONE in TOUCHTONES
		     do (SELECTQ TOUCHTONE.STATE
				 (SIMPLE (SELECTQ TONE
						  (0 (SETQ TOUCHTONE.STATE (QUOTE ZERO)))
						  (1 (SETQ TOUCHTONE.STATE (QUOTE ONE)))
						  [(2 3 4 5 6 7 8 9)
						    (push LETTER.LIST (CAR (NTH (ASSOC TONE 
										 P.TOUCHTONE.LIST)
										2]
						  (SHOULDNT)))
				 (ZERO (SELECTQ TONE
						(0 (SETQ TOUCHTONE.STATE (QUOTE ZEROZERO)))
						(1 (push LETTER.LIST (QUOTE Q))
						   (SETQ TOUCHTONE.STATE (QUOTE SIMPLE)))
						((2 3 4 5 6 7 8 9)
						  (push LETTER.LIST (CAR (NTH (ASSOC TONE 
										 P.TOUCHTONE.LIST)
									      3)))
						  (SETQ TOUCHTONE.STATE (QUOTE SIMPLE)))
						(SHOULDNT)))
				 (ZEROZERO (SELECTQ TONE
						    ((0 1 2 3 4 5 6 7 8 9)
						      (push LETTER.LIST TONE)
						      (SETQ TOUCHTONE.STATE (QUOTE SIMPLE)))
						    (SHOULDNT)))
				 (ONE (SELECTQ TONE
					       [0 (COND
						    (LETTER.LIST (SETQ LETTER.LIST (CDR LETTER.LIST]
					       (1 (push LETTER.LIST (QUOTE Z)))
					       [(2 3 4 5 6 7 8 9)
						 (push LETTER.LIST (CAR (NTH (ASSOC TONE 
										 P.TOUCHTONE.LIST)
									     4]
					       (SHOULDNT))
				      (SETQ TOUCHTONE.STATE (QUOTE SIMPLE)))
				 (SHOULDNT))
		     finally (COND
			       [(EQ TOUCHTONE.STATE (QUOTE SIMPLE))
				 (RETURN (PACK (REVERSE LETTER.LIST]
			       (T (P.INVALID.TOUCHTONES TOUCHTONE.STATE])

(P.INVALID.TOUCHTONES
  [LAMBDA (TOUCHTONE.STATE)                                  (* BBB " 9-Jan-85 09:25")
    (SELECTQ TOUCHTONE.STATE
	     (ZERO (P.CHUNK "Zero "))
	     (ONE (P.CHUNK "One "))
	     (ZEROZERO (P.CHUNK "Zero Zero "))
	     (SHOULDNT))
    (P.CHUNK "with nothing following is invalid."])

(P.CONTROLLER.RESET
  [LAMBDA (DONTTOUCH)                                        (* pkh: " 4-Jan-85 12:31")
                                                             (* Initializes the variables which control the behavior
							     of P.CONTROLLER)
    (COND
      [DONTTOUCH (for X in (RECORDFIELDNAMES (QUOTE STATE)) unless (MEMBER X DONTTOUCH)
		    do (EVAL (BQUOTE (REPLACE (STATE , X) of STATE with NIL]
      (T (LAFITECLEARCACHE)
	 (SETQ STATE (create STATE using NIL PROSESETTINGS ← PROSE.DEFAULT.SETTINGS)
	   (SETQ PROSESETTINGS PROSE.DEFAULT.SETTINGS))
	 (replace (STATE PROCESS) of STATE with \PROSE.PROCESS)
	 (replace (STATE TONEPROCESS) of STATE with \TONE.MONITOR.PROCESS)
	 (replace (STATE OPERATORPROCESS) of STATE with \PROSE.OPERATOR.PROCESS)
                                                             (* Make sure the PROCESS field is bound to the Prose 
							     process)
	 (SETQ \LAFITE.LAST.STATUS NIL)
	 (SETQ LAFITEDEFAULTHOST&DIR)
	 (SETQ ALL.NUMERIC.PASSWORD NIL])
)
(PUTPROPS PROSE-CONTROLLER COPYRIGHT ("Xerox Corporation" 1984 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (1038 15414 (P.CONTROLLER 1048 . 8038) (P.SET.PASSWORD 8040 . 10048) (P.SET.USERNAME 
10050 . 11258) (P.USER.INIT 11260 . 11472) (P.DECIPHER.TOUCHTONES 11474 . 13918) (P.INVALID.TOUCHTONES
 13920 . 14263) (P.CONTROLLER.RESET 14265 . 15412)))))
STOP