home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
d
/
k20mit-262.mac
< prev
next >
Wrap
Text File
|
2020-01-01
|
127KB
|
3,976 lines
;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
SALL ; SHUT YOUR FACE
.DIRECTIVE FLBLST
$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>