(FILECREATED "11-Oct-85 16:04:27" {ERIS}<LISPCORE>LIBRARY>KERMIT.;19 74738  

      changes to:  (FNS \MODEM.RECEIVE.FILE.BYTES)

      previous date: " 7-Oct-85 10:32:02" {ERIS}<LISPCORE>LIBRARY>KERMIT.;18)


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

(PRETTYCOMPRINT KERMITCOMS)

(RPAQQ KERMITCOMS ((COMS (* KERMIT terminal stream based file transfer protocol)
			 (DECLARE: DONTCOPY
				   (EXPORT (CONSTANTS * KERMIT.PACKET.TYPES)
					   (CONSTANTS * KERMIT.PACKET.OFFSETS)
					   (CONSTANTS * \KERMIT.INIT.PARAMETER.OFFSETS)
					   (CONSTANTS (\KERMITOVLEN 5))
					   (RECORDS KERMITSTATE)
					   (MACROS \KERMIT.CHAR \KERMIT.CTL \KERMIT.DEFAULT.CHECKSUM 
						   \KERMIT.UNCHAR \KERMIT.PARAM.DEFAULT 
						   \KERMIT.SEND.ACK \KERMIT.SEND.NAK \KERMIT.ABORT 
						   \KERMIT.DATASECTION \KERMITMSG \KERMITTRACE 
						   \KERMIT.SEND.BREAK \KERMIT.SEND.DATA 
						   \KERMIT.SEND.EOF \KERMIT.INCREMENT.SEQNO 
						   \KERMIT.SEND.ERROR)))
			 (INITRECORDS KERMITSTATE)
			 (CONSTANTS (KERMIT.MAX.PACKET.SIZE 94))
			 (INITVARS (KERMIT.DEFAULT.MARK.CHARACTER (CHARCODE ↑A))
				   (KERMIT.DEFAULT.RECV.PACKET.SIZE 80)
				   (KERMIT.DEFAULT.TIMEOUT.TIME (ITIMES 10 1000))
				   (KERMIT.DEFAULT.PAD.CHARS 0)
				   (KERMIT.DEFAULT.PAD.CHARACTER 0)
				   (KERMIT.DEFAULT.EOL.CHARACTER (CHARCODE EOL))
				   (KERMIT.DEFAULT.PREFIX.CHARACTER (CHARCODE #))
				   (KERMIT.DEFAULT.RETRY.COUNT 10)
				   (\KERMITTRACEFILE NIL)
				   (KERMIT.DEFAULT.FILETYPE (QUOTE TEXT))
				   (KERMIT.DEFAULT.CHATWINDOW))
			 (GLOBALVARS KERMIT.DEFAULT.MARK.CHARACTER KERMIT.DEFAULT.RECV.PACKET.SIZE 
				     KERMIT.DEFAULT.TIMEOUT.TIME KERMIT.DEFAULT.PAD.CHARS 
				     KERMIT.DEFAULT.PAD.CHARACTER KERMIT.DEFAULT.EOL.CHARACTER 
				     KERMIT.DEFAULT.PREFIX.CHARACTER KERMIT.DEFAULT.RETRY.COUNT 
				     \KERMITTRACEFILE KERMIT.DEFAULT.FILETYPE 
				     KERMIT.DEFAULT.CHATWINDOW)
			 (FNS \KERMIT.CLEAR.INPUT.BUFFER \KERMIT.DO.FILE.HEADER \KERMIT.GET.PACKET 
			      \KERMIT.INITIALIZE \KERMIT.NEGOTIATE \KERMIT.PARSE.REMOTE.PARAMETERS 
			      \KERMIT.RECEIVE.FILE \KERMIT.RECEIVE.FILE.BYTES \KERMIT.SEND.FILE 
			      \KERMIT.SEND.FILE.BYTES \KERMIT.SEND.FILE.HEADER \KERMIT.SEND.PACKET 
			      \KERMIT.SEND.PARAMETERS \KERMIT.SEND.STRING \KERMIT.SHOW.PACKET 
			      \KERMIT.TIMED.BIN \KERMIT.UNPREFIXIFY \KERMIT.WRITE))
	(COMS (* User callable functions)
	      (FNS KERMIT.RECEIVE KERMIT.SEND KERMIT.SERVER.COMMAND))
	(COMS (* Kermit TTY executive, for running Kermit without the TEdit menu)
	      (FNS KERMIT KERMIT.EXEC.DEBUGGING KERMIT.EXEC.FILE KERMIT.EXEC.FILE.TYPE 
		   KERMIT.EXEC.ON.OFF KERMIT.EXEC.RECEIVE KERMIT.EXEC.SEND KERMIT.EXEC.SET 
		   KERMIT.SET.KERMIT.WINDOW \KERMIT.LIVE.CHATWINDOW))
	(COMS (* The MODEM program. A sad subset and precursor to KERMIT, but here only for the sake 
		 of compatibility)
	      [DECLARE: DONTCOPY (EXPORT (CONSTANTS * MODEMCOMMANDS)
					 (CONSTANTS (MODEM.PACKET.LENGTH 128]
	      (INITVARS (MODEM.MAX.RETRIES 10)
			(MODEM.TIMEOUT 10000))
	      (GLOBALVARS MODEM.TIMEOUT MODEM.MAX.RETRIES)
	      (FNS MODEM.RECEIVE MODEM.SEND \MODEM.INITIALIZE \MODEM.SEND.FILE \MODEM.SEND.FILE.BYTES 
		   \MODEM.SEND.PACKET \MODEM.CLEAR.INPUT \MODEM.RECEIVE.FILE.BYTES 
		   \MODEM.RECEIVE.PACKET))))



(* KERMIT terminal stream based file transfer protocol)

(DECLARE: DONTCOPY 
(* FOLLOWING DEFINITIONS EXPORTED)



(RPAQQ KERMIT.PACKET.TYPES ((KERMIT.DATA.PACKET (CHARCODE D))
			    (KERMIT.ACK.PACKET (CHARCODE Y))
			    (KERMIT.NAK.PACKET (CHARCODE N))
			    (KERMIT.SENDINIT.PACKET (CHARCODE S))
			    (KERMIT.BREAK.PACKET (CHARCODE B))
			    (KERMIT.FILEHEADER.PACKET (CHARCODE F))
			    (KERMIT.EOF.PACKET (CHARCODE Z))
			    (KERMIT.ERROR.PACKET (CHARCODE E))
			    (KERMIT.ILLEGAL.PACKET (CHARCODE T))
			    (KERMIT.GENERIC.SERVER.COMMAND (CHARCODE G))))
(DECLARE: EVAL@COMPILE 

(RPAQ KERMIT.DATA.PACKET (CHARCODE D))

(RPAQ KERMIT.ACK.PACKET (CHARCODE Y))

(RPAQ KERMIT.NAK.PACKET (CHARCODE N))

(RPAQ KERMIT.SENDINIT.PACKET (CHARCODE S))

(RPAQ KERMIT.BREAK.PACKET (CHARCODE B))

(RPAQ KERMIT.FILEHEADER.PACKET (CHARCODE F))

(RPAQ KERMIT.EOF.PACKET (CHARCODE Z))

(RPAQ KERMIT.ERROR.PACKET (CHARCODE E))

(RPAQ KERMIT.ILLEGAL.PACKET (CHARCODE T))

(RPAQ KERMIT.GENERIC.SERVER.COMMAND (CHARCODE G))

(CONSTANTS (KERMIT.DATA.PACKET (CHARCODE D))
	   (KERMIT.ACK.PACKET (CHARCODE Y))
	   (KERMIT.NAK.PACKET (CHARCODE N))
	   (KERMIT.SENDINIT.PACKET (CHARCODE S))
	   (KERMIT.BREAK.PACKET (CHARCODE B))
	   (KERMIT.FILEHEADER.PACKET (CHARCODE F))
	   (KERMIT.EOF.PACKET (CHARCODE Z))
	   (KERMIT.ERROR.PACKET (CHARCODE E))
	   (KERMIT.ILLEGAL.PACKET (CHARCODE T))
	   (KERMIT.GENERIC.SERVER.COMMAND (CHARCODE G)))
)

(RPAQQ KERMIT.PACKET.OFFSETS ((KERMIT.PACKET.MARK 1)
			      (KERMIT.PACKET.LEN 2)
			      (KERMIT.PACKET.SEQ 3)
			      (KERMIT.PACKET.TYPE 4)
			      (KERMIT.PACKET.DATA 5)))
(DECLARE: EVAL@COMPILE 

(RPAQQ KERMIT.PACKET.MARK 1)

(RPAQQ KERMIT.PACKET.LEN 2)

(RPAQQ KERMIT.PACKET.SEQ 3)

(RPAQQ KERMIT.PACKET.TYPE 4)

(RPAQQ KERMIT.PACKET.DATA 5)

(CONSTANTS (KERMIT.PACKET.MARK 1)
	   (KERMIT.PACKET.LEN 2)
	   (KERMIT.PACKET.SEQ 3)
	   (KERMIT.PACKET.TYPE 4)
	   (KERMIT.PACKET.DATA 5))
)

(RPAQQ \KERMIT.INIT.PARAMETER.OFFSETS ((\KPARM.MAXL 1)
				       (\KPARM.TIME 2)
				       (\KPARM.NPAD 3)
				       (\KPARM.PADC 4)
				       (\KPARM.EOL 5)
				       (\KPARM.QCTL 6)
				       (\KPARM.QBIN 7)))
(DECLARE: EVAL@COMPILE 

(RPAQQ \KPARM.MAXL 1)

(RPAQQ \KPARM.TIME 2)

(RPAQQ \KPARM.NPAD 3)

(RPAQQ \KPARM.PADC 4)

(RPAQQ \KPARM.EOL 5)

(RPAQQ \KPARM.QCTL 6)

(RPAQQ \KPARM.QBIN 7)

(CONSTANTS (\KPARM.MAXL 1)
	   (\KPARM.TIME 2)
	   (\KPARM.NPAD 3)
	   (\KPARM.PADC 4)
	   (\KPARM.EOL 5)
	   (\KPARM.QCTL 6)
	   (\KPARM.QBIN 7))
)
(DECLARE: EVAL@COMPILE 

(RPAQQ \KERMITOVLEN 5)

(CONSTANTS (\KERMITOVLEN 5))
)
[DECLARE: EVAL@COMPILE 

(DATATYPE KERMITSTATE ((LASTPACKETIN POINTER)
	   (LASTPACKETOUT POINTER)
	   (STATE POINTER)
	   (INSTREAM POINTER)
	   (OUTSTREAM POINTER)
	   (EOLCONVENTION POINTER)
	   (EOL POINTER)
	   (QBIN POINTER)
	   (TIME FIXP)
	   (CURRENTSEQNO BYTE)
	   (MARKCHAR BYTE)
	   (MAXL BYTE)
	   (NPAD BYTE)
	   (PADC BYTE)
	   (QCTL BYTE)
	   (CHKT BYTE)
	   (REPT BYTE))
	  CURRENTSEQNO ← 0 MARKCHAR ← KERMIT.DEFAULT.MARK.CHARACTER MAXL ← 
	  KERMIT.DEFAULT.RECV.PACKET.SIZE TIME ← KERMIT.DEFAULT.TIMEOUT.TIME NPAD ← 
	  KERMIT.DEFAULT.PAD.CHARS PADC ← KERMIT.DEFAULT.PAD.CHARACTER QCTL ← 
	  KERMIT.DEFAULT.PREFIX.CHARACTER EOL ← KERMIT.DEFAULT.EOL.CHARACTER)
]
(/DECLAREDATATYPE (QUOTE KERMITSTATE)
		  (QUOTE (POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER FIXP BYTE 
				  BYTE BYTE BYTE BYTE BYTE BYTE BYTE))
		  [QUOTE ((KERMITSTATE 0 POINTER)
			  (KERMITSTATE 2 POINTER)
			  (KERMITSTATE 4 POINTER)
			  (KERMITSTATE 6 POINTER)
			  (KERMITSTATE 8 POINTER)
			  (KERMITSTATE 10 POINTER)
			  (KERMITSTATE 12 POINTER)
			  (KERMITSTATE 14 POINTER)
			  (KERMITSTATE 16 FIXP)
			  (KERMITSTATE 14 (BITS . 7))
			  (KERMITSTATE 12 (BITS . 7))
			  (KERMITSTATE 10 (BITS . 7))
			  (KERMITSTATE 8 (BITS . 7))
			  (KERMITSTATE 6 (BITS . 7))
			  (KERMITSTATE 4 (BITS . 7))
			  (KERMITSTATE 2 (BITS . 7))
			  (KERMITSTATE 0 (BITS . 7]
		  (QUOTE 18))
(DECLARE: EVAL@COMPILE 
(DEFMACRO \KERMIT.CHAR (X)
	  (BQUOTE (IPLUS (\, X)
			 32)))
[DEFMACRO \KERMIT.CTL (X)
	  (BQUOTE (LOGAND (MASK.1'S 0 8)
			  (LOGXOR , X 64]
[DEFMACRO \KERMIT.DEFAULT.CHECKSUM (S)
	  (BQUOTE (\KERMIT.CHAR (LOGAND (IPLUS (\, S)
					       (FOLDLO (LOGAND (\, S)
							       192)
						       64))
					(MASK.1'S 0 6]
[DEFMACRO \KERMIT.UNCHAR (X)
	  (BQUOTE (LOGAND (IDIFFERENCE (\, X)
				       32)
			  (MASK.1'S 0 7]
[DEFMACRO \KERMIT.PARAM.DEFAULT (DEFAULTVALUE PACKETVALUE)
	  (BQUOTE (COND ((EQ , PACKETVALUE 0)
			 , DEFAULTVALUE)
			(T , PACKETVALUE]
[DEFMACRO \KERMIT.SEND.ACK (KERMITSTATE &OPTIONAL (SEQNO NIL))
	  (BQUOTE (\KERMIT.SEND.DATA "" KERMIT.ACK.PACKET (\, KERMITSTATE)
				     (\, SEQNO]
[DEFMACRO \KERMIT.SEND.NAK (KERMITSTATE)
	  (BQUOTE (\KERMIT.SEND.STRING "" KERMIT.NAK.PACKET (\, KERMITSTATE]
[DEFMACRO \KERMIT.ABORT (KERMITSTATE)
	  (BQUOTE (PROGN (\KERMIT.SEND.NAK , KERMITSTATE)
			 (replace (KERMITSTATE STATE)
				  of , KERMITSTATE with 'ABORT]
(DEFMACRO \KERMIT.DATASECTION (STRING)
	  (BQUOTE (SUBSTRING , STRING KERMIT.PACKET.DATA -2)))
[DEFMACRO \KERMITMSG (&OPTIONAL (MSG))
	  (BQUOTE (PROGN (CLEARW KERMITSTATUSWINDOW)
			 (COND ((LISTP (\, MSG))
				(printout KERMITSTATUSWINDOW .PPVTL (\, MSG)))
			       ((\, MSG)
				(printout KERMITSTATUSWINDOW (\, MSG]
[DEFMACRO \KERMITTRACE (MSG)
	  (BQUOTE (COND (\KERMITTRACEFILE (PRIN1 (\, MSG)
						 \KERMITTRACEFILE]
[DEFMACRO \KERMIT.SEND.BREAK (KERMITSTATE)
	  (BQUOTE (\KERMIT.SEND.PACKET "" KERMIT.BREAK.PACKET (\, KERMITSTATE]
[DEFMACRO \KERMIT.SEND.DATA (STRING TYPE KERMITSTATE &OPTIONAL (SEQNO))
	  (BQUOTE (PROGN (\KERMIT.SEND.STRING (\, STRING)
					      (\, TYPE)
					      (\, KERMITSTATE)
					      (\, SEQNO))
			 (COND ((NOT (\, SEQNO))
				(\KERMIT.INCREMENT.SEQNO (\, KERMITSTATE]
[DEFMACRO \KERMIT.SEND.EOF (KERMITSTATE &OPTIONAL (DISCARD))
	  (BQUOTE (COND ((\, DISCARD)
			 (\KERMIT.SEND.PACKET "D" KERMIT.EOF.PACKET (\, KERMITSTATE)))
			(T (\KERMIT.SEND.PACKET "" KERMIT.EOF.PACKET (\, KERMITSTATE]
[DEFMACRO \KERMIT.INCREMENT.SEQNO (KERMITSTATE)
	  (BQUOTE (change (fetch (KERMITSTATE CURRENTSEQNO)
				 of
				 (\, KERMITSTATE))
			  (IMOD (ADD1 DATUM)
				64]
[DEFMACRO \KERMIT.SEND.ERROR (STRING KERMITSTATE)
	  (BQUOTE (\KERMIT.SEND.STRING (\, STRING)
				       KERMIT.ERROR.PACKET
				       (\, KERMITSTATE]
)


(* END EXPORTED DEFINITIONS)

)
(/DECLAREDATATYPE (QUOTE KERMITSTATE)
		  (QUOTE (POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER FIXP BYTE 
				  BYTE BYTE BYTE BYTE BYTE BYTE BYTE))
		  [QUOTE ((KERMITSTATE 0 POINTER)
			  (KERMITSTATE 2 POINTER)
			  (KERMITSTATE 4 POINTER)
			  (KERMITSTATE 6 POINTER)
			  (KERMITSTATE 8 POINTER)
			  (KERMITSTATE 10 POINTER)
			  (KERMITSTATE 12 POINTER)
			  (KERMITSTATE 14 POINTER)
			  (KERMITSTATE 16 FIXP)
			  (KERMITSTATE 14 (BITS . 7))
			  (KERMITSTATE 12 (BITS . 7))
			  (KERMITSTATE 10 (BITS . 7))
			  (KERMITSTATE 8 (BITS . 7))
			  (KERMITSTATE 6 (BITS . 7))
			  (KERMITSTATE 4 (BITS . 7))
			  (KERMITSTATE 2 (BITS . 7))
			  (KERMITSTATE 0 (BITS . 7]
		  (QUOTE 18))
(DECLARE: EVAL@COMPILE 

(RPAQQ KERMIT.MAX.PACKET.SIZE 94)

(CONSTANTS (KERMIT.MAX.PACKET.SIZE 94))
)

(RPAQ? KERMIT.DEFAULT.MARK.CHARACTER (CHARCODE ↑A))

(RPAQ? KERMIT.DEFAULT.RECV.PACKET.SIZE 80)

(RPAQ? KERMIT.DEFAULT.TIMEOUT.TIME (ITIMES 10 1000))

(RPAQ? KERMIT.DEFAULT.PAD.CHARS 0)

(RPAQ? KERMIT.DEFAULT.PAD.CHARACTER 0)

(RPAQ? KERMIT.DEFAULT.EOL.CHARACTER (CHARCODE EOL))

(RPAQ? KERMIT.DEFAULT.PREFIX.CHARACTER (CHARCODE #))

(RPAQ? KERMIT.DEFAULT.RETRY.COUNT 10)

(RPAQ? \KERMITTRACEFILE NIL)

(RPAQ? KERMIT.DEFAULT.FILETYPE (QUOTE TEXT))

(RPAQ? KERMIT.DEFAULT.CHATWINDOW )
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS KERMIT.DEFAULT.MARK.CHARACTER KERMIT.DEFAULT.RECV.PACKET.SIZE KERMIT.DEFAULT.TIMEOUT.TIME 
	    KERMIT.DEFAULT.PAD.CHARS KERMIT.DEFAULT.PAD.CHARACTER KERMIT.DEFAULT.EOL.CHARACTER 
	    KERMIT.DEFAULT.PREFIX.CHARACTER KERMIT.DEFAULT.RETRY.COUNT \KERMITTRACEFILE 
	    KERMIT.DEFAULT.FILETYPE KERMIT.DEFAULT.CHATWINDOW)
)
(DEFINEQ

(\KERMIT.CLEAR.INPUT.BUFFER
  (LAMBDA (STREAM)                                           (* ejs: " 7-Jun-85 20:31")
    (while (READP STREAM) do (BIN STREAM))))

(\KERMIT.DO.FILE.HEADER
  [LAMBDA (LOCALFILE FILETYPE KERMITSTATE)                   (* ejs: " 5-Jul-85 17:42")

          (* * Receive the file header, open the file according to TYPE, and return)


    (LET* ((FILEHEADERPACKET (\KERMIT.GET.PACKET KERMITSTATE))
	   (TYPE (AND FILEHEADERPACKET (NTHCHARCODE FILEHEADERPACKET KERMIT.PACKET.TYPE)))
	   FILESTREAM)
          (SELECTC TYPE
		   [KERMIT.FILEHEADER.PACKET (COND
					       ([SETQ FILESTREAM (OPENSTREAM LOCALFILE (QUOTE OUTPUT)
									     (QUOTE NEW)
									     (BQUOTE ((TYPE , 
											 FILETYPE)
										      (SEQUENTIAL
											T]
						 (\KERMIT.SEND.ACK KERMITSTATE)
						 (replace (KERMITSTATE STATE) of KERMITSTATE
						    with (QUOTE REC.DATA))
						 FILESTREAM)
					       (T (\KERMIT.ABORT KERMITSTATE]
		   (KERMIT.BREAK.PACKET (\KERMIT.SEND.ACK KERMITSTATE)
					(replace (KERMITSTATE STATE) of KERMITSTATE
					   with (QUOTE COMPLETE))
					NIL)
		   (KERMIT.ERROR.PACKET (ERROR (\KERMIT.DATASECTION FILEHEADERPACKET)))
		   (ERROR "Unexpected packet type in DO.FILE.HEADER" (CHARACTER TYPE])

(\KERMIT.GET.PACKET
  (LAMBDA (KERMITSTATE)                                      (* ejs: " 7-Oct-85 09:03")

          (* * Called to get the next packet on the kermit connection. Handles timeout, retransmission, etc)


    (LET ((STREAM (fetch (KERMITSTATE INSTREAM) of KERMITSTATE))
	    (OUTSTREAM (fetch (KERMITSTATE OUTSTREAM) of KERMITSTATE))
	    (TIMEOUT (fetch (KERMITSTATE TIME) of KERMITSTATE))
	    PACKET.TIMER PACKET SEQ LEN TYPE CHAR (CHECKSUM 0))
           (\KERMIT.CLEAR.INPUT.BUFFER STREAM)
           (\KERMITTRACE "G:")
           (for RETRIES from 1 to KERMIT.DEFAULT.RETRY.COUNT until PACKET
	      do (COND
		     ((NEQ RETRIES 1)
		       (PRIN1 "." KERMITSTATUSWINDOW)))
		   (COND
		     ((bind GOTIT until (OR (AND (EQ (SETQ CHAR (\KERMIT.TIMED.BIN
								   STREAM TIMEOUT))
							       (fetch (KERMITSTATE MARKCHAR)
								  of KERMITSTATE))
							 (SETQ GOTIT T))
						  (NULL CHAR))
			 finally (RETURN GOTIT))
		       (\KERMITTRACE "[")
		       (COND
			 ((NOT (SETQ CHECKSUM (\KERMIT.TIMED.BIN STREAM TIMEOUT)))
			   (\KERMIT.SEND.NAK KERMITSTATE)
			   (GO $$ITERATE)))
		       (SETQ LEN (\KERMIT.UNCHAR CHECKSUM))
		       (SETQ PACKET (ALLOCSTRING (IPLUS LEN KERMIT.PACKET.LEN)))
		       (\KERMITTRACE LEN)
		       (RPLCHARCODE PACKET KERMIT.PACKET.LEN LEN)
		       (COND
			 ((NOT (for I from KERMIT.PACKET.SEQ to (IPLUS LEN (SUB1 
										KERMIT.PACKET.LEN))
				    do (COND
					   ((NOT (SETQ CHAR (\KERMIT.TIMED.BIN STREAM TIMEOUT)))
					     (RETURN)))
					 (add CHECKSUM CHAR)
					 (RPLCHARCODE PACKET I CHAR)
				    finally (RETURN T)))
			   (SETQ PACKET NIL)
			   (\KERMIT.SEND.NAK KERMITSTATE)
			   (GO $$ITERATE)))
		       (SETQ TYPE (NTHCHARCODE PACKET KERMIT.PACKET.TYPE))
		       (\KERMITTRACE (CONCAT " " (CHARACTER TYPE)
					       "]"))
		       (COND
			 ((ILESSP (SETQ SEQ (\KERMIT.UNCHAR (NTHCHARCODE PACKET 
									       KERMIT.PACKET.SEQ)))
				    0)
			   (SETQ PACKET NIL)
			   (\KERMIT.SEND.NAK KERMITSTATE)
			   (GO $$ITERATE)))
		       (RPLCHARCODE PACKET KERMIT.PACKET.SEQ SEQ)
		       (COND
			 ((NEQ (\KERMIT.DEFAULT.CHECKSUM CHECKSUM)
				 (\KERMIT.TIMED.BIN STREAM TIMEOUT))
			   (\KERMITTRACE "X ")
			   (\KERMIT.SEND.NAK KERMITSTATE)
			   (SETQ PACKET NIL))
			 ((EQ TYPE KERMIT.NAK.PACKET)
			   (SETQ PACKET NIL)
			   (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
					    OUTSTREAM))
			 ((EQ SEQ (fetch (KERMITSTATE CURRENTSEQNO) of KERMITSTATE))
			   (replace (KERMITSTATE LASTPACKETIN) of KERMITSTATE with PACKET)
			   (\KERMITTRACE "A ")
			   (RETURN))
			 ((ILESSP SEQ (fetch (KERMITSTATE CURRENTSEQNO) of KERMITSTATE))
			   (\KERMITTRACE "O ")
			   (COND
			     ((EQ (NTHCHARCODE PACKET KERMIT.PACKET.TYPE)
				    KERMIT.EOF.PACKET)
			       (\KERMIT.SEND.ACK (SUB1 (fetch (KERMITSTATE CURRENTSEQNO)
							    of KERMITSTATE))
						 KERMITSTATE))
			     (T (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of 
										      KERMITSTATE)
						 KERMITSTATE)))
			   (SETQ PACKET NIL))
			 (T (\KERMITTRACE (CONCAT "E(" SEQ ")"))
			    (\KERMIT.SEND.NAK KERMITSTATE)
			    (SETQ PACKET NIL))))
		     (T (\KERMIT.SEND.NAK KERMITSTATE))))
           (COND
	     (PACKET PACKET)
	     (T (\KERMITMSG "Remote KERMIT is not responding")
		(ERROR!))))))

(\KERMIT.INITIALIZE
  [LAMBDA (KERMITSTATE FORWHAT)                              (* ejs: " 8-Jun-85 20:38")
    (with KERMITSTATE KERMITSTATE (SETQ CURRENTSEQNO 0)
	  (COND
	    ((NOT (OPENP OUTSTREAM (QUOTE OUTPUT)))
	      (ERROR "KERMIT output stream is not open for output!" OUTSTREAM))
	    ((NOT (OPENP INSTREAM (QUOTE INPUT)))
	      (ERROR "KERMIT input stream is not open for input!" INSTREAM)))
	  (SELECTQ FORWHAT
		   (RECEIVE (SETQ STATE (QUOTE REC.INIT)))
		   (STORE (SETQ STATE (QUOTE SEND.INIT)))
		   (ERROR "Illegal Kermit operation" FORWHAT))
	  KERMITSTATE])

(\KERMIT.NEGOTIATE
  [LAMBDA (KERMITSTATE)                                      (* ejs: " 5-Jul-85 17:46")
    (LET (PARAMETER.PACKET)
         (SELECTQ (fetch (KERMITSTATE STATE) of KERMITSTATE)
		  (REC.INIT (SETQ PARAMETER.PACKET (\KERMIT.GET.PACKET KERMITSTATE))
			    (SELECTC (NTHCHARCODE PARAMETER.PACKET KERMIT.PACKET.TYPE)
				     (KERMIT.SENDINIT.PACKET (\KERMIT.PARSE.REMOTE.PARAMETERS 
										 PARAMETER.PACKET 
										      KERMITSTATE))
				     (KERMIT.ERROR.PACKET (HELP (\KERMIT.DATASECTION PARAMETER.PACKET)
								))
				     (ERROR "Unexpected packet type: " PARAMETER.PACKET))
			    [LET ((QBIN (fetch (KERMITSTATE QBIN) of KERMITSTATE)))
			         (SELECTC QBIN
					  ((CHARCODE N)
					    (replace (KERMITSTATE QBIN) of KERMITSTATE with NIL))
					  ((CHARCODE Y)
					    (replace (KERMITSTATE QBIN) of KERMITSTATE
					       with (CHARCODE &)))
					  (COND
					    ((OR (AND (GEQ QBIN 33)
						      (LEQ QBIN 62))
						 (AND (GEQ QBIN 96)
						      (LEQ QBIN 126)))
					      (replace (KERMITSTATE QBIN) of KERMITSTATE
						 with QBIN]
			    (\KERMIT.SEND.PARAMETERS KERMITSTATE)
			    (replace (KERMITSTATE STATE) of KERMITSTATE with (QUOTE REC.FILE)))
		  (SEND.INIT (SETQ PARAMETER.PACKET (\KERMIT.SEND.PARAMETERS KERMITSTATE))
			     (\KERMIT.PARSE.REMOTE.PARAMETERS PARAMETER.PACKET KERMITSTATE)
			     (LET ((QBIN (fetch (KERMITSTATE QBIN) of KERMITSTATE)))
			          (SELECTC QBIN
					   ((CHARCODE &))
					   ((CHARCODE Y)
					     (replace (KERMITSTATE QBIN) of KERMITSTATE
						with (CHARCODE &)))
					   (replace (KERMITSTATE QBIN) of KERMITSTATE with NIL)))
			     (replace (KERMITSTATE STATE) of KERMITSTATE with (QUOTE SEND.FILE)))
		  (HELP "Illegal Kermit state" (fetch (KERMITSTATE STATE) of KERMITSTATE])

(\KERMIT.PARSE.REMOTE.PARAMETERS
  [LAMBDA (PACKET KERMITSTATE)                               (* ejs: " 8-Jun-85 17:40")
    (LET* ((PARAMETERS (\KERMIT.DATASECTION PACKET))
	   (NPARAMS (NCHARS PARAMETERS))
	   (OFFSET 1))
          (COND
	    ((ILEQ OFFSET NPARAMS)
	      [replace (KERMITSTATE MAXL) of KERMITSTATE with (\KERMIT.PARAM.DEFAULT
								KERMIT.DEFAULT.RECV.PACKET.SIZE
								(\KERMIT.UNCHAR (NTHCHARCODE 
										       PARAMETERS 
										      \KPARM.MAXL]
	      (add OFFSET 1)))
          (COND
	    ((ILEQ OFFSET NPARAMS)
	      [replace (KERMITSTATE TIME) of KERMITSTATE
		 with (ITIMES 1000 (\KERMIT.PARAM.DEFAULT (IQUOTIENT KERMIT.DEFAULT.TIMEOUT.TIME 1000)
							  (\KERMIT.UNCHAR (NTHCHARCODE PARAMETERS 
										      \KPARM.TIME]
	      (add OFFSET 1)))
          (COND
	    ((ILEQ OFFSET NPARAMS)
	      [replace (KERMITSTATE NPAD) of KERMITSTATE with (\KERMIT.PARAM.DEFAULT
								0
								(\KERMIT.UNCHAR (NTHCHARCODE 
										       PARAMETERS 
										      \KPARM.NPAD]
	      (add OFFSET 1)))
          (COND
	    ((ILEQ OFFSET NPARAMS)
	      [replace (KERMITSTATE PADC) of KERMITSTATE with (\KERMIT.PARAM.DEFAULT
								0
								(\KERMIT.CTL (NTHCHARCODE PARAMETERS 
										      \KPARM.PADC]
	      (add OFFSET 1)))
          (COND
	    ((ILEQ OFFSET NPARAMS)
	      [replace (KERMITSTATE EOL) of KERMITSTATE with (\KERMIT.PARAM.DEFAULT
							       NIL
							       (\KERMIT.UNCHAR (NTHCHARCODE 
										       PARAMETERS 
										       \KPARM.EOL]
	      (add OFFSET 1)))
          (COND
	    ((ILEQ OFFSET NPARAMS)
	      (replace (KERMITSTATE QCTL) of KERMITSTATE with (\KERMIT.PARAM.DEFAULT 
								  KERMIT.DEFAULT.PREFIX.CHARACTER
										     (NTHCHARCODE
										       PARAMETERS 
										      \KPARM.QCTL)))
	      (add OFFSET 1)))
          (COND
	    ((ILEQ OFFSET NPARAMS)
	      (replace (KERMITSTATE QBIN) of KERMITSTATE with (\KERMIT.PARAM.DEFAULT NIL
										     (NTHCHARCODE
										       PARAMETERS 
										      \KPARM.QBIN)))
	      (add OFFSET 1])

(\KERMIT.RECEIVE.FILE
  [LAMBDA (LOCALFILE KERMITSTATE KERMITSTATUSWINDOW)         (* ejs: " 3-Jul-85 21:50")
    (LET [FILESTREAM (TYPE (COND
			     ((fetch (KERMITSTATE EOLCONVENTION) of KERMITSTATE)
			       (QUOTE TEXT))
			     (T (QUOTE BINARY]
         (\KERMIT.INITIALIZE KERMITSTATE (QUOTE RECEIVE))
         (\KERMITMSG "Kermit initialized.  Waiting for server.")
         (COND
	   ((\KERMIT.NEGOTIATE KERMITSTATE)
	     (\KERMITMSG "Connection established.  Waiting for file")
	     (while (EQ (fetch (KERMITSTATE STATE) of KERMITSTATE)
			(QUOTE REC.FILE))
		do (SETQ FILESTREAM (\KERMIT.DO.FILE.HEADER LOCALFILE TYPE KERMITSTATE))
		   (SELECTQ (fetch (KERMITSTATE STATE) of KERMITSTATE)
			    (REC.DATA (\KERMITMSG (LIST (QUOTE Retrieving)
							(FULLNAME FILESTREAM)))
				      (RESETLST (RESETSAVE NIL (LIST [FUNCTION (LAMBDA (STREAM)
									 (AND RESETSTATE
									      (CLOSEF? STREAM)
									      (DELFILE (FULLNAME
											 STREAM]
								     FILESTREAM))
						(\KERMIT.RECEIVE.FILE.BYTES FILESTREAM KERMITSTATE 
									    TYPE)))
			    (COMPLETE (\KERMITMSG "Done")
				      (RETURN (FULLNAME FILESTREAM)))
			    (ABORT (ERROR "Remote kermit aborted"))
			    (ERROR "Unexpected state after REC.FILE" KERMITSTATE])

(\KERMIT.RECEIVE.FILE.BYTES
  [LAMBDA (FILESTREAM KERMITSTATE FILETYPE)                  (* ejs: " 4-Sep-85 03:12")
    (bind DONE STRING STRINGSTREAM NOEOLWORRIES SKIPFIRST FILEOLCHAR (FILEOL ←(fetch (STREAM 
										    EOLCONVENTION)
										 of FILESTREAM))
       first [COND
	       ((OR (EQ FILETYPE (QUOTE BINARY))
		    (EQ FILEOL CRLF.EOLC))
		 (SETQ NOEOLWORRIES T))
	       (T (SETQ FILEOLCHAR (SELECTC FILEOL
					    (CR.EOLC (CHARCODE CR))
					    (LF.EOLC (CHARCODE LF))
					    (SHOULDNT]
       until DONE as I from 1
       do (LET* ((DATA (\KERMIT.GET.PACKET KERMITSTATE))
		 (TYPE (NTHCHARCODE DATA KERMIT.PACKET.TYPE))
		 NBYTES)
	        (SELECTC TYPE
			 (KERMIT.DATA.PACKET (SETQ STRING (\KERMIT.UNPREFIXIFY (\KERMIT.DATASECTION
										 DATA)
									       (fetch (KERMITSTATE
											QCTL)
										  of KERMITSTATE)
									       (fetch (KERMITSTATE
											QBIN)
										  of KERMITSTATE)
									       STRING))
					     (SETQ STRINGSTREAM (\MAKEBASEBYTESTREAM
						 (fetch (STRINGP BASE) of STRING)
						 (fetch (STRINGP OFFST) of STRING)
						 (fetch (STRINGP LENGTH) of STRING)
						 (QUOTE INPUT)
						 NIL STRINGSTREAM))
					     [COND
					       (SKIPFIRST (SETQ SKIPFIRST NIL)
							  (LET ((CH (BIN STRINGSTREAM)))
							       (COND
								 ((EQ CH (CHARCODE LF))
								   (BOUT FILESTREAM FILEOLCHAR))
								 (T (BOUT FILESTREAM CH]
					     [COND
					       (NOEOLWORRIES (COPYBYTES STRINGSTREAM FILESTREAM))
					       (T            (* The file's eol convention is not CRLF)
						  [COND
						    [(EQ (CHARCODE CR)
							 (NTHCHARCODE STRING (NCHARS STRING)))
						      (SETQ SKIPFIRST T)
						      (SETQ NBYTES (SUB1 (NCHARS STRING]
						    (T (SETQ NBYTES (NCHARS STRING]
						  (bind CH for I from (ADD1 (GETFILEPTR STRINGSTREAM))
						     to NBYTES
						     do (SETQ CH (BIN STRINGSTREAM))
							(COND
							  ((NEQ CH (CHARCODE CR))
							    (BOUT FILESTREAM CH))
							  ((NEQ (SETQ CH (PROGN (add I 1)
										(BIN STRINGSTREAM)))
								(CHARCODE LF))
							    (BOUT FILESTREAM CH))
							  (T (BOUT FILESTREAM FILEOLCHAR]
					     (\KERMITMSG I)
					     (\KERMIT.SEND.ACK KERMITSTATE))
			 (KERMIT.EOF.PACKET (\KERMIT.SEND.ACK KERMITSTATE)
					    (CLOSEF FILESTREAM)
					    (\KERMITMSG (CONCAT "Received " (FULLNAME FILESTREAM)))
					    (replace (KERMITSTATE STATE) of KERMITSTATE
					       with (QUOTE REC.FILE))
					    (SETQ DONE T))
			 (KERMIT.ERROR.PACKET (ERROR (\KERMIT.DATASECTION DATA)
						     (fetch (KERMITSTATE LASTPACKETOUT) of 
										      KERMITSTATE)))
			 (ERROR "Unexpected packet type" (CHARACTER TYPE])

(\KERMIT.SEND.FILE
  (LAMBDA (LOCALFILE REMOTEFILE TYPE KERMITSTATE KERMITSTATUSWINDOW)
                                                             (* ejs: " 7-Oct-85 08:19")

          (* * Send a file)


    (LET (FILESTREAM)
           (\KERMIT.INITIALIZE KERMITSTATE (QUOTE STORE))
           (\KERMITMSG "Kermit initialized.  Waiting for server.")
           (COND
	     ((\KERMIT.NEGOTIATE KERMITSTATE)
	       (\KERMITMSG (CONCAT "Connection established.  Sending file header for "
				     (FULLNAME LOCALFILE)))
	       (while (EQ (fetch (KERMITSTATE STATE) of KERMITSTATE)
			      (QUOTE SEND.FILE))
		  do (SETQ FILESTREAM (OPENSTREAM LOCALFILE (QUOTE INPUT)
							(QUOTE OLD)
							(BQUOTE ((TYPE , TYPE)
								   (SEQUENTIAL T)))))
		       (SELECTQ (fetch (KERMITSTATE STATE) of KERMITSTATE)
				  (SEND.FILE (\KERMIT.SEND.FILE.HEADER REMOTEFILE KERMITSTATE)
					     (\KERMITMSG (LIST (QUOTE Sending)
								 (FULLNAME FILESTREAM)))
					     (RESETLST (RESETSAVE NIL
								      (LIST
									(FUNCTION (LAMBDA (STREAM)
									    (CLOSEF? STREAM)
									    (COND
									      ((NOT RESETSTATE)
										(\KERMIT.SEND.EOF
										  KERMITSTATE 
										  RESETSTATE)
										(\KERMIT.SEND.BREAK
										  KERMITSTATE)))
									    (replace (KERMITSTATE
											 STATE)
									       of KERMITSTATE
									       with (QUOTE 
											 COMPLETE))))
									FILESTREAM))
							 (\KERMIT.SEND.FILE.BYTES FILESTREAM 
										    KERMITSTATE TYPE))
					     )
				  (COMPLETE (\KERMITMSG "Done")
					    (RETURN))
				  (ABORT (ERROR "Remote kermit aborted"))
				  (ERROR "Unexpected state after SEND.FILE" KERMITSTATE))))))))

(\KERMIT.SEND.FILE.BYTES
  [LAMBDA (FILESTREAM KERMITSTATE TYPE)                      (* ejs: " 3-Jul-85 22:33")

          (* * Send all the bytes of file)


    (replace (STREAM ENDOFSTREAMOP) of FILESTREAM with (FUNCTION [LAMBDA NIL -1]))
    (bind (PACKET ←(ALLOCSTRING (fetch (KERMITSTATE MAXL) of KERMITSTATE)))
	  (QCTL ←(fetch (KERMITSTATE QCTL) of KERMITSTATE))
	  (QBIN ←(fetch (KERMITSTATE QBIN) of KERMITSTATE))
	  (EOLWORRIES ←(AND (NEQ TYPE (QUOTE BINARY))
			    (NEQ (fetch (STREAM EOLCONVENTION) of FILESTREAM)
				 CRLF.EOLC)))
	  (FILEOLCHAR ←(AND (NEQ TYPE (QUOTE BINARY))
			    (SELECTC (fetch (STREAM EOLCONVENTION) of FILESTREAM)
				     (LF.EOLC (CHARCODE LF))
				     (CR.EOLC (CHARCODE CR))
				     NIL)))
	  DONE CHAR MASKEDCHAR WAITINGCHAR DATASECTION FILLEDATASECTION MAXCHARS CHARINDEX LFPENDING
       first (SETQ DATASECTION (\KERMIT.DATASECTION PACKET))
	     (SETQ MAXCHARS (NCHARS DATASECTION))
       until DONE as I from 1
       do (for old CHARINDEX from 1 to MAXCHARS
	     do [SETQ CHAR (COND
		    (WAITINGCHAR (PROG1 (COND
					  (LFPENDING 

          (* The waiting char must have been the eol char of the input file, which could would have been changed below if 
	  input file eol char is LF)


						     FILEOLCHAR)
					  (T WAITINGCHAR))
					(SETQ LFPENDING NIL)
					(SETQ WAITINGCHAR NIL)))
		    (LFPENDING (COND
				 ((EQ FILEOLCHAR (CHARCODE CR))
                                                             (* Have to set LFPENDING to NIL here, otherwise it will
							     stay on forever)
				   (SETQ LFPENDING NIL)))
			       (CHARCODE LF))
		    (T (BIN FILESTREAM]
		(COND
		  ((EQ -1 CHAR)
		    (SETQ DONE T)
		    (RETURN)))
		[COND
		  ((EQ CHAR FILEOLCHAR)                      (* Have to fix up eol convention)
		    (COND
		      ((NOT LFPENDING)
			(SETQ CHAR (CHARCODE CR))
			(SETQ LFPENDING T))
		      (T                                     (* If CHAR=EOLCHAR and LFPENDING is T, EOL char must be
							     LF)
			 (SETQ LFPENDING NIL]
		(COND
		  ((AND QBIN (IGREATERP CHAR (MASK.1'S 0 7)))
		    (SETQ MASKEDCHAR (LOGAND CHAR (MASK.1'S 0 7)))
		    (COND
		      ([OR (EQ CHARINDEX MAXCHARS)
			   (AND (EQ CHARINDEX (SUB1 MAXCHARS))
				(OR (ILESSP MASKEDCHAR (CHARCODE SPACE))
				    (EQ MASKEDCHAR QBIN)
				    (EQ MASKEDCHAR QCTL)
				    (EQ MASKEDCHAR (CHARCODE DEL]
                                                             (* No room for possible quoted and controlified 
							     character)
			(SETQ WAITINGCHAR CHAR)
			(RETURN)))
		    (RPLCHARCODE DATASECTION CHARINDEX QBIN)
		    (SETQ CHAR (LOGAND CHAR (MASK.1'S 0 7)))
		    (add CHARINDEX 1)))
		(COND
		  ((OR (ILESSP CHAR (CHARCODE SPACE))
		       (EQ CHAR QBIN)
		       (EQ CHAR QCTL)
		       (EQ CHAR (CHARCODE DEL)))
		    (COND
		      ((EQ CHARINDEX MAXCHARS)               (* No room for both prefix and controlified character)
			(SETQ WAITINGCHAR CHAR)
			(RETURN)))
		    (RPLCHARCODE DATASECTION CHARINDEX QCTL)
		    [COND
		      ((OR (EQ CHAR QBIN)
			   (EQ CHAR QCTL)))
		      (T (SETQ CHAR (\KERMIT.CTL CHAR]
		    (add CHARINDEX 1)))
		(RPLCHARCODE DATASECTION CHARINDEX CHAR))
	  (SETQ FILLEDATASECTION (SUBSTRING DATASECTION 1 (SUB1 CHARINDEX)
					    FILLEDATASECTION))
	  (COND
	    ((NEQ 0 (NCHARS FILLEDATASECTION))
	      (\KERMIT.SEND.PACKET FILLEDATASECTION KERMIT.DATA.PACKET KERMITSTATE)
	      (\KERMITMSG I))
	    ((NOT DONE)
	      (ERROR "No characters to send, but not done either." KERMITSTATE])

(\KERMIT.SEND.FILE.HEADER
  [LAMBDA (FILENAME KERMITSTATE)                             (* ejs: " 3-Jul-85 16:10")

          (* * Receive the file header, open the file according to TYPE, and return)


    (\KERMIT.SEND.PACKET (PACKFILENAME.STRING (QUOTE NAME)
					      (FILENAMEFIELD FILENAME (QUOTE NAME))
					      (QUOTE EXTENSION)
					      (FILENAMEFIELD FILENAME (QUOTE EXTENSION)))
			 KERMIT.FILEHEADER.PACKET KERMITSTATE)
    (replace (KERMITSTATE STATE) of KERMITSTATE with (QUOTE SEND.DATA])

(\KERMIT.SEND.PACKET
  (LAMBDA (CONTENTS TYPE KERMITSTATE SEQNO)                  (* ejs: " 4-Oct-85 16:36")

          (* * Send a packet and wait for the response)


    (DECLARE (USEDFREE KERMITSTATUSWINDOW))
    (LET ((INSTREAM (fetch (KERMITSTATE INSTREAM) of KERMITSTATE))
	  (OUTSTREAM (fetch (KERMITSTATE OUTSTREAM) of KERMITSTATE))
	  (CURRENTSEQNO (fetch (KERMITSTATE CURRENTSEQNO) of KERMITSTATE))
	  ANSWER.PACKET LENGTH SEQ ANSWER.TYPE CHAR (CHECKSUM 0))
         (\KERMIT.CLEAR.INPUT.BUFFER INSTREAM)
         (\KERMITTRACE "P:")
         (\KERMIT.SEND.STRING CONTENTS TYPE KERMITSTATE SEQNO)
         (COND
	   ((AND (EQ TYPE KERMIT.GENERIC.SERVER.COMMAND)
		   (FMEMB (CHCON1 CONTENTS)
			    (CONSTANT (BQUOTE (, (CHARCODE F)
						     ,
						     (CHARCODE L))))))
	     (SETQ ANSWER.PACKET T))
	   (T (for RETRIES from 1 to KERMIT.DEFAULT.RETRY.COUNT until ANSWER.PACKET
		 do (COND
			((NEQ RETRIES 1)
			  (PRIN1 "." KERMITSTATUSWINDOW)))
		      (COND
			((bind GOTIT until (OR (AND (EQ (SETQ CHAR (\KERMIT.TIMED.BIN
								      INSTREAM 
								      KERMIT.DEFAULT.TIMEOUT.TIME))
								  (fetch (KERMITSTATE MARKCHAR)
								     of KERMITSTATE))
							    (SETQ GOTIT T))
						     (NULL CHAR))
			    finally (RETURN GOTIT))
			  (\KERMITTRACE "[")
			  (COND
			    ((NOT (SETQ CHECKSUM (\KERMIT.TIMED.BIN INSTREAM 
								      KERMIT.DEFAULT.TIMEOUT.TIME)))
			      (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
					       KERMITSTATE)
			      (GO $$ITERATE)))
			  (COND
			    ((ILEQ (SETQ LENGTH (\KERMIT.UNCHAR CHECKSUM))
				     0)
			      (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
					       KERMITSTATE)
			      (GO $$ITERATE)))
			  (SETQ ANSWER.PACKET (ALLOCSTRING (IPLUS LENGTH KERMIT.PACKET.LEN)))
			  (\KERMITTRACE LENGTH)
			  (RPLCHARCODE ANSWER.PACKET KERMIT.PACKET.LEN LENGTH)
			  (COND
			    ((NOT (for I from KERMIT.PACKET.SEQ
				       to (IPLUS LENGTH (CONSTANT (SUB1 KERMIT.PACKET.LEN)))
				       do (COND
					      ((NOT (SETQ CHAR (\KERMIT.TIMED.BIN INSTREAM 
								      KERMIT.DEFAULT.TIMEOUT.TIME)))
						(\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT)
								    of KERMITSTATE)
								 KERMITSTATE)
						(SETQ ANSWER.PACKET NIL)
						(RETURN)))
					    (add CHECKSUM CHAR)
					    (RPLCHARCODE ANSWER.PACKET I CHAR)
				       finally (RETURN T)))
			      (GO $$ITERATE)))
			  (SETQ TYPE (NTHCHARCODE ANSWER.PACKET KERMIT.PACKET.TYPE))
			  (\KERMITTRACE (CONCAT " " (CHARACTER TYPE)
						  "]"))
			  (COND
			    ((ILESSP (SETQ SEQ (\KERMIT.UNCHAR (NTHCHARCODE ANSWER.PACKET 
										KERMIT.PACKET.SEQ)))
				       0)
			      (SETQ ANSWER.PACKET NIL)
			      (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
					       KERMITSTATE)
			      (GO $$ITERATE)))
			  (RPLCHARCODE ANSWER.PACKET KERMIT.PACKET.SEQ SEQ)
			  (COND
			    ((NEQ (\KERMIT.DEFAULT.CHECKSUM CHECKSUM)
				    (\KERMIT.TIMED.BIN INSTREAM KERMIT.DEFAULT.TIMEOUT.TIME))
			      (\KERMITTRACE "X ")
			      (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
					       KERMITSTATE)
			      (SETQ ANSWER.PACKET NIL))
			    ((OR (AND (EQ SEQ CURRENTSEQNO)
					  (EQ TYPE KERMIT.ACK.PACKET))
				   (AND (EQ SEQ (ADD1 CURRENTSEQNO))
					  (EQ TYPE KERMIT.NAK.PACKET)))
			      (replace (KERMITSTATE LASTPACKETIN) of KERMITSTATE with 
										    ANSWER.PACKET)
			      (\KERMITTRACE SEQ)
			      (\KERMIT.INCREMENT.SEQNO KERMITSTATE)
			      (RETURN))
			    ((EQ TYPE KERMIT.ERROR.PACKET)
			      (ERROR (\KERMIT.DATASECTION ANSWER.PACKET)
				       (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)))
			    ((EQ TYPE KERMIT.NAK.PACKET)
			      (\KERMITTRACE SEQ)
			      (BREAK1 NIL T)
			      (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
					       KERMITSTATE)
			      (SETQ ANSWER.PACKET NIL))
			    (T (\KERMITTRACE (CONCAT "E(" SEQ "-" CURRENTSEQNO ")"))
			       (\KERMITTRACE (\KERMIT.DATASECTION ANSWER.PACKET))
			       (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
						KERMITSTATE)
			       (SETQ ANSWER.PACKET NIL))))
			(T (\KERMIT.WRITE (fetch (KERMITSTATE LASTPACKETOUT) of KERMITSTATE)
					    KERMITSTATE))))))
         (COND
	   (ANSWER.PACKET)
	   (T (ERROR "Remote Kermit not responding"))))))

(\KERMIT.SEND.PARAMETERS
  [LAMBDA (KERMITSTATE)                                      (* ejs: " 8-Jun-85 17:48")
    (LET [(MYPARAMETERS (ALLOCSTRING (CONSTANT (LENGTH \KERMIT.INIT.PARAMETER.OFFSETS]
         (RPLCHARCODE MYPARAMETERS \KPARM.MAXL (\KERMIT.CHAR KERMIT.DEFAULT.RECV.PACKET.SIZE))
         (RPLCHARCODE MYPARAMETERS \KPARM.TIME (\KERMIT.CHAR (IQUOTIENT KERMIT.DEFAULT.TIMEOUT.TIME 
									1000)))
         (RPLCHARCODE MYPARAMETERS \KPARM.NPAD (\KERMIT.CHAR 0))
         (RPLCHARCODE MYPARAMETERS \KPARM.PADC (\KERMIT.CHAR 0))
         (RPLCHARCODE MYPARAMETERS \KPARM.EOL (\KERMIT.CHAR 0))
         (RPLCHARCODE MYPARAMETERS \KPARM.QCTL KERMIT.DEFAULT.PREFIX.CHARACTER)
         (RPLCHARCODE MYPARAMETERS \KPARM.QBIN (CHARCODE &))
         (SELECTQ (fetch (KERMITSTATE STATE) of KERMITSTATE)
		  (REC.INIT (\KERMIT.SEND.DATA MYPARAMETERS KERMIT.ACK.PACKET KERMITSTATE))
		  (SEND.INIT (\KERMIT.SEND.PACKET MYPARAMETERS KERMIT.SENDINIT.PACKET KERMITSTATE))
		  (ERROR "Illegal Kermit state"])

(\KERMIT.SEND.STRING
  (LAMBDA (STRING TYPE KERMITSTATE SEQNO)                    (* ejs: " 7-Oct-85 09:06")

          (* * Send a string of data to the remote kermit. The string MUST have been prefixified already)


    (LET* ((STREAM (fetch (KERMITSTATE OUTSTREAM) of KERMITSTATE))
	   (LENGTH (NCHARS STRING))
	   (PACKET (ALLOCSTRING (IPLUS LENGTH \KERMITOVLEN)))
	   (CHECKSUM 0)
	   TEMP)
          (RPLCHARCODE PACKET KERMIT.PACKET.MARK (fetch (KERMITSTATE MARKCHAR) of KERMITSTATE))
          (RPLCHARCODE PACKET KERMIT.PACKET.LEN (SETQ CHECKSUM
			   (\KERMIT.CHAR (IPLUS LENGTH (CONSTANT (IDIFFERENCE \KERMITOVLEN 
										KERMIT.PACKET.LEN)))))
			 )
          (SETQ TEMP (\KERMIT.CHAR (OR SEQNO (fetch (KERMITSTATE CURRENTSEQNO) of KERMITSTATE)
					   )))
          (add CHECKSUM TEMP)
          (RPLCHARCODE PACKET KERMIT.PACKET.SEQ TEMP)
          (add CHECKSUM TYPE)
          (RPLCHARCODE PACKET KERMIT.PACKET.TYPE TYPE)
          (COND
	    ((NEQ 0 LENGTH)
	      (bind CHAR for I from \KERMITOVLEN to (IPLUS LENGTH (CONSTANT (SUB1
											  
										     \KERMITOVLEN)))
		 as J from 1 to LENGTH
		 do (SETQ CHAR (NTHCHARCODE STRING J))
		      (COND
			((ILESSP CHAR (CHARCODE SPACE))
			  (ERROR "Call to \KERMIT.SEND.STRING with unprefixed characters: " STRING))
			)
		      (add CHECKSUM CHAR)
		      (RPLCHARCODE PACKET I CHAR))))
          (RPLCHARCODE PACKET (NCHARS PACKET)
			 (\KERMIT.DEFAULT.CHECKSUM CHECKSUM))
          (\KERMIT.WRITE PACKET KERMITSTATE)
          (replace (KERMITSTATE LASTPACKETOUT) of KERMITSTATE with PACKET)
      PACKET)))

(\KERMIT.SHOW.PACKET
  (LAMBDA (PACKET)                                           (* ejs: " 8-Jun-85 16:03")
    (printout T T "[1]" 20 (CHARACTER (NTHCHARCODE PACKET 1))
	      T "[2]" 20 (\KERMIT.UNCHAR (NTHCHARCODE PACKET 2))
	      T "[3]" 20 (NTHCHARCODE PACKET 3)
	      T "[4]" 20 (CHARACTER (NTHCHARCODE PACKET 4))
	      T)
    (LET ((LEN (\KERMIT.UNCHAR (NTHCHARCODE PACKET 2))))
      (for I from KERMIT.PACKET.DATA to (IPLUS KERMIT.PACKET.DATA (IDIFFERENCE LEN KERMIT.PACKET.DATA)
					       )
	 do (printout T "[" I "]" 20 (CHARACTER (NTHCHARCODE PACKET I))
		      T))
      (printout T "[" (NCHARS PACKET)
		"]" 20 (\KERMIT.UNCHAR (NTHCHARCODE PACKET (NCHARS PACKET)))
		T))))

(\KERMIT.TIMED.BIN
  (LAMBDA (STREAM TIMER.OR.TIMEOUT TIMERP)                   (* ejs: " 5-Jul-85 17:20")

          (* * If stream is READP, does a BIN, otherwise, waits for the stream's READPEVENT to be notified, using 
	  TIMER.OR.TIMEOUT arg to AWAIT.EVENT. If stream is not READP at the end of this interval, returns NIL)


    (COND
      ((READP STREAM)
	(BIN STREAM))
      (T (bind (EVENT ←(STREAMPROP STREAM (QUOTE READPEVENT)))
	       (TIMER ←(COND
			(TIMERP TIMER.OR.TIMEOUT)
			(T (SETUPTIMER TIMER.OR.TIMEOUT))))
	       READP until (OR (SETQ READP (READP STREAM))
			       (TIMEREXPIRED? TIMER))
	    do (COND
		 (EVENT (AWAIT.EVENT EVENT TIMER T))
		 (T (BLOCK)))
	    finally (RETURN (COND
			      (READP (BIN STREAM)))))))))

(\KERMIT.UNPREFIXIFY
  (LAMBDA (STRING QCTL QBIN OLDSUBSTRING)                    (* ejs: " 3-Jul-85 21:04")

          (* * Return a string in which all prefix chars have been undone)


    (LET* ((ORIGINALLENGTH (NCHARS STRING))
       (NEWSTRING (ALLOCSTRING ORIGINALLENGTH)))
      (bind CHAR 8BITPREFIX for I from 1 to ORIGINALLENGTH as J from 1
	 do (SETQ CHAR (NTHCHARCODE STRING I))
	    (COND
	      ((EQ CHAR QBIN)
		(add I 1)
		(SETQ CHAR (NTHCHARCODE STRING I))
		(SETQ 8BITPREFIX T)))
	    (COND
	      ((EQ CHAR QCTL)
		(add I 1)
		(SETQ CHAR (NTHCHARCODE STRING I))
		(COND
		  ((AND (NEQ CHAR QCTL)
			(NEQ CHAR QBIN))
		    (SETQ CHAR (\KERMIT.CTL CHAR))))))
	    (COND
	      (8BITPREFIX (SETQ 8BITPREFIX NIL)
			  (RPLCHARCODE NEWSTRING J (LOGOR CHAR 128)))
	      (T (RPLCHARCODE NEWSTRING J CHAR)))
	 finally (RETURN (SUBSTRING NEWSTRING 1 (SUB1 J)
				    OLDSUBSTRING))))))

(\KERMIT.WRITE
  [LAMBDA (STRING KERMITSTATE)                               (* ejs: " 8-Jun-85 13:25")

          (* * Sends STRING out on STREAM with FORCEOUTPUT)


    (LET ((STREAM (fetch (KERMITSTATE OUTSTREAM) of KERMITSTATE))
	  (EOL (fetch (KERMITSTATE EOL) of KERMITSTATE))
	  (NPAD (fetch (KERMITSTATE NPAD) of KERMITSTATE))
	  PADC)
         [COND
	   ((NEQ 0 NPAD)
	     (SETQ PADC (fetch (KERMITSTATE PADC) of KERMITSTATE))
	     (for I from 1 to NPAD do (BOUT STREAM PADC]
         (PRIN3 STRING STREAM)
         (COND
	   (EOL (BOUT STREAM EOL)))
         (FORCEOUTPUT STREAM])
)



(* User callable functions)

(DEFINEQ

(KERMIT.RECEIVE
  (LAMBDA (REMOTEFILE LOCALFILE WINDOW TYPE)                 (* ejs: " 4-Oct-85 17:47")

          (* * Receive a file from a remote Kermit)


    (DECLARE (SPECVARS KERMITSTATUSWINDOW))
    (OR WINDOW (SETQ WINDOW (GETTOPVAL (QUOTE CHATWINDOW))))
    (COND
      ((NOT (WINDOWPROP WINDOW (QUOTE CHATSTATE)))
	(ERROR WINDOW "is not a Chat window"))
      ((AND REMOTEFILE LOCALFILE)
	(LET* ((CHATSTATE (WINDOWPROP WINDOW (QUOTE CHATSTATE)))
	       (TYPEOUTPROC (fetch (CHAT.STATE TYPEOUTPROC) of CHATSTATE))
	       (KERMITSTATUSWINDOW (GETPROMPTWINDOW WINDOW))
	       (OUTSTREAM (fetch (CHAT.STATE OUTSTREAM) of CHATSTATE))
	       (KERMITSTATE (create KERMITSTATE
				      INSTREAM ←(fetch (CHAT.STATE INSTREAM) of CHATSTATE)
				      OUTSTREAM ← OUTSTREAM
				      EOLCONVENTION ←(COND
					((EQ TYPE (QUOTE TEXT))
					  CRLF.EOLC)
					(T NIL)))))
	      (\KERMIT.SEND.STRING (MKSTRING REMOTEFILE)
				     (CHARCODE R)
				     KERMITSTATE 0)
	      (RESETLST (RESETSAVE (PROGN (SUSPEND.PROCESS TYPEOUTPROC)
						(CLEARW WINDOW))
				       (LIST (FUNCTION (LAMBDA NIL
						   (AND RESETSTATE (\KERMIT.SEND.ERROR 
								       "User aborted transaction"
											 KERMITSTATE))
						   (RESTART.PROCESS TYPEOUTPROC)
						   (\KERMITMSG (COND
								 (RESETSTATE "Kermit aborted")
								 (T "Kermit file transfer completed"))
							       )))))
			  (\KERMIT.RECEIVE.FILE LOCALFILE KERMITSTATE KERMITSTATUSWINDOW))))
      (T (printout (GETPROMPTWINDOW WINDOW)
		   T "You must specify both a local and remote file name")))))

(KERMIT.SEND
  (LAMBDA (LOCALFILE REMOTEFILE WINDOW TYPE)                 (* ejs: " 7-Oct-85 08:19")

          (* * Send a file to a remote kermit)


    (DECLARE (SPECVARS KERMITSTATUSWINDOW))
    (OR WINDOW (SETQ WINDOW (GETTOPVAL (QUOTE CHATWINDOW))))
    (COND
      (LOCALFILE (LET* ((CHATSTATE (WINDOWPROP WINDOW (QUOTE CHATSTATE)))
			(TYPEOUTPROC (fetch (CHAT.STATE TYPEOUTPROC) of CHATSTATE))
			(KERMITSTATUSWINDOW (GETPROMPTWINDOW WINDOW))
			(OUTSTREAM (fetch (CHAT.STATE OUTSTREAM) of CHATSTATE))
			(KERMITSTATE (create KERMITSTATE
					       INSTREAM ← (fetch (CHAT.STATE INSTREAM)
							     of CHATSTATE)
					       OUTSTREAM ← OUTSTREAM
					       EOL ← (CHARCODE EOL)
					       EOLCONVENTION ← (COND
						 ((EQ TYPE (QUOTE TEXT))
						   CRLF.EOLC)
						 (T NIL)))))
		       (RESETLST (RESETSAVE (PROGN (SUSPEND.PROCESS TYPEOUTPROC)
							 (CLEARW WINDOW))
						(LIST (FUNCTION (LAMBDA NIL
							    (COND
							      (RESETSTATE (\KERMIT.SEND.ERROR 
										 "Kermit aborted"
											      
										      KERMITSTATE)))
							    (RESTART.PROCESS TYPEOUTPROC)
							    (\KERMITMSG (COND
									  (RESETSTATE 
										 "Kermit aborted")
									  (T 
								 "Kermit file transfer completed")))))
							))
				   (\KERMIT.SEND.FILE LOCALFILE REMOTEFILE TYPE KERMITSTATE 
							KERMITSTATUSWINDOW))))
      (T "You must specify a file name"))))

(KERMIT.SERVER.COMMAND
  (LAMBDA (COMMAND SUBCOMMAND WINDOW)                      (* ejs: " 4-Oct-85 16:33")

          (* * Cause the remote Kermit to execute a subcommand)


    (LET* ((CHATSTATE (WINDOWPROP WINDOW (QUOTE CHATSTATE)))
	   (TYPEOUTPROC (fetch (CHAT.STATE TYPEOUTPROC) of CHATSTATE))
	   (KERMITSTATUSWINDOW (GETPROMPTWINDOW WINDOW NIL NIL T))
	   (OUTSTREAM (fetch (CHAT.STATE OUTSTREAM) of CHATSTATE))
	   (KERMITSTATE (create KERMITSTATE
				  INSTREAM ←(fetch (CHAT.STATE INSTREAM) of CHATSTATE)
				  OUTSTREAM ← OUTSTREAM)))
          (\KERMIT.SEND.PACKET (MKSTRING SUBCOMMAND)
				 (COND
				   ((SMALLP COMMAND)
				     COMMAND)
				   ((OR (ATOM COMMAND)
					  (STRINGP COMMAND))
				     (CHCON1 COMMAND))
				   (T (ERROR "Bad command" COMMAND)))
				 KERMITSTATE 0))))
)



(* Kermit TTY executive, for running Kermit without the TEdit menu)

(DEFINEQ

(KERMIT
  (LAMBDA NIL                                                (* ejs: " 7-Jul-85 23:11")
    (bind COMMAND while T
       do (COND
	    ((NEQ 1 (POSITION))
	      (TERPRI)))
	  (SETQ COMMAND (ASKUSER NIL NIL "Kermit> " (QUOTE ((PUSH 
				      " (to a lower Interlisp exec--type OK to return to Kermit)")
							     (QUIT " (Kermit)")
							     (RECEIVE " (file) ")
							     (SEND " (file) ")
							     (SET " (parameter) ")))))
	  (SELECTQ COMMAND
		   (PUSH (TERPRI)
			 (USEREXEC "←←"))
		   (QUIT (TERPRI)
			 (RETURN))
		   (RECEIVE (KERMIT.EXEC.RECEIVE))
		   (SEND (KERMIT.EXEC.SEND))
		   (SET (KERMIT.EXEC.SET))
		   NIL))))

(KERMIT.EXEC.DEBUGGING
  (LAMBDA NIL                                                (* ejs: " 7-Jul-85 22:47")
    (COND
      ((KERMIT.EXEC.ON.OFF NIL)
	(SETQ \KERMITTRACEFILE PROMPTWINDOW))
      (T (SETQ \KERMITTRACEFILE NIL)))))

(KERMIT.EXEC.FILE
  (LAMBDA NIL                                                (* ejs: " 7-Jul-85 22:57")
    (SELECTQ (ASKUSER NIL NIL NIL (QUOTE ((TYPE " (of files transferred) "))))
	     (TYPE (KERMIT.EXEC.FILE.TYPE))
	     NIL)))

(KERMIT.EXEC.FILE.TYPE
  (LAMBDA (PROMPT)                                           (* ejs: " 7-Jul-85 23:19")
    (SETQ KERMIT.DEFAULT.FILETYPE (ASKUSER NIL NIL PROMPT (QUOTE ((BINARY " (files)")
								   (TEXT " (files)")))))))

(KERMIT.EXEC.ON.OFF
  (LAMBDA (PROMPT)                                           (* ejs: " 7-Jul-85 22:43")
    (ASKUSER NIL NIL PROMPT (QUOTE ((ON "" RETURN T)
				     (OFF "" RETURN NIL))))))

(KERMIT.EXEC.RECEIVE
  (LAMBDA NIL                                                (* ejs: " 7-Jul-85 23:21")
    (LET ((REMOTEFILE (bind F until (SETQ F (PROMPTFORWORD " (remote file) ")) finally (RETURN F)))
       (LOCALFILE (bind F until (SETQ F (PROMPTFORWORD " (to local file) ")) finally (RETURN F))))
      (COND
	((NOT (\KERMIT.LIVE.CHATWINDOW KERMIT.DEFAULT.CHATWINDOW))
	  (printout T T "You must choose a valid Chat window first")
	  (KERMIT.SET.KERMIT.WINDOW)))
      (COND
	((NOT (FMEMB KERMIT.DEFAULT.FILETYPE (QUOTE (TEXT BINARY))))
	  (KERMIT.EXEC.FILE.TYPE "Kermit> SET (parameter) FILE (mode) TYPE (of files transferred) ")))
      (KERMIT.RECEIVE REMOTEFILE LOCALFILE KERMIT.DEFAULT.CHATWINDOW KERMIT.DEFAULT.FILETYPE))))

(KERMIT.EXEC.SEND
  (LAMBDA NIL                                                (* ejs: " 7-Jul-85 23:18")
    (LET ((LOCALFILE (bind F until (INFILEP (SETQ F (PROMPTFORWORD))) do (printout T " (local file) ")
			finally (RETURN F)))
       (REMOTEFILE (bind F until (SETQ F (PROMPTFORWORD " (to remote file) ")) finally (RETURN F))))
      (COND
	((NOT (\KERMIT.LIVE.CHATWINDOW KERMIT.DEFAULT.CHATWINDOW))
	  (printout T T "You must choose a valid Chat window first")
	  (KERMIT.SET.KERMIT.WINDOW)))
      (COND
	((NOT (FMEMB KERMIT.DEFAULT.FILETYPE (QUOTE (TEXT BINARY))))
	  (KERMIT.EXEC.FILE.TYPE "Kermit> SET (parameter) FILE (mode) TYPE (of files transferred) ")))
      (KERMIT.SEND LOCALFILE REMOTEFILE KERMIT.DEFAULT.CHATWINDOW KERMIT.DEFAULT.FILETYPE))))

(KERMIT.EXEC.SET
  (LAMBDA NIL                                                (* ejs: " 7-Jul-85 23:11")
    (LET ((MODE (ASKUSER NIL NIL NIL (QUOTE ((DEBUGGING " (mode) ")
					      (FILE " (mode) ")
					      (WINDOW " (for Kermit operations) "))))))
      (SELECTQ MODE
	       (DEBUGGING (KERMIT.EXEC.DEBUGGING))
	       (FILE (KERMIT.EXEC.FILE))
	       (WINDOW (KERMIT.SET.KERMIT.WINDOW))
	       NIL))))

(KERMIT.SET.KERMIT.WINDOW
  (LAMBDA NIL                                                (* ejs: " 7-Jul-85 23:06")
    (printout PROMPTWINDOW T "Please button inside an open Chat window")
    (bind WINDOW until (\KERMIT.LIVE.CHATWINDOW (SETQ WINDOW (WHICHW (GETPOSITION))))
       do (COND
	    (WINDOW (printout PROMPTWINDOW T "That window is not a live Chat window"))
	    (T printout PROMPTWINDOW T "Please button INSIDE an open Chat window"))
       finally (RETURN (SETQ KERMIT.DEFAULT.CHATWINDOW WINDOW)))))

(\KERMIT.LIVE.CHATWINDOW
  (LAMBDA (WINDOW)                                           (* ejs: " 7-Jul-85 23:02")
    (COND
      ((WINDOWP WINDOW)
	(COND
	  ((WINDOWPROP WINDOW (QUOTE CHATSTATE))
	    T))))))
)



(* The MODEM program. A sad subset and precursor to KERMIT, but here only for the sake of 
compatibility)

(DECLARE: DONTCOPY 
(* FOLLOWING DEFINITIONS EXPORTED)



(RPAQQ MODEMCOMMANDS ((MODEM.SOH 1)
		      (MODEM.ACK 6)
		      (MODEM.NAK 21)
		      (MODEM.EOT 4)))
(DECLARE: EVAL@COMPILE 

(RPAQQ MODEM.SOH 1)

(RPAQQ MODEM.ACK 6)

(RPAQQ MODEM.NAK 21)

(RPAQQ MODEM.EOT 4)

(CONSTANTS (MODEM.SOH 1)
	   (MODEM.ACK 6)
	   (MODEM.NAK 21)
	   (MODEM.EOT 4))
)
(DECLARE: EVAL@COMPILE 

(RPAQQ MODEM.PACKET.LENGTH 128)

(CONSTANTS (MODEM.PACKET.LENGTH 128))
)


(* END EXPORTED DEFINITIONS)

)

(RPAQ? MODEM.MAX.RETRIES 10)

(RPAQ? MODEM.TIMEOUT 10000)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS MODEM.TIMEOUT MODEM.MAX.RETRIES)
)
(DEFINEQ

(MODEM.RECEIVE
  (LAMBDA (LOCALFILE WINDOW TYPE EOLCONVENTION)              (* ejs: " 7-Oct-85 09:01")
    (DECLARE (SPECVARS KERMITSTATUSWINDOW))
    (OR WINDOW (SETQ WINDOW (GETTOPVAL (QUOTE CHATWINDOW))))
    (LET* ((CHATSTATE (WINDOWPROP WINDOW (QUOTE CHATSTATE)))
	   (TYPEOUTPROC (fetch (CHAT.STATE TYPEOUTPROC) of CHATSTATE))
	   (KERMITSTATUSWINDOW (GETPROMPTWINDOW WINDOW))
	   (OUTSTREAM (fetch (CHAT.STATE OUTSTREAM) of CHATSTATE))
	   (EOLTYPE (SELECTQ EOLCONVENTION
			       (CR CR.EOLC)
			       (LF LF.EOLC)
			       (CRLF CRLF.EOLC)
			       (\ILLEGAL.ARG EOLCONVENTION)))
	   (FILESTREAM (OPENSTREAM LOCALFILE (QUOTE OUTPUT)
				     (QUOTE NEW)
				     (BQUOTE ((TYPE (\, TYPE)))))))
          (RESETLST (RESETSAVE NIL (LIST (FUNCTION (LAMBDA (STR)
						   (CLOSEF STR)
						   (COND
						     (RESETSTATE (DELFILE (FULLNAME STR))))))
					       FILESTREAM))
		      (RESETSAVE (PROGN (SUSPEND.PROCESS TYPEOUTPROC)
					    (CLEARW WINDOW))
				   (LIST (FUNCTION (LAMBDA NIL
					       (RESTART.PROCESS TYPEOUTPROC)
					       (\KERMITMSG (COND
							     (RESETSTATE "Modem aborted")
							     (T "Modem file transfer completed")))))))
		      (\KERMITMSG (BQUOTE (Receiving file (\, (FULLNAME FILESTREAM)))))
		      (\MODEM.RECEIVE.FILE.BYTES FILESTREAM (\MODEM.INITIALIZE
						     (create KERMITSTATE
							       INSTREAM ← (fetch (CHAT.STATE 
											 INSTREAM)
									     of CHATSTATE)
							       OUTSTREAM ← OUTSTREAM
							       EOLCONVENTION ←
							       (COND
								 ((EQ TYPE (QUOTE TEXT))
								   EOLTYPE)
								 (T NIL)))
						     (QUOTE RECEIVE))
						   TYPE)))))

(MODEM.SEND
  [LAMBDA (LOCALFILE WINDOW TYPE EOLCONVENTION)              (* ejs: "15-Sep-85 17:23")

          (* * Send a file to a remote modem program)


    (DECLARE (SPECVARS KERMITSTATUSWINDOW))
    [OR WINDOW (SETQ WINDOW (GETTOPVAL (QUOTE CHATWINDOW]
    (COND
      [(AND LOCALFILE (SETQ LOCALFILE (INFILEP LOCALFILE)))
	(LET* [(CHATSTATE (WINDOWPROP WINDOW (QUOTE CHATSTATE)))
	       (TYPEOUTPROC (fetch (CHAT.STATE TYPEOUTPROC) of CHATSTATE))
	       (KERMITSTATUSWINDOW (GETPROMPTWINDOW WINDOW))
	       (OUTSTREAM (fetch (CHAT.STATE OUTSTREAM) of CHATSTATE))
	       (EOLTYPE (SELECTQ EOLCONVENTION
				 (CR CR.EOLC)
				 (LF LF.EOLC)
				 (CRLF CRLF.EOLC)
				 (\ILLEGAL.ARG EOLCONVENTION)))
	       (KERMITSTATE (create KERMITSTATE
				    INSTREAM ←(fetch (CHAT.STATE INSTREAM) of CHATSTATE)
				    OUTSTREAM ← OUTSTREAM
				    EOLCONVENTION ←(COND
				      ((EQ TYPE (QUOTE TEXT))
					EOLTYPE)
				      (T NIL]
	      (RESETLST [RESETSAVE (PROGN (SUSPEND.PROCESS TYPEOUTPROC)
					  (CLEARW WINDOW))
				   (LIST (FUNCTION (LAMBDA NIL
					     (RESTART.PROCESS TYPEOUTPROC)
					     (\KERMITMSG (COND
							   (RESETSTATE "Modem aborted")
							   (T "Modem file transfer completed"]
			(\MODEM.SEND.FILE LOCALFILE REMOTEFILE TYPE KERMITSTATE KERMITSTATUSWINDOW]
      (T (HELP "Can't find input file"])

(\MODEM.INITIALIZE
  [LAMBDA (KERMITSTATE FORWHAT)                              (* ejs: " 3-Sep-85 20:31")
    (with KERMITSTATE KERMITSTATE (COND
	    ((NOT (OPENP OUTSTREAM (QUOTE OUTPUT)))
	      (ERROR "KERMIT output stream is not open for output!" OUTSTREAM))
	    ((NOT (OPENP INSTREAM (QUOTE INPUT)))
	      (ERROR "KERMIT input stream is not open for input!" INSTREAM)))
	  (SELECTQ FORWHAT
		   (RECEIVE (SETQ CURRENTSEQNO 1)
			    (SETQ STATE (QUOTE REC.INIT)))
		   (STORE (SETQ CURRENTSEQNO 0)
			  (SETQ STATE (QUOTE SEND.INIT)))
		   (ERROR "Illegal Kermit operation" FORWHAT))
	  KERMITSTATE])

(\MODEM.SEND.FILE
  [LAMBDA (LOCALFILE REMOTEFILE TYPE KERMITSTATE KERMITSTATUSWINDOW)
                                                             (* ejs: " 3-Sep-85 12:25")

          (* * Send a file)


    (LET (FILESTREAM)
         (\MODEM.INITIALIZE KERMITSTATE (QUOTE STORE))
         [SETQ FILESTREAM (OPENSTREAM LOCALFILE (QUOTE INPUT)
				      (QUOTE OLD)
				      (BQUOTE ((TYPE , TYPE)
					       (SEQUENTIAL T]
         (SELECTQ (fetch (KERMITSTATE STATE) of KERMITSTATE)
		  (SEND.INIT (\KERMITMSG (LIST (QUOTE Sending)
					       (FULLNAME FILESTREAM)))
			     (RESETLST (RESETSAVE NIL (LIST [FUNCTION (LAMBDA (STREAM)
								(CLOSEF? STREAM)
								(\MODEM.SEND.PACKET NIL MODEM.EOT 
										    KERMITSTATE)
								(replace (KERMITSTATE STATE)
								   of KERMITSTATE
								   with (QUOTE COMPLETE]
							    FILESTREAM))
				       (\MODEM.SEND.FILE.BYTES FILESTREAM KERMITSTATE TYPE)))
		  (COMPLETE (\KERMITMSG "Done"))
		  (ABORT (ERROR "Remote kermit aborted"))
		  (ERROR "Unexpected state after SEND.FILE" KERMITSTATE])

(\MODEM.SEND.FILE.BYTES
  [LAMBDA (FILESTREAM KERMITSTATE TYPE)                      (* ejs: "15-Sep-85 15:38")

          (* * Send all the bytes of file)


    (replace (STREAM ENDOFSTREAMOP) of FILESTREAM with (FUNCTION [LAMBDA NIL -1]))
    (LET ([EOLWORRIES (AND (NEQ TYPE (QUOTE BINARY))
			   (NEQ (fetch (STREAM EOLCONVENTION) of FILESTREAM)
				(fetch (KERMITSTATE EOLCONVENTION) of KERMITSTATE]
	  (INPUT.EOL.IS.CRLF (EQ (fetch (STREAM EOLCONVENTION) of FILESTREAM)
				 CRLF.EOLC)))
         (bind (PACKET ←(ALLOCSTRING MODEM.PACKET.LENGTH))
	       [EASYEOLWORRIES ←(AND EOLWORRIES (OR (AND (EQ (fetch (STREAM EOLCONVENTION)
								of FILESTREAM)
							     CR.EOLC)
							 (EQ (fetch (KERMITSTATE EOLCONVENTION)
								of KERMITSTATE)
							     LF.EOLC))
						    (AND (EQ (fetch (STREAM EOLCONVENTION)
								of FILESTREAM)
							     LF.EOLC)
							 (EQ (fetch (KERMITSTATE EOLCONVENTION)
								of KERMITSTATE)
							     CR.EOLC]
	       [FILEOLCHAR ←(AND EOLWORRIES (SELECTC (fetch (STREAM EOLCONVENTION) of FILESTREAM)
						     (LF.EOLC (CHARCODE LF))
						     (CR.EOLC (CHARCODE CR))
						     [CRLF.EOLC (CONSTANT (LIST (CHARCODE CR)
										(CHARCODE LF]
						     (ERROR "Illegal EOL convention on file"
							    (fetch (STREAM EOLCONVENTION)
							       of FILESTREAM]
	       [MODEMEOLCHAR ←(AND EOLWORRIES (SELECTC (fetch (KERMITSTATE EOLCONVENTION)
							  of KERMITSTATE)
						       (LF.EOLC (CHARCODE LF))
						       (CR.EOLC (CHARCODE CR))
						       [CRLF.EOLC (CONSTANT (LIST (CHARCODE CR)
										  (CHARCODE LF]
						       (ERROR 
						     "Illegal EOL convention on modem connection"
							      (fetch (STREAM EOLCONVENTION)
								 of FILESTREAM]
	       DONE CHAR WAITINGCHAR LFPENDING CHARINDEX until DONE as I from 1
	    do (\ZEROBYTES (\ADDBASE (fetch (STRINGP BASE) of PACKET)
				     (fetch (STRINGP OFFST) of PACKET))
			   0
			   (SUB1 (fetch (STRINGP LENGTH) of PACKET)))
	       (for old CHARINDEX from 1 to MODEM.PACKET.LENGTH
		  do [SETQ CHAR (COND
			 (LFPENDING (SETQ LFPENDING NIL)
				    (CHARCODE LF))
			 (T (BIN FILESTREAM]
		     [COND
		       ((EQ -1 CHAR)                         (* Reached EOL on input file)
			 (SETQ DONE T)
			 (RETURN))
		       ((NULL EOLWORRIES)                    (* EOL conventions are no problem)
			 )
		       [EASYEOLWORRIES                       (* EOL convention can be taken care of easily)
				       (COND
					 ((EQ CHAR FILEOLCHAR)
					   (SETQ CHAR MODEMEOLCHAR]
		       [INPUT.EOL.IS.CRLF 

          (* EOL convention will be hard. This means that the input file's EOL convention is CRLF, while the remote file's 
	  convention is CR or LF alone.)


					  (COND
					    ((EQ CHAR (CHARCODE CR))
                                                             (* Perhaps an EOL)
					      (COND
						((EQ (\PEEKBIN FILESTREAM T)
						     (CHARCODE LF))
                                                             (* Yes)
						  (BIN FILESTREAM)
						  (SETQ CHAR MODEMEOLCHAR]
		       (T 

          (* EOL convention is even harder. The input file's EOL convention is CR or LF, while the output file's convention is
	  CRLF. We may have the buffer the LF char across packets)


			  (COND
			    ((EQ CHAR FILEOLCHAR)
			      (SETQ CHAR (CHARCODE CR))
			      (SETQ LFPENDING T]
		     (RPLCHARCODE PACKET CHARINDEX CHAR))
	       (COND
		 ((NEQ 1 CHARINDEX)
		   (\MODEM.SEND.PACKET PACKET MODEM.SOH KERMITSTATE)
		   (\KERMITMSG I))
		 ((NOT DONE)
		   (ERROR "No characters to send, but not done either." KERMITSTATE])

(\MODEM.SEND.PACKET
  (LAMBDA (STRING TYPE KERMITSTATE)                          (* ejs: " 7-Oct-85 10:00")
    (LET ((INSTREAM (fetch (KERMITSTATE INSTREAM) of KERMITSTATE))
	    (OUTSTREAM (fetch (KERMITSTATE OUTSTREAM) of KERMITSTATE))
	    SEQNO NOTSEQNO RESPONSE CHECKSUM)
           (COND
	     ((EQ TYPE MODEM.SOH)

          (* * This packet contains data, and we expect an ack)


	       (SETQ SEQNO (replace (KERMITSTATE CURRENTSEQNO) of KERMITSTATE
				with (LOGAND (ADD1 (fetch (KERMITSTATE CURRENTSEQNO)
							    of KERMITSTATE))
						 (MASK.1'S 0 BITSPERBYTE))))
	       (SETQ NOTSEQNO (LOGAND (LOGNOT SEQNO)
					  (MASK.1'S 0 BITSPERBYTE)))
	       (\KERMITTRACE (CONCAT "P:SOH--" SEQNO "->" NOTSEQNO))
	       (SETQ CHECKSUM (LOGAND (IPLUS MODEM.SOH SEQNO NOTSEQNO
						   (for CHAR instring STRING sum CHAR))
					  (MASK.1'S 0 BITSPERBYTE)))
	       (bind ACKNOWLEDGED (RETRYCOUNT ← 0) until ACKNOWLEDGED
		  do (BOUT OUTSTREAM MODEM.SOH)          (* Send the start of packet indicator)
		       (BOUT OUTSTREAM SEQNO)              (* Send the sequence number)
		       (BOUT OUTSTREAM NOTSEQNO)           (* Send the 1's complement of the seqno)
		       (\BOUTS OUTSTREAM (fetch (STRINGP BASE) of STRING)
				 (fetch (STRINGP OFFST) of STRING)
				 (fetch (STRINGP LENGTH) of STRING))
                                                             (* Send the data)
		       (BOUT OUTSTREAM CHECKSUM)           (* Send the checksum)
		       (COND
			 ((fetch (FDEV BUFFERED) of (fetch (STREAM DEVICE) of OUTSTREAM))
			   (FORCEOUTPUT OUTSTREAM)))       (* If necessary, force the block on its way)
		       (SETQ RESPONSE (\KERMIT.TIMED.BIN INSTREAM MODEM.TIMEOUT))
		       (SELECTC RESPONSE
				  (MODEM.ACK (SETQ ACKNOWLEDGED T)
					     (\KERMITTRACE "! "))
				  (MODEM.NAK (\KERMITTRACE "R")
					     (COND
					       ((EQ (add RETRYCOUNT 1)
						      MODEM.MAX.RETRIES)
						 (\KERMITMSG "Remote MODEM program not responding")
						 (ERROR!))))
				  (PROGN (PRIN1 "." KERMITSTATUSWINDOW)
					   (\KERMITTRACE (COND
							   (RESPONSE (CHARACTER RESPONSE))
							   (T "?")))))))
	     ((EQ TYPE MODEM.EOT)
	       (\KERMITTRACE "P:EOT--")
	       (bind ACKNOWLEDGED (RETRYCOUNT ← 0) until ACKNOWLEDGED
		  do (BOUT OUTSTREAM MODEM.EOT)
		       (COND
			 ((fetch (FDEV BUFFERED) of (fetch (STREAM DEVICE) of OUTSTREAM))
			   (FORCEOUTPUT OUTSTREAM)))
		       (COND
			 ((EQ (\KERMIT.TIMED.BIN INSTREAM MODEM.TIMEOUT)
				MODEM.ACK)
			   (SETQ ACKNOWLEDGED T)
			   (\KERMITTRACE "! "))
			 (T (COND
			      ((EQ (add RETRYCOUNT 1)
				     MODEM.MAX.RETRIES)
				(\KERMITTRACE "R")
				(\KERMITMSG "Remote MODEM program not responding")
				(ERROR!)))))))
	     (T (BOUT OUTSTREAM TYPE)
		(FORCEOUTPUT OUTSTREAM)
		(\KERMITTRACE "P:")
		(\KERMITTRACE (CHARACTER TYPE)))))))

(\MODEM.CLEAR.INPUT
  (LAMBDA (STREAM)                                           (* ejs: " 3-Sep-85 19:59")
    (while (READP STREAM) do (BIN STREAM))))

(\MODEM.RECEIVE.FILE.BYTES
  [LAMBDA (FILESTREAM KERMITSTATE TYPE)                      (* jmh "11-Oct-85 15:58")
    (LET* ([EOLWORRIES (AND (NEQ TYPE (QUOTE BINARY))
			    (NEQ (fetch (STREAM EOLCONVENTION) of FILESTREAM)
				 (fetch (KERMITSTATE EOLCONVENTION) of KERMITSTATE]
	   [FILEOLCHAR (AND (NEQ TYPE (QUOTE BINARY))
			    (SELECTC (fetch (STREAM EOLCONVENTION) of FILESTREAM)
				     (CR.EOLC (CHARCODE CR))
				     (LF.EOLC (CHARCODE LF))
				     [CRLF.EOLC (CONSTANT (LIST (CHARCODE CR)
								(CHARCODE LF]
				     (HELP "Unknown file EOL convention"]
	   [MODEMEOLCHAR (AND (NEQ TYPE (QUOTE BINARY))
			      (SELECTC (fetch (KERMITSTATE EOLCONVENTION) of KERMITSTATE)
				       (CR.EOLC (CHARCODE CR))
				       (LF.EOLC (CHARCODE LF))
				       [CRLF.EOLC (CONSTANT (LIST (CHARCODE CR)
								  (CHARCODE LF]
				       (HELP "Unknown file EOL convention"]
	   [EASYEOLWORRIES (AND EOLWORRIES (OR (AND (EQ FILEOLCHAR (CHARCODE CR))
						    (EQ MODEMEOLCHAR (CHARCODE LF)))
					       (AND (EQ FILEOLCHAR (CHARCODE LF))
						    (EQ MODEMEOLCHAR (CHARCODE CR]
	   (REMOTE.EOL.IS.CRLF (EQ (fetch (KERMITSTATE EOLCONVENTION) of KERMITSTATE)
				   CRLF.EOLC))
	   PACKET LASTWASCR)
          (for I from 1 while (STRINGP (SETQ PACKET (\MODEM.RECEIVE.PACKET KERMITSTATE MODEM.SOH)))
	     do (COND
		  (\KERMITTRACEFILE (TERPRI \KERMITTRACEFILE)
				    [for CH instring PACKET do (COND
								 ((ILESSP CH (CHARCODE SPACE))
								   (printout \KERMITTRACEFILE "[" CH 
									     "]"))
								 (T (PRIN1 (CHARACTER CH)
									   \KERMITTRACEFILE]
				    (TERPRI \KERMITTRACEFILE)))
		[COND
		  ((NULL EOLWORRIES)                         (* EOL convention is no problem.
							     Dump out the packet in one shot)
		    (\BOUTS FILESTREAM (fetch (STRINGP BASE) of PACKET)
			    (fetch (STRINGP OFFST) of PACKET)
			    (fetch (STRINGP LENGTH) of PACKET)))
		  (EASYEOLWORRIES                            (* EOL convention switch is a simple character mapping)
				  (for CHAR instring PACKET
				     do (COND
					  ((EQ CHAR MODEMEOLCHAR)
					    (SETQ CHAR FILEOLCHAR)))
					(BOUT FILESTREAM CHAR)))
		  [(NOT REMOTE.EOL.IS.CRLF)                  (* The local EOL convention is CRLF while the remote is
							     either CR or LF)
		    (for CHAR instring PACKET do (COND
						   ((EQ CHAR MODEMEOLCHAR)
						     (BOUT FILESTREAM (CHARCODE CR))
						     (BOUT FILESTREAM (CHARCODE LF)))
						   (T (BOUT FILESTREAM CHAR]
		  (T                                         (* This is hard. The remote eol convention is CRLF and 
							     ours is either CR or LF)
		     (LET ((BASE (\ADDBASE (fetch (STRINGP BASE) of PACKET)
					   (fetch (STRINGP OFFST) of PACKET)))
			   (LENGTH (fetch (STRINGP LENGTH) of PACKET))
			   (START 0))
		          [COND
			    (LASTWASCR 

          (* The last character of the last packet was a CR. If the first character of the current packet is an LF, we output 
	  a file eol character)


				       (SETQ LASTWASCR NIL)
				       (COND
					 ((EQ (\GETBASEBYTE BASE 0)
					      (CHARCODE LF))
					   (BOUT FILESTREAM FILEOLCHAR)
                                                             (* Yes. Output the right EOL char and skip the first 
							     character in this packet)
					   (SETQ START 1))
					 (T                  (* No, output the CR on its own)
					    (BOUT FILESTREAM (CHARCODE CR]
		          (bind CHAR for I from START to (SUB1 LENGTH)
			     do (SETQ CHAR (\GETBASEBYTE BASE I))
				(COND
				  [(EQ CHAR (CHARCODE CR))   (* Possible CRLF coming in)
				    (COND
				      ((EQ I (SUB1 LENGTH))
                                                             (* This was the last character in the packet)
					(SETQ LASTWASCR T))
				      ((EQ (\GETBASEBYTE BASE (ADD1 I))
					   (CHARCODE LF))    (* Reading a CRLF)
					(add I 1)
					(BOUT FILESTREAM FILEOLCHAR))
				      (T (BOUT FILESTREAM CHAR]
				  (T (BOUT FILESTREAM CHAR]
		(\KERMITMSG I)
	     finally (RETURN (COND
			       ((EQ PACKET (QUOTE DONE))
				 T])

(\MODEM.RECEIVE.PACKET
  (LAMBDA (KERMITSTATE TYPE)                                 (* ejs: " 7-Oct-85 08:49")
    (LET ((INSTREAM (fetch (KERMITSTATE INSTREAM) of KERMITSTATE))
	    (OUTSTREAM (fetch (KERMITSTATE OUTSTREAM) of KERMITSTATE))
	    (PACKET (fetch (KERMITSTATE LASTPACKETIN) of KERMITSTATE))
	    CHAR PACKETSEQNO CHECKSUM)
           (COND
	     ((NOT PACKET)
	       (SETQ PACKET (replace (KERMITSTATE LASTPACKETIN) of KERMITSTATE
				 with (ALLOCSTRING MODEM.PACKET.LENGTH))))
	     (T (\ZEROBYTES (\ADDBASE (fetch (STRINGP BASE) of PACKET)
					  (fetch (STRINGP OFFST) of PACKET))
			      0
			      (SUB1 (fetch (STRINGP LENGTH) of PACKET)))))
           (bind OK (RETRYCOUNT ← 0) until OK
	      do (COND
		     ((EQ (add RETRYCOUNT 1)
			    MODEM.MAX.RETRIES)
		       (\KERMITMSG "Remote MODEM not responding.")
		       (ERROR!)))
		   (COND
		     ((EQ (SETQ CHAR (\KERMIT.TIMED.BIN INSTREAM MODEM.TIMEOUT))
			    TYPE)
		       (SETQ CHECKSUM CHAR)
		       (COND
			 ((EQ CHAR MODEM.SOH)              (* There's more to come)
			   (\KERMITTRACE "G:")
			   (\KERMITTRACE (CHARACTER CHAR))
			   (COND
			     ((SMALLP (SETQ PACKETSEQNO (\KERMIT.TIMED.BIN INSTREAM 
										 MODEM.TIMEOUT)))
			       (add CHECKSUM PACKETSEQNO))
			     (T (PRIN1 "." KERMITSTATUSWINDOW)
				(\MODEM.CLEAR.INPUT INSTREAM)
				(\MODEM.SEND.PACKET NIL MODEM.NAK KERMITSTATE)
				(GO $$ITERATE)))
			   (COND
			     ((SMALLP (SETQ CHAR (\KERMIT.TIMED.BIN INSTREAM MODEM.TIMEOUT)))
			       (add CHECKSUM CHAR))
			     (T (PRIN1 "." KERMITSTATUSWINDOW)
				(\MODEM.CLEAR.INPUT INSTREAM)
				(\MODEM.SEND.PACKET NIL MODEM.NAK KERMITSTATE)
				(GO $$ITERATE)))
			   (\KERMITTRACE PACKETSEQNO)
			   (COND
			     ((NEQ 0 (LOGAND CHECKSUM (MASK.1'S 0 BITSPERBYTE)))
			       (\MODEM.CLEAR.INPUT INSTREAM)
			       (\MODEM.SEND.PACKET NIL MODEM.NAK KERMITSTATE))
			     ((EQ PACKETSEQNO (SUB1 (fetch (KERMITSTATE CURRENTSEQNO)
							   of KERMITSTATE)))
			       (\MODEM.CLEAR.INPUT INSTREAM)
			       (\MODEM.SEND.PACKET NIL MODEM.ACK KERMITSTATE))
			     ((NEQ PACKETSEQNO (fetch (KERMITSTATE CURRENTSEQNO) of KERMITSTATE)
				     )
			       (\MODEM.CLEAR.INPUT INSTREAM)
			       (\MODEM.SEND.PACKET NIL MODEM.NAK KERMITSTATE))
			     (T (for I from 1 to MODEM.PACKET.LENGTH
				   do (COND
					  ((SMALLP (SETQ CHAR (\KERMIT.TIMED.BIN INSTREAM 
										    MODEM.TIMEOUT)))
					    (add CHECKSUM CHAR)
					    (RPLCHARCODE PACKET I CHAR))
					  (T (PRIN1 "." KERMITSTATUSWINDOW)
					     (\MODEM.CLEAR.INPUT INSTREAM)
					     (\MODEM.SEND.PACKET NIL MODEM.NAK KERMITSTATE)
					     (GO $$ITERATE))))
				(COND
				  ((NEQ (\KERMIT.TIMED.BIN INSTREAM MODEM.TIMEOUT)
					  (LOGAND CHECKSUM (MASK.1'S 0 BITSPERBYTE)))
				    (PRIN1 "." KERMITSTATUSWINDOW)
				    (\MODEM.SEND.PACKET NIL MODEM.NAK KERMITSTATE))
				  (T (SETQ OK T)
				     (replace (KERMITSTATE CURRENTSEQNO) of KERMITSTATE
					with (LOGAND (ADD1 (fetch (KERMITSTATE CURRENTSEQNO)
								    of KERMITSTATE))
							 (MASK.1'S 0 BITSPERBYTE)))
				     (\MODEM.SEND.PACKET NIL MODEM.ACK KERMITSTATE))))))))
		     ((EQ CHAR MODEM.EOT)

          (* * We're done)


		       (\KERMITTRACE "EOT")
		       (SETQ OK T)
		       (\MODEM.SEND.PACKET NIL MODEM.ACK KERMITSTATE)
		       (SETQ PACKET (QUOTE DONE)))
		     (T (\KERMITTRACE "?")
			(COND
			  (CHAR (\KERMITTRACE (CHARACTER CHAR))))
			(\MODEM.CLEAR.INPUT INSTREAM)
			(\MODEM.SEND.PACKET NIL MODEM.NAK KERMITSTATE))))
       PACKET)))
)
(PUTPROPS KERMIT COPYRIGHT ("Xerox Corporation" 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (11473 43592 (\KERMIT.CLEAR.INPUT.BUFFER 11483 . 11667) (\KERMIT.DO.FILE.HEADER 11669 . 
12855) (\KERMIT.GET.PACKET 12857 . 16581) (\KERMIT.INITIALIZE 16583 . 17238) (\KERMIT.NEGOTIATE 17240
 . 19272) (\KERMIT.PARSE.REMOTE.PARAMETERS 19274 . 21543) (\KERMIT.RECEIVE.FILE 21545 . 22958) (
\KERMIT.RECEIVE.FILE.BYTES 22960 . 26011) (\KERMIT.SEND.FILE 26013 . 27867) (\KERMIT.SEND.FILE.BYTES 
27869 . 31881) (\KERMIT.SEND.FILE.HEADER 31883 . 32450) (\KERMIT.SEND.PACKET 32452 . 37341) (
\KERMIT.SEND.PARAMETERS 37343 . 38427) (\KERMIT.SEND.STRING 38429 . 40224) (\KERMIT.SHOW.PACKET 40226
 . 40998) (\KERMIT.TIMED.BIN 41000 . 41851) (\KERMIT.UNPREFIXIFY 41853 . 42905) (\KERMIT.WRITE 42907
 . 43590)) (43629 47806 (KERMIT.RECEIVE 43639 . 45374) (KERMIT.SEND 45376 . 46911) (
KERMIT.SERVER.COMMAND 46913 . 47804)) (47883 52579 (KERMIT 47893 . 48633) (KERMIT.EXEC.DEBUGGING 48635
 . 48891) (KERMIT.EXEC.FILE 48893 . 49151) (KERMIT.EXEC.FILE.TYPE 49153 . 49404) (KERMIT.EXEC.ON.OFF 
49406 . 49620) (KERMIT.EXEC.RECEIVE 49622 . 50458) (KERMIT.EXEC.SEND 50460 . 51327) (KERMIT.EXEC.SET 
51329 . 51773) (KERMIT.SET.KERMIT.WINDOW 51775 . 52339) (\KERMIT.LIVE.CHATWINDOW 52341 . 52577)) (
53355 74661 (MODEM.RECEIVE 53365 . 55196) (MODEM.SEND 55198 . 56684) (\MODEM.INITIALIZE 56686 . 57375)
 (\MODEM.SEND.FILE 57377 . 58551) (\MODEM.SEND.FILE.BYTES 58553 . 62629) (\MODEM.SEND.PACKET 62631 . 
65811) (\MODEM.CLEAR.INPUT 65813 . 65989) (\MODEM.RECEIVE.FILE.BYTES 65991 . 70688) (
\MODEM.RECEIVE.PACKET 70690 . 74659)))))
STOP