(FILECREATED " 3-Apr-85 18:59:55" {ERIS}<SPEECH>MAILREADER>CALLTEXT>PROSE-CONTROLLER.;3 18255  

      changes to:  (FNS P.CONTROLLER)

      previous date: "29-Mar-85 18:16:22" {ERIS}<SPEECH>MAILREADER>CALLTEXT>PROSE-CONTROLLER.;2)


(* 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.USERNAME P.SET.PASSWORD 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 " 3-Apr-85 16:16")
                                                             (* 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)


    (PROG NIL
          (IGNORETIMER T)
          (SETQ TRIGGERBUTTON (CAR (fetch DTMFINPUT of STATE)))
                                                             (* 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 (fetch (STATE DTMFINPUT) of STATE))   (* Set the COMMAND field)
          (MAKECOMMAND)
          (if (AND (EQ (fetch QUIT of STATE)
		       T)
		   (OR (fetch (STATE COMMAND) of STATE)
		       (NEQ TRIGGERBUTTON (QUOTE *)))
		   (NOT (fetch (STATE LAFITEINFO NONEWMAIL) of STATE)))
	      then (replace QUIT of STATE with NIL))         (* If a command to quit (a single *) was given and was 
							     not followed by another * then reset the quit flag)
                                                             (* Main control of operations)
          (if [AND (EQ TRIGGERBUTTON (QUOTE #))
		   (EQUAL (fetch (STATE COMMAND) of STATE)
			  (QUOTE (0]
	      then                                           (* No user logged in; log the new user 
							     (in; help is wanted))
		   (P.HELP (QUOTE LOGIN.HELP))
	    elseif (AND (EQ TRIGGERBUTTON (QUOTE *))
			(NULL (fetch (STATE COMMAND) of STATE)))
	      then                                           (* If we get a * when STATE:QUIT is T then we want to 
							     log out)
		   (if (EQ (fetch (STATE MESSAGEQUERY?) of STATE)
			   (QUOTE T))
		       then (replace (STATE MESSAGEQUERY?) of STATE with NIL)
			    (P.CHUNK "Specify another message. ")
		     elseif (EQ (fetch QUIT of STATE)
				T)
		       then (P.BYE)
			    (RETURN)
		     elseif (EQ (fetch TALKING of STATE)
				(QUOTE HALTED))
		       then (PROSE.STOP)
			    (replace (STATE TALKING) of STATE with NIL)
			    (replace (STATE HALTSPEECH) of STATE with NIL)
			    (replace MESSAGEQUERY? of STATE with NIL)
			    (P.CHUNK " Message aborted. Ready to read another message. ")
		     else                                    (* Prepare to quit)
			  (replace (STATE QUIT) of STATE with T)
			  (PROSE.STOP)
			  (P.CHUNK 
	       " You gave a command to quit.  If you really want to quit type another asterisk. "))
	    elseif (NULL (fetch (STATE USERINFO USER) of STATE))
	      then                                           (* No user logged in; log the new user in)
		   (P.SET.USERNAME)
	    elseif (NULL (fetch (STATE USERINFO PASSWORD) of STATE))
	      then                                           (* Password not yet obtained;
							     obtain it)
		   (if [AND (NOT ALL.NUMERIC.PASSWORD)
			    (AND (EQUAL TRIGGERBUTTON (QUOTE #))
				 (NULL (fetch COMMAND of STATE]
		       then (SETQ ALL.NUMERIC.PASSWORD T)
		     elseif (P.SET.PASSWORD)
		       then                                  (* Login was successfull so we start LAFITE up for the 
							     new user)
			    (P.USER.INIT (fetch (STATE USER) of STATE))
			    (P.LAFITE.START.NEW.USER))
	    elseif (fetch (STATE STATEINFO QUIT) of STATE)
	      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 (fetch (STATE STATEINFO TALKING) of STATE)
			  (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 (fetch (STATE COMMAND) of STATE))
			    (replace (STATE STATEINFO HALTSPEECH) of STATE with NIL)
			    (COPYMSGBYTES (fetch (STATE PROSEINPUT TEMPFILE) of STATE)
					  (GETSTREAM (QUOTE {RS232})))
		     elseif (EQUAL TRIGGERBUTTON (QUOTE *))
		       then                                  (* The user specified a number of sentences to back up)
			    (BACK.SENTENCE TRIGGERBUTTON (fetch (STATE COMMAND) of STATE))
			    (replace (STATE STATEINFO HALTSPEECH) of STATE with NIL)
			    (COPYMSGBYTES (fetch (STATE PROSEINPUT TEMPFILE) of STATE)
					  (GETSTREAM (QUOTE {RS232})))
		     else                                    (* The user simply wanted to quit out of reading the 
							     msg alltogether)
			  (P.FINISHED.ACTIONS))
	    elseif (NOT (fetch (STATE LAFITEINFO FOLDEROPEN) of STATE))
	      then                                           (* No browser open so open one)
		   (if (fetch (STATE LAFITEINFO NEWMAIL) of STATE)
		       then                                  (* Both open it and get new mail)
			    (P.OPEN.FOLDER.AND.GET.NEW.MAIL (fetch (STATE USERINFO USER)
							       of STATE))
		     elseif (fetch (STATE LAFITEINFO NONEWMAIL) of STATE)
		       then                                  (* No new mail, so we just open the browser on the 
							     mailfile associated with USER)
			    (PROG ((MAILFILE (P.MAILFILE (fetch (STATE USERINFO USER) of STATE)
							 T)))
			          (if MAILFILE
				      then (P.READ.OLD.MAIL MAILFILE)))
		     else (SHOULDNT))
	    elseif (fetch (STATE STATEINFO MESSAGEQUERY?) of STATE)
	      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 (EQ TRIGGERBUTTON (QUOTE *))
		       then                                  (* Don't read it)
                                                             (* Reset MESSAGEQUERY?; another # or MSG.NO# has to be 
							     pushed in order to hear another message)
			    (replace (STATE MESSAGEQUERY?) of STATE with NIL)
		     elseif (EQ TRIGGERBUTTON (QUOTE #))
		       then                                  (* Read it)
			    (replace (STATE MESSAGEQUERY?) of STATE with NIL)
			    (P.SAY.BODY (fetch (STATE LAFITEINFO MAILFOLDER) of STATE)
					(OR (fetch (STATE PROSEINPUT MSGDESCRIPTOR) of STATE)
					    (PROGN (P.SELECT.MSG (fetch (STATE LAFITEINFO MAILFOLDER)
								    of STATE))
						   (fetch (STATE PROSEINPUT MSGDESCRIPTOR)
						      of STATE]
	    else                                             (* Default case is that we are reading mail;
							     we select a message to utter from the phone input)
		 (P.SELECT.AND.SAY.MSG (fetch (STATE INPUTINFO COMMAND) of STATE)))
          (P.RESET.TIMER)
          (IGNORETIMER NIL])

(P.SET.USERNAME
  [LAMBDA NIL                                                (* BBB "21-Feb-85 16:05")
    (PROG ([TOUCHTONES (MKSTRING (PACK (fetch (STATE INPUTINFO COMMAND) of STATE]
	   (PEOPLE.WITH.SAME.TOUCHTONES)
	   (ACTUAL.PERSON))
          (SETQ PEOPLE.WITH.SAME.TOUCHTONES (GETHASHFILE TOUCHTONES MAILREADERUSERSFILE))
          (if PEOPLE.WITH.SAME.TOUCHTONES
	      then (if (NEQ (FLENGTH PEOPLE.WITH.SAME.TOUCHTONES)
			    1)
		       then 

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


			    (SETQ ACTUAL.PERSON (CAR PEOPLE.WITH.SAME.TOUCHTONES))
			    (P.CHUNK 
		"Sorry, the touch tones you entered represent more than one name. You could be: ")
			    (for PERSON in PEOPLE.WITH.SAME.TOUCHTONES
			       do (P.CHUNK (CONCAT " " (fetch (LOGININFO NAME) of PERSON)
						   " "))
			       finally (P.CHUNK "."))
			    (P.CHUNK (CONCAT " Assuming you are " (fetch NAME of ACTUAL.PERSON)))
		     else (SETQ ACTUAL.PERSON (CAR PEOPLE.WITH.SAME.TOUCHTONES)))
		   (replace (STATE USERINFO USER) of STATE with (fetch NAME of ACTUAL.PERSON))
		   (replace (STATE USERINFO TOUCHTONES) of STATE with TOUCHTONES)
		   (if (fetch (LOGININFO PRONUNCIATION) of ACTUAL.PERSON)
		       then (P.CHUNK " User ")
			    (SAY.PHONEMES (fetch (LOGININFO PRONUNCIATION) of ACTUAL.PERSON))
		     else (P.CHUNK (CONCAT " User " (L-CASE (fetch NAME of ACTUAL.PERSON)
							    T)
					   ",")))
		   (P.CHUNK " Please enter your password.")
	    else (P.CHUNK " Please re-enter your name. ")    (* P.CONTROLLER.RESET)])

(P.SET.PASSWORD
  [LAMBDA NIL                                                (* BBB "21-Feb-85 13:53")
    (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.")
			(printout MAILREADERLOGFILE "User: " (fetch (STATE USER) of STATE)
				  T)
			T)))
      (T (replace (STATE PASSWORD) of STATE with NIL)
	 (P.CHUNK " Please re-enter your password. ")
	 NIL])

(P.USER.INIT
  [LAMBDA (USER)                                             (* BBB "15-Feb-85 16:03")

          (* * comment)


    (if (EQ USER (QUOTE HALVORSEN))
	then (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)                                        (* BBB "28-Mar-85 11:28")
                                                             (* 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 (SETUSERNAME "")
	 (SETPASSWORD NIL (fetch (STATE USER) of STATE)
		      "")
	 (SETPASSWORD (QUOTE PHYLUM)
		      (fetch (STATE USER) of STATE)
		      "")
	 (SETPASSWORD (QUOTE IVY)
		      (fetch (STATE USER) of STATE)
		      "")
	 (SETPASSWORD (QUOTE INDIGO)
		      (fetch (STATE USER) of STATE)
		      "")
	 (SETPASSWORD (QUOTE ERIS)
		      (fetch (STATE USER) of STATE)
		      "")
	 (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 CALLTEXTPROCESS) of STATE with \CALLTEXT.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 NIL)
	 (SETQ ALL.NUMERIC.PASSWORD NIL)
	 (DEL.PROCESS (FIND.PROCESS (QUOTE LAFITEMAILWATCH])
)
(PUTPROPS PROSE-CONTROLLER COPYRIGHT ("Xerox Corporation" 1984 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (1095 18163 (P.CONTROLLER 1105 . 9474) (P.SET.USERNAME 9476 . 11345) (P.SET.PASSWORD 
11347 . 13445) (P.USER.INIT 13447 . 13670) (P.DECIPHER.TOUCHTONES 13672 . 16116) (P.INVALID.TOUCHTONES
 16118 . 16461) (P.CONTROLLER.RESET 16463 . 18161)))))
STOP