;PS:<TIMREK>KERMIT.MAC.56,  4-May-83 09:01:16, Frank
;[32] Report bad checksums correctly when debugging.  
; Report error message from server & "abort" if it can't get a file.
;PS:<TIMREK>KERMIT.MAC.54, 26-Apr-83 19:08:00, Frank
;[31] Beep when done with a transfer, if local.
;PS:<KERMIT>20KERMIT.MAC.8, 15-Apr-83 14:45:36, Frank
;[30] A NAK for the next packet is *not* the same as an ACK for the current
; packet if the current packet is Send-Init.
;PS:<TIMREK>KERMIT.MAC.42, 15-Apr-83 11:39:08, Frank
;[29] When debugging packets, print checksum of incoming packets, and  
; print bad packets.
;PS:<TIMREK>KERMIT.MAC.41,  8-Apr-83 19:31:28, Frank
;[28] Add FINISH command.  
;PS:<TIMREK>KERMIT.MAC.29,  8-Apr-83 12:43:02, Frank
;[27] Fix ^C trap to DEBRK to the right place in all cases.
;PS:<TIMREK>KERMIT.MAC.28,  8-Apr-83 09:38:49, Frank
;[26] Save and restore normal send timeout when going in & out of server 
; command-wait.
;PS:<TIMREK>KERMIT.MAC.27,  7-Apr-83 20:20:15, Bill C.
;[25] Neaten up SERVER mode time out changes.
;PS:<TIMREK>KERMIT.MAC.20,  5-Apr-83 18:14:14, Frank
;[24] Fix SPAR to account for the actual length of an incoming SEND-INIT.  
;PS:<TIMREK>KERMIT.MAC.19,  5-Apr-83 17:46:23, Frank
;[23] Include both send and receieve parameters in SHOW command.  
;PS:<TIMREK>KERMIT.MAC.4, 3:20pm  Tuesday, 5 April 1983, Frank
;[22] Add debugging options.  Remove i/o to DIAJFN and just test LOCAL and
; DEBUG flag values.  Make DEBUG an AC, move RTOT & STOT to memory.
;PS:<TIMREK>KERMIT.MAC.81,  1-Apr-83 15:59:19, Frank
;[21] Change SET SEND/RECEIVE QUOTE to parse an octal number.  The hairy
; .CMUQS/breakmask/.CMTOK parsing tended to hang the program...
;PS:<TIMREK>KERMIT.MAC.75,  1-Apr-83 15:13:43, Bill C.
;[20] Make packet time outs longer if in server mode awaiting commands.
;PS:<TIMREK>KERMIT.MAC.72,  1-Apr-83 12:55:40, Frank
;[19] Print "[OK]" for each file successfully sent or received, if local.  
;PS:<TIMREK>KERMIT.MAC.65, 31-Mar-83 16:43:20, Frank
;[18] Expanded help text, with individual help for each command.
; Added SET DUPLEX, SET SEND/RECEIVE START-OF-PACKET.
;PS:<TIMREK>KERMIT.MAC.58, 31-Mar-83 13:35:57, Bill C.
;[17] Restore CFIBFs of yore.  Clears up packet echoing and stacking.
;PS:<TIMREK>KERMIT.MAC.52, 31-Mar-83 10:58:12, Frank
;[16] Add SET ESCAPE (for CONNECT), try to print remote message after BYE.  
;PS:<TIMREK>KERMIT.MAC.48, 30-Mar-83 19:54:32, Frank
;[15] Don't bomb if we can't open a file to be sent, just print nice msg.
;PS:<TIMREK>KERMIT.MAC.47, 30-Mar-83 18:16:53, Frank
;[14] Add code for ^B interrupts, but don't use it for anything yet.
;PS:<TIMREK>KERMIT.MAC.45, 30-Mar-83 15:06:42, Frank
;[13] Don't delay before send if local.  
;PS:<TIMREK>KERMIT.MAC.41, 30-Mar-83 13:52:57, Frank
;[12] When local, print name of file being sent or received.
;PS:<TIMREK>KERMIT.MAC.33, 29-Mar-83 17:59:47, Frank
;[11] Talk to Kermit server.  Added BYE and GET commands.  
;************* Version 3 ****************
;PS:<TIMREK>KERMIT.MAC.22, 28-Mar-83 14:56:39, Frank
;[10] Enable ^C capability if not on already (reported by Willis Dair, SCU).
; If we can't enable it, don't go on unless we're running under batch.
;PS:<TIMREK>KERMIT.MAC.21, 20-Mar-83 17:55:27, Bill C.
;[9] Fixed SHOW command to print number of blips correctly.
;PS:<TIMREK>KERMIT.MAC.17, 18-Mar-83 20:31:00, Frank
;[8] Added some help to the help text.
;PS:<TIMREK>KERMIT.MAC.15, 18-Mar-83 19:03:51, Frank
;[7] Assign & deassign line if not already assigned.  This prevents
; "?Line is not active" and similar errors if Kermit is run on top of TTLINK
; rather than vice versa, and not under DIAL (both TTLINK and DIAL will do
; their own assigning, if necessary).  Thanks to Willis Dair, Santa Clara
; University, for pointing out the bug.
;PS:<TIMREK>KERMIT.MAC.14, 18-Mar-83 18:44:39, Frank
;[6] Differentiate between remote & local timeouts in SHOW command.  
; Add version #, date/time, etc, to SHOW.
; Replace a zillion NOUTs with NUMOUT macro.
;PS:<TIMREK>KERMIT.MAC.12, 17-Mar-83 18:47:21, Frank
;[5] Give error message when initial connection can't be made, if local.
;PS:<TIMREK>KERMIT.MAC.7, 17-Mar-83 15:54:33, Frank
;[4] When acting as local Kermit, show packet traffic by typing blips.
;PS:<TIMREK>KERMIT.MAC.6, 17-Mar-83 15:31:30, Frank
;[3] When comparing packet numbers, allow for wraparound.
;PS:<TIMREK>KERMIT.MAC.3, 17-Mar-83 10:53:03, Frank
;[2] Cont'd... Show range of timeouts in SHOW command.
;PS:<TIMREK>KERMIT.MAC.2, 15-Mar-83 12:51:12, Frank
;[2] Make timeouts load-dependent.  Fix spelling of "interrupt" everywhere.
;PS:<KERMIT>20KERMIT.MAC.22, 20-Feb-83 14:13:19, Bill C.
;[1] Put in a CFIBF% in the INILIN code to clear the line at the beginning
; of each send or receive of backed up NAKs.  This may not be just right.  This
; can lose a Send Init packet some times.  This will work til the problem can
; be looked at more closely.
;*************************** Major Version 2 ********************************
;PS:<SY.WBC3>KERMIT.MAC.20,  8-Feb-83 14:43:48, Bill C.
; Put in (FINALLY!) the SHOW command.
;PS:<SY.WBC3>KERMIT.MAC.11,  8-Feb-83 10:04:10, Bill C.
; Add SET PARITY command.  Eliminate IGNORE-PARITY as its functionality is
; replaced by SET PARITY SPACE.
;PS:<KERMIT>20KERMIT.MAC.3,  4-Feb-83 11:04:08, Bill C.
; Change TELNET to TTLINK (by FdC) and remove TELNET command.
;PS:<SY.WBC3>KERMIT.MAC.38, 26-Jan-83 15:35:37, Bill C.
; Make Kermit able to act as a SERVER.
;PS:<KERMIT>20-KERMIT.MAC.29, 18-Jan-83 14:08:45, Bill C.
; Take care of the case where user set terminal pause char to ^A.
;PS:<KERMIT>20-KERMIT.MAC.27, 11-Jan-83 13:19:06, Bill C.
; Fix ^C trap bug that caused illegal instruction.
;PS:<KERMIT>20-KERMIT.MAC.22, 11-Jan-83 11:40:01, Bill C.
; Fix bug in SET IGNORE-PARITY COMMAND.
;PS:<KERMIT>20-KERMIT.MAC.11, 10-Jan-83 16:52:03, Bill C.
; Add turn around char for the IBM running VM/CMS.
;PS:<KERMIT>20-KERMIT.MAC.8,  7-Jan-83 17:59:01, Bill C.
; Fix numerous mispellings of received.
;PS:<KERMIT>20-KERMIT.MAC.3,  7-Jan-83 16:06:04, Bill C.
; Clean up the diagnostic and error message code.
;PS:<KERMIT>20-KERMIT.MAC.2,  7-Jan-83 15:06:02, Bill C.
; Add the TELNET command (thanks to Bill Schilit.)  Change EXIT/CONT
;    sequence to not throw away JFN.
;PS:<KERMIT>KERMIT-20.MAC.2, 14-Dec-82 15:25:40, Bill C.
; Be scrupulous in PMAP use after errors.  Don't make files with holes.
;PS:<KERMIT>KERMIT.MAC.44, 28-Sep-82 09:47:32, Bill C.
; Add ignore parity option for some UNIX systems.
;PS:<KERMIT>KERMIT.MAC.19, 28-Apr-82 16:00:31, Bill C.
; Big clean up.  Consolidate duplicate sections of code.  Also,
;    no longer die on bad packet type, just NAK or retransmit.
;    Removed empty show command.
;PS:<KERMIT>KERMIT.MAC.18, 21-Apr-82 16:31:04, Bill C.
; Clean up line on ^C from transfer. 
;PS:<KERMIT>KERMIT.MAC.17, 17-Feb-82 16:16:10, Bill C.
; Add eight bit file mode.
;PS:<KERMIT>KERMIT.MAC.16, 28-Jan-82 12:31:09, Bill C.
; Clean up better on some error conditions.
;PS:<KERMIT>KERMIT.MAC.15,  6-Jan-82 12:18:06, Bill C.
; Fill out some of the SET command options.

; THINGS TO DO...
;
; * Add new server functions: directory, type, delete, etc, and user commands
;   to invoke them.  Must first implement "X" packet handling.
;
; * Add host commands.  Fork an Exec, pass commands to it in rescan, somehow
;   pipe the Exec's typeout back, packetized.  Too bad this isn't UNIX...
;
; * Show incoming as well as outgoing packets when in debug mode?
;
; * Terminal interrupt for local Kermit to report status.
;
; * Terminal interrupt to "abort" transmission of current file.  Stopping
;   transmission of an outgoing file can be done easily by sending an error
;   packet.  The side receiving a file, upon receipt of an error packet should
;   know to discard the file rather than simply close it. (?)
;
; * It would be even better to have a one way to quit the current file
;   and go on to the next in a wildcard group, and another way to quit a whole
;   file group.
;
; * Terminal interrupts to switch debugging modes during a transfer.
;
; * 2-character checksum option: parse, put it in the packet routines, add
;   to SHOW command, etc.
;
; * Do 8th-bit quoting.  There's code for this laying around somewhere.  First
;   get it working 20-to-20, then add it to Kermit-80 &/or -86.
;
; * Data compression using repeat count for repeated characters -- best savings
;   realized in binary files.
;
; * Try this (make sure it doesn't break the other KERMITs) -- When receiving
;   a file, put the name I open the file under in the data field of the ACK to
;   the File Header.  When receiving File Headers in local mode, print the
;   contents of the data field instead of doing a JFNS if the data field is not
;   empty.  If this works OK, then try it out in some other KERMITs that
;   actually have to change the file name to avoid conflicts.
;
; * Investigate complaint about server mode versus autobyte after output of
;   an 8-bit file...
;
; * PUSH command.
;
; * TAKE command.
;
; * Automatic take of KERMIT.INIT or KERMIT.CMD?
;
; * Think a little more carefully about the load-dependent timeouts.  If the
;   timeout interval is set very long, maybe upon timing out we should check to
;   see if a packet has partially arrived before NAKing it...  Also, we should
;   do some experimentation to adjust the timeout function & its parameters
;   optimally -- right now, they're just rough stabs based on guesses.  Also,
;   take class scheduling into account when getting load average.

	Title Kermit -- That's Celtic for "free".

; Needs only standard DEC-distributed external files MONSYM, MACSYM, CMD.

	search monsym,macsym,cmd
	.require sys:macrel,sys:cmd

$verno==^d3			; Major version number.
$mnver==^d0			; Minor version number.
$edno==^d32			; Edit number.
$who==^d0			; Who edited.

; Written by Bill Catchings, April 1981.
;
; This program is the DEC-20 implementation of a file transfer protocol for
; use over serial asynchronous communication lines.  See the KERMIT user and
; protocol manuals for the specifications.
;
; Version 1, 1981-82:  Basic service.
;
; Version 2, Feb 83:   Server service.
;
; Version 3, March 83: Talk to server.

	subttl Help Text.	;[18] All of this is edit 18.

hkermi:	asciz |
KERMIT is a file transfer protocol for use over an asynchronous serial
telecommunication line.  Files are broken up into "packets" with checksums and
other control information to ensure (with high probability) error-free and
complete transmission.

KERMIT-20 is the KERMIT implementation for the DECSYSTEM-20.  KERMIT-20 can be
run "locally" with a remote Kermit on the other end of an assigned TTY line
(e.g. over an autodialer connection), or "remotely" from another computer
(e.g.  a microcomputer).

You can run Kermit interactively by typing repeated commands in response to
its "Kermit-20>" prompt, or you can invoke it from the TOPS-20 Exec with a
command line argument (e.g. "kermit receive"), or you can run it as a remote
server.

KERMIT-20 commands -- optional parts are in [brackets]:

* For exchanging files:		SEND file(s) [(INITIAL) file]
				RECEIVE [file]
				GET remote-file(s)

* For acting as local Kermit:	SET LINE, SET PARITY, DUPLEX, ESCAPE
				CONNECT [line]

* For acting as a server:	SERVER

* For talking to a server:	BYE, GET remote-file(s), SEND file(s)

* For running interactively:	PROMPT

* Setting nonstandard transmission and file parameters:
	SET DEBUG, DELAY, FILE-BYTE-SIZE, PARITY
	SET SEND (or RECEIVE) END-OF-LINE, START-OF-PACKET, PACKET-LENGTH,
		TIMEOUT, PADDING.

* Getting information:		HELP [topic], STATUS, SHOW

* Leaving the program:		EXIT, QUIT, BYE


For further information, type "help" for any of the above, e.g. "help set",
or see the "Kermit Users Guide" and the "Kermit Protocol Manual" for complete
details.
|

hsend:	asciz |
SEND filespec1 [(INITIAL) filespec2]

Send a file or file group from the DEC-20 to the other host.  If filespec1
contains wildcard characters (* or %) then all matching files will be sent, in
alphabetical order by name.  The name of each file is passed to the other host
in a file header packet, so that the file can be stored there with the same
name.

The INITIAL file in a wildcard group can be specified with the optional
filespec2.  This is handy to continue a previously interrupted wildcard
transfer from where it left off, or to skip some files that would be
transmitted first.

If running as a local Kermit, the name of each file will be displayed on your
screen as the transfer begins, a "." will be printed for every 5 data packets
sucessfully sent, and a "%" for every retransmission or timeout that occurs.
If you see many "%" characters, you are probably suffering from a noisy
connection.

If running as a remote Kermit, you should escape back to your local Kermit and
give the RECEIVE command.  If you don't do this fast enough, several
"send-init" packets may arrive prematurely; don't worry, KERMIT-20 will keep
sending them until it gets a response.
|

hrecei:	asciz |
RECEIVE	[filespec]

Receive a file or file group from the other host.  If only one file is being
received, you may include the optional filespec as the name to store it under
when it arrives; otherwise, the name is taken from the incoming file header
packet.  Even if the name in the header packet is not a legal TOPS-20 file
name, KERMIT-20 will store it under that name, in which case you can refer to
it later only by quoting the illegal characters (spaces, lower case letters,
control characters, etc) with ^V.

If a file with the same name already exists, KERMIT-20 just creates a new
generation.

If running as a local Kermit, the names of the incoming files will be
displayed on your screen, along with "." and "%" characters to indicate the
packet traffic.  If running as a remote Kermit, you should escape back to your
local Kermit and give the SEND command.
|

hset:	asciz |
SET
  Establish system-dependent parameters.  You can examine their values with the
  SHOW command.  The following may be SET:

 DEBUG option
   Show packet traffic explicitly.  Only use when local.  Options are:
     OFF      Don't show debugging information (OFF by default).
     STATES   Show Kermit state transitions and packet numbers (brief).
     PACKETS  Display each incoming and outgoing packet (verbose).

 DELAY number
   How many seconds to wait before sending the first packet.  Use when remote
   and SENDing files back to your local Kermit.  This gives you time to
   "escape" back and issue a RECEIVE command.

 FILE-BYTE-SIZE keyword
   Byte size for DEC-20 file input/output.  The choices are SEVEN, EIGHT, and
   AUTO.  If SEVEN, do normal ASCII character i/o.  EIGHT is necessary for
   transmission of non-DEC-20 binary files, like .COM files from
   microcomputers.  AUTO is equivalent to SEVEN for incoming files, and for
   outgoing files means to use EIGHT if the DEC-20 file bytsize (as shown by
   the Exec VDIR command) is 8, otherwise use SEVEN.  The default is AUTO.

 PARITY keyword
   If the other computer is using parity on the communication line, you must
   inform KERMIT-20, so it can send the desired parity on outgoing characters,
   and strip it from incoming ones.  The DEC-20 does not use parity on
   communication lines.  The choices are NONE (the default), ODD, EVEN, MARK,
   and SPACE.  NONE means no parity processing is done, and the 8th bit of
   each character can be used for data when transmitting binary files.
   The specified parity is used both for terminal connection (CONNECT) and
   file transfer (SEND, RECEIVE, GET).

 DUPLEX keyword
   For use when CONNECTed to a remote system.  The choices are FULL and HALF.
   Full means the remote system echoes the characters you type, HALF means
   the local system echoes them.  FULL is the default, and is used by most
   hosts.  HALF is necessary when connecting to IBM mainframes.

 IBM-FLAG
   Equivalent to SET PARITY MARK and SET DUPLEX HALF, plus it instructs
   KERMIT-20 to look for the IBM system's "line turnaround" character before
   sending packets.

 LINE number
   Specify the octal TTY number to use for file transfer or CONNECT.
   If you issue this command, you will be running as a local Kermit, and you
   must log in to the remote system and run Kermit on that side in order to
   transfer a file.  If you don't issue this command, KERMIT-20 assumes it is
   running remotely, and does file transfer over its job's controlling
   terminal line.

 ESCAPE number
   Tell what control character you want to use to "escape" from remote
   connections.  31 (Control-Y) by default.  The number is the octal value of
   the ASCII control character, 1 to 37.

 SEND parameter
   Parameters for outgoing packets, as follows:

   END-OF-LINE number 
     The octal value of the ASCII character to be used as a line terminator
     for packets, if one is required by the other system.  Carriage return
     (15) by default. 

   PACKET-LENGTH number
     Maximum packet length to send, decimal number, between 10 and 94, 80 by
     default. 

   TIMEOUT number
     How many seconds to wait for a packet before trying again.

   PADDING number, PADCHAR number
     How much padding to send before a packet, if the other side needs padding,
     and what character to use for padding.  Defaults are no padding, and NUL
     (0) for the padding character.  No cases are presently known where this
     is necessary.

   QUOTE number
     What printable character to use for quoting of control characters.
     Specify an octal ASCII value.  "#" (43) by default.  There should be no
     reason to change this. 

   START-OF-PACKET number
     The control character that marks the beginning of a packet.  Normally
     SOH (Control-A, ASCII 1).  There should be no reason to change this.

 RECEIVE parameter
   Parameters to request or expect for incoming packets, as follows:

   END-OF-LINE number 
     Carriage return (15) by default.  The DEC-20 does not actually need any
     line terminator for incoming packets.

   PACKET-LENGTH number
     Maximum packet length packet for the other side to send, decimal number,
     between 10 and 94, 80 by default. 

   TIMEOUT number
     How many seconds the other Kermit should wait for a packet before asking
     for retransmission.

   PADDING number, PADCHAR number
     Never necessary; the DEC-20 needs no padding.

   QUOTE number
     What printable character to use for quoting of control characters.
     Specify the octal ASCII value.  "#" (43) by default.  There should be no
     reason to change this. 

   START-OF-PACKET number
     The control character to mark the beginning of incoming packets.  Normally
     SOH (Control-A, ASCII 1).  There should be no reason to change this.
|

hshow:	asciz |
SHOW

Display current SET parameters, version of KERMIT-20, and other info.
Items under RECEIVE column show parameters for packets KERMIT-20 expects
to receive, under SEND shows parameters for outgoing packets.
|

hstatu:	asciz |
STATUS

Give statistics about the most recent file transfer.
|

hconne:	asciz |
CONNECT [number]

Establish a terminal connection to the system connected to the octal TTY
number specified here or in the most recent SET LINE command, using full
duplex echoing and no parity unless otherwise specified in previous SET
commands.  Get back to KERMIT-20 by typing the escape character followed by
the letter C.  The escape character is Control-Y by default.  When you type
the escape character, several single-character commands are possible:

C -- Close the connection and return to KERMIT-20.
S -- Show status of the connection.
P -- Push to a new Exec.  POP from the Exec to get back to the connection.
^Y (or whatever you have set the escape character to be) -- Typing the escape
 character twice sends one copy of it to the connected host.

You can use the SET ESCAPE command to define a different escape character.

KERMIT-20 accomplishes the connection by running the TTLINK program in a lower
fork.  If all you want to do connect to a remote host over a TTY line, without
file transfer, you can run TTLINK itself.  TTLINK also provides other options,
like logging of the remote session to provide "unguarded" capturing of files
or typescripts from systems that do not have KERMIT.
|

hserve:	asciz |
SERVER

Act as a server for another Kermit.  Take all further commands only from the
other Kermit.  Only works when running remotely.  After issuing this command,
escape back to your local system and issue SEND, RECEIVE or GET, BYE, or other
server-oriented commands from there.  If your local KERMIT does not have a BYE
command, it does not have the full ability to communicate with a KERMIT server
(in which case you can only use the SEND command).  If your local KERMIT does
have a BYE command, use it to shut down and log out the KERMIT server when you
are done with it; otherwise, connect back to the DEC-20, type several
Control-C's to stop the server, and logout.

For doing nonstandard kinds of file transfer (for instance to send binary
files from a microcomputer), you should issue the appropriate SET commands
before the SERVER command.
|

hfinis:	asciz |
FINISH

When running as a local Kermit, talking to a KERMIT server over a TTY line
specified in a SET LINE command, use the FINISH command to shut down the
server without logging out the remote job, so that you can CONNECT back to it.
|
hbye:	asciz |
BYE	 

When running as a local Kermit, talking to a KERMIT server over a TTY line
specified in a SET LINE command, use the BYE command to shut down and log out
the server.  This will also exit from the local KERMIT.
|

hhelp:	asciz |
HELP [topic]

Typing HELP alone prints a brief summary of KERMIT-20 and its commands.
You can also type

   HELP command

for any Kermit-20 command, e.g. "help send", to get more detailed information
about a specific command.  Type

   HELP ?

to see a list of all the available help commands, or consult the Kermit
Users Guide.
|

hexit:	asciz |
EXIT

Exit from KERMIT-20.  You can CONTINUE the program from the TOPS-20 Exec,
provided you haven't run another program on top of it.
|

hquit:	asciz |
QUIT

Synonym for EXIT.
|

hpromp:	asciz |
PROMPT

If KERMIT-20 runs in server mode by default, typing the following command
to the TOPS-20 Exec

   kermit prompt

will start it up in interactive mode, and leave you at the "Kermit-20>" prompt.
|

hget:	asciz |
GET remote-filespec

For use only when talking to a KERMIT server.

When running as a local KERMIT (i.e. when communicating with a remote KERMIT
over an assigned TTY line, which you have specified with the SET LINE
command), you may use the GET command to request the remote KERMIT server to
send you the specified files.  The filespec is any string that can be a legal
file specification for the remote system; it is not parsed or validated
locally.  As files arrive, their names will be displayed on your screen, along
with "." and "%" characters to indicate the packet traffic.

If the remote KERMIT is not capable of server functions, then you will
probably get an error message back from it like "Illegal packet type".
In this case, you must connect to the other Kermit, give a SEND command, 
escape back, and give a RECEIVE command.

The GET command has no effect when running as a remote KERMIT.
|

	subttl Definitions

pdlsiz==^d100			; Stack size.

f=0				; AC defs:  flag AC,
t4=<t3=<t2=<t1=1>+1>+1>+1	;  temporary AC's,
q4=<q3=<q2=<q1=t4+1>+1>+1>+1	;  and preserved AC's.
state=q4+1			; State of the automaton.
rchr=state+1			; Total data chars received.
schr=rchr+1			; Total data chars sent.
debug=schr+1			;[22] Debugging status (none, some, verbose)

mappag==200			; Where to map things in.

SOH==^o001			; Start of header char.
XON==^o021			; Control-Q.

maxpkt=="~"-" "+2		; Maximum size of a packet.
dmxtry==5			; Default number of retries on a packet.
dimxtr==20			; Default number of retries send initiate.
drpsiz==^d80			; Default receive packet size.
dspsiz==^d80			; Default send packet size.
dstim==^d10			; Default send time out interval.
drtim==^d8			; Default receive time out interval.
dsrvtm==^d30			;[20] Def timout when awaiting server commands.
dspad==^o000			; Default send padding char.
drpad==^o000			; Default receive padding char.
dspadn==^d0			; Default number of send padding chars.
drpadn==^d0			; Default number of receive padding chars.
dseol==.chcrt			; Default send EOL char.
dreol==.chcrt			; Default receive EOL char.
dsquot=="#"			; Default send quote char.
drquot=="#"			; Default receive quote char.
ddelay==^d5			; Default delay before the first packet, secs.
dtrnrn==XON			; Default half duplex turnaround character.
dxfull==0			;[18] Full duplex.
dxhalf==1			;[18] Half duplex.
ibmdpx==dxhalf			;[18] Duplex for IBM host.
defpar==none			; Default parity.
ibmpar==mark			; Parity for IBM host.
maxtim=^d94			;[2] Maximum timeout interval to set, secs.
minlod=4.0			;[2] Minimum ldav to consider for timeout.
maxlod=50.0			;[2] Maximum ldav to consider for timeout.
blip=^d5			;[4] Every this many packets, print a blip.
diasw==0			; Default is diagnostics off.


	subttl Macros


define	diamsg (msg) <		;;[22] Print state if normal debugging.
	call [	skipe local	;;[22] If not local, forget it.
		 caie debug, 1	;;[22] Only do this in normal debugging mode.
		 ret		;;[22]
		saveac <t1>	;;[22]
		hrroi t1, [asciz/'msg/] ;;[22]
		PSOUT		;;[22]
		ret ]		;;[22]
> ;[22] diamsg

define ermsg (msg) <
	 call [	tmsg <
>
		hrroi t1, [asciz/?Kermit:  'msg/]
		movem t1, errptr ;; Save pointer to error mess for status.
		PSOUT%
		tmsg <
>
		ret ]
>

; Change the order to increase the likelyhood of the micro seeing
;  the error packet.

define kermsg (msg) <
	$count=0
	irpc msg, <$count=$count+1>
	 call [	movei t1, "E"	;; Send an error packet to the other side.
		move t2, pktnum	;; Packet number.
		movei t3, $count+^d13 ;; The count.
		move t4, [point 7, [asciz/?Kermit-20:  'msg/]] ;; Error mess.
		movem t4, errptr ;; Save pointer to error mess for status.
		call spack	;; Send the error packet.
		 nop
		tmsg <
?Kermit:  'msg
>
		ret ]
>

; Error handling macros.

define %jserr (msg, label) <	;; Use this immediately following a JSYS.
	erjmp [	tmsg <
?Kermit:  'msg>			;; Type given msg with our prefix,
ifnb <msg>,<	call jserr0>	;;  if given, put JSYS error after dash,
ifb <msg>,<	call jsmsg0>	;;  else right after "?Kermit:  "
ifb <label>,<	HALTF%		;; then if no label was specified, halt,
		jrst .+1	;; continuably,
>;ifb
ifnb <label>,<	jrst label>	;; or if there was, go there.
	      ]
>;%jserr

jserr0:	movei t1,.priin
	CFIBF%			; Clear typeahead.
	movei t1,.priou
	DOBE%			; Wait for previous output to finish.
	tmsg < - >
jsmsg0:	movei t1,.priou
	hrloi t2,.fhslf		; Say:  this fork ,, last error.
	setz t3,
	ERSTR%
	 jfcl
	 jfcl
	tmsg <
>
	ret

; Improve order to facilitate error packets.

define %jsker (msg, label) <	;; Use this immediately following a JSYS.
	erjmp [	move t1, [point 7, [asciz/?Kermit-20:  'msg   /]] ;; Error.
		movem t1, errptr ;; Save pointer to error mess for status.
		call %%krms
		tmsg <
?Kermit:  'msg>			;; Type given msg with our prefix,
ifnb <msg>,<	call jserr0>	;;  if given, put JSYS error after dash,
ifb <msg>,<	call jsmsg0>	;;  else right after "?Kermit:  "
ifb <label>,<	HALTF%		;; then if no label was specified, halt,
		jrst .+1	;; continuably,
>;ifb
ifnb <label>,<	jrst label>	;; or if there was, go there.
	      ]
>;%jsKer

%%krms:	move t3, [point 7, %%krbf] ;; Get a pointer to the buffer.
	setz t4,		;; Zero the counter.
%%krm1:	ildb t2, t1		;; Get the byte.
	jumpe t2, %%krm2	;; Is it a null?
	addi t4, 1		;; Increment the counter.
	idpb t2, t3		;; Deposit the byte.
	jrst %%krm1
%%krm2:	move t1, t3		;; Put the information into the buffer.
	hrloi t2, .fhslf	;; Say:  this fork ,, last error.
	movei t3, ^d80		;; Eighty chars minus the number so far.
	sub t3, t4
	ERSTR%
	 trn
	 trn
	move t2, t1		;; Put in the correct AC.
	move t1, [point 7, %%krbf] ;; Find the length of the string.
	call subbp		;; Subtract byte pointers.
	 movei t3, ^d80		;; If there is an error assume this count.
	movei t1, "E"		;; An error packet.
	move t2, pktnum		;; Packet number.
	move t4, [point 7, %%krbf] ;; Pointer to string.
	call spack		;; Send the error packet.
	 trn
	ret

; %Clear
;
;    This macro takes three args, two of which are optional.  The first,
; non-optional, argument is the starting address of the area to be cleared.
; The next is the number of locations to clear, which defaults to one.
; The last argument is the desired filler, which defaults to zero.

define %clear (area, length, fill) <
   ifb <fill>, <setzm area>
   ifnb<fill>, <
	movx .sac, <fill>
	movem .sac, area
   >
   if1, <ifnb <length>, <exp 0, 0, 0>>
   if2, <
      ifb <length>, <%%%clr==1>
      ifnb<length>, <%%%clr==<length>>
      ifg <%%%clr-1>, <
	   hrli .sac, area
	   hrri .sac, <1>+area
	   blt .sac, <%%%clr-1>+area
      >
   >
>


define numout(num,base<^d10>) <	;; Type number in desired base, free format.
	call [	move b, num
		movei a, .PRIOU
		movei c, base
		NOUT%
		 nop
		ret ]	
>;numout

define	OUTCHR(char) <
	jrst [	push p,1
		move 1,char
		PBOUT%
		pop p,1
		jrst .+1 ]
>;OUTCHR

; Parsing aids

defstr %prsadr,0,17,18		; Parse routine address
defstr %evladr,0,35,18		; Evaluation routine address

; %Table
;
;    This macro is used to start a keyword table definition.

define %table <
	%%tbst== .		;; Plant start of table
	exp 0			;;  and leave a hole for %tbend to fill
>

; %TBend 
;
;    This macro is the compliment of %Table; it ends a keyword table.

define %tbend <
	%%tbnd==.-1		;; Get address of last entry in table
	.org %%tbst		;; Move back to start
	xwd %%tbnd-%%tbst, %%tbnd-%%tbst;;  and build table header
	.org			;; Finally, get back to the way we were
>

; %Key
;
;    This macro takes three arguments: an (alphanumerics only!) keyword, the
; data to be associated with the keywod, and an (optional) flag value.  It
; creates either a flagless keyword (the normal case), or, if flags are
; given, a keyword with flags in the first word (and CM%FW set).  Thus,
; the result is a TBLUK table entry, suitable for use by the .CMKEY COMND
; JSYS function.  Note that all %Key words in a table must be bracketed
; by %Table and %TbEnd macros (see above).

define %key (name, data, flags) < ;; Flags are optional
   ifb <flags>, <
	xwd [asciz\name\],data	;; No-flags case
   >
   ifnb<flags>, <
	xwd [<flags>!cm%fw	;; Flags: first word holds them,
	     asciz\name\], data	;;  second is start of name
   >
>

	subttl Check rescan line

rescan:	saveac <t2,q4>		; Save the used AC's.
	move q4, t1		; Save AC1.

	movx t1, .rsini		; Any rescan arguments?
	RSCAN%			;  ...
	 erjmp rskp		;  If not return.

	movx t1, .rscnt		; Get the size of the rescan.
	RSCAN%			;  ...
	 erjmp rskp		;  Return if unsucessful.
	jumpe t1, rskp		; If the size is zero return.

	prompt <>		; Null prompt.

	movei t1, r+1		; Get the address we want to go to on reparse.
	movem t1, repara	; Fudge it.  This is to prevent looping back
				;  to prompt <> for ever on an error on the 
				;  rescan line.
	move t1, q4		; Parse for the "keyword" in q4.
	call rflde		; Parse it, returning +2 on success.
	 retskp			;  If we don't find it return.
	movei t1, [flddb. (.cmcfm,cm%sdh)] ; See if we can parse a confirm.
	call rflde
	 ret			;  If not, we have a rescan argument.
	retskp			; Say we haven't got one.


Kermit:	jrst start		; Start entry.
	jrst reen		; Re-entry.
versio:	byte (3)$who(9)$verno(6)$mnver(18)$edno	; Program version.

reen:	jrst start

start:	RESET%			; Normal startup: reset everything
	move p, [iowd pdlsiz,pdl] ;  and set up a stack.
	setzm telfrk		; 
	setzm netjfn
	setzm f$exit
	call main		; The actual program.
halt:	HALTF%			; Stop.
	jrst cont		; Go around again.

cont:	setzm f$exit		; Turn off the exit flag.
	call prsint
	jrst halt

main:	call pinit		; Initialize interrupt system.
	GJINF%			; Get the our terminal number.
	movem t4, pars3		; Make believe we parsed it.
	movem t3, myjob		;[7] Job number of my job.
	movem t4, mytty		;[4] Remember this is my controlling terminal.
	setzm local		;[4] Assume we're running remotely.
	setz debug,		;[22] And no debugging
	call $setln		; Set the line to our own.
	call cmdini		; Initialize the command package.
	movei t1, [flddb. (.cmkey,,<[exp <1,,1>,<[asciz/Kermit/],,0>]>)]
	call rescan		; Check rescan buffer.
	 jrst [	skipe f$exit	;  Is the exit flag already on?
		 jrst prsint	;   Yes, then we have parsed an error on the
				;    rescan line.  Go handle it.
		setom f$exit	;  Turn on the exit flag.
		jrst parse]	;  Parse the rescan line

	jrst @dfstrt		; No rescan go to default: PROMPT or SERVER.

server:	jrst getcom

promp:	setzm f$exit		; They don't really want to exit yet.
	jrst prsint		; Where we go for experts.

prsint:	skipe f$exit		; Exit?
	 ret			;  If so, return.
	prompt (Kermit-20>)
parse:	%clear pars1, parsnm	; Clear parse values.
	setzm cjfnbk+.gjgen	; Clear the JFN bits.
	movei t1, [flddb. (.cmkey,,cmdtab,,,)]
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the command routine addresses.
	movem t2, pars1		; Save into pars1.
	load t1, %prsad, (t2)	; Get the next level routine.
	call (t1)		; Call it.
eval:	move t2, pars1		; Get back data value.
	load t1, %evlad, (t2)	; Get evaluation routine.
	call (t1)		; Call it.
	jrst prsint		; Do it again.

	subttl	EXIT command

.exit:	noise <from Kermit>
	confrm			; Confirm.
	ret

$exit:	setom f$exit		; Set exit flag.
	skipn assflg		;[7] Did I assign a TTY?
	 ret			;[7]  No.
	move t1, ttynum		;[7] Yes, so I should deassign it.
	movei t1, .ttdes(t1)	;[7]
	RELD%			;[7]
	 %jserr (,r)		;[7]
	ret

	subttl	HELP command

.help:	noise <about>		;[18] HELP
	movei t1, [flddb. .cmkey,,hlptab,,<kermit>]
	call cfield	
	move t2, (t2)		; Get help text address.
	movem t2, pars3
	ret

hlptab:	%table			;[18] Table of help commands.
	%key <bye>,hbye
	%key <connect>,hconne
	%key <exit>,hexit
	%key <finish>,hfinis
	%key <get>,hget
	%key <help>,hhelp
	%key <kermit>,hkermi
	%key <prompt>,hpromp
	%key <quit>,hquit
	%key <receive>,hrecei
	%key <send>,hsend
	%key <server>,hserve
	%key <set>,hset
	%key <show>,hshow
	%key <status>,hstatu
	%tbend

$help:	hrro t1, pars3		;[18] Print the desired help text.
	PSOUT
	hrroi t1, crlf
	PSOUT
	ret

	subttl	SET command

.set:	movei t1, [flddb. .cmkey,,setabl,,,]
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the command routine addresses.
	movem t2, pars2		; Save into pars2.
	load t1, %prsad, (t2)	; Get the next level routine.
	call (t1)		; Call it.
	ret

.setdb:	noise <protocol mode>
	movei t1, [flddb. .cmkey,,dbgtab,,states]
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the value for the keyword (0 or 1).
	movem t2, pars3		; Save into pars3.
	confrm
	ret

dbgtab:	%table
	%key	<off>, 0
	%key	<packets>, 2	;[22]
	%key	<states>, 1	;[22]
	%tbend

.setf8:	noise <to>
	movei t1, [flddb. (.cmkey,,sftab,<DEC-20 file byte size,>,auto-byte,)]
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the value for the keyword (0 or 1).
	movem t2, pars3		; Save into pars3.
	confrm
	ret

.setpa:	noise <to>
	movei t1, [flddb. .cmkey,,partab,,none,]
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the value for the keyword.
	movem t2, pars3		; Save into pars3.
	confrm
	ret

.setib:	movei t1, [flddb. .cmkey,,offon,,on,]
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the value for the keyword (0 or 1).
	movem t2, pars3		; Save into pars3.
	confrm
	ret

offon:	%table
	%key	<off>, 0
	%key	<on>, 1
	%tbend

.setln:	noise <to tty>
	movei t1, [flddb. (.cmnum,cm%sdh,^d8,<octal tty to transfer files over>,,[
		   flddb. (.cmcfm,cm%sdh,,<confirm to reset>)])]
	call rfield		; Parse a tty number.
	ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
	caie t3, .cmnum		; Is it a TTY number?
	 jrst .setl1		;  If not it must be a confirm.
	movem t2, pars3		; Save the tty number.
	confrm
	ret

.setl1:	move t4, mytty		; Get the our terminal number.
	movem t4, pars3		; Make believe we parsed it.
	ret

	;...

.setdl:	noise <to>		; DELAY
	movei t1, [flddb. (.cmnum,cm%sdh,^d10,<decimal number of seconds>,)]
	call cfield		; Parse a number.
	movem t2, pars3		; Save the number.
	ret

.setdu:	noise <to>		;[18] DUPLEX
	movei t1, [flddb. .cmkey,,duptab,,<full>]
	call cfield
	hrrz t2, (t2)
	movem t2, pars3
	ret

duptab:	%table			;[18] legal duplexes
	%key <full>,dxfull
	%key <half>,dxhalf
	%tbend

.setes:	noise <character for connect to> ;[16] ESCAPE
	movei t1, [flddb. (.cmnum,cm%sdh,^d8,<Octal value of ASCII control character>,<31>)]
	call cfield
	movem t2, pars3
	ret

.setrc:	movei t1, [flddb. (.cmkey,,srtabl,,)] ; SET SEND ...
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the command routine addresses.
	movem t2, pars3		; Save into pars3.
	load t1, %prsad, (t2)	; Get the next level routine.
	call (t1)		; Call it.
	ret

.setsn:	movei t1, [flddb. (.cmkey,,sstabl,,)] ; SET RECEIVE ...
	call rfield		; Parse a keyword.
	hrrz t2, (t2)		; Get the command routine addresses.
	movem t2, pars3		; Save into pars3.
	load t1, %prsad, (t2)	; Get the next level routine.
	call (t1)		; Call it.
	ret

.setpk:	noise <to>		; SET SEND/RECEIVE PACKET-LENGTH
	movei t1, [flddb. (.cmnum,cm%sdh,^d10,<Decimal number between 10 and 94>,)]
	call rfield		; Parse the packet size.
	movem t2, pars4		; Save the packet size.
	confrm
	move t2, pars4		; Get the packet size we parsed.
	cail t2, ^d10		; Is the number in the right range?
	 caile t2, ^d94
	  jrst [tmsg <?Illegal packet size>
		jrst cmder1 ]
	ret

	;...

.setpd:	noise <to>		; SET SEND/RECEIVE PADDING
	movei t1, [flddb. (.cmnum,cm%sdh,^d10,<positive decimal number of padding characters>,)]
	call rfield		; Parse the number of padding chars.
	movem t2, pars4		; Save the number.
	confrm
	move t2, pars4		; Get the amount of padding we parsed.
	skipge t2		; Is the number in the right range?
	 jrst [	tmsg <?Must be a positive number>
		jrst cmder1 ]
	ret

.setpc:	noise <to>		; SET SEND/RECEIVE PADCHAR
	movei t1, [flddb. (.cmnum,cm%sdh,^o10,<octal number of character between 0 and 37 or 177>,)]
	call rfield		; Parse the padding character.
	movem t2, pars4		; Save the padding char.
	confrm
	move t2, pars4		; Get the padding char we parsed.
	skipl t2		; Is the number in the right range?
	 caile t2, ^o37		;  Fix to compare correctly.
	  jrst [caie t2, ^o177
		tmsg <?Illegal padding character>
		jrst cmder1 ]
	ret

.seteo:	noise <to>		; END-OF-LINE
	movei t1, [flddb. .cmnum,cm%sdh,^o10,<octal value of ASCII control character>,<15>]
	call cfield		; Parse the EOL char.
	skipl t2		; Is the number in the right range?
	 caile t2, ^o37		;  Fix to compare correctly.
	  jrst [tmsg <?Illegal EOL character>
		jrst cmder1 ]
	movem t2, pars4		; Get the EOL char we parsed.
	ret


.setsp:	noise <to>		;[18] START-OF-PACKET
	movei t1, [flddb. .cmnum,cm%sdh,^d8,<Octal value of ASCII control character>,<1>]
	call cfield
	skipl t2		; Is the number in the right range?
	 caile t2, ^o37		;  Fix to compare correctly.
	  jrst [tmsg <?Illegal start-of-packet character>
		jrst cmder1 ]
	movem t2, pars4
	ret

	;...

.setqu:	noise <to>		; SET SEND/RECEIVE QUOTE
	movei t1, [flddb. .cmnum,cm%sdh,^d8,<Octal value of printable ASCII character>,<43>] ;[21] 
	call cfield		;[21]
	caile t2," "		;[21] Printable?
	 caile t2, "~"		;[21]
	 jrst [	tmsg <?Must be printable character, range 41-176>
		jrst cmder1 ]	;[21]
	movem t2, pars4		;[21] OK, stash it.
	ret

.setim:	noise <to>		; SET TIMEOUT
	movei t1, [flddb. (.cmnum,cm%sdh,^d10,<Number of seconds before timing out, 1 to 94>,)]
	call rfield		; Parse the number.
	movem t2, pars4		; Save the number.
	confrm
	move t2, pars4		; Get the number we parsed.
	cail t2, 1		; Is the number in the right range?
	 caile t2, ^d94		;  Fix to compare correctly.
	  jrst [tmsg <?Illegal number of seconds>
		jrst cmder1 ]
	ret

$set:	move t2, pars2		; Get back data value.
	load t1, %evlad, (t2)	; Get evaluation routine.
	call (t1)		; Call it.
	ret

$setdb:	skipl debug, pars3	; DEBUG. Get the value we parsed.
	 caile debug, 2		;[22] Make sure it's 0, 1, or 2.
	 movei debug, 1		;[22] ...
	ret

$setrs:	move t1, @pars3		; SEND/RECEIVE.  Address of variable to set.
	move t2, pars4		; The value that was parsed.
	movem t2, (t1)		; Save the value.
	ret

$setdl:	move t1, pars3		; DELAY. Get the number of seconds to delay.
	movem t1, delay		; Save the delay time.
	movem t1, odelay	;[27] Here too, for saving & restoring.
	ret

$setdu:	move t1, pars3		;[18] DUPLEX.  Get what was parsed.
	movem t1, duplex
	ret

$setes:	move t1, pars3		;[16] ESCAPE.  Get what we parsed.
	cail t1, 1
	cail t1, " "
	 skipa
	 jrst [	movem t1, escape
		ret ]
	tmsg <
?Escape character must be between 1 (CTRL-A) and 37 (CTRL-_)>
	setzm escape
	ret

$setf8:	move t1, pars3		; FILE-BYTE... Get the value of the flag.
	cain t1, 2		; Is it autobyte?
	 jrst [ setom autbyt	;  If so, say so.
		ret ]
	setzm autbyt		; Say no auto-byte.
	movem t1, ebtflg	; Set the flag.
	ret

$setpa:	move t1, pars3		; SET PARITY
	movem t1, parity
	ret

$setib:	move t1, pars3		; SET IBM-FLAG
	movem t1, ibmflg	; Say whether we want to talk to IBM host.
	skipe ibmflg		; If we turned IBM flag ON,
	 jrst [	movei t1, ibmpar ; then set IBM parity,
		movem t1, parity ; ...
		movei t1, ibmdpx ;[18] and IBM duplex.
		movem t1, duplex ;[18]
		ret ]		; 
	movei t1, defpar	; else we turned it OFF, so
	movem t1, parity	; put back default parity
	movei t1, dxfull	;[18] and default duplex, which is FULL
	movem t1, duplex	;[18]
	ret

$setln:	stkvar <oldjfn>		; SET LINE
	move t1, ttynum		;[7] Previous line number, if any.
	movem t1, oldnum	;[7] Remember it.
	move t1, pars3		;[7] Now get new one.
	movem t1, ttynum	;[7]
	setzm local		;[4] Assume we're a remote Kermit.
	came t1, mytty		;[4] Lines the same?
	 setom local		;[4] No, so we're local.
	movei t1, .ttdes(t1)	;[7] Form device designator.
	DVCHR			;[7] 
	 erjmp asser1		;[7]
	hlre t1, t3		;[7] Who has it?
	movem t1, job		;[7] Job number of who has it, or -1 (or -2).
	move t1, assflg		;[7] Remember in case we already had another...
	movem t1, oasflg	;[7] 
	setzm assflg		;[7] Assume I don't have to assign it.
	skipn local		;[7] If it's my own controlling TTY I don't
	 jrst $stln2		;[7]  have to assign it.
	move t3, myjob		;[7] My job number.
	camn t3, job		;[7] If I had it assigned already,
	 jrst $stln2		;[7]  just go get a JFN on it.
	move t1, ttynum		;[7] Form device designator again,
	movei t1, .ttdes(t1)	;[7]  and...
	ASND			;[7]  give it a try.
	 erjmp asser1		;[7] Uh oh, can't assign it.
	setom assflg		;[7] Assigned it.  Set this flag to remember.

$stln2:	move t1, netjfn		; Get the present JFN.
	movem t1, oldjfn	; Save it so we can close it up.
	move t1, [170700,,filbuf] ; Pointer to file name buffer.
	move t2, [ascii/TTY/]	; Build TTY: filename.
	movem t2, filbuf	; Into filbuf.
	move t2, ttynum		; TTY number.
	movei t3, ^d8		; Octal.
	NOUT%
	 erjmp [ermsg <Can't NOUT TTY number>
		ret ]
	movei t2, ":"		; Add a colon.
	idpb t2, t1
	setz t2,
	idpb t2, t1
	movx t1, gj%sht		; Now try to get a JFN on the TTY:.
	hrroi t2, filbuf
	GTJFN%
	 erjmp [ermsg <Can't get JFN on TTY> ;  Probably no such device.
		ret ]
	hrrzm t1, netjfn	; Save it as the net JFN.
	movx t2, fld(8,of%bsz)!of%wr!of%rd ; 8-bit bytes, read & write access.
	OPENF%			; Assign the TTY.
	 erjmp asserr		;[7] Can't, print informative error message.
	move t1, oldjfn		; OK, get the old tty jfn.
	jumpe t1, $stlnx
	skipe oasflg		;[7] Had I assigned the old one?
	 jrst [	skipn t1, oldnum ;[7] Yes,
		 jrst .+1
		movei t1, .ttdes(t1) ;[7] deassign it. 
		RELD%		;[7]
		 %jserr (,.+1)	;[7]
		setzm oldnum	;[7] Set these to zero...
		setzm oasflg	;[7]
		jrst .+1 ]	;[7]
	CLOSF%			; Close it.
	 %jserr (,.+1)
$stlnx:	move t1, netjfn
	movei t2, .chcrt	; Send a CR down the line to get things going.
	BOUT%
	 %jserr (,r)
	ret

;[7] (this whole section...) Get here if error assigning link tty.


asserr:	movei t1, .fhslf		; Got error trying to open link tty.
	GETER%
	hrrzs t2
	caie t2, opnx7		; Somebody else has it?
	 jrst [	ermsg <Can't assign or open TTY>
		move t2, oldjfn	; No, something else.  Restore old JFN.
		movem t2, netjfn
		ret ]
asser1:	tmsg <
?Line >
	numout ttynum, 8
	tmsg < in use by job >
	numout job
	tmsg <, user >
	move t1, job
	hrroi t2, t3
	movei t3, .jiuno
	GETJI
 	 erjmp asserx
	movei t1, .priou
	move t2, t3		; User...
	DIRST
 	 erjmp asserx
	ret

asserx:	tmsg <???
>
	ret

	subttl	STATUS command

.stat:	noise <of Kermit>	; STATUS
	confrm
	ret

$stat:	stkvar <sec>
	tmsg <
 Maximum number of characters in packet:  >
	numout rpsiz
	tmsg < received; >
	numout  spsiz
	tmsg < sent
 Number of characters transmitted in >
	move t2, stdat		; Get the number of thirds of seconds.
	idivi t2, ^d3		; Get the number of seconds.
	movem t2, sec		; Save the number of seconds.
	idivi t2, ^d60		; Divide to get minutes.
	move t4, t3		; Save the remainder.
	jumpe t2, $stat2	; If no minutes then don't print them.
	numout t2
	tmsg < minutes and >
$stat2:	move t2, t4		; Get the remainder.
	jumpe t2, $stat3	; If no seconds then don't print them.
	numout t2
	tmsg < seconds>
$stat3:	tmsg <
	Sent:      >
	numout stot
	tmsg <    	Overhead:	>
	movei t1, .priou	; Output the number of chars in decimal.
	move t2, stot
	sub t2, stchr
	numout t2
	tmsg <
	Received:  >
	numout rtot
	tmsg <    	Overhead:	>
	movei t1, .priou	; Output the number of chars in decimal.
	move t2, rtot
	sub t2, rtchr
	numout t2
	tmsg <
  Total received:  >
	movei t1, .priou	; Output the number of chars in decimal.
	move t2, rtot
	add t2, stot
	move t4, t2		; Save the total number of chars.
	numout t2
	tmsg <    	Overhead:	>
	movei t1, .priou	; Output the number of chars in decimal.
	move t2, t4		; Get total chars.
	sub t2, rtchr
	numout t2
	tmsg <
 Total characters transmitted per second:	>
	move t2, t4		; Total chars transmitted.
	idiv t2, sec		; Divided by the number of seconds.
	numout t2
	tmsg <
 Effective data rate:	>
	skipn t2, stchr		; Is the number of chars sent zero?
	 move t2, rtchr		;  If so we were receiving.
	idiv t2, sec		; Divided by the number of seconds.
	imuli t2, ^d10		; Multiply chars/sec by 10 to get bits/sec.
	numout t2
	tmsg < Baud
>
	skipn errptr		; Was there an error?
	 jrst $statx		;  If not, done.
	tmsg < Aborted by error:  >
	move t1, errptr
	PSOUT%			; If so output it.
$statx:	tmsg <

>
	ret

.show:	noise <Kermit parameters>
	confrm
	ret

$show:	tmsg <
TOPS-20 KERMIT version >
	ldb t2, [301100,,versio] ; major version
	numout t2, 8
	ldb t1, [220600,,versio]
	skipe t1		; minor version
	 call [	addi t1, "A"-1	; make it a letter (A=1)
		PBOUT
		ret ]
	hrrz t3, versio		; edit
	skipe t3
	 call [	movei t1, "("
		PBOUT
		numout t3, 8
		movei t1, ")"
		PBOUT
		ret ]
	ldb t4, [410300,,versio] ; who
	skipe t4
	 call [	movei t1, "-"
		PBOUT
		numout t4, 8
		ret ]

time:	hrroi t1, crlf
	PSOUT
	movx t1, .priou		; Current date and time.
	seto t2,		; 
	movx t3, ot%day!ot%fdy!ot%fmn!ot%4yr!ot%dam!ot%spa!ot%scl
	ODTIM%
	 erjmp .+1
	call moon		; Phase of the moon.

	tmsg <
TTY for file transfer:  >
	numout ttynum, 8
	move t4, mytty		; See whether we're local or remote...
	hrroi t1, [asciz/ (job's controlling terminal, KERMIT-20 is REMOTE)/]
	came t4, ttynum
	 hrroi t1, [asciz/ (assigned TTY line, KERMIT-20 is LOCAL)/]
	PSOUT%

$show2:	tmsg <

  Byte size for file I/O:  >
	hrroi t1, [ASCIZ/"Auto-Byte"/]
	skipn autbyt
	 jrst [	hrroi t1, [ASCIZ/Seven-Bit/]
		skipe ebtflg
		 hrroi t1, [ASCIZ/Eight-Bit/]
		jrst .+1 ]
	PSOUT%
$show3:	tmsg <
  IBM-Flag:  >
	hrroi t1, [ASCIZ/On/]
	skipn ibmflg
	 hrroi t1, [ASCIZ/Off/]
	PSOUT%
	skipe ibmflg
	 jrst [	tmsg <, Handshake: >
		move t1, trnrnd
		call putc
		jrst .+1 ]
$show4:	tmsg <
  Parity:    >
	move t2, parity
	hrroi t1, [ASCIZ/None/]
	cain t2, space
	 hrroi t1, [ASCIZ/Space/]
	cain t2, mark
	 hrroi t1, [ASCIZ/Mark/]
	cain t2, odd
	 hrroi t1, [ASCIZ/Odd/]
	cain t2, even
	 hrroi t1, [ASCIZ/Even/]
	PSOUT%

$sho4a:	tmsg <
  Duplex:    >			;[18]
	move t2, duplex
	hrroi t1, [asciz/Full/]
	caie t2, dxfull
	 hrroi t1, [asciz/Half/]
	PSOUT

$sho4b:	tmsg <
  Escape:    >
	move t1, escape
	call putc

$show5:	tmsg <
  Debugging: >
	hrro t1, [
		[asciz/Off/]
		[asciz/States/]
		[asciz/Packets/]
		](debug)
	PSOUT%
$show6:	tmsg <

Packet parameters:

              Receive         Send
  Size:            >
	numout rpsiz,^d10
	tmsg <		>
	numout spsiz,^d10

	tmsg <
  Timeout:         >
	numout rtimou
	tmsg <		>
	numout stimou
	movei t1, "-"		;[6]
	PBOUT%			;[6]
	numout [maxtim]		;[6]
	tmsg < sec>

$show7:	tmsg <
  Padding:         >
	numout rpadnm
	tmsg <		>
	numout spadnm
	tmsg <
  Pad Character:   >
	move t1, rpadch
	call putc
	tmsg <		>
	move t1, spadch
	call putc

$show8:	tmsg <
  End-Of-Line:     >
	move t1, reolch
	call putc
	tmsg <		>
	move t1, seolch
	call putc

	tmsg <
  Control Quote:   >
	move t1, rquote
	call putc
	tmsg <		>
	move t1, squote
	call putc
	
$showa: tmsg <
  Start-Of-Packet: >
	move t1, ssthdr		;[18]
	call putc
	tmsg <		>
	move t1, rsthdr		;[18]
	call putc

$show9:	tmsg <

Delay before sending first packet:  >
	numout delay
	tmsg < sec>
$showb:	tmsg <
Packet retries before timeout:      >
	numout maxtry
$showc:	tmsg <
Number of retries for init packet:  >
	numout imxtry

	tmsg <
Server sends NAKs every >
	numout [dsrvtm]
	tmsg < sec while waiting for command.>

	skipn debug		; No blips if debugging.
	skipn local		; Or if not local.
	 jrst $showx		;  ...

$showd:	tmsg <

"." for every >			;[4]
	numout [blip]		;[9]
	tmsg < packets, "%" for each NAK.>

$showx:	tmsg <

>				;[4]
	ret

putc:	caile t1, "~"		; Rubout?
	 jrst [ tmsg <DEL>	;  Yes, type this?
		ret ]
	caige t1, " "		; Is it a control char?
	 jrst [ push p, t1	;  Save the char.
		movei t1, "^"	;  Get the control quote.
		PBOUT%
		pop p, t1
		ori t1, ^o100	;  Turn on the non-control bit.
		jrst .+1 ]
	PBOUT%
	ret

	subttl	BYE command

 ;[11] The BYE command is part of edit 11.

.bye:	noise (to remote server) ; Parse rest of BYE command.
	confrm
	ret

$bye:	skipn local		; Local Kermit?
	 jrst [	ermsg <BYE command has no effect without prior SET LINE>
		ret ]
	setzm numtry		; OK, try to do it.

$bye2:	move q1, numtry		; Make sure we haven't tried too much.
	caml q1, maxtry
	 jrst [ ermsg <Can't send BYE, max tries exceeded>
		ret ]
	aos numtry		; Count this try.
	move t1, [byte (8)"L",0] ; Put a Logout command in the data block.
	movem t1, data
	diamsg <GL >		; Say we're sending generic logout command.
	movei t1, "G"		; Generic command.
	setz t2,		; Make the packet number zero.
	movei t3, 1		; Data is one character.
	move t4, [point 8, data] ; Point to data block.
	call spack		; Send it off.
	 jrst [	ermsg <Can't send BYE packet>
		ret ]
	call rpack		; Look for acknowledgment.
	 jrst [	ermsg <Can't get reply to BYE packet>
		ret ]
	cain t1, "Y"		; Got reply.  Is it an ACK?
	 jrst [	setom f$exit	; Turn on the exit flag.
		jrst $byex ]
	cain t1, "E"		; Error packet?
	 jrst [	hrroi t1, [asciz/?Remote error -- /] ; Yes, print it.
		PSOUT%
		move t1, t4	; Get pointer to it,
		PSOUT%		; and print it.
		setzm f$exit	; Don't exit, since the command failed.
		ret ]
	caie t1, "N"		; NAK?
	 cain t1, "T"		; Or Timeout?
	 jrst $bye2		;  One of those, go try again.

	ermsg <Can't send BYE, don't know why>
	ret

;[16] From here to end is part of edit 16.

$byex:	movei q1, 5		; Try this 5 times
	movei t1, ^d750		; Sleep a second.
	DISMS%
$byex2:	movei t1, ^d250		; Sleep a little bit
	DISMS%
	move t1, netjfn		; Any messages?
	SIBE%
	 skipa t3, t2		; Yes, this many characters.
	 jrst $byexx		;  No, try again.
	hrroi t2, buffer	; Get whatever is there.
	movei t4, .chlfd
	SIN%
	setz t3,
	idpb t3, t2
	hrroi t1, buffer	; And print it.
	PSOUT%
$byexx: sojg q1, $byex2		; See if we want to type some more.

	setzm buffer		; Zero this out, just in case.
	tmsg <...>		; No. Maybe there's more, but...
	move t1, netjfn		;  can't wait forever for it,
	CFIBF%			;  throw the rest away.
	ret

	subttl	FINISH command

 ;[28] The FINISH command is edit 28.

.finis:	noise (remote server operation) ; Parse rest of FINISH command.
	confrm
	ret

$finis:	skipn local		; Local Kermit?
	 jrst [	ermsg <FINISH command has no effect without prior SET LINE>
		ret ]
	setzm numtry		; OK, try to do it.

$fini2:	move q1, numtry		; Too many tries?
	caml q1, maxtry
	 jrst [ ermsg <Can't send FINISH, max tries exceeded>
		ret ]
	aos numtry		; Count this try.
	move t1, [byte (8)"F",0] ; Put a Finish command in the data block.
	movem t1, data
	diamsg <GF >		; Say we're sending generic logout command.
	movei t1, "G"		; Generic command.
	setz t2,		; Make the packet number zero.
	movei t3, 1		; Data is one character.
	move t4, [point 8, data] ; Point to data block.
	call spack		; Send it off.
	 jrst [	ermsg <Can't send FINISH packet>
		ret ]
	call rpack		; Look for acknowledgment.
	 jrst [	ermsg <Can't get reply to FINISH packet>
		ret ]
	cain t1, "Y"		; Got reply.  Is it an ACK?
	 jrst [	 tmsg <[OK]>	;  Yes, good.
		 ret ]
	cain t1, "E"		; Error packet?
	 jrst [	hrroi t1, [asciz/?Remote error -- /] ; Yes, print it.
		PSOUT%
		move t1, t4	; Get pointer to it,
		PSOUT%		; and print it.
		ret ]
	caie t1, "N"		; NAK?
	 cain t1, "T"		; Or Timeout?
	 jrst $fini2		;  One of those, go try again.

	ermsg <Can't send FINISH, don't know why>
	ret

	subttl	CONNECT command

.conne:	noise <to tty>
	movei t1, [flddb. (.cmnum,cm%sdh,^d8,<octal tty number to connect to>,,[
		   flddb. (.cmcfm,cm%sdh,,<confirm to connect to selected line>)])]
	call rfield		; Parse a tty number.
	ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
	caie t3, .cmnum		; Is it a number?
	 ret			;  If not it must be a confirm.
	movem t2, pars3		; Save the tty number.
	confrm
	ret

$conne:	stkvar <tjfn,<trscn,20>>
	skipe pars3		; Did we parse a TTY number?
	 call $setln		;  If so, use that one.
	skipe telfrk		; Have a ttlink fork?
	 jrst $conn1		; Yes, continue.
	move t4, mytty		; Find our terminal number.
	camn t4, ttynum		; Is this number the same as the TTLINK tty?
	 jrst [	ermsg <Can't CONNECT to your own line.  Use the SET LINE n command first.>
		ret ]
	movx t1, gj%sht+gj%old	; Find the TTLINK program.
	hrroi t2, [asciz/SYS:TTLINK.EXE/]
	GTJFN%
	 %jserr (Can't find SYS:TTLINK.EXE,r)
	movem t1, tjfn		; Save the JFN.
	movx t1, cr%cap		; Needs Control-C capability.
	setzm t2
	CFORK%
	 %jserr <Can't create TTLINK fork>,r
	movem t1, telfrk	; Remember the fork.
	hrlzs t1		; Move handle into left half.
	hrr t1, tjfn		; JFN in right half.
	setzm t2		; Nothing special.
	GET%			; Do the get.
	 %jserr <Can't GET TTLINK fork>,r

	;...

$conn1:	hrroi t1, trscn		; Now set up the rescan buffer for TTLINK.
	hrroi t2, [asciz/TTLINK CONNECT /]
	setzb t3, t4
	SOUT%
	 %jserr (,.+1)

$conn2:	move t2, ttynum		; Get the tty number.
	movei t3, ^d8		; Octal.
	NOUT%
	 %jserr (,.+1)
	skipe escape		;[16] Escape character specified?
	 jrst [	hrroi t2, [asciz\/ESC:\] ;[16] Yes, make TTLINK switch for it.
		setzb t3, t4	;[16] 
		SOUT%		;[16]
		 %jserr (,.+1)	;[16]
		move t2, escape	;[16] Octal value of escape character.
		movei t3, ^d8	;[16]
		NOUT%		;[16]
		 %jserr (,.+1)	;[16]
		jrst .+1 ]
	move t3, duplex		;[18] Duplex.
	caie t3, dxfull		;[18] Full is the default.
	 jrst [	hrroi t2, [asciz\/DUP:HALF\] ;[18] Want half, include switch.
		setzb t3, t4	;[18]
		SOUT%		;[18]
		 %jserr (,.+1)	;[18]
		jrst .+1 ]	;[18]

$conn3:	hrroi t2, [asciz\/PARITY:\] ; Parity switch
	setzb t3, t4
	SOUT%
	 %jserr (,.+1)
	move t3, parity
	hrroi t2, [ASCIZ/NONE/]
	cain t3, space
	 hrroi t2, [ASCIZ/SPACE/]
	cain t3, mark
	 hrroi t2, [ASCIZ/MARK/]
	cain t3, odd
	 hrroi t2, [ASCIZ/ODD/]
	cain t3, even
	 hrroi t2, [ASCIZ/EVEN/]
	setzb t3, t4
	SOUT%
	 %jserr (,.+1)

$conn5:	hrroi t2, crlf		; End with a CRLF.
	setzb t3, t4
	SOUT%
	 %jserr (,.+1)
$conn6:	hrroi t1, trscn		; Here is the pointer.
	RSCAN%			; Make it readable.
	 %jserr (,r)
$conn7:	move t1, telfrk		; Here is the fork.
	setz t2,		; Primary start address.
	SFRKV%			;  Start it up.
	 %jserr <Can't start TTLINK fork>,r
$conn8:	WFORK%			; wait for the fork
	 %jserr <Can't wait for TTLINK fork>,r
	ret			; Fork done, just return.

	subttl	PROMPT command

.promp:	confrm			; Confirm.
	ret

$promp:	setzm f$exit		; Set exit flag.
	ret

	subttl	SERVER command

.serve:	confrm			; Confirm.
	ret

$serve:	setom f$exit		; Set exit flag.
	call getcom		; Go serve.
	ret

	subttl	GET remote files

;[11] This whole command is part of edit 11

.get:	noise <remote files>
	movei t1, [flddb. .cmtxt,cm%sdh,,<remote file specification>]
	call cfield
	ret

$get:	skipe local		; This only works if local Kermit.
	 jrst $get2
	ermsg <Can't GET without prior SET LINE>
	ret

$get2:	move t1, [point 7, atmbuf] ; Copy the string out of the atom buffer.
	move t2, [point 8, data]
	seto t3,		; Counter, started at -1.

$get3:	ildb t4, t1		; Get a character.
	idpb t4, t2		; Copy it.
	aos t3			; Count it.
	jumpn t4, $get3		; Everything up to & including the first null.

	jumpe t3, [ermsg <No remote filespec given>
		ret ]
	movei t1, "R"		; Send a Receive-Init packet.
	setz t2,		; Number 0.
	move t4, [point 8, data] ; Point to remote filespec.
	call spack
	 jrst [	ermsg <Can't send Receive-Init>
		ret ]
	callret $recv		; Go into receive state.

	subttl	RECEIVE command

.recv:	noise <into file>
	movei t1, [flddb. (.cmofi,cm%sdh,,<output file specification>,,[
		   flddb. (.cmcfm,cm%sdh,,<confirm to use micro's filespec>,,)])]
	call rfield		; Parse a file spec or a confirm.
	ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
	caie t3, .cmofi		; Is it an input file spec?
	 jrst .recv2		;  If not it must be a confirm.
	movem t2, filjfn	; Save the JFN.
	movei t1, [flddb. .cmcfm]
	call rflde
	 jrst [ move t1, filjfn	;  Get the JFN.
		RLJFN%		;  Release it.
		 erjmp .recv1	;   Ignore.
.recv1:		setzm filjfn	;  Set the JFN to zero.
		tmsg <?Not confirmed>
		jrst cmder1 ]
.recv2:	ret

$recv:	setzm stot		; Initialize character counters.
	setzm rtot
	setzb schr, stchr
	setzb rchr, rtchr
	setom rptot		;[4] Init received-packet counter to -1.
	setzm errptr		; Zero the error message pointer.
	skipe autbyt		; Using autobyte?
	 setzm ebtflg		;  If so reset eight bit flag.
	call inilin		; Initialize the line.
	call ccon		; Turn on the ^C trap so line is restored.
	 jrst reslin		;[27] On ^C, go reset line & return from there.
	setzm pktnum		; Inititial the packet sequence number.
	movei state, "R"	; Set the state to receive initiate.
	setzm numtry		; Set the number of tries to zero.

$recv2:	skipe local		;[22] Local?
	 caie debug, 1		;[22] Normal debugging?
	 skipa			;[22]  No.
	 jrst [	movei t1, .priou ;[22]  Yes, output the packet number.
		move t2, pktnum	; 
		movei t3, ^d10	; In decimal.
		NOUT%		; 
		 jrst .+1	;  Can't, but it's not the end of the world...
		jrst .+1 ]
	cain state, "D"		; Are we in the data send state?
	 jrst [ diamsg <D >
		call rdata
		jrst $recv2 ]
	cain state, "F"		; Are we in the file receive state?
	 jrst [ diamsg <F >
		move t1, filjfn	;  Get the file's JFN.
		call rfile	;  Call receive file.
		jrst $recv2 ]
	cain state, "R"		; Are we in the receive initiate state?
	 jrst [	diamsg <R >
		call rinit	;  Call receive initiate.
		jrst $recv2 ]
	cain state, "C"		; Are we in the receive complete state?
	 jrst [	diamsg <C >
		call reslin	;  Restore the line.
		GTAD%		;  Get the time we ended.
		subm t1, stdat	;  Figure how long it all took.
		call ccoff	;  Turn off ^C trap.
		movei t1, .chbel ;[31] Give a beep
		skipe local	;[31] if local
		 PBOUT		;[31]
		ret ]
	cain state, "A"		; Are we in the receive abort state?
	 jrst [	diamsg <A >
		call reslin	;  Restore the line.
		GTAD%		;  Get the time we ended.
		subm t1, stdat	;  Figure how long it all took.
		call ccoff	;  Turn off ^C trap.
		ret ]
	diamsg <U >		; Something else...
	call ccoff		; Turn off ^C trap.
	ret


	subttl receive routines

rinit:	saveac <q1>
	move q1, numtry		; Get the number of tries.
	caml q1, imxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to receive initiate>
		movei state, "A" ;  Change the state to abort.
		ret ]
	aos numtry		; Increment the number of tries.
	call rpack		; Get a packet.
	 ret			;  Trashed packet don't change state, retry.
	cain t1, "E"		;[32] Error packet?
	 jrst [	hrroi t1, [asciz/?Remote error -- /] ;[32] Yes, print it.
		PSOUT%		;[32]
		move t1, t4	;[32] Get pointer to it,
		PSOUT%		;[32] and print it.
		movei state, "A" ;[32] "Abort" the transfer.
		ret ]		;[32]  Return gracefully.
	move q1, t1		; Not error, save the packet type.
	GTAD%			; Get the time we start.
	movem t1, stdat		; Save it.
	caie q1, "S"		; Got a send-init?
	 jrst [	move t2, pktnum	;  No, something else, or timed out.
		call NAK	;  Just NAK the packet we wanted.
		ret ]
	movem t2, pktnum	; Yes, synchronize packet numbers.
	call spar		; Get the information
	move t4, [point 8, data] ; Get a pointer to our data block.
	call rpar		; Set the information.
	movei t1, "Y"		; Acknowledge packet.
	move t2, pktnum		; Packet number.
	move t4, [point 8, data] ; The address of the data.
	call spack		; Send the packet.
	 jrst [	movei state, "A" ; Failed, set state to "abort".
		ret ]
	move t2, numtry		; Get the number of tries.
	movem t2, oldtry	; Save it.
	setzm numtry		; Reset the number of tries.
	move t2, pktnum		; Get the packet number.
	addi t2, 1		; Increment it.
	dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
	movei state, "F"	; Set the state to file send.
	ret 

rfile:	saveac <q1,q2>
	move q1, numtry		; Get the number of tries.
	caml q1, maxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to receive file header
>
		movei state, "A" ;  Change the state to abort.
		ret ]
	aos numtry		; Increment number of tries.
	move q1, t1		; Save the arguments.
	move q2, t2
	call rpack		; Get a packet.
	 ret			;  Trashed packet, don't change state, retry.

rfile1:	caie t1, "S"		; Check the packet.
	 jrst rfile2
	move q1, oldtry		; Get the number of tries.
	caml q1, imxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to receive initiate>
		movei state, "A" ; Change the state to abort.
		ret ]
	aos oldtry		; Save the updated number of tries.
	skipg q1, pktnum	;[3] Get the present packet number.
	 movei q1, 100		;[3]  If it just wrapped around, do this.
	caie t2, -1(q1)		; Is the packet's number one less than now?
	 jrst [ ermsg <Error receiving initiate>
		movei state, "A" ; Change the state to "abort".
		ret ]
	setzm numtry		 ; Start count over.
	move t4, [point 8, data] ; Get a pointer to our data block.
	call rpar		 ; Set the information.
	movei t1, "Y"		 ; Acknowledge packet.
	move t4, [point 8, data] ; The address of the data.
	call spack		 ; Send the packet.
	 movei state, "A" ;  Can't, set state to "abort".
	ret

rfile2:	caie t1, "Z"		; Check the packet.
	 jrst rfile3
	move q1, oldtry		; Get the number of tries.
	caml q1, maxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Maximum retries exceeded, unable to receive EOF>
		movei state, "A" ; Change the state to abort.
		ret ]
	aos oldtry		; Save the updated number of tries.
	skipg q1, pktnum	;[3] Get the present packet number.
	 movei q1, 100		;[3] If it just wrapped around, do this.
	caie t2, -1(q1)		; Is the packet's number one less than now?
	 jrst [ ermsg <Invalid EOF packet received>
		movei state, "A" ; Change the state to abort.
		ret ]
	setzm numtry		; Start count over.
	movei t1, "Y"		; Acknowledge packet.
	setzb t3, t4		; No data.
	call spack		; Send the packet.
	 movei state, "A"	; Can't, set state to abort.
	ret

rfile3:	caie t1, "F"		; Start of file?
	 jrst rfile4
	came t2, pktnum		; Is it the right packet number?
	 jrst [ ermsg <Incorrect packet number on start of file packet>
			movei state, "A" ; Change the state to abort.
			ret ]
	move t1, t4		; Get a pointer to the data.
	move t2, t3		; Get the length of the data.
	call gofil		; Get a file to write to.
	 jrst [	movei state, "A" ;  Set state to abort.
		ret ]
	movem t1, filjfn	; Save the JFN.
	movei t1, "Y"		; Acknowledge packet.
	move t2, pktnum
	setzb t3, t4		; No data.
	call spack		; Send the packet.
	 jrst [	movei state, "A" ; Can't, "abort".
		ret ]
	move t1, filjfn
	movx t2, fld(7,of%bsz)!of%wr ;  7-bit bytes, write access.
	skipe ebtflg		;  Eight bit access?
	 movx t2, fld(8,of%bsz)!of%wr ;  8-bit bytes, write access.
	OPENF%			; Open the file.
	 erjmp [kermsg <Unable to open file
>
		move t1, filjfn	; Get the output JFN.
		RLJFN%		; Release the JFN.
		 erjmp .+1	;  Ignore the error.
		setzm filjfn	; Clear the JFN.
		movei state, "A" ; Change state to EOF
		ret ]
	skipe local		;[12] Local Kermit?
	 jrst [	movei t1, .priou ;[12] Yes, print the file name.
		RFPOS%		;[12] First see if we need to start a new line.
		hrroi t1, crlf	;[12]  ...
		trne t2, -1	;[12]  ...
		 PSOUT%		;[12]
		movei t1, .priou ;[12] Now print the file name.
		hrrz t2, filjfn ;[12]
		setz t3,	;[12]
		JFNS%		;[12]
		 erjmp .+1	;[12]
		movei t1, " "	;[12]
		PBOUT%		;[12]
		jrst .+1 ]	;[12]

	setzm mapflg		; Say no pages mapped in yet.
	move t2, numtry		; Get the number of tries.
	movem t2, oldtry	; Save it.
	setzm numtry		; Reset the number of tries.
	move t2, pktnum		; Get the packet number.
	addi t2, 1		; Increment it.
	dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
	movei state, "D"	; Set the state to file send.
	ret

rfile4:	caie t1, "B"		; End of transmission?
	 jrst rfile5		;  No.
	came t2, pktnum		; Is it the right packet number?
	 jrst [ ermsg <Incorrect packet number on EOT packet
>
		movei state, "A" ; Change the state to abort.
		ret ]
	movei t1, "Y"		; Acknowledge packet.
	setzb t3, t4		; No data.
	call spack		; Send the packet.
	 skipa state, "A"	; Can't, abort.
	movei state, "C"	; Set state to complete.
	ret

rfile5:	cain t1, "T"		; Timer interrupt pseudo packet?
	 jrst [	movei t1, "N"	; Yes, send a NAK
		move t2, pktnum	; for the expected packet.
		setzb t3, t4	; No data.
		call spack	; Send the packet.
		 movei state, "A" ; Can't, "abort".
		ret ]

rfilex:	movei state, "A"	; Anything else: "abort".
	ret


rdata:	saveac <q1,q2>
	move q1, numtry		; Get the number of tries.
	caml q1, maxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to receive data
>
		jrst rdterr]
	addi q1, 1		; Increment it.
	movem q1, numtry	; Save the updated number of tries.
	move q1, t1		; Save the arguments.
	move q2, t2
	call rpack		; Get a packet.
	 ret			;  Trashed packet don't change state, retry.
	cain t1, "D"		; Data packet?
	 jrst [	came t2, pktnum	;  Is it the right packet?
		 jrst .+1
		move t1, t4	;  Get the pointer to the data.
		move t2, t3	;  Get the length of the data.
		call ptchr	;  Write the chars to a file.
		 jrst rdterr	;   Die cleanly.
		movei t1, "Y"	;  Acknowledge packet.
		move t2, pktnum	;  Get the sequence number.
		setzb t3, t4	;  No data.
		call spack	;  Send the packet.
		 jrst rdterr	;   Die cleanly.
		move t2, numtry ;  Get the number of tries.
		movem t2, oldtry ;  Save it.
		setzm numtry	;  Reset the number of tries.
		move t2, pktnum ;  Get the packet number.
		addi t2, 1	;  Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		ret ]
	cain t1, "D"		; Is it a previous data packet?
	 jrst [	move q1, oldtry	;  Get the number of tries.
		caml q1, maxtry	;  Have we reached the maximum number of tries?
		 jrst [ ermsg <Unable to receive data
>
			jrst rdterr ] ; Die cleanly.
		aos oldtry	; Updated number of tries.
		skipg q1, pktnum ;[3]  Get the present packet number.
		 movei q1, 100	;[3]  If it just wrapped around, do this.
		caie t2, -1(q1)	;  Is the packet's number one less than now?
		 jrst [ ermsg <Error receiving data
>
			 jrst rdterr] ;  Die cleanly
		setzm numtry	;  Start count over.
		movei t1, "Y"	;  Acknowledge packet.
		setzb t3, t4	;  No data.
		call spack	;  Send the packet.
		 movei state, "A" ;   Set state to abort.
		ret ]

	cain t1, "F"		; Check the packet.
	 jrst [	move q1, oldtry	;  Get the number of tries.
		caml q1, maxtry	;  Have we reached the maximum number of tries?
		 jrst [ ermsg <Unable to acknowledge file header
>
			 jrst rdterr] ;  Die cleanly
		aos oldtry	;  Save the updated number of tries.
		skipg q1, pktnum ;[3]  Get the present packet number.
		 movei q1, 100	;[3]  If it just wrapped around, do this.
		caie t2, -1(q1)	;  Is the packet's number one less than now?
		 jrst [ ermsg <Error receiving file header
>
			 jrst rdterr] ;  Die cleanly
		setzm numtry	;  Start count over.
		movei t1, "Y"	;  Acknowledge packet.
		setzb t3, t4	;  No data.
		call spack	;  Send the packet.
		 jrst rdterr	;   Die cleanly
		ret ]
	cain t1, "Z"		; Is it an EOF?
	 jrst [	came t2, pktnum	;  Yes, is the packet number correct?
		 jrst [ ermsg <Invalid EOF packet received
>
			movei state, "A" ; Change the state to "abort".
			ret ]
		movei t1, "Y"	; OK, acknowledge the packet.
		setzb t3, t4	; (no data)
		call spack	; Send the ACK.
		 jrst [	movei state, "A" ; Can't, set state to "abort".
			ret ]
		skipe mapflg	;  Any pages mapped in?
		 jrst [	movx t1, <.fhslf,,mappag> ;   <our fork,,mapping page>
			hrl t2, filjfn ;  <file JFN,, page #>
			hrr t2, prepag
			movx t3, pm%rd!pm%wr ;   Read and write.
			PMAP%	;   Map it out.
		 	 %jsker (,r)
			setzm mapflg ;   Say no page mapped in.
			jrst rd1 ]

rd1:		movx t1, co%nrj
		hrr t1, filjfn	;  Get the JFN.
		CLOSF%		;  Close it.
		 erjmp rd2
		movx cf%nud
		hrli t1, .fbsiz	;  Set the number of bytes
		ior t1, [cf%nud]
		hrr t1, filjfn	;  Get the JFN.
		seto t2,	;  Change all bits.
		move t3, rchr	;  Get the number of bytes.
		CHFDB%
		 erjmp rd12
rd12:		hrli t1, .fbbyv	;  Set the byte size.
		hrr t1, filjfn
		move t2, [007700,,0] ;  Just the correct six bits.
		move t3, [000700,,0] ;  Seven bit.
		skipe ebtflg	;  Eight bit mode?
		 move t3, [001000,,0] ;  Set it as such.
		CHFDB%
		 erjmp rd2
rd2:		hrr t1, filjfn	;  Get the JFN.
		RLJFN%		;  Release the JFN.
		 nop
		hrroi t1, [asciz/[OK]/]	;[19] Comforting message.
		skipe local	;[19]  Print it if local.
		 PSOUT%		;[19]
		setzm filjfn	;  Say we have no file.
		addm rchr, rtchr ;  Add to the total.
		setz rchr,
		move t2, numtry ;  Get the number of tries.
		movem t2, oldtry ;  Save it.
		setzm numtry	;  Reset the number of tries.
		move t2, pktnum ;  Get the packet number.
		addi t2, 1	;  Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		movei state, "F"
		ret ]
	cain t1, "T"		; Timer interrupt pseudo packet?
	 jrst [	movei t1, "N"	;  Send a NAK.
		move t2, pktnum
		setzb t3, t4	;  No data.
		call spack	;  Send the packet.
		 movei state, "A" ; Can't, set state to "abort".
		ret ]
rdterr:	movx t1, cz%abt		; Abort the file.
	hrr t1, filjfn		; Get the JFN.
	CLOSF%			; Close it.
	 erjmp .+1
	setzm filjfn		; Say we have no file.
	movei state, "A"	; Change the state to abort.
	ret

	subttl	Utility protocol routines

; Send a NAK.  Expects to find the packet number to NAK in AC2.

nak:	movei t1, "N"		; Send a NAK.
	setzb t3, t4		; No data.
	call spack		; Send the packet.
	 jrst [	movei state, "A" ;  Set state to abort.
		ret ]
	ret

; Get the arguments from a Send_Init packet.
;
; The length of the data (i.e. the number of fields) should be in t3.

spar:	sojl t3, r		;[24] Make sure the field is there.
	ildb t2, t4		; Get the first argument.
	subi t2, " "		; Convert it to a number.
	movem t2, spsiz		; Set the maximum packet size to send.

spar2:	sojl t3, r		;[24] Make sure the field is there.
	ildb t2, t4		; Get the second argument.
	subi t2, " "		; Convert it to a real number.
	movem t2, stimou	; Set the time out interval.
	movem t2, otimou	;[26] Here too, in case we want to change it.

spar3:	sojl t3, r		;[24] Make sure the field is there.
	ildb t2, t4		; Get the second argument.
	subi t2, " "		; Convert it to a number.
	movem t2, spadnm	; Set the padding.

spar4:	sojl t3, r		;[24] Make sure the field is there.
	ildb t2, t4		; Get the second argument.
	addi t2, ^o100
	andi t2, ^o177
	movem t2, spadch	; Set the padding char.

spar5:	sojl t3, r		;[24] Make sure the field is there.
	ildb t2, t4		; Get the second argument.
	subi t2, " "		; Convert it to a number.
	movem t2, seolch	; Set the EOL char.

spar6:	sojl t3, r		;[24] Make sure the field is there.
	ildb t2, t4		; Get the second argument.
	movem t2, squote	; Set the quote char.

; Add additional fields here.

sparx:	ret

; Sets up the init packet.  Returns number of elements in T3.

rpar:	saveac <q1>
	move q1, rpsiz		; Get the packet size.
	addi q1, " "		; Make the char printable.
	idpb q1, t4		; Put it in the data block.
	move q1, rtimou		; Get the time out interval.
	addi q1, " "		; Make the char printable.
	idpb q1, t4		; Put it in the data block.
	move q1, rpadnm		; Get the padding.
	addi q1, " "		; Make the char printable.
	idpb q1, t4		; Put it in the data block.
	move q1, rpadch		; Get the padding char.
	addi q1, ^o100		; De-controlify it.
	andi q1, ^o177
	idpb q1, t4		; Put it in the data block.
	move q1, reolch		; Get the EOL char.
	addi q1, " "		; Make the char printable.
	idpb q1, t4		; Put it in the data block.
	move q1, rquote		; Get the quote char.
	idpb q1, t4		; Put it in the data block.
	movei t3, 6		; Six pieces of data.
	ret


	subttl	SEND command

.send:	noise <from files>
	move t2, cjfnbk+.gjgen	; Get the JFN flag bits.
	txo t2, gj%ifg!gj%old	; Turn on wild carding for old files only.
	movem t2, cjfnbk+.gjgen	; Return the JFN flag bits.
	movei t1, [flddb. (.cmfil,cm%sdh,,<input file spec (possibly wild)>,,)]
	call rfield		; Parse a file spec or a confirm.
	movem t2, ndxjfn	; Save the indexable JFN.
	hrrm t2, filjfn		; Save the JFN.
	noise <initial>
	movei t1, [flddb. (.cmcfm,cm%sdh,,<Carriage return to send them all>,,[
		   flddb. (.cmfil,cm%sdh,,<Initial filespec>)])]
	call rflde
	 jrst [ move t1, filjfn	;  Get the JFN.
		RLJFN%		;  Release it.
		 erjmp .snd2	;   Ignore.
.snd1:		setzm filjfn	;  Set the JFN to zero.
		tmsg <?Not confirmed>
		jrst cmder1 ]
	ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
	cain t3, .cmcfm		; Confirmation?
	 ret			;  Yes, just return.
	hrrm t2, ndxjfn		; No, initial filespec - substitute it.
	hrrm t2, filjfn
	movei t1, [flddb. .cmcfm]
	call rflde
	 jrst [ move t1, filjfn	; Get the JFN.
		RLJFN%		; Release it.
		 erjmp .snd2	;  Ignore.
.snd2:		setzm filjfn	; Set the JFN to zero.
		tmsg <?Not confirmed>
		jrst cmder1 ]
	ret

$send:	setzm stot		; Initialize character counters.
	setzm rtot
	setzb schr, stchr
	setzb rchr, rtchr
	setom sptot		;[4] Init the sent-packet counter to -1.
	setzm errptr		; Zero the error message pointer.
	GTAD%			; Get the time we start.
	movem t1, stdat		; Save it for statistics.
	skipn srvflg		; In server mode?
	 jrst [	call inilin	; No, need to initialize the line
		call ccon	;  and turn on ^C trap so we can restore line.
		 jrst reslin	;[10] Don't go on if this fails.
		jrst .+1 ]

	move t1, delay		; The specified delay in seconds,
        imuli t1, ^d1000	;  converted to milliseconds.
	skipn local		;[13] If acting as remote Kermit,
	 DISMS%			;  sleep to let them set up other side.

$send1:	setzm pktnum		; Inititial the packet sequence number.
	movei state, "S"	; Set the state to send initiate.
	setzm numtry		; Set the number of tries to zero.

	;...cont'd

$send2:	skipe local		;[22] If local
	 caie debug, 1		;[22] and doing "state" debugging,
	 skipa			;[22]
	 jrst [	movei t1, .priou ;[22]
		move t2, pktnum	; type the packet number,
		movei t3, ^d10	; in decimal.
		NOUT%
		 jrst .+1
		jrst .+1 ]

	cain state, "D"		; Are we in the data send state?
	 jrst [ diamsg <D >
		call sdata
		jrst $send2 ]
	cain state, "F"		; Are we in the file send state?
	 jrst [	diamsg <F >
		move t1, filjfn	;  Get the file's JFN.
		call sfile	;  Call send file.
		jrst $send2 ]
	cain state, "Z"		; Are we in the end of file state?
	 jrst [	diamsg <Z >
		call seof
		jrst $send2 ]
	cain state, "S"		; Are we in the send initiate state?
	 jrst [	diamsg <S >
		call sinit	;  Call send initiate.
		jrst $send2 ]
	cain state, "B"		; Are we in the end of send state?
	 jrst [	diamsg <B >
		call seot
		jrst $send2 ]
	cain state, "C"		; Are we in the send complete state?
	 jrst [	diamsg <C >
		call reslin	;  Restore the line.
		GTAD%		;  Get the time we ended.
		subm t1, stdat	;  Figure how long it all took.
		call ccoff	;  Turn off ^C trap.
		movei t1, .chbel ;[31] Give a beep
		skipe local	;[31] if local
		 PBOUT		;[31]
		ret ]
	cain state, "A"		; Are we in the send abort state?
	 jrst [	diamsg <A >
		call reslin	;  Restore the line.
		GTAD%		;  Get the time we ended.
		subm t1, stdat	;  Figure how long it all took.
		call ccoff	;  Turn off ^C trap.
		ret ]
	diamsg <U >
	call ccoff		; Turn off ^C trap.
	ret


	subttl Send routines

sinit:	saveac <q1>
	move q1, numtry		; Get the number of tries.
	caml q1, imxtry		; Have we reached the maximum number of tries?
	 jrst [	skipe local	;[5]
		 ermsg <Send-Init not ACK'd> ;[5]
		movei state, "A" ;  Change the state to abort.
		ret ]
	aos numtry		; Save updated number of tries.
	move t4, [point 8, data] ; Get a pointer to our data block.
	call rpar		; Set the information.
	movei t1, "S"		; Send initiate packet.
	move t2, pktnum		; Packet number.
	move t4, [point 8, data] ; The address of the data.
	call spack		; Send the packet.
	 jrst [	movei state, "A" ; Can't, set state to "abort".
		ret ]
	call rpack		; Get a packet.
	 ret			;  Trashed packet don't change state, retry.
	cain t1, "Y"		; Check the packet.
	 jrst [	came t2, pktnum	; Is it the right ACK?
		 ret		;  No, don't settle, hold out for right one.
		call spar	; Get the information
		setzm numtry	; Reset the number of tries.
		move t2, pktnum ; Get the packet number.
		aos t2		; Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		movei state, "F" ; Set the state to file send.
		ret ]
	caie t1, "N"		;[30] NAK?
	cain t1, "T"		; Timer interrupt pseudo packet?
	 ret			;[30] One of those, just keep trying.
	movei state, "A"	; Anything else, just "abort".
	cain t1, "E"		; But also print message if error packet.
	 jrst [	hrroi t1, [asciz/?Remote error -- /] ; Yes, print it.
		PSOUT%
		move t1, t4	; Get pointer to it,
		PSOUT%		; and print it.
		ret ]
	ret

sfile:	saveac <q1>
	move q1, numtry		; Get the number of tries.
	caml q1, maxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to send file name
>
		movei state, "A" ;  Change the state to abort.
		ret ]
	addi q1, 1		; Increment it.
	movem q1, numtry	; Save the updated number of tries.

sfilea:	skipe local		;[12] Local Kermit?
	 jrst [	movei t1, .priou ;[12] Yes, print the file name.
		RFPOS%		;[12] First see if we need to start a new line.
		hrroi t1, crlf	;[12]  ...
		trne t2, -1	;[12]  ...
		 PSOUT%		;[12]
		movei t1, .priou ;[12] Now print the file name.
		hrrz t2, filjfn ;[12]
		setz t3,	;[12]
		JFNS%		;[12]
		 erjmp .+1	;[12]
		movei t1, " "	;[12] and a space.
		PBOUT%		;[12]
		jrst .+1 ]	;[12]

	move t1, filjfn		;[15] Try to open the file.
	movx t2, fld(7,of%bsz)+of%rd ;[15]
	skipe ebtflg		;[15] 8-bit access?
	 movx t2, fld(8,of%bsz)+of%rd ;[15]
	OPENF%			;[15]
	 erjmp [skipe local	;[15]
		 call [	movei t1, " " ;[15]
			PBOUT%	;[15]
			movei t1, .priou ;[15]
			move t2, [.fhslf,,-1] ;[15] Print OPENF error msg.
			setz t3, ;[15]
			ERSTR%	;[15]
			 nop	;[15]
			 nop	;[15]
			tmsg < (not sent)> ;[15]
			ret ]	;[15]
		call gtnfil	;[15] Try to get the next file.
		 jrst [	setzm filjfn ;[15]
			movei state, "B" ;[15] No more, break transmission.
			ret ]	;[15]
		jrst sfilea ]	;[15] Got one, go try to open it.

	move t2, filjfn		; Get the JFN.
	move t1, [point 8, data] ; Get a pointer to the data buffer.
	movx t3, js%nam+js%typ+js%paf ; Just the file name and type.
	setz t4,
	JFNS%			; Get the file name.
	move t2, t1		; Set up to subtract the byte pointers.
	move t1, [point 8, data] ; Get a pointer to our data block.
	call subbp		; Subtract the byte pointers.
	 ret
	movei t1, "F"		; File send packet.
	move t2, pktnum		; Packet number.
	move t4, [point 8, data] ; Get a pointer to our data block.
	call spack		; Send the packet.
	 jrst [	movei state, "A" ;  Set state to abort.
		ret ]
	call rpack		; Get a packet.
	 ret			;  Trashed packet don't change state, retry.
	caie t1, "Y"		; Check the packet, is it an ACK?
	 jrst sfile3		;  No.
sfile2:	came t2, pktnum		; Yes, but is it the right ACK?
	 ret			;   No, don't settle, hold out for right one.
	setzm numtry		;  Reset the number of tries.
	move t2, pktnum		;  Get the packet number.
	addi t2, 1		;  Increment it.
	dpb t2, [point 6, pktnum, 35] ;  Save modulo 64 of the number.
	setzm mapflg		; Say no pages mapped in yet.
	move t1, spsiz		; Get the send packet size.
	subi t1, 5		; Subtract the overhead.
	call gtchr		; Get the chars.
	 jrst [	movei state, "Z" ; Assume end of file
		skipe t1	; Was it?
		 movei state, "A" ; No, "abort".
		ret ]
	movei state, "D"	;  Set the state to file send.
	movem t1, size		;  Save the length of the data.
	ret

sfile3:	caie t1, "N"		; NAK?
	 jrst sfile4
	ldb t1, [point 6, pktnum, 35] ;[3] Get expected packet number.
	caie t2, 1(t1)		;  Is the NAK for the next packet?
	 ret			;   Assume its for this packet.
	setzm numtry		;  Yes, means the same as ACK.  
	addi t1, 1		;  Increment it.
	dpb t1, [point 6, pktnum, 35] ; Save modulo 64 of the number.
	setzm mapflg		; Say no pages mapped in yet.
	move t1, spsiz		; Get the send packet size.
	subi t1, 5		; Subtract the overhead.
	call gtchr		; Get the chars.
	 jrst [	movei state, "Z" ; Assume end of file
		skipe t1	; Was it?
		 movei state, "A" ; No, "abort".
		ret ]
	movei state, "D"	;  Set the state to file send.
	movem t1, size		;  Save the length of the data.
	ret

sfile4:	cain t1, "T"		; Timer interrupt pseudo packet?
	 ret
	movei state, "A"	; Otherwise abort.
	ret

sdata:	saveac <q1>
	move q1, numtry		; Get the number of tries.
	caml q1, maxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to send data
>
		movei state, "A" ;  Change the state to abort.
		ret ]
	aos numtry		; Increment number of tries.
	movei t1, "D"		; File send packet.
	move t2, pktnum		; Packet number.
	move t3, size		; Get the data length.
	move t4, [point 8, data] ; Get a pointer to our data block.
	call spack		; Send the packet.
	 skipa state, "A"	;  Can't, "abort".
	call rpack		; Get a packet.
	 ret			;  Trashed packet don't change state, retry.
	cain t1, "Y"		; Check the packet.
	 jrst [	came t2, pktnum	;  Is it the right ACK?
		 ret		;   No, don't settle, hold out for right one.
		setzm numtry	;  Reset the number of tries.
		move t2, pktnum ;  Get the packet number.
		addi t2, 1	;  Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		move t1, spsiz	;  Get the send packet size.
		subi t1, 5	;  Subtract the overhead.
		call gtchr
		 jrst [	skipe t1 ; Is it end of file?
			 skipa state, "A" ; No, change state to abort.
			 movei state, "Z" ; Yes, set state to end of file.
			ret ]
		movem t1, size	;  Save the length of the data.
		ret ]

	cain t1, "N"		; NAK?
	 jrst [	ldb t1, [point 6, pktnum, 35] ;[3] Get expected packet number.
		caie t2, 1(t1)	;  Is the NAK for the next packet?
		 ret		;   Assume its for this packet.
		setzm numtry	;  Yes, means the same as ACK.  
		addi t1, 1	;  Increment it.
		dpb t1, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		move t1, spsiz	;  Get the send packet size.
		subi t1, 5	;  Subtract the overhead.
		call gtchr
		 jrst [	skipe t1 ; Is it end of file?
            		 skipa state, "A" ; No, change state to abort.
			 movei state, "Z" ; Set state to end of file.
			ret ]
		movem t1, size	;  Save the length of the data.
		ret ]

	cain t1, "T"		; Timer interrupt pseudo packet?
	 ret
	movei state, "A"	; Otherwise abort.
	ret

seof:	saveac <q1>
	move q1, numtry		; Get the number of tries.
	caml q1, maxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to send end of file>
		movei state, "A" ;  Change the state to abort.
		ret ]
	aos numtry		; Increment number of tries.
	movei t1, "Z"
	move t2, pktnum		; Packet number.
	setzb t3, t4		; No data.
	call spack		; Send the packet.
	 skipa state, "A"	;  Can't, "abort".
	call rpack		; Get a packet.
	 ret			;  Trashed packet don't change state, retry.
	cain t1, "Y"		; Check the packet.
	 jrst [	came t2, pktnum	;  Is it the right ACK?
		 ret		;   No, don't settle, hold out for right one.
		setzm numtry	;  Reset the number of tries.
		move t2, pktnum ;  Get the packet number.
		addi t2, 1	;  Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		move t1, filjfn	;  Get the file JFN.
		txo t1, co%nrj	;  Don't release the JFN (for GNJFN%).
		CLOSF%
		 erjmp gt3
		hrroi t1, [asciz/[OK]/]	;[19] Comforting message.
		skipe local	;[19]  Print it if local.
		 PSOUT%		;[19]
		addm schr, stchr ;  Add the last file's size to the total.
		setz schr,	;  Zero the present count.
gt3:		call gtnfil	;  Get the next file.
		 jrst [	setzm filjfn ;   Zero the JFN.
			movei state, "B" ;   No more, set state to complete.
			ret ]
		movei state, "F" ;  File send state.
		ret ]
	cain t1, "N"		; NAK?
	 jrst [	ldb t1, [point 6, pktnum, 35] ;[3] Get expected packet number.
		caie t2, 1(t1)	;  Is the NAK for the next packet?
		 ret		;   Assume its for this packet.
		setzm numtry	;  Reset the number of tries.
		move t2, pktnum ;  Get the packet number.
		addi t2, 1	;  Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		move t1, filjfn	;  Get the file JFN.
		txo t1, co%nrj	;  Don't release the JFN (for GNJFN%).
		CLOSF%
		 erjmp gt3
		hrroi t1, [asciz/[OK]/]	;[19] Comforting message.
		skipe local	;[19]  Print it if local.
		 PSOUT%		;[19]
		addm schr, stchr ;  Add the last file's size to the total.
		setz schr,	;  Zero the present count.
		call gtnfil	;  Get the next file.
		 jrst [	setzm filjfn ;   Zero the JFN.
			movei state, "B" ; No more, set state to complete.
			ret ]
		movei state, "F" ;  File send state.
		ret ]
	cain t1, "T"		; Timer interrupt pseudo packet?
	 ret
	movei state, "A"	; Otherwise "abort".
	ret


seot:	saveac <q1>
	move q1, numtry		; Get the number of tries.
	caml q1, maxtry		; Have we reached the maximum number of tries?
	 jrst [ ermsg <Unable to send end of file
>
		movei state, "A" ;  Change the state to abort.
		ret ]
	aos numtry		; Increment number of tries.
	movei t1, "B"
	move t2, pktnum		; Packet number.
	setzb t3, t4		; No data.
	call spack		; Send the packet.
	 skipa state, "A"	;  Can't...
	call rpack		; Get a packet.
	 ret			;  Trashed packet don't change state, retry.
	cain t1, "Y"		; Check the packet.
	 jrst [	came t2, pktnum	;  Is it the right ACK?
		 ret		;   No, don't settle, hold out for right one.
		setzm numtry	;  Reset the number of tries.
		move t2, pktnum ;  Get the packet number.
		addi t2, 1	;  Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		movei state, "C" ;  Complete state.
		ret ]
	cain t1, "N"		; NAK?
	 jrst [	ldb t1, [point 6, pktnum, 35] ;[3] Get expected packet number.
		caie t2, 1(t1)	;  Is the NAK for the next packet?
		 ret		;   Assume its for this packet.
		setzm numtry	;  Reset the number of tries.
		move t2, pktnum ;  Get the packet number.
		addi t2, 1	;  Increment it.
		dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
		movei state, "C" ;  Complete state.
		ret ]
	cain t1, "T"		; Timer interrupt pseudo packet?
	 ret
	movei state, "A"	; Otherwise abort.
	ret

	subttl File routines

gtchr:	saveac <q1,q2,q3,q4>
	stkvar <len,tmpac>
	subi t1, 1		; So we don't mess up on quoting.
	movem t1, len		; Save the length.
	skipe eoflag		; Is the end of file flag set?
	 jrst [	setz t1,	;  Indicate EOF.
		setzm eoflag
		ret ]
	skipe mapflg		; Do we have any thing mapped in?
	 jrst gtchr1		;  If so don't map anything in.
	move t1, filjfn		; Get the JFN.
	movx t2, <2,,.fbbyv>	; Get number of pages and bytes
	movei t3, filpag	;  into filpag and filbyt.
	GTFDB%			; Get the file descriptor block.
	 %jsker <Can't get file length>,r ;  Error close up.
	skipn filbyt		; Any bytes in the file?
	 jrst [	setom eoflag	;  No, set end of file flag.
		setz t1,	;  Say no chars.
		retskp]
	ldb t2, [point 6, filpag, 11] ; Get the byte size.
	movem t2, filbsz	; Save the file byte size.
	skipe autbyt		; Are we using autobyte?
	 jrst [	setzm ebtflg	;  Probably seven bit.
		cain t2, ^d8	;  Is the file eight bit?
		 setom ebtflg	;   If so, act like user requested 8-bit.
		jrst .+1 ]
	skipe ebtflg		; Eight bit mode?
	 jrst [	cain t2, ^d8	;  Is the byte size 8?
		 jrst gtchr0	;  If so nothing to do.
		movei t3, ^d36	;  If so, get the size of a word.
		idiv t3, t2	;  Divide by the byte size.
		move q1, filbyt	;  Get the number of bytes in file.
		idiv q1, t3	;  Divide by the bytes/word to get words.
		imuli q1, 4	;  Multilply by 4 (as if 8bit bytes).
		movem q1, filbyt ;  Save the new byte size.
		jrst gtchr0 ]
	caie t2, 7		; Is the byte size seven?
	 jrst [	movei t3, ^d36	;  If not, get the size of a word.
		idiv t3, t2	;  Divide by the byte size.
		move q1, filbyt	;  Get the number of bytes in file.
		idiv q1, t3	;  Divide by the bytes/word to get words.
		imuli q1, 5	;  Multiply by 5 (as if 7bit bytes).
		movem q1, filbyt ;  Save the new byte size.
		jrst gtchr0 ]

	;... (cont'd)

gtchr0:	hrlzs t1		; If so continue.  <file JFN,, page 0>
	hrlm t1, filpag		; Zero the left half of filpag.
	movx t2, <.fhslf,,mappag> ; <our fork,,mapping page>
	movx t3, pm%rd		; Just want to read it.
	PMAP%			; Map it in.
	 %jsker <Can't map in file page>,r ;  Error close up.
	move q4, [point 7, mappag*1000]	; Get a pointer to it.
	skipe ebtflg		; Eight bit access?
	 move q4, [point 8, mappag*1000] ; Get a pointer to it.
	setzm prepag		; Present page is zero.
	setom mapflg		; Say we've got a page mapped in.
	skipa			; Skip the next.
gtchr1:	 move q4, mapptr	; Get the PMAP buffer pointer.
	setz q1,		; Initialize the character count.
	move q2, [point 8, data] ; Get a pointer to where to put the chars.
gtchr2:	caml q1, len		; Have we exceeded the length?
	 jrst [	move t1, q1	;  Return the length.
		movem q4, mapptr ;  Save the pointer.
		retskp ]
	caml schr, filbyt	; Any more chars?
	 jrst [	setom eoflag	; Set the end of file flag.
		seto t1,	; Indicate unmap.
		movx t2, <.fhslf,,mappag> ; This process.
		setz t3,
		PMAP%		; Unmap the page.
		 %jsker <Error unmapping page>,r
		setzm mapflg	;  Say nothing mapped in.
		move t1, q1	;  Return the size in the right AC.
		retskp ]
	ildb t2, q4		; Get the next byte.
	movei t1, <mappag+1>*1000 ; Are we at the end yet
	caig t1, (q4)
	 jrst [	seto t1,	;  Indicate unmap.
		movx t2, <.fhslf,,mappag> ;  This process.
		setz t3,
		PMAP%		;  Unmap the page.
		 %jsker <Error unmapping page>,r
		move t1, prepag	;  Get the present page number.
		addi t1, 1	;  Increment it.
		caml t1, filpag	;  Any more pages?
		 jrst [	setom eoflag ;   Set the end of file flag.
			move t1, q1 ;   Return the size in the right AC.
			setzm mapflg ;   Say nothing mapped in.
			retskp ]
		movem t1, prepag ;  Save the new number.
		hrl t1, filjfn	;  <file JFN,, page 0>
		movx t2, <.fhslf,,mappag> ;  <our fork,,mapping page>
		movx t3, pm%rd	;  Just want to read it.
		PMAP%		;  Map it in.
	 	 %jsker <Can't map in file>,r ;   Error close up.
		move q4, [point 7, mappag*1000]	; Get a pointer to it.		
		skipe ebtflg	;  Eight bit access?
		 move q4, [point 8, mappag*1000] ;  Get a pointer to it.
		ildb t2, q4	;  Get the next byte.
		jrst .+1 ]
	;...

gtch2a:	aos schr		; Increment the file chars sent total.
	aos q1			; Increment char count.
	movem t2, tmpac		; Save the char.
	andi t2, ^o177		; Turn off the 8th bit.
	cail t2, " "		; Is it a control char?
	 cain t2, .chdel	;  Or a delete?
	  jrst [move q3, squote	;   Get the quote character.
		addi q1, 1	;   Increment char count.
		idpb q3, q2	;   Put in the quote character.
		move t2, tmpac	;   Restore the char.
		xori t2, ^o100	;   Make the char noncontrol.
		jrst gtchr3 ]
	camn t2, squote		; Is it the quote character?
	 jrst [	addi q1, 1	;  Increment char count.
		idpb t2, q2	;  Put in the quote character.
		jrst .+1 ]
	move t2, tmpac		; Restore the char.

gtchr3:	move q3, schr		; Get the char count.
	skipe ebtflg		; Eight bit mode?
	 jrst gtchr4		;  If so don't fool with this hack.
	movem q4, tmpac		; Save the AC.
	idivi q3, 5
	skipn q4		; Is this the last char in the word?
	 jrst [	hrr q4, tmpac	;  Get the address of the word.
		move q4, (q4)	;  Get its contents.
		andi q4, 1	;  Get just bit 35.
		lsh q4, 7	;  Shift it over into bit 8.
		ior t2, q4	;  Or in that bit to the char.
		jrst .+1 ]
	move q4, tmpac		; Restore the AC.
gtchr4:	idpb t2, q2		; Put in the character.
	jrst gtchr2		; Loop way back...

ptchr:	saveac <q1,q2,q3,q4>
	stkvar <siz,tmp>
	movem t2, siz		; Save the size.
	move q1, t1		; Save the arguments.
	move q2, t2
	skipn mapflg		; Is there a page mapped in?
	 jrst [	move q3, [point 7, mappag*1000]	;  Get a pointer to it.
		skipe ebtflg	;  Eight bit access?
		 move q3, [point 8, mappag*1000] ;  Get a pointer to it.
		setzm prepag	;  Present page is zero.
		setom mapflg	;  Say we've got a page mapped in.
		jrst ptchr1 ]
	move q3, mapptr		; Get a pointer to the buffer.
ptchr1:	setz q4,		; Zero quote char count.
ptchr2:	skipg q2		; Are we done?
	 jrst [	movem q3, mapptr ;  Save the byte pointer.
		retskp ]
	addi rchr, 1		; Add to the character count.
	subi q2, 1		; Decrement char count.
	ildb t2, q1		; Get the char.
	camn t2, rquote		; Is it the quote character?
	 jrst [	subi q2, 1	;  Decrement char count.
		addi q4, 1	;  Increment quote char count.
		ildb t2, q1	;  Get the quoted character.
		move t1, t2	;  Save the parity bit.
		andi t1, ^o177	;  Save modulo 200 of the number.
		camn t1, rquote	;  Is it the quote character?
		 jrst .+1	;   Yes, don't convert it.
		xori t2, ^o100	;  Make the char noncontrol.
		jrst .+1 ]
	idpb t2, q3		; Put it in the page.
	skipn ebtflg		; Eight bit mode?
	 caige t2, ^o200	; Is the parity bit on?
	 skipa
	 jrst [	move t3, rchr	;  If so, get the char count.
		idivi t3, 5
		skipn t4	;  Is this the last char in the word?
		 jrst [	move t4, (q3) ;   If so, get its contents.
			iori t4, 1 ;   Turn on bit 35.
			movem t4, (q3)
			jrst .+1 ]
		jrst .+1 ]
	;...

ptchr3:	movei t1, <mappag+1>*1000 ; Are we at the end yet?
	caig t1, (q3)
	 jrst [	movem t2, tmp	;  Save char we just put in the wrong place.
		movx t1, <.fhslf,,mappag> ;  <our fork,,mapping page>
		hrl t2, filjfn ;  <file JFN,, page #>
		hrr t2, prepag
		movx t3, pm%rd!pm%wr ;  Read and write.
		PMAP%		;  Map it out.
	 	 %jsker (Unable to map out file page,r) ;   Error close.
		move t1, prepag	;  Get the present page number.
		addi t1, 1	;  Increment it.
		movem t1, prepag ;  Save the new number.
		move q3, [point 7, mappag*1000]	;  Get a pointer to it.		
		skipe ebtflg	;  Eight bit access?
		 move q3, [point 8, mappag*1000] ;  Get a pointer to it.
		move t2, tmp	;  Get back our char.
		idpb t2, q3	;  Put it into the new page.
		jrst .+1 ]
	jrst ptchr2		; Loop.

; Get next file from wild file specification.

gtnfil:	move t1, ndxjfn		; Get the indexable JFN.
	GNJFN%			; Get the next JFN.
	 ret			;  No more files, so give up.
	hrrm t1, ndxjfn		; Save the new JFN.
	hrrm t1, filjfn		; Save the new JFN.
	retskp


; Get an output file spec.
;  AC1 - Pointer to a file name from the micro.
;  AC2 - Number of characters.

gofil:	saveac <q1>
	move q1, t1		; Save the pointer to the file name.
	skipe t1, filjfn	; Do we have a file yet?
	 retskp			;  If so just return its JFN.
	skipg t2		; Are there at least a few chars?
	 jrst [	kermsg <Micro did not specify file name>
		ret ]
	move t1, q1		; Get the file name pointer.
	call filfix		; Go check & fix the filename syntax.
	movx t1, gj%sht!gj%fou	; Short form.
	GTJFN%
	 %jsker <Unable to get a JFN on the file>,r
	retskp

filfix:	move t3, [point 7, filbuf]
filfx2:	ildb t2, t1		; Get the next char.
	skipn t2		; The end?
	 jrst [	idpb t2, t3	; Put the null in.
		move t2, [point 7, filbuf] ; Return a pointer to the file.
		ret ]
	caile t2, " "		; Space or less?
	 cain t2, ^o177		;  Or a delete?
	  jrst filfx2		;   If so skip it and move on.
	cain t2, "."
	 jrst filfx4
	cail t2, "0"		; Test if it is legal.
	 caile t2, "z"
	  jrst filfx3
	caige t2, "a"
	 caig t2, "9"
	  jrst filfx4
	cail t2, "A"
	 caile t2, "Z"
	  jrst filfx3
	jrst filfx4
filfx3:	movei t4, ^o26		; If illegal get a control V.
	idpb t4, t3		; Quote the illegal character.
filfx4:	idpb t2, t3		; Put the character in.
	jrst filfx2



	subttl	Line routines

inilin:	move t1, netjfn		; Get the line.
	movei t2, .morxo	; Get the terminal pause characters.
	MTOPR%
	 %jserr (,r)
	movem t3, oldpau	; Save the old pause mode.
	movei t2, .moxof	; Set the terminal pause characters.
	movei t3, .mooff	; Set no pause on end.
	MTOPR%
	 %jserr (,r)
	RFMOD%			; Get current mode for this line.
	 %jserr (,r)
	movem t2, oldmod	; Save the present mode.
	movx t2, tt%mff+tt%tab+tt%lca+tt%dum+tt%pgm ; No conversion, half
				; .. duplex, pause on com and no echo.
	skipe ibmflg		; Are we talking to the IBM?
	 movx t2, tt%mff+tt%tab+tt%lca+tt%dum ; If so, same minus XON/XOFF.
	SFMOD%
	 %jserr (,.+1)
	STPAR%
	 %jserr (,.+1)
	CFIBF%			;[1] Clear the line in case a bunch of NAKs
	 %jserr (,.+1)		;[1]  have piled up.
	ret

reslin:	move t1, netjfn		; Get the line.
	movei t2, .moxof	; Set the terminal pause on end mode.
	move t3, oldpau		; Get the old pause mode.
	MTOPR%
	 %jserr (,r)
	move t2, oldmod		; Get the previous mode.
	SFMOD%
	 %jserr (,.+1)
	STPAR%
	 %jserr (,.+1)
	ret


	subttl Packet routines

; Send_Packet
; This routine assembles a packet from the arguments given and sends it
; to the micro.
;
; Expects the following:
;	AC1 - Type of packet (D,Y,N,S,R,E,F,Z,T)
;	AC2 - Packet sequence number
;	AC3 - Number of data characters
;	AC4 - Byte pointer to data characters
; Returns: +1 on failure
;	   +2 on success

spack:	saveac <q1,q2,q3>
	stkvar <type>		; Local storage.
	movem t1, type		; Save the type.
	setz q2,		; Zero the checksum AC.
	move q1, [point 8, sndpkt] ; Get a byte pointer to the send packet.
	move t1, ssthdr		;[18] Get the start of header char.
	call @parity		; Call the appropriate parity routine.
	idpb t1, q1		; Put in the packet.
	move t1, spsiz		; Get the send packet size.
	caml t3, [-3]		; Does the packet have some length?
	 caile t3, -5(t1)	;  Is this packet small enough?
	  jrst [ermsg <Invalid data field of message>
		ret ]
	movei t1, 5(t3)		;[22] We need the count for later.
	addm t1, stot		;[22]
	addi t1, <" "-2>	;[22] Real packet character count, printable.
	add q2, t1		; Add the count to the checksum.
	call @parity		; Call the appropriate parity routine.
	idpb t1, q1		; Put the count into the packet.
	skipl t1, t2		; Is the sequence number valid? (0-64)?
	 cail t2, ^o100
	  jrst [ermsg <Invalid message sequence number>
		ret ]
	addi t1, " "		; Add a space so the number is printable.
	add q2, t1		; Add the number to the checksum.
	call @parity		; Call the appropriate parity routine.
	idpb t1, q1		; Put the sequence number into the packet.
	move t1, type		; Get the type.
	cail t1, "A"		; Check if the type is a capital letter.
	 caile t1, "Z"
	  jrst [ermsg <Illegal message type>
		ret ]
	add q2, t1		; Add in the message type to the checksum.
	call @parity		; Call the appropriate parity routine.
	idpb t1, q1		; Put the type into the packet.
	skipg t3		; Are there any chars of data?
	 jrst spack3		;  No, finish up.

	;...

spack2:	ildb t1, t4		; Get the next char.
	add q2, t1		; Add the char to the checksum.
	call @parity		; Call the appropriate parity routine.
	idpb t1, q1		; Put it into the packet.
	subi t3, 1		; Decrement the char count.
	skiple t3		; Are there any chars of data left?
	 jrst spack2		;  Yes, go get another.
spack3:	move t3, q2		; Save the character total.
	andi q2, ^o300		; And out all but 2 bits.
	lsh q2, -6		; Shift them to the far right.
	add q2, t3		; Add in the original value.
	ldb t1, [point 6, q2, 35] ; Get the modulo 64 of the char total.
	addi t1, " "		; Add a space so the number is printable.
	call @parity		; Call the appropriate parity routine.
	idpb t1, q1		; Put the checksum into the packet.
	move t1, seolch		; Get the requested EOL char.
	call @parity		; Call the appropriate parity routine.
	idpb t1, q1		; Add it to the packet.
	setz t1,		; Get a null.
	idpb t1, q1		; Put it at the end.
	skipn ibmflg		; Are we talking to the IBM?
	 jrst spack5		;  No, proceed.
	cain state, "S"		; Is this the send init packet?
	 jrst spack5		; If so don't wait for the turn around.
	movei t1, spack6	; Where to go on time out.
	call timeit		; Time the wait for the turn around.
	move t1, netjfn
spack4:	BIN%			; Get a character from the host.
	 %jserr(Error inputing character from micro,r)
	andi t2, ^o177		; Turn off the parity.
	came t2, trnrnd		; Is it the turn around char?
	 jrst spack4		;  If not go til it is.
	call timoff		; Turn off the timer.
spack5:	move t1, netjfn		; Output to the tty (micro).
	move t2, [point 8, sndpkt] ; The address of the packet.
	setzb t3, t4		; End on a null.
	SOUT%			; Send the string.
	 %jserr <Send packet SOUT% failed>,r
	aos sptot		;[4] Count the packet we sent.
	skipe debug		;[4] Debugging?
	 jrst [	move t2, [point 8, sndpkt] ;[22] Point to packet.
		call typpkt	;[22] Yes, skip blips but maybe type packet.
		retskp ]	;[22]
	skipn local		;[4] Not debugging, but still local?
	 retskp			;[4]  Remote, don't make blips.
	move t3, type		;[4] Local, am I sending a NAK packet?
	movei t1, "%"		;[4] Print a "%" for each one I send.
	move t2, numtry		;[4] Or each resend I have to do.
	caig t2, 1		;[4]
	cain t3, "N"		;[4]
	 jrst spackx		;[4]
	setz t3,		;[4] Not a NAK, is it time to blip?
	move t4, sptot		;[4] Check the absolute packet number.
	divi t3, blip		;[4] We do it every "blip" packets.
	jumpn t4, rskp		;[4] Not time for a blip.
	movei t1, "."		;[4] It's time, here's the blip.
spackx:	PBOUT%			;[4] .
	retskp

spack6: diamsg <T>		; Time out returns here.
	jrst spack5		; Join the regular code.


; Receive_Packet
; This routine waits for a packet to arrive from the micro.  It reads
; characters until it finds a SOH.  It then reads the packet into recpkt.
;
; Returns:  +1 failure (if the checksum is wrong or the packet trashed)
;	    +2 success with AC1:  message type
;			    AC2:  message number
;                           AC3:  length of data
;			    AC4:  byte pointer to data

rpack:	saveac <q1,q2,q3>
	stkvar <type,num>
	movei t1, tmout		; Place to go on time out.
	call timeit		; Time out if it takes too long.
	move t1, netjfn		; Get the chars from the net.
rpack0:	call inchar		; Get a character from the micro.
	 jrst rperr
	came t2, rsthdr		;[18] Is the char the start of header char?
	 jrst rpack0		;  No, go until it is (or we are timed out).
rpack1:	move q1, [point 8, recpkt] ; Get a pointer to the packet buffer.
	idpb t2, q1		; Put the char into the packet.
	call inchar		; Get a character from the micro.
	 jrst rperr
	camn t2, rsthdr		;[18] Is the char the start of header char?
	 jrst rpack1		;  Yes, then go start over.
	idpb t2, q1		; Put the char into the packet.
	move q2, t2		; Start the checksum.
	subi t2, " "+3		; Get the real data count.
	skipge t2		; Make sure the number makes sense.
	 jrst [	ermsg <Bad character count
>
		jrst rperr ]
	move t3, t2		; Prepare it for returning.
	call inchar		; Get a character from the micro.
	 jrst rperr
	camn t2, rsthdr		;[18] Is the char the start of header char?
	 jrst rpack1		;  Yes, then go start over.
	idpb t2, q1		; Put the char into the packet.
	add q2, t2		; Add it to the checksum.
	subi t2, " "		; Get the real packet number.
	movem t2, num		; Save it for later.
	call inchar		; Get a character from the micro.
	 jrst rperr
	camn t2, rsthdr		;[18] Is the char the start of header char?
	 jrst rpack1		;  Yes, then go start over.
	idpb t2, q1		; Put the char into the packet.
	add q2, t2		; Add it to the checksum.
	movem t2, type		; Save the message type.
	move q3, t3		; Get the number of data characters.
	move t4, q1		; For returning the data pointer.
	skipg q3		; Any data characters?
	 jrst rpack3		;  If not go get the checksum.
	;...

rpack2:	call inchar		; Get a character from the other side.
	 jrst rperr		;  Oops, can't.
	camn t2, rsthdr		;[18] Is the char the start of header char?
	 jrst rpack1		;  Yes, then go start over.
	idpb t2, q1		; Put the char into the packet.
	add q2, t2		; Add it to the checksum.
	sojg q3, rpack2		; Get next character, if any.

; Count exhausted, next character will be the checksum.

rpack3:	call inchar		; Get a character.
	 jrst rperr
	camn t2, rsthdr		;[18] Is the char the start of header char?
	 jrst rpack1		;  Yes, then go start over.
	skipe local		;[29] If remote, skip next little part.
	call [	saveac <t2,q1>	;[29] Preserve the current environment.
		idpb t2, q1	;[29] Deposit the checksum after the data.
		setz t1,	;[29] Terminate the string after the checksum.
		idpb t1, q1	;[29]
		move t2, [point 8, recpkt] ;[29] Point at start of packet,
		call typpkt	;[29] and type it if debugging packets.
		ret ]		;[29] Back to previous environment.
	setz t1,		; Terminate the data string, nullifying
	idpb t1, q1		;  the checksum character if it's there.
	move q3, q2		; Save the character total.
	andi q2, ^o300		; And out all but 2 bits.
	lsh q2, -6		; Shift them to the far right.
	add q2, q3		; Add in the original value.
	ldb q2, [point 6, q2, 35] ; Get the modulo 64 of the char total.
	subi t2, " "		; Get the numeric received checksum.
	came t2, q2		; Are they equal?
	 jrst [	skipn local	;[22] No, local Kermit?
		 jrst rperr	;[29] No, skip messages.
		jumpe debug, rperr ;[29] Yes, but skip msg if not debugging.
		tmsg <
%Bad checksum >			;[29] Local and debugging, say what we got.
		movei t1, " "(t2) ;[32]
		PBOUT		;[29]
		tmsg <, I get >	;[29] And what we expected to get.
		movei t1, " "(q2) ;[32]
		PBOUT		;[29]
		movei t1, " "	;[29]
		PBOUT		;[29]
		jrst rperr ]
	call timoff		; It's OK, turn the timer interrupt off.
	move t1, netjfn		;[17]
	CFIBF%			;[17] Prevent stacked packets.
	 erjmp .+1		;[17]
	aos rptot		;[4] Count the packet we got.

rpackx:	move t1, type		; Return the type in T1
	move t2, num		; and the sequence number in T2.
	retskp

inchar:	saveac <q1>
	BIN%			; Get a character from the micro.
	 %jserr<Can't get character in INCHAR>,r
	aos rtot		; Increment total count.
	move q1, parity		; What type of parity?
	caie q1, none		; If none, don't touch the parity.
	 andi t2, ^o177		;  Else, take out parity.
	retskp

rperr:	call timoff		; Cancel the time out.
	move t1, netjfn		;[17] Prevent stacked-up packets.
	CFIBF%			;[17]
	 erjmp .+1		;[17]
	hrroi t1, [asciz/ (bad)/] ;[29] And say it was bad,
	jumpe debug, r		;[29] if we're debugging,
	skipe local		;[29] and local.
	 PSOUT			;[29]
	ret

;[22] Type out a packet pointed to by t2, if verbose debugging.

typpkt:	skipe local		; Local?
	 caie debug, 2		;  And verbose debugging?
	 ret			;  Not both, don't do this.
	saveac <t3,t4>		; It's verbose debugging.  Save these,
	hrroi t1, crlf		; and print the packet preceded by crlf.
	PSOUT			;
	movei t1, .priou	;
	setzb t3, t4		;
	SOUT			;
	 erjmp .+1		;
	ret

	subttl	Parity routines

; Default, don't touch the eighth bit.

none:	ret

; Mark, bit 8 is always 1.

mark:	ori t1, ^o200		; Turn on the parity bit.
	ret

; Space, opposite of mark, bit 8 is always zero.

space:	andi t1, ^o177		; Turn off the parity bit.
	ret

; Even, the total number of on bits should be even.

even:	saveac <t2>
	andi t1, ^o177		; Start off with bit 8 = 0.
	move t2, t1
	jrst evnodd

; Odd, the total number of on bits should be odd.

odd:	saveac <t2>
	andi t1, ^o177		; Turn off the parity bit.
	movei t2, ^o200(t1)	; Start off with bit 8 = 1.

evnodd:	lsh t2, -4		; Get high order 4 bits of character
	xori t2, (t1)		; Fold into 4 bits.
	trce t2, 14		; Left two bits both 0 or 1?
	 trnn t2, 14		;  or both 1?
	 xori t1, 200		; Yes, set parity
	trce t2, 3		; Right two bits both 0?
	 trnn t2, 3		;  or both 1?
	 xori t1, 200		; Yes, set parity.
	ret

; We come here if we are in server mode.  This just waits for a
; packet of one of the following types:
;
;	S	Send init - just follow the normal path from here
;	R	Receive init - fake like we parsed a send <file-spec>
;	G	Generic command
;		L	Logout - the micro is done, log out this job
;		F	Finish - exit from Kermit

getcom:	tmsg <
[Kermit Server running on DEC-20 host.  Please type your escape sequence to
 return to your local machine.  Shut down the server by typing the Kermit BYE
 command on your local machine.]
>
	setom srvflg		; Say we are serving.
	call inilin		; Initialize the line.
	call ccon		; Don't let someone ^C without reseting line.
	 jrst [	move t1, otimou ;[26]  What to do on ^C:
		movem t1, stimou ;[20] Restore normal timeout interval.
		move t1, odelay ;[27]  And normal delay
		movem t1, delay	;[20]  ...
		setzm srvflg	;[27]  Not a server any more.
		jrst reslin ]	;[27]  Go reset line & return from there.
	setzm delay		; No delay in server mode.

gtcmlp:	movei t1, dsrvtm	;[25] Get the default server packet time out.
	movem t1, stimou	;[25] Set it so we don't time out as often.
getcm1:				;[25]
	setzm pktnum		; Inititial packet sequence number.
	call rpack		; Get a packet.
	 jrst [	move t2, pktnum	;  Timed out or something.
		call nak	;  NAK that pack.
		 jrst getcm1	;[25]
		jrst getcm1 ]	;[25]  Go round again.

	cain t1, "T"		; Timer interrupt pseudo packet?
	 jrst [	move t2, pktnum
		call nak	; NAK that "packet".
		 jrst getcm1	;[25]
		jrst getcm1 ]	;[25] Go round again.

; Got a real command.  Restore the normal timeout interval and do the command.

	push p, t1		;[26] We can't use any normal AC's here...
	move t1, otimou		;[26] Put normal timeout back.
	movem t1, stimou	;[26] 
	pop p, t1		;[26]

	cain t1, "S"		; Send command.
	 jrst xsend		; 
	cain t1, "R"		; Receive (get) command.
	 jrst xrecv		; 
	cain t1, "G"		; Generic command.
	 jrst xgen
	cain t1, "H"		; Host command.
	 jrst xhost

; (add new commands here...)

getcm2:	kermsg <Unimplemented server command> ; Something else.

	move t2, pktnum		; Don't know what it is, just NAK it.
	call nak
	 jrst .+1
	jrst gtcmlp		; Listen again.

	subttl Server commands.

; Server SEND command (i.e. send to server)

xsend:	setzm stot		; Initialize character counters.
	setzm rtot
	setzb schr, stchr
	setzb rchr, rtchr
	setzm errptr		; Zero the error message pointer.
	setzm numtry		; Set the number of tries to zero.
	GTAD%			; Get the time.
	movem t1, stdat		; Hang on to the time for statistics.
	movem t2, pktnum	; Synchronize packet numbers.
	call spar		; Get the information
	move t4, [point 8, data] ; Get a pointer to our data block.
	call rpar		; Set the information.
	movei t1, "Y"		; Acknowledge packet.
	move t2, pktnum		; Packet number.
	move t4, [point 8, data] ; The address of the data.
	call spack		; Send the packet.
	 jrst gtcmlp		; Give up.
	move t2, numtry		; Get the number of tries.
	movem t2, oldtry	; Save it.
	setzm numtry		; Reset the number of tries.
	move t2, pktnum		; Get the packet number.
	addi t2, 1		; Increment it.
	dpb t2, [point 6, pktnum, 35] ; Save modulo 64 of the number.
	movei state, "F"	; Set the state to file send.
	call $recv2		; Go look like we're receiving.
	jrst gtcmlp		; Get another command when done.


; Server RECEIVE (or GET) command -- Server sends files.

xrecv:	movem t2, pktnum	; Save the packet number.
	move t2, t4		;  Get a pointer to the file spec.
	movx t1, gj%sht!gj%old!gj%ifg ; Old file and allow wildcarding.
	GTJFN%
	 %jsker (,gtcmlp)	; Can't, say forget it and loop.
	movem t1, ndxjfn	; OK, Save the indexable JFN.
	hrrm t1, filjfn		; Save the JFN of the first file.
	call $send		; Go send the file(s).
	jrst gtcmlp

; HOST command.

xhost:	kermsg <Host commands not implemented in KERMIT-20>
	jrst gtcmlp


; Server GENERIC command.  See which one.

xgen:	ildb t1, t4		; Get the data char.
	cain t1, "F"		; Finish.
	 jrst xgfin		;  
	cain t1, "L"		; Logout.
	 jrst xglogo 		;   

; (add new generic commands here...)

	kermsg <Unimplemented generic command>
	jrst gtcmlp


; Generic commands...

; FINISH.  Shut down the server, but don't log out.

xgfin:	movei t1, "Y"		;  Acknowledge packet.
	setzb t3, t4		;  No data.
	call spack		;  Send the packet.
	call ccoff		;  Turn off the ^C trap.
	call reslin		;  Set the line back to a nice state.
	move t1, odelay		;[27] Restore normal delay
	movem t1, delay		;[27]
	move t1, otimou		;[27] and timout interval
	movem t1, stimou	;[27]
	setzm srvflg		;[27] and reset the server flag 
	ret			; in case we're continued...

; LOGOUT (or BYE) -- Shut down the server and log out.

xglogo:	movei t1, "Y"		; Acknowledge the command.
	setzb t3, t4		; No data.
	call spack		; Send the packet.
	call ccoff		; Turn off the ^C trap.
	call reslin		; Set the line back to a nice state.
	move t1, odelay		;[27] Restore normal delay
	movem t1, delay		;[27]
	move t1, otimou		;[27] and timout interval
	movem t1, stimou	;[27]
	setzm srvflg		;[27] and reset the server flag.
	seto t1,		; Myself.
	LGOUT%			; Log me out.
	%jserr (,r)		;[27] If this fails, print msg & go back.

	Remark - Initialize the Priority Interrupt system.

pinit:	movei t1, .FHSLF	; This fork.
	move t2, [levtab,,chntab] ; Say where our tables are.
	SIR%
	EIR%			; Enable the interrupt system.
	ret

	Remark - Set timer.

timeit:	pop p, t2		; Get the return address off the stack.
	movem p, intstk		; Save the stack.
	push p, t2		; Restore stack.
	hrr t2, t1		; Make interrupt PC point to time out addr.
	movem t2, intpc		; Save the PC.
	movei t1, .fhslf
	movx t2, 1b0		; Turn on channel 0.
	AIC%

;[2] Adjust timeout based on load average, LDAV.
;[2] Calculate T = STIMOU + (LDAV-MINLOD)*((MAXTIM-STIMOU)/MAXLOD)
;[2] If the load is low, this gives the requested timeout, STIMOU.
;[2] If the load is very high, this gives the maximum timeout, MAXTIM.
;[2] In between, the timeout goes up linearly with load average.

timei2:	move t1, [14,,.systa]	;[2] Get load average.
	setz t2,		;[2] Assume zero in case GETAB fails.
	GETAB%			;[2] Not bothering with class scheduler...
	 erjmp timei3		;[2]  Can't get it, assume zero.
	fsb t1, [minlod]	;[2] Adjust by subtracting the minimum.
	skipg t1		;[2] If negative, make it zero.
	 setz t1,		;[2]
	caml t1, [maxlod]	;[2] If too big, cut it off.
	 move t1, [maxlod]	;[2]
	movei t2, maxtim	;[2] Maximum timeout, seconds.
	sub t2, stimou		;[2] Less specified timeout interval.
	fltr t2, t2		;[2] Floated.
	fdv t2, [maxlod]	;[2] Divided by maximum load.
	fmp t1, t2		;[2] Multiplied by actual (adjusted) load.
	fixr t2, t1		;[2] Fixed & rounded.
timei3:	add t2, stimou		;[2] Add in requested timeout.

	move t1, [.fhslf,,.timel] ; Our process and time from now.
	imuli t2, ^d1000	; Make time into milliseconds.
	setz t3,		; Channel zero.
	TIMER%
	 kermsg <Unable to set timer interrupt>
	ret

	Remark - Turn off timer.

timoff:	saveac <t1,t2>
	move t1, [.fhslf,,.timbf]
	move t2, [377777,,-1]	; Time way out in the boonies (won't
				; clobber any runtime limit setting).
	TIMER%
	 jrst .+1		; Ignore errors.
	movx t1, .fhslf		; Turn off ^O trap.
	movx t2, 1b0
	DIC%			; Deactivate the channel.
	ret

	Remark - Time out trap.	

tmtrp:	push p, t1		; Get a work AC.
	move t1, intpc		; Get the PC we want.
	movem t1, pc1		; Restore as if we came from there.
	pop p, t1
	move p, intstk		; Restore the stack.
	DEBRK%

	Remark - Return time out packet.

tmout:	diamsg <T>		;* Temporary.
	movei t1, "T"		; Say we timed out on the packet.
	move t2, pktnum		; Tell which packet num.
	setzb t3, t4		; No data.
	retskp


	subttl subbp - Subtract two arbitrary byte pointers

; Subroutine to subtract two byte pointers in current section.
; The two byte pointers must point to bytes of the same size.
;
; Call with:
;   t1/ First byte pointer.
;   t2/ Second byte pointer.
;	CALL SUBBP
;
; Returns:
;   +1 if the byte sizes are different, with t1-t3 unchanged, or else
;   +2 with:
;   t1,t2/ Unchanged.
;   t3/ The number of bytes of the specified bytesize in the string pointed to
;       by the first byte pointer (in t1) up to, but not including, the byte
;       pointed to by the second byte pointer (in t2).

subbp:	saveac	<q1,q2,q3,q4>	; Save permanent regs for work below.
	ldb q1, [point 6, t1, 11] ; q1 := bytesize 1.
	ldb q2, [point 6, t2, 11] ; q2 := bytesize 2.
	came q1, q2		; Are they equal?
	 ret			; No, failure

; Byte sizes are equal, can do arithmetic.

	movei q2, @t1		; Do address calculation for t1
	movei q4, @t2		;  and t2.
	sub q4, q2		; q4 := (A1 - A2) = N words.
	movei q2, ^d36		; q2 := bits/word.
	idiv q2, q1		; q2 := bytes/word.
	imul q4, q2		; q4 := bytes in N words.
	move q2, q4		; (to leave q3-q4 free for IDIV)
	ldb q3, [point 6, t2, 5] ; q3 := Q2
	ldb t3, [point 6, t1, 5] ; t3 := Q1
	sub t3, q3		; t3 := (Q1 - Q2)
	idiv t3, q1		; t3 := (Q1 - Q2) / S
	add t3, q2		; Adjust previous count.
	retskp			; And return, with success.

	subttl Interrupt routines.

; Turn Control-C trap on.

$ccn==2				; Number of ^C's to get out of ^C trap.

ccon:	movei t1, .fhslf	; Read current process capabilities.
	RPCAP%
	tloe t3, (sc%ctc)	;[10] Do we have Control-C capas?
	 jrst ccon2		;[10]  Yes, go on.
	EPCAP%			;[10] Nope, try to get them.
	RPCAP%			;[10] Did we?
	tloe t3, (sc%ctc)	;[10] Check the ^C bit.
	 jrst ccon2		;[10]  We got them.
	seto t1,		;[10] We don't have them.
	hrroi t2, t4		;[10] Let's see if we're running under batch,
	movei t3, .jibat	;[10] in which case we don't need them anyway.
	setz t4,		;[10]
	GETJI%			;[10]
	 nop			;[10]
	skipe t4		;[10]
	 jrst ccon2		;[10] Under batch, can proceed.
	ermsg <Can't enable ^C capability> ;[10] Not under batch.
	ret 			;[10] Give up.

ccon2:	movem t3, capas		; Save them.
	movei t1, $ccn 		; Initialize ^C count to this.
	movem t1, ccn
;[27]	move t1, p		; Save stack pointer of our caller.
;[27]	sub t1, [1,,1]
;[27]	movem t1, psave
	movem p, psave		;[27] Save stack pointer.
	move t1, (p)		;[27] And what it points to...
	movem t1, psave2	;[27]
	movx t1, .fhslf		; Now, for this fork,
	movx t2, 1b1		;  activate channel 1
	AIC%			;  ...
	 erjmp .+1		;[10]
	move t1, [.ticcc,,1]	;  for ^C.
	ATI%			; 
	 erjmp .+1		;[10]
	retskp


; Turn Control-C trap off.

ccoff:	setzm ccn		; Put ^C count back to 0.
	movx t1, .fhslf		; This fork.
	movx t2, 1b1		; Deactivate channel 1.
	DIC%
	RTIW%			; Fix up the interrupt mask
	tlz t2, 040000		;  for ^C... (^C = ASCII 3 = bit 3)
	STIW%			;  ...
	move t3, capas		; Restore capabilities.
	EPCAP%
	 erjmp .+1
	ret


cctrap:	sosle ccn		; Count the ^C's.
	 DEBRK%			; If they haven't typed enough, just resume.
	call timoff		; Time to go... turn off the timer.
;[27]	move t1, [1b5+reslin]	; Put clean-up line address
;[27]	movem t1, pc1		;  in PC for level 1, 1b5 means user space.
	hrroi t1, [asciz/^C
/]
	PSOUT%			; Echo the ^C.

	move p, psave		;[27] Make sure stack pointer is right.
	move t1, psave2		;[27] And stack top.
	movem t1, (p)		;[27]
	hrli t1, (1b5)		;[27] Get into user mode.
	movem t1, pc1		; Put this place into our PC.
	setom f$exit		; Say we want to exit.
	DEBRK%			; Resume at clean up line code.

;[14] Control-B trap handler.

cbtrap:	push p, t1		; Save this.
	setom cbseen		; Set flag saying ^B was typed.
	skipn t1, cbloc		; Do we have someplace special to go?
	 move t1, pc2		;  No, just use this to escape from JSYS.
	txo t1, 1b5		; Set user mode bit.
	movem t1, pc2		; Where to go.
	pop p, t1		; Restore the AC.
	DEBRK%			; Resume.

;[6] (this whole routine, just for fun...)

moon:	saveac <5,6>

; This code stolen from MOON.MAC (anybody know who wrote it?).
; Just changed OUTCHR's to PBOUT%'s via a macro.  - Frank.
;
	setzb 3,4
	seto 2,
	ODCNV%
	 erjmp r
	tlz 4,77
	IDCNV%
	 erjmp r		; Return upon any error.
	tmsg <, Moon: >		; OK so far, say what we're doing.

; AC2= Universal time adjusted for time zone.

	move 1,2		; Right place.
	sub 1,newmn		; Sub off base new moon
	idiv 1,period		; Divide by the period
	idiv 2,perio4		; Get fractions of a period
	camg 3,perio8		; Check for pahse + or -
	 jrst moon1		; Not more than 3+ days

	sub 3,perio4		; Make it next phase -n days
	cain 2,3		; Is it LQ+3D+?
	 tdza 2,2		; It is
	 aoj 2,			; Increment phase

moon1:	hllz 1,table(2)		; Get SIXBIT phase
	skipge 3		; 3 < 0 then minus phase output
	 tloa 1,'-'		; -
	 tloa 1,'+'		; +
	 movms 3		; Fix mag of 3
	move 2,[point 6,1]	; Byte pointer
	movei 5,2		; Loop 3 times

moon2:	ildb 4,2		; Get a character
	addi 4," "		; Make ASCII
	OUTCHR 4		; Type it
	sojge 5,moon2		; Loop

	movsi 4,-4		; Make aobjn pointer
	;...

moon3:	hrrz 2,table(4)		; Get a multiplier
	trz 2,774000		; Strip off ascii character
	imuli 3,(2)		; Get the value decoded
	hlrz 1,3		; Get value
	tlz 3,-1		; Zap old LH
	move 5,1		; Use 5 & 6 here
	idivi 5,12		; Radix 10
	addi 5,60		; Make ASCII
	caile 5,60		; Check for leading zero
	 OUTCHR 5		;  Type it.
	addi 6,60		; Make ASCII
	OUTCHR 6
	ldb 5,[point 7,table(4),24] ; Get d/h/m/s
	OUTCHR 5		; Type it.
	OUTCHR ["."]		; Follow with a dot.
	aobjn 4,moon3		; Loop.

	tmsg <
>				; A CRLF at the end.
	ret			; Done, return.

; Pure data for moon.

newmn:	125575,,34343		; 28-jan-79 0120 est
per==35,,422752			; 29d.12h.53m.19s
period:	per
perio4:	per/4
perio8:	per/10

table:	byte(18)'NM '(7)"d"(11)^D1 ; New moon - days - 1
	byte(18)'FQ '(7)"h"(11)^D24 ; First quarter - hours - 24
	byte(18)'FM '(7)"m"(11)^D60 ; Full moon - minutes - 60
	byte(18)'LQ '(7)"s"(11)^D60 ; Last quarter - seconds - 60

	subttl	Comnd tables

cmdtab:	%table
	%key	<bye>, [xwd .bye,$bye] ;[11]
	%key	<connect>, [xwd .conne,$conne]
	%key	<exit>, [xwd .exit,$exit]
	%key	<finish>, [xwd .finis,$finis] ;[28]
	%key	<get>,  [xwd .get,$get]	;[11]
	%key	<help>, [xwd .help,$help]
	%key	<prompt>, [xwd .promp,$promp], cm%inv
	%key	<quit>, [xwd .exit,$exit]
	%key	<receive>, [xwd .recv,$recv]
	%key	<s>, send, cm%inv+cm%abr
send:	%key	<send>, [xwd .send,$send]
	%key	<server>, [xwd .serve,$serve]
	%key	<set>, [xwd .set,$set]
	%key	<show>, [xwd .show,$show]
	%key	<status>, [xwd .stat,$stat]
	%tbend

setabl:	%table
	%key	<debugging>, [xwd .setdb,$setdb]
	%key	<delay>, [xwd .setdl,$setdl]
	%key	<duplex>, [xwd .setdu,$setdu]
	%key	<escape>, [xwd .setes,$setes]
	%key	<file-byte-size>, [xwd .setf8,$setf8]
	%key	<IBM-flag>, [xwd .setib,$setib]
	%key	<line>, [xwd .setln,$setln]
	%key	<parity>, [xwd .setpa,$setpa]
	%key	<receive>, [xwd .setrc,$setrs]
	%key	<send>, [xwd .setsn,$setrs]
	%tbend

sftab:	%table
	%key	<7-bit>, 0
	%key	<8-bit>, 1
	%key	<auto-byte>, 2
	%key	<eight-bit>, 1
	%key	<seven-bit>, 0
	%tbend

partab:	%table
	%key	<even>, even
	%key	<mark>, mark
	%key	<none>, none
	%key	<odd>, odd
	%key	<space>, space
	%tbend

srtabl:	%table
	%key	<end-of-line>, [xwd .seteo,reolch]
	%key	<packet-length>, [xwd .setpk,rpsiz]
	%key	<padchar>, [xwd .setpc,rpadch]
	%key	<padding>, [xwd .setpd,rpadnm]
	%key	<quote>, [xwd .setqu,rquote]
	%key	<start-of-packet>, [xwd .setsp,rsthdr] ;[18]
	%key	<timeout>,[xwd .setim,rtimou]
	%tbend

sstabl:	%table
	%key	<end-of-line>, [xwd .seteo,seolch]
	%key	<packet-length>, [xwd .setpk,spsiz]
	%key	<padchar>, [xwd .setpc,spadch]
	%key	<padding>, [xwd .setpd,spadnm]
	%key	<quote>, [xwd .setqu,squote]
	%key	<start-of-packet>, [xwd .setsp,ssthdr] ;[18] 
	%key	<timeout>,[xwd .setim,stimou]
	%tbend

	Remark	Pure storage

levtab:	pc1
	pc2
	pc3
chntab:	1,,tmtrp		; Timer trap on channel 0, priority 1.
	1,,cctrap		; ^C trap on channel 1, same priority.
	2,,cbtrap		; ^B trap on channel 0, lower priority.
	repeat <^d34>,<0>	; Nothing on other channels.

lits:	lit			; Assemble literals here.


	subttl	Impure data storage

CMDSTG				; Allocate COMND JSYS storage
pdl:	block pdlsiz		;  and stack.
pc1:	0			; Interrupt PC storage, levels 1,
pc2:	0			;  2,
pc3:	0			;  and 3.
intpc:	z			; PC to restore on timer interrupt.
intstk:	z			; Stack pointer to restore on timer interrupt.
ccn:	z			; Number of ^C's typed.
cbseen:	z			; Flag for ^B trap.
psave:	z			; Stack pointer for ^C interrupt.
psave2:	z			; Stack top for ^C interrupt.
cbloc:	z			; Where to go on ^B interrupt.
capas:	z			; Process capabilities.

pars1:	z			; Data from first parse.
pars2:	z			; Data from second parse.
pars3:	z			; Data from third parse (flags to turn on).
pars4:	z			; Data from fourth parse.
jbdlm:	z			; Delimiter character for job command
srvflg:	z			; Are we serving?  Erase if we go for command.
parsnm==.-pars1

dfstrt:	promp			; Are we to be a SERVER or go to the PROMPT?
				;  (Use PROMP not PROMPT to avoid collision
				;  with CMD PROMPT macro.)
f$exit:	z			; Exit flag.
filjfn:	z			; File JFN.
ndxjfn:	z			; Indexable JFN.
netjfn:	z			; Where to transmit the information.
oldmod:	z			; Previous mode of the line.
oldpau:	z			; Previous terminal pause on end mode.
ttynum:	z			; Number of the TTY being used.
oldnum:	0			;[7] Number of previous TTY in case of change.
mytty:	0			;[4] TTY number of job's controlling terminal.
myjob:	0			;[7] My job number.
job:	0			;[7] Number of job that has TTY I want.
telfrk:	z			; Fork number of the ttlink fork.
errptr:	z			; Storage for previous error.
ebtflg:	0			; One if file is to be used in 8-bit mode.
autbyt:	1			; One if auto-byte is to be used.
ibmflg:	0			; One if we are talking to the IBM.
assflg:	0			;[7] -1 if I asg'd the TTY, 0 if already asg'd.
oasflg:	0			;[7] Same, but for previous TTY.
parity:	defpar			; Type of parity to use.
trnrnd:	dtrnrn			; Turn around character.
mapflg:	0			; One if a page is mapped in.  (Init to 0.)
local:	0			; -1 = local Kermit, 0 = remote.
mapptr:	z			; Pointer into the page.
filpag:	z			; Number of pages in the file.
filbyt:	z			; Number of bytes in the file.
filbsz:	z			; Byte size of file.
prepag:	z			; Present page number.
stdat:	z			; Time taken in transmitting.
size:	z			; Size of the present data.
spsiz:	dspsiz			; Maximum size packet to send.
rpsiz:	drpsiz			; Maximum size packet to receive.
stimou:	dstim			; Interval for my own timer.
otimou:	dstim			;[26] Place to save old timout interval.
rtimou:	drtim			; Time out interval I need.
spadch:	dspad			; Pad char micro wants.
rpadch:	drpad			; Pad char I want.
spadnm:	dspadn			; Number of pad chars for micro.
rpadnm:	drpadn			; Number for me.
seolch:	dseol			; EOL char micro needs.
reolch:	dreol			; EOL I need.
squote:	dsquot			; Quote character micro wants.
rquote:	drquot			; Quote character I want.
delay:	ddelay			; How long before I send the first packet.
odelay:	ddelay			;[27] For saving & restoring delay.
escape:	31			; Escape character for connecting (default ^Y).
duplex:	dxfull			; Duplex for connecting.
ssthdr:	SOH			; Start of header character to send.
rsthdr:	SOH			; Start of header character to receive.
rtchr:	z			; Total characters received.
stchr:	z			;  ... sent.
rtot:	z			; Some more counters..
stot:	z			; 
numtry:	z			; Number of tries on a packet.
oldtry:	z			; Number of tries for previous packet.
maxtry:	dmxtry			; Maximum number of times to try.
imxtry: dimxtr			; Maximum retries in send initiate.
pktnum:	z			; Packet sequence number.
rptot:	0			;[4] Counter for received packets.
sptot:	0			;[4] Counter for sent packets.
eoflag:	z			; End of file flag.
crlf:	asciz/
/				; A carriage-return-linefeed.
filbuf:	block ^d20		; File name building buffer.
buffer:	block maxpkt/4		; Buffer for file I/O.
data:	block maxpkt/4		; Temp data storage.
sndpkt:	byte (7) SOH,0		; Start with the start of header char.
	block maxpkt/4
recpkt:	byte (7) SOH,0		; Start with the start of header char.	
	block maxpkt/4
%%krbf:	asciz/                                                                                /		; Storage for error packet.


	end	<3,,Kermit>

