(FILECREATED "22-May-85 18:03:37" {EROS}<SPEECH>MAILREADER>CALLTEXT>PROSE-UTIL.;11 50542  

      changes to:  (FNS P.HELP)

      previous date: "17-Apr-85 11:49:13" {EROS}<SPEECH>MAILREADER>CALLTEXT>PROSE-UTIL.;10)


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

(PRETTYCOMPRINT PROSE-UTILCOMS)

(RPAQQ PROSE-UTILCOMS [(FNS ACTIVEWINDOW ADVISE.FOR.TYPEOUT VERIFYINPUT DESCRIBE.STATE GETSTATEFIELD 
			    P.INDEX.SEQ? P.RS232.INIT P.FINISHED? P.INTERPRET.OUTPUT 
			    P.LAST.SENTENCE.SAID P.MESSAGE.QUERY P.PROCESS P.NO.RS232 DEBUGOUTPUT? 
			    PROSEDEBUGINFO MAKECOMMAND MSG.LEN.TO.TIME MSG.LEN.TO.SECS 
			    MSG.LEN.TO.MINS PLURAL? BACK.SENTENCE P.SPEED P.QUIT.READING.MSG 
			    BACK.SENTENCE1 BOUT.FROM.STRING LETTERP READ.TTY SAYT SETSTATEFIELD 
			    START.PROSE.PROCESSES PHONE.MONITOR START.PROSE.PROCESS SYNCH 
			    CHARS.TO.MINUTES CHECK.RS232.SETTINGS COPYMSGBYTES BINARYLCASE BINLETTERP 
			    P.USER.MESSAGE PHONE.INTERRUPT EOSP P.CHECK.GLOBAL.VARS P.HELP P.CHUNK 
			    P.RESET.TIMER SIMPLESYNCH IGNORETIMER P.COMMAND P.ENSURE.ESC.SEQ 
			    P.FIND.ESC.SEQ P.FINISHED.ACTIONS P.FIX P.FIND.IMAGE.OBJS 
			    P.SEARCH.SELECT.AND.SAY.MSG P.SEND.ESC.SEQ TEDIT.LIST.OF.OBJECTS 
			    P.SAY.BODY P.SAY.BODY1)
	(FNS ACTIVEWINDOW)
	(RECORDS PROSESETTINGS STATE)
	(VARS (\TIMEOUTFLG NIL)
	      (TOPLEVELTTYWINDOW (TTYDISPLAYSTREAM))
	      (\IGNORETIMER NIL))
	(VARS (EOSENTCHARCODES (QUOTE (46 59 33)))
	      (IMAGEOBJMSG 
"  Uh!  There is a bitmap here which I can not describe.  I will continue reading the text after the bitmap. "
			   )
	      (STATE (CREATE STATE))
	      (PROSEDEBUG NIL))
	(INITVARS (PROSE.DEFAULT.SETTINGS (CREATE PROSESETTINGS SPEECHRATE ← 160)))
	(* Modifications to LAFITE)
	(FNS PROSE.LAFITE.WRITE.PROFILE PROSE.LAFITE.BROWSE)
	[P (SETQ P.TIMEOUTTIMER (SETUPTIMER 1000 NIL (QUOTE TICKS]
	(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDVARS (NLAMA)
									      (NLAML)
									      (LAMA])
(DEFINEQ

(ACTIVEWINDOW
  [LAMBDA (WINDOWNAME REGION WINDOWPROPLST)                  (* pkh: "14-Nov-84 13:34")
    [COND
      ([OR (NOT (BOUNDP WINDOWNAME))
	   (NOT (WINDOWP (EVAL WINDOWNAME]
	(SET WINDOWNAME (CREATEW REGION (L-CASE WINDOWNAME T)))
	(for X in WINDOWPROPLST do (WINDOWPROP (EVAL WINDOWNAME)
					       (CAR WINDOWPROPLST)
					       (CADR WINDOWPROPLST]
    WINDOWNAME])

(ADVISE.FOR.TYPEOUT
  [LAMBDA (READVISE/UNADVISE)                                (* pkh: "14-Dec-84 15:25")
    (for F in PROSETYPEOUTADVISEDFNS do (COND
					  ((EQ READVISE/UNADVISE (QUOTE READVISE))
					    (APPLY (FUNCTION READVISE)
						   F))
					  ((EQ READVISE/UNADVISE (QUOTE UNADVISE))
					    (APPLY (FUNCTION UNADVISE)
						   F))
					  (T (SHOULDNT])

(VERIFYINPUT
  [LAMBDA (INPUTLIST)                                        (* BBB " 2-Apr-85 11:15")

          (* Checks that the input from the phone is well-formed; if it is ill-formed reset PHONEINPUT and ask for new input;
	  somebody should suggest what kind of input)


    (COND
      ([NOT (OR (for X in (CDR INPUTLIST) always (NUMBERP X))
		(AND (OR (EQ (CAR INPUTLIST)
			     (QUOTE #))
			 (EQ (CAR INPUTLIST)
			     (QUOTE *)))
		     (NOT (OR (FMEMB (QUOTE #)
				     (CDR INPUTLIST))
			      (FMEMB (QUOTE *)
				     (CDR INPUTLIST]
	(WITH.MONITOR DTMF.LOCK (replace DTMFINPUT of STATE with NIL))
	(DESCRIBE.STATE)
	(P.CHUNK "Illegal command. Please reenter the command. ")

          (* Should maybe decipher the touch tones and tell the user what it had (received; if so we have to do the 
	  deciphering here))


	(RETFROM (QUOTE P.CONTROLLER])

(DESCRIBE.STATE
  [LAMBDA NIL                                                (* pkh: " 7-Jan-85 14:26")
    NIL])

(GETSTATEFIELD
  [LAMBDA (FIELDLIST)                                        (* pkh: "12-Nov-84 21:12")
    (EVAL (BQUOTE (fetch , (CONS (QUOTE STATE)
				 FIELDLIST)
		     of STATE])

(P.INDEX.SEQ?
  [LAMBDA (REVOUTPUT)                                        (* pkh: "11-Dec-84 16:45")

          (* Ascertain that the tail of the output characters constitute and index marker, and return the index;
	  or return NIL if we don't have an index marker; we do this by ignoring the "i" in the index sequence, then reading 
	  bytes as long as the bytes represent numbers (i.e. indices) collecting the bytes, converting them to single digits 
	  and packing them up into a number)


    (for X in (CDR REVOUTPUT) while (NUMBERP (CHARACTER X)) collect X
       finally (RETURN (COND
			 [(AND (EQ [CAR (NTH REVOUTPUT (IPLUS 2 (LENGTH $$VAL]
				   91)
			       (EQ [CADR (NTH REVOUTPUT (IPLUS 2 (LENGTH $$VAL]
				   27))
			   (PACK (MAPCAR (REVERSE $$VAL)
					 (QUOTE CHARACTER]
			 (T NIL])

(P.RS232.INIT
  [LAMBDA (RS232CONNECTED?)                                  (* pkh: " 4-Jan-85 17:50")
    (COND
      (RS232CONNECTED? (RS232INIT 600)                       (* Obey XON XOF protocol)
		       (RS232XON\XOFF? (QUOTE ON))
		       (SETQ RECLAIMWAIT 10000)
		       (RS232BACKGROUND (QUOTE ON))
		       (CHECK.RS232.SETTINGS))
      (T (P.NO.RS232])

(P.FINISHED?
  [LAMBDA NIL                                                (* BBB "10-Apr-85 10:45")

          (* Monitors PROSEOUTPUT for the receipt of index markers which indicates that the utterance of specific sentences 
	  have been completed. The whole message has been uttered when the index marker corresponding to the sentence number 
	  in the dotted pair on the front of the SYNCHLIST has been received)


    (for INPUT FLG TIMER first (SETQ TIMER (SETUPTIMER 1042380 NIL (QUOTE TICKS)))
       until (OR (SETQ FLG (PHONE.INTERRUPT))
		 (EQUAL (CAAR (fetch SYNCHLIST of STATE))
			(P.INTERPRET.OUTPUT))
		 (TIMEREXPIRED? TIMER (QUOTE TICKS)))
       do                                                    (* The index marker corresponding to the last sentence 
							     in the message has not yet been received so keep 
							     checking for indexmarkers)
	  (BLOCK)
	  [COND
	    ((SETQ INPUT (NO.WAIT.READ.TTS))
	      (replace (STATE STATEINFO PROSEOUTPUT) of STATE with (push (fetch (STATE STATEINFO 
										      PROSEOUTPUT)
									    of STATE)
									 INPUT]
       finally (COND
		 (FLG                                        (* We were interrupted)
		      (replace (STATE STATEINFO TALKING) of STATE with (QUOTE HALTED))
		      (WITH.MONITOR DTMF.LOCK (replace (STATE DTMFINPUT) of STATE with NIL))
		      (replace (STATE COMMAND) of STATE with NIL)
		      (P.CHUNK " Interrupted.  Back up, change speed or abort. ")
		      (RETFROM (QUOTE COPYMSGBYTES)))
		 (T (P.FINISHED.ACTIONS])

(P.INTERPRET.OUTPUT
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 10:51")
    (PROG ((PROSEOUTPUT (fetch (STATE PROSEOUTPUT) of STATE)))
          (RETURN (P.LAST.SENTENCE.SAID PROSEOUTPUT])

(P.LAST.SENTENCE.SAID
  [LAMBDA (REVPROSEOUTPUT)                                   (* BBB " 2-Apr-85 10:25")
                                                             (* Finds which was the last completed sentence by 
							     looking for index marker output sequences in the output
							     list from the PROSE)
    (PROG (LASTINDEX)

          (* Index marker sequences end with "i". PROSEOUTPUT is a list of lists of output eg. (QUOTE 
	  ((10 i) (9 i) (8 i) (S) (7 i))))



          (* Set LASTINDEX to the result of stripping off any output characters that have been received after the last index 
	  (i.e. after the last i))


          (RETURN (OR (for OUTPUT in REVPROSEOUTPUT when (EQ (QUOTE i)
							     (CADR OUTPUT))
			 do (RETURN (CAR OUTPUT)))
		      NIL])

(P.MESSAGE.QUERY
  [LAMBDA (MSGDESCRIPTOR MSGNO)                              (* pkh: "11-Dec-84 17:57")
    (P.CHUNK (fetch (STATE PROSEINPUT HEADER) of STATE))     (* It should maybe be the message number rather than 
							     the message descriptor which we list as heard)
    (replace (STATE STATEINFO HEARDMSGS EXAMINED) of STATE
       with (CONS (fetch (STATE PROSEINPUT MSGNO) of STATE)
		  (fetch (STATE STATEINFO HEARDMSGS EXAMINED) of STATE)))
    (P.HELP (QUOTE P.MESSAGE.QUERY))
    (replace (STATE STATEINFO MESSAGEQUERY?) of STATE with T])

(P.PROCESS
  [LAMBDA NIL                                                (* pkh: "30-Jan-85 14:17")
    (while T
       do (BLOCK T)
	  (COND
	    ((NOT (NLSETQ (P.CONTROLLER)))
	      (P.CHUNK "Error encountered.  Please try again. "])

(P.NO.RS232
  [LAMBDA NIL                                                (* pkh: " 4-Jan-85 11:59")
    (MOVD (QUOTE RS232FORCEOUTPUT)
	  (QUOTE ORIGINAL.RS232FORCEOUTPUT))
    (MOVD (QUOTE NILL)
	  (QUOTE RS232FORCEOUTPUT))
    (MOVD (QUOTE RS232CLEARBUFFER)
	  (QUOTE ORIGINAL.RS232CLEARBUFFER))
    (MOVD (QUOTE NILL)
	  (QUOTE RS232CLEARBUFFER))
    (MOVD (QUOTE RS232WRITEBYTE)
	  (QUOTE ORIGINAL.RS232WRITEBYTE))
    (MOVD (QUOTE CHARACTER)
	  (QUOTE RS232WRITEBYTE))
    (MOVD (QUOTE RS232WRITECHARS)
	  (QUOTE ORIGINAL.RS232WRITECHARS))
    (MOVD (QUOTE PRIN1)
	  (QUOTE RS232WRITECHARS))
    (MOVD (QUOTE RS232WRITESTRING)
	  (QUOTE ORIGINAL.RS232WRITESTRING))
    (MOVD (QUOTE PRIN1)
	  (QUOTE RS232WRITESTRING))
    (MOVD (QUOTE RS232READBYTE)
	  (QUOTE ORIGINAL.RS232READBYTE))
    (MOVD (QUOTE NILL)
	  (QUOTE RS232READBYTE))
    (printout T 
     "RS232 functions redefined to allow running without any device connected to the RS232 port."
	      T])

(DEBUGOUTPUT?
  [LAMBDA NIL                                                (* pkh: " 7-Jan-85 13:27")
    (GLOBALVARS PROSEDEBUG)
    (USEDFREE PROSEDEBUG)
    (COND
      (PROSEDEBUG                                            (* True if we are debugging)
		  (PROSEDEBUGINFO])

(PROSEDEBUGINFO
  [LAMBDA NIL                                                (* pkh: "31-Jan-85 11:31")
    (ACTIVEWINDOW (QUOTE PROSESTATUS)
		  NIL
		  (QUOTE (BUTTONEVENTFN PROSEDEBUGINFO)))
    (CLEARW PROSESTATUS)
    (for X VAL in (RECORDFIELDNAMES (QUOTE STATE))
       do                                                    (* COND ((AND (NOT (MEMBER X DONTPRINTVARS)) 
							     (NOT (STRPOS (QUOTE \) X 1 NIL T)))))
	  (printout PROSESTATUS X .TAB 16 (PROGN [SETQ VAL (EVAL (BQUOTE (FETCH (STATE , X)
									    of STATE]
						 (COND
						   ((STRINGP VAL)
						     (SUBSTRING VAL 1 25))
						   (T VAL)))
		    T])

(MAKECOMMAND
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 11:17")

          (* All the information regarding the state of the system is located in the global variable STATE which is a record 
	  of the type STATE; SETSTATEFIELD and GETSTATEFIELD updates this record)


    [replace (STATE INPUTINFO COMMAND) of STATE
       with (COND
	      ((NULL (CDR (fetch (STATE INPUTINFO DTMFINPUT) of STATE)))

          (* PHONEINPUT is a list of the touchtones received (last tone first) which is computed by the routine which monitors
	  to phone (or the menu simulating the phone); here we make up COMMAND which is a stringified and appropriately 
	  reversed version of PHONEINPUT *)


		NIL)
	      (T (COND
		   [(AND (fetch (STATE USERINFO USER) of STATE)
			 (fetch (STATE USERINFO PASSWORD) of STATE))
                                                             (* We are packing because P.DECIPHER.TOUCHTONES expects
							     this)
		     (PACK (REVERSE (CDR (fetch (STATE INPUTINFO DTMFINPUT) of STATE]
		   (T                                        (* No packing because there is not necessarily any 
							     touch tone decoding)
		      (REVERSE (CDR (fetch (STATE INPUTINFO DTMFINPUT) of STATE]
                                                             (* Reset PHONEINPUT)
    (WITH.MONITOR DTMF.LOCK (replace (STATE INPUTINFO DTMFINPUT) of STATE with NIL])

(MSG.LEN.TO.TIME
  [LAMBDA (MSGLENGTH)                                        (* pkh: " 9-Nov-84 21:37")
    (PROG (SECS)
          (SETQ SECS (MSG.LEN.TO.SECS MSGLENGTH))
          (RETURN (COND
		    ((IGREATERP SECS 60)
		      (MSG.LEN.TO.MINS SECS))
		    (T (CONCAT " " SECS " seconds "])

(MSG.LEN.TO.SECS
  [LAMBDA (MSGLENGTH)                                        (* pkh: "17-Nov-84 14:15")
    (ITIMES (FTIMES (FQUOTIENT (IQUOTIENT MSGLENGTH 6)
			       (fetch (STATE PROSESETTINGS SPEECHRATE) of STATE))
		    60)
	    1])

(MSG.LEN.TO.MINS
  [LAMBDA (SECS)                                             (* pkh: " 9-Nov-84 21:36")
    (PROG (MINS REMAININGSECS)
          (SETQ MINS (IQUOTIENT SECS 60))
          (SETQ REMAININGSECS (IREMAINDER SECS 60))
          (RETURN (CONCAT " " MINS (PLURAL? MINS " minute " " minutes ")
			  (COND
			    ((NOT (ZEROP REMAININGSECS))
			      (CONCAT " " REMAININGSECS (PLURAL? REMAININGSECS " second " " seconds ")
				      ))
			    (T ". "])

(PLURAL?
  [LAMBDA (VALUE SG PL)                                      (* pkh: " 9-Nov-84 21:32")
    (COND
      ((IGEQ VALUE 2)
	PL)
      (T SG])

(BACK.SENTENCE
  [LAMBDA (TRIGGERBUTTON NO.OF.SENTENCES)                    (* pkh: "30-Jan-85 14:46")

          (* Checks how many sentences to back up, sets the file ptr of the TEMPFILE holding the message to the appropriate 
	  place; If the user sends * then he wants to quit hearing the current message altogether)


    (COND
      ((NULL NO.OF.SENTENCES)
	(SETQ NO.OF.SENTENCES 1)))
    (COND
      ((AND (EQ TRIGGERBUTTON (QUOTE *))
	    (NULL (fetch COMMAND of STATE)))
	(P.QUIT.READING.MSG (fetch (STATE TEMPFILE) of STATE))
	(P.HELP (QUOTE QUIT.READING.MESSAGE))
	(RETFROM (QUOTE P.CONTROLLER)))
      ((AND (EQ TRIGGERBUTTON (QUOTE *))
	    (EQUAL (fetch COMMAND of STATE)
		   0))
	(P.SPEED (IDIFFERENCE (fetch SPEECHRATE of (fetch PROSESETTINGS of STATE))
			      20))
	(BACK.SENTENCE1 0))
      ((AND (EQ TRIGGERBUTTON (QUOTE *))
	    (EQUAL (fetch COMMAND of STATE)
		   1))
	(P.SPEED (IPLUS (fetch SPEECHRATE of (fetch PROSESETTINGS of STATE))
			20))
	(BACK.SENTENCE1 0))
      ((AND (EQ TRIGGERBUTTON (QUOTE *))
	    (NUMBERP (fetch COMMAND of STATE)))
	(P.SPEED (fetch COMMAND of STATE))
	(BACK.SENTENCE1 0))
      (T (BACK.SENTENCE1 NO.OF.SENTENCES])

(P.SPEED
  [LAMBDA (WPM)                                              (* bbb: "27-Feb-85 17:30")
    (PROG NIL
          (COND
	    ((IGEQ WPM 201)
	      (P.CHUNK " I can't talk that fast.  ")
	      (P.SEND.ESC.SEQ (PACK* WPM "r"))
	      (RETURN))
	    ((ILEQ WPM 79)
	      (P.CHUNK " I can't talk that slow.  ")
	      (RETURN)))
          (P.SEND.ESC.SEQ (PACK* WPM "r"))
          (replace (STATE PROSESETTINGS SPEECHRATE) of STATE with WPM])

(P.QUIT.READING.MSG
  [LAMBDA (MSGFILE)                                          (* pkh: "10-Dec-84 17:00")
                                                             (* Actions to be taken when we abort the reading of a 
							     message)
    (CLOSEF (fetch (STATE TEMPFILE) of STATE))
    (replace (STATE TALKING) of STATE with NIL)
    (replace (STATE HALTSPEECH) of STATE with NIL)
    (replace (STATE TEMPFILE) of STATE with NIL)
    (replace (STATE SYNCHLIST) of STATE with NIL)
    (replace (STATE PROSEOUTPUT) of STATE with NIL])

(BACK.SENTENCE1
  [LAMBDA (NO.OF.SENTENCES)                                  (* pkh: "30-Jan-85 14:38")

          (* Sets the file pointer in the file which holds the message to the point where the sentence begins which the user 
	  wants to back up to)


    (PROG (FPTR (MSGFILE (fetch (STATE TEMPFILE) of STATE))
		(SYNCHLIST (fetch SYNCHLIST of STATE))
		START.SENTENCE SENT.PTR.PAIR)
          (COND
	    ((ZEROP NO.OF.SENTENCES)
	      (SETQ NO.OF.SENTENCES 1)))
          (SETQ LAST.SENTENCE.UTTERED (P.INTERPRET.OUTPUT))
          [COND
	    ((NULL LAST.SENTENCE.UTTERED)                    (* Not even a single sentence has been completed, so we
							     start over from the beginning of the message body)
	      (RETURN (SETFILEPTR MSGFILE (fetch MSGBODYBEGIN of STATE]
          (SETQ START.SENTENCE (IDIFFERENCE LAST.SENTENCE.UTTERED (SUB1 NO.OF.SENTENCES)))
          [COND
	    ((ILEQ START.SENTENCE 0)
	      (RETURN (SETFILEPTR MSGFILE (fetch MSGBODYBEGIN of STATE]
          (SETQ SENT.PTR.PAIR (ASSOC START.SENTENCE SYNCHLIST))
          (SETQ FPTR (CDR SENT.PTR.PAIR))
          (replace (STATE SYNCHLIST) of STATE with (MEMBER SENT.PTR.PAIR (fetch SYNCHLIST
									    of STATE)))
          (COND
	    ((AND FPTR MSGFILE)
	      (SETFILEPTR MSGFILE FPTR))
	    (T (SHOULDNT])

(BOUT.FROM.STRING
  [LAMBDA (TOSTREAM STRING)
    (PROG ((WORKSTRING (SUBSTRING STRING 1)))
          (for X from 1 to (NCHARS WORKSTRING) do (BOUT TOSTREAM (CHCON1 (GNC WORKSTRING])

(LETTERP
  [LAMBDA (CHAR)                                             (* pkh: " 8-Nov-84 21:17")
                                                             (* T if CHAR is in the English alphabeth, NIL 
							     otherwise)
    (PROG ((CODE (CHCON1 CHAR)))
          (RETURN (BINLETTERP CODE])

(READ.TTY
  [LAMBDA NIL                                                (* pkh: "12-Dec-84 12:33")
    (for X while (EQ T T)
       do (SETQ X (READ TOPLEVELTTYWINDOW))
	  (PRINT X])

(SAYT
  [LAMBDA (INSTRING DONTLOWERCASE)                           (* BBB " 1-Apr-85 15:12")
                                                             (* If DONTLOWERCASE is T then the output will not be 
							     put in lower case before it is sent to the mailreader.)
                                                             (* FOR BYTE IN OUTPUTBYTES DO 
							     (RS232WRITEBYTE BYTE) FINALLY 
							     (RS232FORCEOUTPUT))

          (* * comment)


    (PROG ((STRING (SUBSTRING INSTRING 1))
	   CHAR OUTPUTBYTES PHONEMEMODE (ESCAPECHAR (CHCON1 (QUOTE ←)))
	   (P.READBUFFER))                                   (* SETQ PORTCONTENT.BEFORE (READPORT))
          (if DONTLOWERCASE
	      then (RS232WRITECHARS INSTRING T)
	    else (RS232WRITECHARS (L-CASE INSTRING)
				  T))

          (* while (SETQ CHAR (GNC STRING)) do (COND ((EQ (CHCON1 CHAR) ESCAPECHAR) (SETQ PHONEMEMODE 
	  (NOT PHONEMEMODE)) (if PHONEMEMODE then (PHONEMEMODE (QUOTE ON)) else (PHONEMEMODE (QUOTE OFF)))) 
	  (T (RS232WRITEBYTE (CHCON1 CHAR)))) finally (PROSE.COMMENCE.OUTPUT))


          (PROSE.COMMENCE.OUTPUT)
          (RETURN (PROGN                                     (* P.READBUFFER)
			 (PACK NIL])

(SETSTATEFIELD
  [LAMBDA (FIELDLIST VALUE)                                  (* pkh: "12-Nov-84 21:10")
    (EVAL (BQUOTE (REPLACE , (CONS (QUOTE STATE)
				   FIELDLIST)
		     of STATE with VALUE])

(START.PROSE.PROCESSES
  [LAMBDA NIL                                                (* BBB " 3-Apr-85 14:05")
    (SETQ TTS.LOCK (CREATE.MONITORLOCK (QUOTE TTS.LOCK)))
    (SETQ DTMF.LOCK (CREATE.MONITORLOCK (QUOTE DTMF.LOCK)))
    (SETQ PHONECONTROL.LOCK (CREATE.MONITORLOCK (QUOTE PHONECONTROL.LOCK)))
    (SETQ STATE (create STATE using NIL PROSESETTINGS ← PROSE.DEFAULT.SETTINGS))
    (SETQ LOGINHOST/DIR (QUOTE {DSK}))
    (RS232BACKGROUND (QUOTE ON))
    (START.CALLTEXT.MONITOR.PROCESS)
    (SETUP.PHONE)
    (START.PROSE.PROCESS)
    (START.OPERATOR.PROCESS])

(PHONE.MONITOR
  [LAMBDA NIL                                                (* BBB "29-Mar-85 11:52")

          (* Monitoring of the phone (or menu input); any incoming digits/letters should be pushed onto the list which is the 
	  value of the PHONEINPUT field of STATE)


    (PROG (DUMMY)                                            (* Interrupt)
          [COND
	    ([AND (EQUAL (fetch (STATE STATEINFO TALKING) of STATE)
			 (QUOTE TALKING))
		  (EQUAL (fetch DTMFINPUT of STATE)
			 (QUOTE (*]
	      (RETURN (replace (STATE STATEINFO HALTSPEECH) of STATE with T]
          (COND
	    ([OR (EQUAL (QUOTE *)
			(CAR (fetch DTMFINPUT of STATE)))
		 (EQUAL (QUOTE #)
			(CAR (fetch DTMFINPUT of STATE]
	      (COND
		((PROCESSP (fetch PROCESS of STATE)))
		(T                                           (* There was no live process so we have to start one)
		   (START.PROSE.PROCESS)                     (* Has to block to make sure the process gets started 
							     before we try to wake it in the next statement)
		   (BLOCK)))
	      (WAKE.PROCESS (fetch PROCESS of STATE)
			    T])

(START.PROSE.PROCESS
  [LAMBDA NIL                                                (* pkh: "12-Dec-84 13:18")
    (USEDFREE \PROSE.PROCESS)
    (COND
      ((AND (BOUNDP (QUOTE \PROSE.PROCESS))
	    (PROCESSP \PROSE.PROCESS))
	(replace (STATE PROCESS) of STATE with \PROSE.PROCESS))
      (T [SETQ \PROSE.PROCESS (ADD.PROCESS (QUOTE (P.PROCESS]
	 (replace (STATE PROCESS) of STATE with \PROSE.PROCESS])

(SYNCH
  [LAMBDA (INSTREAM)                                         (* pkh: "10-Dec-84 17:24")

          (* Computes index markers which signal the end of each sentence and updates the SYNCHLIST with a dotted pair 
	  consisting of the index marker and the FILEPOS for the end of the sentence)


    (PROG ((PTR (GETFILEPTR INSTREAM))
	   (LASTSYNCH# (CAAR (fetch (STATE PROSEINPUT SYNCHLIST) of STATE)))
	   NEWSYNCH#)                                        (* Compute the new index marker)
          (SETQ NEWSYNCH# (COND
	      ((NUMBERP LASTSYNCH#)
		(SETQ LASTSYNCH# (ADD1 LASTSYNCH#)))
	      (T 1)))                                        (* Send out and index marker escape sequence)
          (P.SEND.ESC.SEQ (CONCAT NEWSYNCH# "i"))            (* Update the proseinput field SYNCHLIST with the index
							     marker and the filepos of the sentence terminating 
							     character for this sentence)
          (replace (STATE PROSEINPUT SYNCHLIST) of STATE with (push (fetch (STATE PROSEINPUT 
										  SYNCHLIST)
								       of STATE)
								    (CONS NEWSYNCH# PTR])

(CHARS.TO.MINUTES
  [LAMBDA (CHARLENGTH)                                       (* pkh: "17-Nov-84 14:15")
                                                             (* Returns a string of words describing the length of a
							     message)
    (PROG ((RATE (fetch (STATE PROSESETTINGS SPEECHRATE) of STATE))
	   MINUTES SECS)
          (SETQ SECS (ITIMES (IQUOTIENT (IQUOTIENT CHARLENGTH 6)
					RATE)))
          (SETQ MINUTES (IQUOTIENT (ITIMES (IQUOTIENT (IQUOTIENT CHARLENGTH 6)
						      RATE))
				   60))
          (RETURN (CONCAT MINUTES " minutes " (COND
			    ((ILEQ SECS 25)
			      "and about 15 seconds. ")
			    ((ILEQ SECS 30)
			      "and about 30 seconds. ")
			    ((ILEQ SECS 40)
			      "and about 40 seconds.  ")
			    (T "and about 50 seconds.  "])

(CHECK.RS232.SETTINGS
  [LAMBDA NIL                                                (* pkh: " 4-Jan-85 12:22")

          (* * Should check an print out the settings on the RS232 interface)


    (printout T "The RS232 interface has been configured with the following settings:" T T 
	      "Obeying XON/XOF protocol:"
	      .TAB 32 (COND
		(RS232XON\XOFF? (QUOTE Yes))
		(T (QUOTE No)))
	      T "Baudrate:" .TAB 32 (CAR RS232INIT)
	      T "Bits per channel:" .TAB 32 (CADR RS232INIT)
	      T "Eight bit used as parity bit:" .TAB 32 (COND
		((CAR RS232INIT)
		  (QUOTE Yes))
		(T (QUOTE No)))
	      T "Number of stop bits:" .TAB 32 (CADDR RS232INIT)
	      T "RS232 output-broom process: " .TAB 32 (COND
		(RS232XON\XOFF? "  ON")
		(T "  OFF"))
	      T])

(COPYMSGBYTES
  [LAMBDA (INSTREAM OUTSTREAM)                               (* BBB " 2-Apr-85 11:20")
                                                             (* Does the main work of copying bytes from a TEMPMSG 
							     file to the RS232STREAM)
    (PROG (FLG INPUT)                                        (* State that the PROSE is talking)
          [COND
	    ((NOT (OPENP INSTREAM))
	      (SETQ INSTREAM (OPENTEXTSTREAM INSTREAM))
	      (SETFILEINFO INSTREAM (QUOTE ENDOFSTREAMOP)
			   (QUOTE NILL]
          (replace (STATE STATEINFO TALKING) of STATE with (QUOTE TALKING))
                                                             (* Copying out bytes of the message to the RS232 stream
							     until there is an interrupt from the phone)
          (for B as I from (GETFILEPTR INSTREAM) to (SUB1 (GETEOFPTR INSTREAM))
	     while [PROGN (BLOCK)

          (* Removed a call to \PEEKBIN on INSTREAM which seemed to be intended to ensure we don't run past EOF;
	  but the as clause ought to see to that)


			  (NOT (SETQ FLG (PHONE.INTERRUPT]
	     do (SETQ B (BIN INSTREAM))
		[COND
		  ((SETQ INPUT (NO.WAIT.READ.TTS))           (* Monitor the RS232 port)
		    (replace (STATE STATEINFO PROSEOUTPUT) of STATE
		       with (push (fetch (STATE STATEINFO PROSEOUTPUT) of STATE)
				  INPUT]
		(COND
		  [(NOT (EQ (TYPENAME B)
			    (QUOTE IMAGEOBJ)))               (* Not an image object)
		    (BOUT OUTSTREAM (BINARYLCASE B))
		    (COND
		      ((EOSP B INSTREAM)                     (* End of a sentence so update the SYNCHLIST)
			(SYNCH INSTREAM]
		  (T (RS232WRITESTRING IMAGEOBJMSG)))
	     finally (if (SETQ INPUT (NO.WAIT.READ.TTS))
			 then (push (fetch (STATE STATEINFO PROSEOUTPUT) of STATE)
				    INPUT))
		     (if (EQUAL I (GETEOFPTR INSTREAM))
			 then (SYNCH INSTREAM)               (* BOUT a period (byte 46))
			      (BOUT OUTSTREAM 46))
		     (COND
		       (FLG                                  (* We were interrupted)
			    (replace (STATE STATEINFO TALKING) of STATE with (QUOTE HALTED))
			    (WITH.MONITOR DTMF.LOCK (replace (STATE DTMFINPUT) of STATE with NIL))
			    (replace (STATE COMMAND) of STATE with NIL)
			    (P.USER.MESSAGE))
		       (T                                    (* We finished copying out the message)
			  (RS232FORCEOUTPUT)
			  (PROSE.COMMENCE.OUTPUT)
			  (P.FINISHED?)
			  (P.HELP (QUOTE EOM))
			  (P.HELP (QUOTE SPECIFY.ANOTHER.MSG])

(BINARYLCASE
  [LAMBDA (CODE)                                             (* pkh: "11-Dec-84 17:49")
    (COND
      ((AND (IGEQ CODE 65)
	    (LEQ CODE 90))
	(IPLUS CODE 32))
      (T CODE])

(BINLETTERP
  [LAMBDA (CODE UCASEFLG)                                    (* pkh: "11-Dec-84 17:48")
    (COND
      ((OR (AND (IGEQ CODE 65)
		(LEQ CODE 90))
	   (AND (IGEQ CODE 97)
		(ILEQ CODE 122)))
	T)
      (T NIL])

(P.USER.MESSAGE
  [LAMBDA NIL                                                (* BBB "10-Apr-85 10:46")
    (COND
      ((EQ (fetch TALKING of STATE)
	   (QUOTE HALTED))
	(P.CHUNK " Interrupted. Back up, change speed or abort. "])

(PHONE.INTERRUPT
  [LAMBDA NIL                                                (* BBB "17-Apr-85 11:35")

          (* The field (STATE STATEINFO HALTSPEECH) is set to T by P.CONTROLLER if we are talking and we get an incoming *;
	  This is an interrupt from the phone; Here we take the appropriate actions, i.e. stop speech output)


    (COND
      ((fetch (STATE STATEINFO HALTSPEECH) of STATE)
	(P.SEND.ESC.SEQ "S")
	(WITH.MONITOR DTMF.LOCK (replace (STATE DTMFINPUT) of STATE with NIL))
	(READ.TTS)                                           (* RS232CLEARBUFFER)
	T)
      (T NIL])

(EOSP
  [LAMBDA (BYTE STREAM)                                      (* bbb: "27-Feb-85 16:44")
                                                             (* Returns T if we are at the end of a sentence)
    (PROG (NX)
          (RETURN (COND
		    ((MEMBER B EOSENTCHARCODES)              (* B is potentiall a sentence terminator i.e. ". ? !")

          (* AND (SELCHARQ (\PEEKBIN STREAM) ((SPACE CR NIL) T) NIL) (PROGN (BOUT (GETSTREAM (QUOTE {RS232})) 
	  (BIN STREAM)) (SELCHARQ (SETQ NX (\PEEKBIN STREAM)) ((SPACE NIL) T) (BINLETTERP NX T))))


		      (SELCHARQ (\PEEKBIN STREAM)
				((SPACE CR NIL)
				  T)
				NIL))
		    (T NIL])

(P.CHECK.GLOBAL.VARS
  [LAMBDA NIL                                                (* pkh: " 2-Nov-84 16:28")
    (printout TOPLEVELTTYWINDOW "P.USER " P.USER T "P.QUIT " P.QUIT T "PHONE.INPUT " PHONE.INPUT T 
	      "P.MAILFOLDER "
	      P.MAILFOLDER T "P.BROWSEROPEN " P.BROWSEROPEN T "\LAFITE.LAST.STATUS " 
	      \LAFITE.LAST.STATUS T "\LAFITE.AUTHENICATION.FAILURE " \LAFITE.AUTHENTICATION.FAILURE T]
)

(P.HELP
  [LAMBDA (INTERNALSTATE)                                    (* BBB "21-May-85 09:13")
                                                             (* Provides help messages if desired 
							     (i.e. P.HELP.FLG is T))
    (GLOBALVARS P.HELP.FLG)
    (COND
      (P.HELP.FLG (SELECTQ INTERNALSTATE
			   (OPENING.FOLDER (P.CHUNK " Opening mail folder. "))
			   (EOM (P.CHUNK " End of message. "))
			   (SPECIFY.ANOTHER.MSG (P.CHUNK "Specify another message. "))
			   (LOGIN.HELP (P.CHUNK 
" All commands end with sharp sign. Asterisk is the interrupt character.  To log on, simply enter your name by pushing the buttons with the appropriate letters on them. Push 1 to enter Q, Z, or a hyphen in your name.  When you are promted for your password, you have to spell it.  Most of the push buttons are labelled with a number, and three, letters. Simply entering a key enters the first letter on the key.  0 followd by a key enters the second letter on the key.  1 followed by a key enters the third letter on the key.  0 0 followed by a key enters the number on that key.  0 1 enters Q.  1 1 enters Z.  1 0 rubs out the last code.   If your password is all numeric you can type sharp sign followed by the numbers without the 0, 1, preefix.  Terminate the  password with sharp sign.  When a message is being red you can interrupt it by pushing asterisk.  To back up two sentences type 2, followed by sharp sign.  To back up 3, sentences type 3, followed by sharp sign. And so on.  If you want to abort the reading of a message type another asterisk.  When you have interrupted a message using the asterisk command you can increase the speech rate by typing 1, followed by asterisk. You can decrease the speech rate by typing 0, followed by asterisk.  When the mail reader is not talking you can log out by typing asterisk. Please enter your user name now. "
						))
			   (QUIT.READING.MESSAGE (P.CHUNK " Message aborted. ")
						 (P.HELP (QUOTE PLAYING.MESSAGE.INFO)))
			   (PLAYING.MESSAGE.INFO (P.CHUNK 
    " To listen to a message, enter its number, followed by sharp sign.  Push asterisk to quit. "))
			   (READING.OLD.MAIL (P.CHUNK " Retrieving old mail . "))
			   (P.MESSAGE.QUERY (P.CHUNK 
" Push sharp sign if you want to hear the message.  Push asterisk if you don't want to hear it.  "))
			   ((NO.NEW.MAIL NO.MAILSERVERS)
			     (P.CHUNK 
				 " Push asterisk to quit, or, push sharp sign to read old mail. "))
			   (NEW.MAIL (P.CHUNK 
" To hear the new messages keep pushing sharp sign.  To hear an arbitrary message, push its number followed by shar sign.  Push asterisk to quit. "
					      ))
			   (WRONG.INPUT.WHILE.P.QUIT (P.CHUNK (CONCAT MENUINPUT 
" is not a possible command here.  You have to type sharp sign to read old mail,  or astersik to quit.  "
								      )))
			   (WRONG.INPUT.WHILE.P.MESSAGE.QUERY (P.CHUNK (CONCAT MENUINPUT 
" is not a possible command here.  You have to type sharp sign to hear the message,  or astersik to ignore it.  "
									       )))
			   (NO.MORE.MESSAGES (P.CHUNK 
" No more messages.  Push asterisk to quit,  push a message number if you want to hear a specific message.  "
						      ))
			   (FILE.SERVER.DOWN.OR.MAIL.FILE.BUSY (P.CHUNK 
" Either the file server for your mail file is not responding or your mail file is busy. Please logout and try again later. "
									))
			   (CANT.WRITE.MAIL.FILE (P.CHUNK 
" Could not open your mail file for writing. It is probably in use on some other machine. Only old mail is accessible. "
							  ))
			   (CANT.READ.MAIL.FILE (P.CHUNK 
      " Could not open your mail file for reading. It is probably in use on some other machine. "))
			   (WAITING.FOR.BROWSER.READY (P.CHUNK 
					" Waiting for the browser on your mail file to be ready."))
			   (SHOULDNT])

(P.CHUNK
  [LAMBDA (TEXTSTRING DONTLOWERCASE)                         (* BBB "17-Apr-85 11:46")

          (* * If DONTLOWERCASE is T then the mailreader will be sent the text as is which will cause it to spell 
	  unpronounceable words.)



          (* * Separate text characters and control sequences)


    (PROG (CHUNK POS ESC.SEQ REST END.POS SPEED)
          (SETQ SPEED (fetch (STATE PROSESETTINGS SPEECHRATE) of STATE))
          (P.SPEED 160)                                      (* Check for escape sequence)
          (COND
	    ((EQ 0 (NCHARS TEXTSTRING))                      (* The length of the string is 0;
							     punt)
	      (RETURN)))

          (* Set POS to the character number of the beginning of the first escape sequence, if there is no escape sequence set
	  POS to NIL)


          (SETQ POS (P.FIND.ESC.SEQ TEXTSTRING))             (* (SIMPLESYNCH) (P.FINISHED?))

          (* COND (POS (* We did find an escape sequence) (SAYT (SUBSTRING TEXTSTRING 1 (SUB1 POS))) (SETQ REST 
	  (SUBSTRING TEXTSTRING (ADD1 POS))) (SETQ END.POS (STRPOS (QUOTE (escape sequence)) REST)) (SETQ ESC.SEQ 
	  (SUBSTRING REST 1 (SUB1 END.POS))) (COND (ESC.SEQ (P.SEND.ESC.SEQ ESC.SEQ))) (P.CHUNK (SUBSTRING REST 
	  (ADD1 END.POS)))) (T (* No escape sequence, so just say the string) (SAYT TEXTSTRING DONTLOWERCASE)))


          (SAYT TEXTSTRING DONTLOWERCASE)
          (P.SPEED SPEED])

(P.RESET.TIMER
  [LAMBDA NIL                                                (* pkh: " 9-Jan-85 11:13")
    (GLOBALVARS P.TIMEOUTTIMER)
    (SETQ P.TIMEOUTTIMER (SETUPTIMER 1042380 P.TIMEOUTTIMER (QUOTE TICKS])

(SIMPLESYNCH
  [LAMBDA NIL                                                (* pkh: " 8-Jan-85 22:51")

          (* Computes index markers which signal the end of a prompt string; the PTR is always 0 and always present to ensure 
	  compatibility with the SYNCHLIST updates from SYNCH which is more complex and works for sentences where you want to 
	  back up)


    (PROG ((PTR 0)
	   (LASTSYNCH# (CAAR (fetch (STATE PROSEINPUT SYNCHLIST) of STATE)))
	   NEWSYNCH#)                                        (* Compute the new index marker)
          (SETQ NEWSYNCH# (COND
	      ((NUMBERP LASTSYNCH#)
		(SETQ LASTSYNCH# (ADD1 LASTSYNCH#)))
	      (T 1)))                                        (* Send out and index marker escape sequence)
          (P.SEND.ESC.SEQ (CONCAT NEWSYNCH# "i"))            (* Update the proseinput field SYNCHLIST with the index
							     marker and the filepos of the sentence terminating 
							     character for this sentence)
          (replace (STATE PROSEINPUT SYNCHLIST) of STATE with (push (fetch (STATE PROSEINPUT 
										  SYNCHLIST)
								       of STATE)
								    (CONS NEWSYNCH# PTR])

(IGNORETIMER
  [LAMBDA (FLG)                                              (* pkh: " 9-Jan-85 12:05")
    (SETQ \IGNORETIMER FLG])

(P.COMMAND
  [LAMBDA (COMMAND ARG1 ARG2 ARG3 ARG4)                      (* pkh: "12-Nov-84 11:57")

          (* * Control of PROSE synthesizer by means of mnemonically named commands)


    (SELECTQ COMMAND
	     (IMMEDIATE.RESET (PROG (BUFFERCONTENT)
				    (COND
				      ((SETQ BUFFERCONTENT (P.READBUFFER))
					(printout T "This is sitting in the input buffer: " 
						  BUFFERCONTENT T)))
				    (P.RESET T)))
	     (COMMENCE.OUTPUT (P.ESC.SEQ (QUOTE C)))
	     (INDEX.MARKER (P.ESC.SEQ (QUOTE i)
				      ARG1))
	     (INDEXED.STOP (P.ESC.SEQ (QUOTE x)))
	     (IMMEDIATE.STOP (P.ESC.SEQ (QUOTE S)))
	     (HOLD.OUTPUT (P.ESC.SEQ (QUOTE H)))
	     (SHOULDNT])

(P.ENSURE.ESC.SEQ
  [LAMBDA (ESC.STRING.CANDIDATE)
    (COND
      ((for I from 1 to (NCHARS ESC.STRING.CANDIDATE) while (OR (NUMBERP (NTHCHAR 
									     ESC.STRING.CANDIDATE I))
								(AND (EQUAL (NTHCHAR 
									     ESC.STRING.CANDIDATE I)
									    (QUOTE ;))
								     (NEQ I 1)))
	  do (printout T (NTHCHAR ESC.STRING.CANDIDATE I)
		       " " I T)
	  finally (RETURN (PROGN (RETURN (COND
					   ([AND (EQ I 2)
						 (LETTERP (NTHCHAR ESC.STRING.CANDIDATE I))
						 (EQUAL (NTHCHAR ESC.STRING.CANDIDATE (ADD1 I)
								 (QUOTE ↑]
					     T)
					   ((AND (LETTERP (NTHCHAR ESC.STRING.CANDIDATE I))
						 (EQUAL (NTHCHAR ESC.STRING.CANDIDATE (ADD1 I))
							(QUOTE ↑)))
					     T)
					   (T NIL])

(P.FIND.ESC.SEQ
  [LAMBDA (TEXTSTRING)                                       (* pkh: " 4-Nov-84 17:43")
                                                             (* Looking for substrings of the message which may be 
							     escape sequences for controllint the synthesizer;
							     Clues: ↑ followed by another ↑)
    (PROG ((POS (STRPOS (QUOTE ↑)
			TEXTSTRING))
	   NEXTPOS)
          (RETURN (COND
		    ((NULL POS)                              (* Didn't find it)
		      NIL)
		    (POS (SETQ NEXTPOS (STRPOS (QUOTE ↑)
					       TEXTSTRING
					       (ADD1 POS)))
			 (COND
			   ((NULL NEXTPOS)                   (* There is no terminating ↑)
			     NIL)
			   (T (COND
				((P.ENSURE.ESC.SEQ (SUBSTRING TEXTSTRING (ADD1 POS)
							      NEXTPOS))
				  POS)
				(T NIL])

(P.FINISHED.ACTIONS
  [LAMBDA NIL                                                (* BBB " 2-Apr-85 11:16")
                                                             (* Resetting the state information;
							     we are no longer talking)
    [COND
      ((OPENP (fetch TEMPFILE of STATE))
	(CLOSEF (fetch TEMPFILE of STATE]
    (replace (STATE TALKING) of STATE with NIL)
    (replace (STATE TALKING) of STATE with NIL)
    (replace (STATE SYNCHLIST) of STATE with NIL)
    (replace (STATE PROSEOUTPUT) of STATE with NIL)
    (WITH.MONITOR DTMF.LOCK (replace (STATE DTMFINPUT) of STATE with NIL))
    (replace (STATE HALTSPEECH) of STATE with NIL])

(P.FIX
  [LAMBDA NIL                                                (* pkh: "11-Dec-84 10:00")
    (for X in (QUOTE (TALKING HALTSPEECH MESSAGEQUERY? PHONEINPUT MENUINPUT SYNCHLIST TEMPFILE 
			      MSGDESCRIPTOR MSGBODYBEGIN MSGNO PROSEOUTPUT))
       do (EVAL (BQUOTE (REPLACE (STATE , X) of STATE with NIL])

(P.FIND.IMAGE.OBJS
  [LAMBDA (STREAM BEG)                                       (* pkh: "19-Nov-84 14:25")
                                                             (* Counts how many imageobjects there are in the 
							     message)
    (TEDIT.LIST.OF.OBJECTS (TEXTOBJ STREAM])

(P.SEARCH.SELECT.AND.SAY.MSG
  [LAMBDA NIL                                                (* pkh: "17-Nov-84 14:15")
                                                             (* Find the next message to read;
							     select it)
    (PROG (P.SELECTEDMESSAGE (MAILFOLDER (fetch (STATE MAILFOLDER) of STATE)))
          (SETQ P.SELECTEDMESSAGE (SELECTMESSAGETODISPLAY (fetch BROWSERWINDOW of MAILFOLDER)
							  MAILFOLDER))
          [COND
	    ((AND P.SELECTEDMESSAGE (NOT (fetch (LAFITEMSG DELETED?) of P.SELECTEDMESSAGE)))
	      (\LAFITE.DISPLAY NIL MAILFOLDER (QUOTE Display)
			       (fetch BROWSERMENU of MAILFOLDER)
			       (QUOTE LEFT]
          (RETURN P.SELECTEDMESSAGE])

(P.SEND.ESC.SEQ
  [LAMBDA (ESC.STRING)                                       (* pkh: "20-Nov-84 12:56")

          (* * Sends an escape sequence to the prose)


    (RS232WRITEBYTE 27 T)
    (RS232WRITECHARS (CONCAT "[" ESC.STRING)
		     T])

(TEDIT.LIST.OF.OBJECTS
  [LAMBDA (TEXTOBJ TESTFN)                                   (* rrb " 8-Jun-84 11:12")
                                                             (* Map thru all the pieces in a text stream, and select
							     the image objects paired with their character 
							     positions)
    (PROG ((OBJLIST (TCONC NIL)))
          (TEDIT.MAPPIECES TEXTOBJ [FUNCTION (LAMBDA (CH# PC PC# OBL)
			       (COND
				 ([AND PC (NEQ PC (QUOTE LASTPIECE))
				       (fetch POBJ of PC)
				       (OR (NULL TESTFN)
					   (APPLY* TESTFN (fetch POBJ of PC]

          (* If there is an imageobj in this piece, and it passes the caller's test -- if he gave us one -- then add it to the
	  list.)


				   (TCONC OBL (LIST (fetch POBJ of PC)
						    CH#]
			   OBJLIST)
          (RETURN (CDAR OBJLIST])

(P.SAY.BODY
  [LAMBDA (MAILFOLDER MSGDESCRIPTOR)                         (* pkh: "30-Jan-85 14:13")

          (* * Get MSGDESCRIPTOR from MAILFOLDER, prepare to say it)

                                                             (* Based on \LAFITE.DO.DISPLAY)
    (PROG (TEMPMSG)
          (replace (MAILFOLDER CURRENTDISPLAYEDMESSAGE) of MAILFOLDER with NIL)
                                                             (* Clear it here in case of abort)
                                                             (* Create a file, TEMPMSG, which contains the message)
          (LA.COPY.MESSAGE.TEXT MAILFOLDER (SETQ TEMPMSG (OPENSTREAM (QUOTE {NODIRCORE})
								     (QUOTE BOTH)))
				MSGDESCRIPTOR)
          (CLOSEF TEMPMSG)                                   (* Take note of where the message now is;
							     record it in STATE)
          (replace (STATE TEMPFILE) of STATE with TEMPMSG)   (* P.SAY.BODY1 (OPENSTREAM TEMPMSG 
							     (QUOTE INPUT)) MSGDESCRIPTOR)
          (P.SAY.BODY1 TEMPMSG MSGDESCRIPTOR)                (* P.PARSE.MSG sets the PROSEINPUT fields BODY and 
							     HEADER)
          (COND
	    ((NOT (FETCH (LAFITEMSG SEEN?) OF MSGDESCRIPTOR))
	      (MARKMESSAGE MSGDESCRIPTOR MAILFOLDER 64)))
          (replace (MAILFOLDER CURRENTDISPLAYEDSTREAM) of MAILFOLDER with TEMPMSG)
          (replace (MAILFOLDER CURRENTDISPLAYEDMESSAGE) of MAILFOLDER with MSGDESCRIPTOR])

(P.SAY.BODY1
  [LAMBDA (STREAM MSGDESCRIPTOR ITEM MENU BUTTON)            (* pkh: "24-Jan-85 23:09")

          (* Finds the fileptr position for the beginning of the message body; invokes the function which copies bytes from 
	  the message body out to the RS232 port)


    (PROG ((TEXTSTREAM (OPENTEXTSTREAM STREAM))
	   MSGBODYBEGIN MSGBODYEND MSG.STRING IMAGEOBJLIST)
          (SETFILEINFO TEXTSTREAM (QUOTE ENDOFSTREAMOP)
		       (QUOTE NILL))
          (SETQ MSGBODYBEGIN (P.FIND.MSG.BODY TEXTSTREAM))
          (replace (STATE PROSEINPUT MSGBODYBEGIN) of STATE with MSGBODYBEGIN)
          (SETQ MSGBODYEND (GETEOFPTR TEXTSTREAM))
          (COND
	    ((EQ MSGBODYBEGIN MSGBODYEND)
	      (SHOULDNT "Found only header in message")))    (* Find how many image objects there are in the message
							     body)
          (SETQ IMAGEOBJLIST (P.FIND.IMAGE.OBJS TEXTSTREAM MSGBODYBEGIN))
          (replace (STATE PROSEINPUT IMAGEOBJLIST) of STATE with IMAGEOBJLIST)
          [COND
	    (IMAGEOBJLIST (P.CHUNK 
"The message contains image objects, and I can not handle it at the  present.  Please specify another message. "
				   )
			  (RETURN (CLOSEF TEXTSTREAM]
          (P.CHUNK "The body of the message follows. ")
          (SETFILEPTR TEXTSTREAM MSGBODYBEGIN)
          (COPYMSGBYTES TEXTSTREAM (GETSTREAM (QUOTE {RS232})))
          (PROGN                                             (* RS232WRITESTRING "End of message.  ")
                                                             (* Clean up a little)
                                                             (* CLOSEF TEXTSTREAM)
		 NIL])
)
(DEFINEQ

(ACTIVEWINDOW
  [LAMBDA (WINDOWNAME REGION WINDOWPROPLST)                  (* pkh: "14-Nov-84 13:34")
    [COND
      ([OR (NOT (BOUNDP WINDOWNAME))
	   (NOT (WINDOWP (EVAL WINDOWNAME]
	(SET WINDOWNAME (CREATEW REGION (L-CASE WINDOWNAME T)))
	(for X in WINDOWPROPLST do (WINDOWPROP (EVAL WINDOWNAME)
					       (CAR WINDOWPROPLST)
					       (CADR WINDOWPROPLST]
    WINDOWNAME])
)
[DECLARE: EVAL@COMPILE 

(RECORD PROSESETTINGS (SPEECHRATE PROSODY FASTSCAN BASELINEPITCH MONOTONEPITCH ATTENUATION 
				  EMPHATICSTRESSCHAR INPUTMODE ALPHABETICPRONUN PUNCTPRONUN 
				  DIGITPRONUN SPACEPRONUN MINUSPRONUN FULLNUMPRONUN ACRRECOGN 
				  ABBREVRECOGN ALLOPROC ERRORCHARGEN INDEXMARKECHO VOWELEDACRPRONUN 
				  FASTPROC CRAFTEROUTPUT))

(RECORD STATE (USERINFO LAFITEINFO STATEINFO PROSESETTINGS INPUTINFO PROSEINPUT)
	      (RECORD USERINFO (USER PASSWORD TOUCHTONES))
	      (RECORD LAFITEINFO (NEWMAIL NONEWMAIL FOLDEROPEN MAILFOLDER MSG SELECTEDMSGDESCR))
	      [RECORD STATEINFO (QUIT MSGS NEWMAILRETRIEVED READINGNEWMAIL READINGOLDMAIL 
				      MESSAGEQUERY? MSGSURVEY TALKING HALTSPEECH PROSEOUTPUT PROCESS 
				      CALLTEXTPROCESS OPERATORPROCESS)
		      (RECORD MSGS (NOOFMSGS NEWMSGS HEARDMSGS)
			      (RECORD HEARDMSGS (HEARD EXAMINED SKIPPED))
			      (RECORD NEWMSGS (FIRSTNEW LASTNEW]
	      (RECORD INPUTINFO (TTSINPUT DTMFINPUT PHONECONTROLINPUT COMMAND))
	      (RECORD PROSEINPUT (HEADER BODY MSGDESCRIPTOR MSGNO MSGBODYBEGIN IMAGEOBJLIST TEMPFILE 
					 SYNCHLIST)))
]

(RPAQQ \TIMEOUTFLG NIL)

(RPAQ TOPLEVELTTYWINDOW (TTYDISPLAYSTREAM))

(RPAQQ \IGNORETIMER NIL)

(RPAQQ EOSENTCHARCODES (46 59 33))

(RPAQ IMAGEOBJMSG 
"  Uh!  There is a bitmap here which I can not describe.  I will continue reading the text after the bitmap. "
)

(RPAQ STATE (CREATE STATE))

(RPAQQ PROSEDEBUG NIL)

(RPAQ? PROSE.DEFAULT.SETTINGS (CREATE PROSESETTINGS SPEECHRATE ← 160))



(* Modifications to LAFITE)

(DEFINEQ

(PROSE.LAFITE.WRITE.PROFILE
  [LAMBDA NIL                                                (* pkh: " 3-Jan-85 11:48")
    NIL])

(PROSE.LAFITE.BROWSE
  [LAMBDA (ITEM MENU BUTTON FILE OPTIONS)                    (* pkh: " 7-Jan-85 11:38")
    (COND
      ((AND (NULL MENU)
	    (NULL ITEM))
	(SETQQ ITEM ##BROWSE##)
	(SETQ MENU LAFITEMAINMENU)))
    (ORIGINAL.LAFITE.BROWSE ITEM MENU BUTTON FILE OPTIONS])
)
(SETQ P.TIMEOUTTIMER (SETUPTIMER 1000 NIL (QUOTE TICKS)))
(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS 

(ADDTOVAR NLAMA )

(ADDTOVAR NLAML )

(ADDTOVAR LAMA )
)
(PUTPROPS PROSE-UTIL COPYRIGHT ("Xerox Corporation" 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (1998 47734 (ACTIVEWINDOW 2008 . 2465) (ADVISE.FOR.TYPEOUT 2467 . 2896) (VERIFYINPUT 
2898 . 3912) (DESCRIBE.STATE 3914 . 4035) (GETSTATEFIELD 4037 . 4252) (P.INDEX.SEQ? 4254 . 5183) (
P.RS232.INIT 5185 . 5596) (P.FINISHED? 5598 . 7329) (P.INTERPRET.OUTPUT 7331 . 7582) (
P.LAST.SENTENCE.SAID 7584 . 8452) (P.MESSAGE.QUERY 8454 . 9091) (P.PROCESS 9093 . 9368) (P.NO.RS232 
9370 . 10490) (DEBUGOUTPUT? 10492 . 10797) (PROSEDEBUGINFO 10799 . 11524) (MAKECOMMAND 11526 . 13088) 
(MSG.LEN.TO.TIME 13090 . 13424) (MSG.LEN.TO.SECS 13426 . 13697) (MSG.LEN.TO.MINS 13699 . 14220) (
PLURAL? 14222 . 14385) (BACK.SENTENCE 14387 . 15792) (P.SPEED 15794 . 16311) (P.QUIT.READING.MSG 16313
 . 16943) (BACK.SENTENCE1 16945 . 18426) (BOUT.FROM.STRING 18428 . 18654) (LETTERP 18656 . 18985) (
READ.TTY 18987 . 19204) (SAYT 19206 . 20520) (SETSTATEFIELD 20522 . 20756) (START.PROSE.PROCESSES 
20758 . 21413) (PHONE.MONITOR 21415 . 22688) (START.PROSE.PROCESS 22690 . 23163) (SYNCH 23165 . 24367)
 (CHARS.TO.MINUTES 24369 . 25239) (CHECK.RS232.SETTINGS 25241 . 26068) (COPYMSGBYTES 26070 . 28882) (
BINARYLCASE 28884 . 29103) (BINLETTERP 29105 . 29365) (P.USER.MESSAGE 29367 . 29628) (PHONE.INTERRUPT 
29630 . 30266) (EOSP 30268 . 30956) (P.CHECK.GLOBAL.VARS 30958 . 31378) (P.HELP 31380 . 35298) (
P.CHUNK 35300 . 36813) (P.RESET.TIMER 36815 . 37048) (SIMPLESYNCH 37050 . 38298) (IGNORETIMER 38300 . 
38441) (P.COMMAND 38443 . 39203) (P.ENSURE.ESC.SEQ 39205 . 40083) (P.FIND.ESC.SEQ 40085 . 40970) (
P.FINISHED.ACTIONS 40972 . 41740) (P.FIX 41742 . 42097) (P.FIND.IMAGE.OBJS 42099 . 42406) (
P.SEARCH.SELECT.AND.SAY.MSG 42408 . 43187) (P.SEND.ESC.SEQ 43189 . 43455) (TEDIT.LIST.OF.OBJECTS 43457
 . 44390) (P.SAY.BODY 44392 . 45954) (P.SAY.BODY1 45956 . 47732)) (47735 48204 (ACTIVEWINDOW 47745 . 
48202)) (49817 50271 (PROSE.LAFITE.WRITE.PROFILE 49827 . 49960) (PROSE.LAFITE.BROWSE 49962 . 50269))))
)
STOP