home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
dec20.zip
/
k20mit.mac
< prev
next >
Wrap
Text File
|
2006-01-06
|
425KB
|
12,890 lines
$verno==^d5 ; Major version number.
$mnver==^d1 ; Minor version number (minimum: 1).
$edno==^d186 ; [185] Edit# increases independent of version.
$who==^d0 ; [186] Who edited, 0=Columbia.
; [184] 2=ex-Columbia employees ...
verdate: asciz/6-Jan-2006/ ; [186] Version datea
;
; Copyright (C) 1981, 2006,
; The Trustees of Columbia University in the City of New York.
;
; RECENT EDIT HISTORY (more at end):
;
;[TOMMYT]<FDC>K20MIT.MAC.368, Fri Jan 6 17:11:42 2006, Edit by FDC
;[186] Minor reformatting, add version date for 25th Anniversary Edition.
;[TOMMYT]STAR:<KERMIT>K20MIT.MAC.366, 4-Jan-2006 17:27:09, Edit by SLOGIN
;[185] Properly restore terminal length and width for large dimensions
;[TOMMYT]STAR:<KERMIT>K20MIT.MAC.355, 16-Mar-2005 14:47:16, Edit by SLOGIN
;[184] Set program version number to be decimal as typed by the EXEC.
; . Fix internal type out routines to support decimal.
; . Make 183 work when we quit, detach and continue
;[TOMMYT]STAR:<KERMIT>K20MIT.MAC.334, 5-Mar-2005 08:21:36, Edit by SLOGIN
;[183] A small amount of contingency logic. Set the terminal JFN to
; be restricted so that it can't be clobbered.
; . Check to see if a DTACH% happpened during the time we pushed so we
; can punt the terminal JFN. Otherwise we'll gronk on the attach
; and continue.
;[TOMMYT]STAR:<KERMIT>K20MIT.MAC.327, 3-Aug-2003 16:50:33, Edit by SLOGIN
;[182] TVT-Binary automatic mode to check if we are on a TVT
; . Change ARPAnet references in typeout to Internet since there
; may be some children who do know what the ARPAnet was...
;[TOMMYT]STAR:<KERMIT>KERMIT.MAC.259, 30-Jul-2003 12:48:04, Edit by SLOGIN
;[181] Merge PANDA network binary mode
; . Fix reslin and subroutines to always load the terminal jfn,
; we were trying to clear the output buffer of .FHSLF!
; . put in default EMACS editing modes
;/w/fdc/timrek/kermit.mac, Mon Aug 6 14:28:27 2001, Frank (fdc@columbia.edu)
;[180] Buffered packet input instead per-character BIN% + better statistics.
;/w/fdc/timrek/kermit.mac, Sun Jan 28 17:33:20 2001, Frank (fdc@columbia.edu)
;[179] Added Long packets:
; . Added new symbol MAXBUF (10KB)
; . Increased packet buffer sizes to MAXBUF
; . Changed .setpk to allow sizes up to 9000 (near theoretical max)
; . Added CAPAS, WINDO, MAXLX1, MAXLX2 field support to rpar and spar.
; . Added long-packet sending/reading to spack/rpack.
; . Removed hardwired ^d94 packet-length references.
; . Speed improvements by up to a factor of 20.
; Changed default delay to 1 sec.
; Increased version number from 4.2 to 5.1.
; All long-packet related lines are marked "[179]".
;
;******************** Version 5.1 ************************
;PK:<TIMREK>KERMIT.MAC.259, 26-Jan-88 10:28:51, Frank (SY.FDC@CU20B)
;[178] Allow passwords to come from TAKE files.
;PK:<TIMREK>KERMIT.MAC.259, 25-Jan-88 18:38:14, Frank (SY.FDC@CU20B)
;[177] Fix [176]. It wasn't conditioning the line correctly.
;PK:<TIMREK>KERMIT.MAC.258, 11-Dec-87 14:16:09, Frank (SY.FDC@CU20B)
;[176] Allow commands to servers to be issued from TAKE file.
; Also, pass capabilities down to inferior process correctly.
;PS:<TIMREK>KERMIT.MAC.6, 6-May-85 17:39:44, Frank (SY.FDC@CU20B)
;[175] Delete any dot at the end of outbound file names (like 'makefile.').
;PS:<KERMIT>20KERMIT.MAC.256, 2-May-85 12:21:34, Frank (SY.FDC@CU20B)
;[174] Several things:
;. Don't ACK a Z packet if the file can't be closed.
;. Fix server interpretation of remote directory command with no args.
;. Fix "push" command message to not assume connected to remote.
;. Give appropriate messages for local/remote mode server entry.
;. Recover from i/o errors in debug log writing.
;. Recover from incoming filenames that start with dot.
;PS:<TIMREK>KERMIT.MAC.1028, 11-Dec-84 19:00:29, Frank (SY.FDC@CU20B)
;[173] Display contents of any incoming X packet.
;PS:<TIMREK>KERMIT.MAC.1028, 11-Dec-84 18:37:05, Frank (SY.FDC@CU20B)
;[172] Don't use "*" for default file type in SEND command.
;PS:<TIMREK>KERMIT.MAC.1021, 15-Nov-84 15:28:26, Frank (SY.FDC@CU20B)
;[171] Fix LOCAL CWD not to ask for password unless it has to.
;PS:<TIMREK>KERMIT.MAC.1018, 15-Nov-84 11:39:00, Frank (SY.FDC@CU20B)
;[170] Don't send 4 null bytes at end of ITS binary file.
;PS:<TIMREK>KERMIT.MAC.1012, 18-Oct-84 13:20:42, Frank (SY.FDC@CU20B)
;[169] Misc small fixes:
;. Make $XHOST allow ^C interrupt to work during SINFO.
;. Allow ^C interrupt in LOCAL TYPE.
;. REMOTE CWD Password: input was erroneously saying "?Too long"
;. In RUN command, don't let inferior log out.
;PS:<TIMREK>KERMIT.MAC.1012, 18-Oct-84 13:20:42, Frank (SY.FDC@CU20B)
;[168] Fix SPAR not to overrule SET commands when entering server mode.
;PS:<TIMREK>KERMIT.MAC.1004, 3-Oct-84 15:30:24, Frank (SY.FDC@CU20B)
;[167] Add ECHO command.
;PS:<TIMREK>KERMIT.MAC.1000, 3-Oct-84 12:13:10, Frank (SY.FDC@CU20B)
;[166] Add ^M and ^P interrupts for getting unstuck from TRANSMIT
;PS:<TIMREK>KERMIT.MAC.980, 2-Oct-84 19:36:41, Frank (SY.FDC@CU20B)
;[165] Add TRANSMIT command.
;PS:<TIMREK>KERMIT.MAC.972, 1-Oct-84 22:00:43, Frank (SY.FDC@CU20B)
;[164] Make session logging work during script execution.
;PS:<TIMREK>KERMIT.MAC.966, 30-Sep-84 13:27:04, Frank (SY.FDC@CU20B)
;[163] Add PC typeout to %JSERR
;PS:<TIMREK>KERMIT.MAC.962, 28-Sep-84 16:37:25, Frank (SY.FDC@CU20B)
;[162] Add CLEAR command.
;PS:<TIMREK>KERMIT.MAC.961, 28-Sep-84 08:37:26, Frank (SY.FDC@CU20B)
;[161] If SET SPEED done, remember it!
;PS:<TIMREK>KERMIT.MAC.946, 27-Sep-84 15:15:23, Frank (SY.FDC@CU20B)
;[160] Refinements of previous edit, add SET/SHOW INPUT.
;PS:<TIMREK>KERMIT.MAC.924, 26-Sep-84 16:35:53, Frank (SY.FDC@CU20B)
;[159] INPUT, OUTPUT, and PAUSE commands to provide a simple script facility.
;******************** Version 4.2 ************************
;
;PS:<TIMREK>KERMIT.MAC.918, 18-Jul-84 13:50:17, Frank
;[158] Clear up any XOFF condition when leaving protocol mode.
;PS:<TIMREK>KERMIT.MAC.916, 13-Jul-84 17:57:24, Frank
;[157] Don't get stuck if XOFF'd while typing out server message (thanks Jeff).
;PS:<TIMREK>KERMIT.MAC.914, 11-Jul-84 19:51:24, Frank
;[156] Debug previous edits.
;PS:<TIMREK>KERMIT.MAC.899, 10-Jul-84 18:52:39, Frank
;[155] Fix recently introduced bug in INILIN that broke handshake code.
;PS:<TIMREK>KERMIT.MAC.896, 10-Jul-84 17:12:04, Frank
;[154] Fix up session logging - avoid loss of nonopen JFN. Add CLOSE command.
;PS:<TIMREK>KERMIT.MAC.893, 9-Jul-84 18:48:42, Frank
;[153] Always convert lc letters in incoming filenames to uc (for Bernie).
;PS:<TIMREK>KERMIT.MAC.888, 6-Jul-84 16:41:26, Frank
;[152] Add PUSH, SET SPEED, and SET BREAK.
;PS:<TIMREK>KERMIT.MAC.879, 5-Jul-84 12:53:06, Frank
;[151] Integrate connect code into this program, rather than running TTLINK
; in a lower fork. Use TELNET-style separate input & output forks with no
; interrupts. This was done for several reasons:
; . Release 6.0 of TOPS-20 doesn't allow multiple JFNs on a single TTY.
; . TTLINK did interrupt-driven i/o in a single fork, so would not work under
; batch, where BATCON feeds i/o depending on whether "pty hungry".
; . Fewer source files to keep track of.
;******************** Version 4.1 ************************
;
;PS:<TIMREK>KERMIT.MAC.871, 3-Jul-84 10:50:55, Frank
;[150] Add dispatch tables for server and generic commands, to force us
; to think about every case -- e.g. server shouldn't complain about NAKs.
;PS:<TIMREK>KERMIT.MAC.870, 29-Jun-84 13:28:08, Frank
;[149] Fix bug in SET SEND/RECEIVE PADCHAR parsing (thanks, Daphne)
;PS:<TIMREK>KERMIT.MAC.859, 26-Jun-84 14:26:37, Frank
;[148] Allow source & destination filespecs for GET to be given separately.
;
;PS:<TIMREK>KERMIT.MAC.855, 26-Jun-84 12:38:18, Frank
;[147] Fix various problems reported by Ken Harrenstien (KLH@SRI-NIC):
; . Allow user to include !,?,@,;, etc in GET filespec with ^V quote.
; . Refuse links on file-transfer tty, not controlling tty!
; . Restore advice and links to tty after file transfer.
;
;PS:<TIMREK>KERMIT.MAC.840, 28-May-84 17:33:56, Frank
;[146] Get monitor version number at startup. Under V6 or later, we can tell
; the real speed of the communication line (after all these years!). Also, we
; know speed of a local line. Account for all this in CHKLIN, and report the
; percent efficiency in STATISTICS command when baud rate is known.
;
;PS:<TIMREK>KERMIT.MAC.820, 28-May-84 14:23:45, Frank
;[145] Allow LOCAL commands to be issued without the "LOCAL" prefix.
; Change LOCAL/REMOTE "DISK" to "SPACE". Fill in local TYPE and RUN commands.
;
;PS:<TIMREK>KERMIT.MAC.810, 28-May-84 10:06:30, Frank
;[144] Misc bugs fixed:
; . In ENCODE, fix problem when exactly two consecutive repeat prefix
; characters appear in data.
; . In SRVCMD, decode contents of ACK (it was being displayed "bare").
; . Remove test for remote at $SERVE, let server work over asg'd tty line.
; . In DOSRV, don't allow an I packet to cause a state transition.
; . Don't create empty debugging log files.
; . Fix bytesize in OPENF in RFIL3K (cosmetic)
; . Allow SET HANDSHAKE to also accept an octal number.
;
;PS:<TIMREK>KERMIT.MAC.804, 28-May-84 09:55:50, Frank
;[143] Add SET FLOW-CONTROL, SET EXPUNGE.
; Change SET DEBUGGING LOG to LOG DEBUGGING (like other Kermits).
;PS:<TIMREK>KERMIT.MAC.803, 19-Apr-84 12:16:59, Frank
;[142] Fix broken FILCNV for normal-form (from George Boyce, Cornell).
;PS:<TIMREK>KERMIT.MAC.799, 12-Apr-84 16:29:05, Frank
;[141] Decode filename in R packet instead of taking it literally.
; Also, allow ERMSG and KERMSG macros to take addresses, like %JSERR and
; %JSKER, and make their message formats nicer and more consistent.
;PS:<TIMREK>KERMIT.MAC.792, 5-Apr-84 13:23:38, Frank
;[140] Make ^X = ^Z if we're sending a directory (or deleted file) listing.
;PS:<TIMREK>KERMIT.MAC.791, 3-Apr-84 16:40:01, Frank
;[139] Fix "help receive" (table out of order). Fix problem where server was
; sending a directory listing, interrupted, then asked to delete files, and
; sent rest of directory listing before deleting files.
;PS:<TIMREK>KERMIT.MAC.788, 26-Mar-84 13:11:11, Frank
;[138] Make sure any logs are closed after server FIN command.
;
;PS:<TIMREK>KERMIT.MAC.783, 23-Mar-84 11:00:06, Frank
;[137] When server gets a FINISH command, exit from program rather than
; going back to KERMIT command level, as we used to before. Also:
; . Add SET PROMPT
; . Add SET RECEIVE SERVER-TIMEOUT (for Bernie)
; . Fix password delimitation in server CWD command.
; . Fill in LOCAL CWD command.
;
;PS:<TIMREK>KERMIT.MAC.778, 19-Mar-84 19:27:57, Frank
;[136] Fix mistake in CRC calculation when parity being used.
;
;PS:<TIMREK>KERMIT.MAC.767, 15-Mar-84 16:31:22, Frank
;[135] Move handshake code from beginning of SPACK to end of RPACK.
; This allows IBM communication to work again.
; Also, handle carrier drop a little better in SPACK.
; Also, make sure we close any open file after ^C out of file transfer.
;
;PS:<TIMREK>KERMIT.MAC.752, 14-Mar-84 11:50:47, Frank
;[134] Make SHOW LINE really test carrier, rather than possibly old flag.
; Put modem/carrier checking stuff in CHKLIN routine. Also:
; . Be more defensive about terminal modes after running TTLINK.
; . Make sure file gets closed if in cAncel state.
; . Don't assign device if own controlling TTY (even if it is a TVT).
; . In GIVEUP, obey setting of INCOMPLETE FILE DISPOSITION for incoming
; files that ask to be discarded.
;
;PS:<SY.FDC>KERMIT.MAC.736, 13-Mar-84 16:27:08, Frank
;[133] When sending an I packet, keep trying till retry limit exceeded.
; Also, include byte count and byte size in directory listing.
;
;PS:<TIMREK>KERMIT.MAC.735, 9-Mar-84 09:49:03, Frank
;[132] In STATISTICS, only show last JSYS error if debugging. Also:
; . QCTL field in S/I packets and their ACKs was backwards! Fix in SPAR, RPAR.
; . Fix a couple details with timers, clear all pending before setting.
; . In the unlikely event that an incoming filename can't be dealt with, store
; the file as -UNTRANSLATABLE-FILENAME-.KERMIT.-1 to avoid sending an error
; packet & terminating the transfer.
;
;PS:<TIMREK>KERMIT.MAC.726, 7-Mar-84 11:52:31, Frank
;[131] Add time stamps to debugging-packets log (suggested by BillW). Also:
; . When logging incoming data, include current load-adjusted timeout interval.
; . Try to use different timeouts for sending & receiving.
; . Double outgoing IAC bytes in SPACK if TVT-BINARY is set.
;
;PS:<TIMREK>KERMIT.MAC.716, 5-Mar-84 12:15:09, Frank
;[130] Rename SET TAC to SET TVT, because it really applies to all ARPANET
; TVTs. If TVT, must still OPENF line in 8 bit mode. Also:
; . In INCHAR, detect carrier loss and close, deassign line when it happens.
; . Take class scheduler into account when getting load averages.
;
;PS:<TIMREK>KERMIT.MAC.705, 2-Mar-84 10:31:44, Frank
;[129] Install ARPANET TAC support changes from Dale Chase, ISI.
; Code mostly adapted from the TOPS-20 MODEM program (Bill Westfield, SRI).
; Dale's code modified at Columbia to operate through SET TAC rather than by
; determining TVT status through a site-dependent JSYS (DEC vs BBN vs...).
;
; Important installation note from Dale:
;
; Some TOPS-20s may need a patch or two to allow user programs to send the
; necessary telnet protocol negotiations. The monitor cell NVTDOD must contain
; "400000,,RSKP" so that TOPS-20 will accept the negotiation. And some sites
; may have code that "doubles" any IAC (octal 377) characters sent from a
; network terminal. We turned that off here by putting a "RET" in CHKIAC. If
; TOPS-20 doubles IACs, this program will not be able to negotiate telnet
; binary mode.
;
;PS:<TIMREK>KERMIT.MAC.691, 29-Feb-84 17:00:05, Frank
;[128] Several final things before field-test:
; . Accept null data field in server commands.
; . In RPAR, ask other side to time us out based on our 15-min ldav rather
; than hardwired constant, DRTIM. New routine ADJTIM does this.
; Also, raise DRTIM from 8 to 15 seconds, since we're probably in better
; control of the timeouts than the KERMIT on the other side.
; . In local mode, don't mix up blips with debugging output.
; . When starting to send, check for incoming NAKs to cut short any delay.
; . Add support for LOG SESSION command.
; . Fix mistake in setting file size by clearing RCHR before entering RD state.
; . Ditto for SCHR when entering SD state.
; . Exchange parameters before sending file related commands to a server.
; . Don't send garbage in X headers after a timeout.
; . Allow RECEIVE when local, for talking to a remote non-server (undo [94]).
;PS:<TIMREK>KERMIT.MAC.659, 24-Feb-84 18:53:47, Frank
;[127] Don't assign or open comm line if it's the controlling terminal, don't
; reset line between transactions if a server. This prevents a server that got
; detached (e.g. when carrier dropped) from making the line unavailable for
; further use.
;PS:<TIMREK>KERMIT.MAC.653, 24-Feb-84 17:14:45, Frank
;[126] Put in all the transaction logging code, show status of it in SHOW.
;PS:<TIMREK>KERMIT.MAC.641, 23-Feb-84 19:01:24, Frank
;[125] LOG command, parsing only.
;PS:<TIMREK>KERMIT.MAC.638, 23-Feb-84 17:36:40, Frank
;[124] When sending a multipacket response to a server command, start with
; an S packet unless using type 1 block check, in which case start with X.
;PS:<TIMREK>KERMIT.MAC.636, 23-Feb-84 17:10:52, Frank
;[123] Add S and N packet heuristics to RPACK to help resync when fancy
; block check types are being used, but the two sides lose track.
;PS:<TIMREK>KERMIT.MAC.631, 23-Feb-84 14:38:50, Frank
;[122] Make directory listing neater.
;PS:<TIMREK>KERMIT.MAC.629, 23-Feb-84 10:41:34, Frank
;[121] Fix turning off ^C trap after FINISH, again.
; Don't try to CLOSF or GNJFN if sending generated text rather than files.
; Restore normal i/o after sending server help message.
; Fix SRVCMD to actually do what it says it does.
; Fix problem with spurious repeat counts appearing in file headers.
;PS:<TIMREK>KERMIT.MAC.627, 24-Jan-84 18:45:56, Frank
;[120] Add REMOTE HELP and server support for it.
;PS:<TIMREK>KERMIT.MAC.617, 24-Jan-84 13:11:20, Frank
;[119] Decode incoming filenames and validate them more completely.
;PS:<TIMREK>KERMIT.MAC.613, 23-Jan-84 19:28:23, Frank
;[118] Server does file deletions.
;PS:<TIMREK>KERMIT.MAC.612, 23-Jan-84 18:01:33, Frank
;[117] Fix bugs: SEND x (INITIAL) was broken, and check for receive-packet
; buffer overflow, to prevent writing over other data (thanks to Greg Small
; of Berkeley for uncovering that one).
;PS:<TIMREK>KERMIT.MAC.603, 19-Jan-84 17:08:00, Frank
;[116] Server sends directory listings.
;PS:<TIMREK>KERMIT.MAC.570, 18-Jan-84 10:30:07, Frank
;[115] Rewrite directory listing code to allow for i/o redirection.
;PS:<TIMREK>KERMIT.MAC.566, 17-Jan-84 11:03:38, Frank
;[114] Rewrite DIAMSG to give more informative message.
; When logging packets, precede received packets by "R:", sent by "S:".
;PS:<SY.FDC>KERMIT.MAC.31, 16-Jan-84 16:31:57, Frank
;[113] Add LOCAL DELETE command.
;PS:<SY.FDC>KERMIT.MAC.30, 16-Jan-84 16:15:25, Frank
;[112] Fix server command business of ACK vs Text Header; get/send one or the
; other, but not both.
;PS:<SY.FDC>KERMIT.MAC.18, 16-Jan-84 12:15:04, Frank
;[111] Make file stepping mechanism do 1-file lookahead. Add LOCAL DIRECTORY.
;PS:<TIMREK>KERMIT.MAC.551, 13-Jan-84 19:16:44, Frank
;[110] Release TTY JFN when ^C'd out of server mode.
; Thanks to Kimmo Laaksonen (Helsinki), Norm Kincl (HP Labs) for reporting
; this bug, which surfaced when user detached after ^C out of server mode,
; leaving TTY assigned and unavailable for new jobs.
;PS:<TIMREK>KERMIT.MAC.550, 13-Jan-84 17:36:32, Frank
;[109] Fix bad bug in 8th-bit prefixing. Also bug in SET PARITY command that
; prevented SET PARITY NONE from ever working.
;PS:<TIMREK>KERMIT.MAC.542, 11-Jan-84 09:28:05, Frank
;[108] Add REMOTE DELETE, REMOTE DIRECTORY. Misc cleanups, minor fixes.
; Merge SDEBUG and DIAMSG. Better recovery from SPACK failures.
;PS:<TIMREK>KERMIT.MAC.540, 10-Jan-84 17:40:57, Frank
;[107] Added server support for remote CWD command.
;PS:<TIMREK>KERMIT.MAC.521, 9-Jan-84 18:26:43, Frank
;[106] Added REMOTE CWD command.
;PS:<TIMREK>KERMIT.MAC.512, 9-Jan-84 12:44:11, Frank
;[105] Debug [104], add REMOTE HOST command.
;PS:<TIMREK>KERMIT.MAC.500, 6-Jan-84 19:40:33, Frank
;[104] Add server and user TYPE command.
; Collapse a lot of redundant code into routines like SRVCMD and DOSRV.
;PS:<TIMREK>KERMIT.MAC.499, 6-Jan-84 11:50:51, Frank
;[103] Provide disk quota query service in server mode.
;*************** Major Version 4.0 ****************
;
;(Old Edit History moved to end of file, after END statement)
; THINGS TO DO...
;
; * Internal cleanup -- do state transition, packet input & ACK/NAK, etc
; globally like C-Kermit, instead of replicating the same code all over.
;
; * Check/fix bugs:
; . Page mode on/off on assigned line (got some complaints, not verified).
; . ^A in local mode sometimes gets lost.
; . ^A sometimes not turned off (e.g. after ^C out of f.t., then connect)
;
; * Move receive-file opening code to RDATA (& REOF); don't open file until
; first data packet (or EOF if null file) arrives, to prepare for attributes.
;
; * Finish adding server functions: COPY, RENAME, WHO, MESSAGE, STATUS, RUN,
; KERMIT (e.g. "remote kermit set file bytesize 8").
;
; * Do something with the REMOTE ERROR command (like think of a better name,
; make it visible, and document it, maybe put it on ^E).
;
; * When local and receiving a file, if ^Z has no effect, send an error packet
; to shut down the transaction.
;
; * Add host commands. Fork an Exec, pass commands to it in rescan, somehow
; pipe the Exec's typeout back, packetized. Too bad TOPS-20 isn't UNIX...
; Maybe use LOTS's new pipe device?
;
; * Add some support for file attribute packets.
;
; * Integrate %JSERR etc with the debugging log mechanism?
;
; * 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.
;
; * In local mode, allow running as a background fork. Or use ^P as an
; interrupt character during file transfer to Push to an inferior exec while
; the transfer continues above. ^A should still give progress report.
;
; * Separate out the routines according to ISO levels. In particular, make the
; transport-level routines available to any other application (like mail,
; e.g. SMTP) that may want to use them.
;
; * For various reasons, it might be nice to allow KERMIT-20 to send its
; packets to a file, without another KERMIT to talk to. This will translate
; a file into all printable characters (with data compaction, etc) suitable
; for transmission over an RJE link or other picky communication media.
;
; * Parse single characters in nicer ways, like CONTROL X, or "^X", as well
; as octal numbers (in all the SET commands).
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
; Originally written by Bill Catchings, Columbia University, April 1981.
; Taken over by Frank da Cruz, Columbia University, March 1983.
;
; This program is the DEC-20 implementation of Columbia University's KERMIT
; 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 (Bill)
;
; Version 2, Feb 83: Basic server service (Bill)
;
; Version 3, Mar 83: Local mode, TTLINK, talk to server (Frank)
;
; Version 3B, Oct 83: I packets, ^X,^Z interrupts, TAKE, DEFINE, etc (Frank)
; 3C, Nov 83: 8th-bit prefixing, repeat counts.
; 3.4, Dec 83: 2- and 3-character block checks.
;
; Version 4, Jan 84: Advanced server functions, LOG, ARPAnet support (Frank)
;
; Version 4.1, Jul 84: Integrated CONNECT code, no more TTLINK (Frank)
;
; Version 4.2, Oct 84: Non-Protocol upload/download, login scripts (Frank)
subttl Help Text. ;[18] Lengthy help messages added in edit [18].
; Overall summary, more detailed help text is with each command.
;
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 promote error-free and complete transmission.
KERMIT-20 is the KERMIT implementation for the DECSYSTEM-20. KERMIT-20 can be
run "remotely" from another computer (e.g. a microcomputer), or "locally" with
a remote Kermit on the other end of an assigned TTY line (e.g. over an
autodialer connection)
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
single command line argument (e.g. "kermit receive"), or you can run it as a
remote server.
KERMIT-20 command summary -- optional parts are in [brackets]:
* For exchanging files using KERMIT protocol:
SEND file(s) [(INITIAL) file]
RECEIVE [file]
GET remote-file(s)
SERVER
* For acting as local Kermit:
CONNECT [line], INPUT, OUTPUT, CLEAR
SET: LINE, FLOW, PARITY, DUPLEX, HANDSHAKE, ESCAPE, BREAK, SPEED
* For talking to a server:
BYE, FINISH, GET remote-file(s), SEND file(s);
REMOTE: DISK-USAGE, TYPE, CWD, DIRECTORY, DELETE, HELP, HOST
* Setting nonstandard transmission and file parameters:
SET: DEBUG, DELAY, FILE, INCOMPLETE, INPUT, ITS, PROMPT, RETRY, TVT;
SET SEND (or RECEIVE): END-OF-LINE, START-OF-PACKET, PACKET-LENGTH,
PAUSE, PADDING, TIMEOUT, SERVER-TIMEOUT
DEFINE a macro for a combination of SET commands.
* For non-protocol data transfer:
INPUT, OUTPUT, PAUSE, CLEAR, TRANSMIT, LOG SESSION
* For interrupting transmission: Control-X (^X), ^Z, ^C
* Getting information: HELP [topic], STATISTICS, SHOW, ^A
* Recording information: LOG or CLOSE TRANSACTIONS, SESSION, DEBUGGING
* Executing command files: TAKE
* Leaving the program: EXIT, QUIT, BYE, PUSH
If you have a file called KERMIT.INI in your login directory, KERMIT-20 will
execute an implicit TAKE command on it upon initial startup. KERMIT.INI may
contain any KERMIT-20 commands; DEFINE and SET commands are the most useful.
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.
|
subttl Definitions
pdlsiz==^d200 ; Stack size, be generous.
takel==^d20 ;[78] TAKE command JFN stack size.
f=0 ; AC definitions: flag AC (not used),
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 file characters received.
schr=rchr+1 ; Total file characters sent.
debug=schr+1 ;[22] Debugging (0=none, 1=states, 2=packets)
mappag==200 ; Single page window for mapping files.
SOH==^o001 ; ASCII Start of header character.
XON==^o021 ; XON is defined to be Control-Q (ASCII DC1).
MAXBUF==^d10240 ; Packet buffer size [179]
MAXPKT==^d94 ; Packet buffer size [179]
IOBUF==^d1024 ; Communications i/o buffer [180]
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.
spmin==^d10 ;[47] Minimum size packet we want to send.
spmax==^d9000 ;[47] Maximum ...
dstim==^d8 ; Default send time out interval.
drtim==^d13 ;[128] Default receive time out interval.
dsrvtm==^d30 ;[20] Def timout when awaiting server commands.
drpaus==0.0 ;[35] Default pause before ACKing packets.
dspaus==0.0 ;[36] Default pause before sending packets.
dspad==^o0 ; Default send padding char.
drpad==^d0 ; 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 outbound control prefix.
drquot=="#" ; Default incoming control prefix.
dqbin=="&" ; Default 8th-bit prefix.
drept=="~" ; Default repeat count prefix.
ddelay==^d1 ; Default delay before the first packet, secs.
dxfull==0 ;[18] Full duplex.
dxhalf==1 ;[18] Half duplex.
defesc==34 ; Default CONNECT escape character is ^\.
defpar==none ; Default parity.
defits==-1 ;[75] Handle ITS binary files by default.
defics==0 ;[160] Default case search for INPUT commands.
defita==0 ;[160] Default timeout action for INPUTs.
defito==5 ;[160] Default timeout interval for INPUTs.
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.
mnblen==^d200 ;[77] Macro name buffer length (words).
mtblen==^d1000 ;[77] Macro text buffer length (words).
macmax==^d100 ;[77] Maximum number of macros.
;[129] ARPA definitions
ifndef STAT%,<opdef STAT% [JSYS 745]> ; So this will assemble
ifndef TCP%NT,<TCP%NT==40000000> ; without symbols from BBN TCP monitor.
iac==377 ; arpanet telnet IAC
will==373 ; telnet will <option>
wont==374 ; telnet wont <option>
do==375 ; telnet do <option>
dont==376 ; telnet don't <option>
trnbin==0 ; transmit binary
ifdef .MORLT,<PANDASW==1> ;[181] Assemble if we have monitor support
ifndef .MORLT,<PANDASW==0> ;[181] Or not...
define panda <ifn PANDASW , > ;[181] and a handy abbreviation!
;[182] Wouldn't it be REAL nice if these fields were defined in MONSYM?
ntflag==MASKB(0,8) ;[182] Terminal flags
nttype==MASKB(9,17) ;[182] Network type
ntline==MASKB(18,35) ;[182] Line type
ntblen==<.NWNU1+2> ;[182] Minimum length
subttl Macros
; ERMSG -- Type error message on local terminal, and save a pointer to the
; error string, that can be used when querying most recent error.
define ermsg (msg,label) <
jrst [ tmsg <
>
hrroi t1, [asciz/?KERMIT-20: 'msg/]
movem t1, errptr ;; Save pointer to error msg for stats.
PSOUT%
tmsg <
>
ifb <label>,< jrst .+1>
ifnb <label>,< jrst label>
]
>;ermsg
; KERMSG -- Like ERMSG, but also send the message to the other KERMIT in
; an error packet, which cancels the current transfer.
define kermsg (msg,label) <
$count=0
irpc msg, <$count=$count+1>
jrst [ movei t1, "E" ;; Send an error packet to the other side.
move t2, pktnum ;; Packet number.
movei t3, $count+^d11 ;; The count.
move t4, [point 7, [asciz/KERMIT-20: 'msg/]] ;; The msg.
movem t4, errptr ;; Save pointer to error msg for status.
call spack ;; Send the error packet.
nop
tmsg <
?KERMIT-20: 'msg
>
ifb <label>,< jrst .+1>
ifnb <label>,< jrst label>
]
>
; Error handling macros, cont'd
; %JSERR -- Invoked by ERJMP after a JSYS call. Prints the given message,
; if any, then the JSYS error message, and then jumps to the address given
; or else halts (continuably) if no jump address given.
;[163] Make it include the address of the failing JSYS at end of message.
define %jserr (msg, label) < ;; Use this immediately following a JSYS.
ercal [ ttcrlf ;; Output a crlf if necessary
tmsg <?KERMIT-20: '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-20: "
tmsg < at PC > ;; Say where it happened.
pop p, t2 ;; Pop the return address off the stack.
hrrzs t2 ;; Clear out junk from left half.
subi t2, 2 ;; Adjust to point at offending JSYS.
numout t2, ^d8 ;; Type JSYS PC in octal.
tmsg <
> ;; And a trailing CR.
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
define %ermsg (msg, label) < ;; Use this in any skipping context.
jrst [ ttcrlf
tmsg <?KERMIT-20: 'msg> ;; Otherwise, just like %JSERR.
ifnb <msg>,< call jserr0> ;; Except no PC typeout.
ifb <msg>,< call jsmsg0>
tmsg <
>
ifb <label>,< HALTF%
jrst .+1
>;ifb
ifnb <label>,< jrst label>
]
>;%ermsg
; %JSKER -- Like %JSERR, but also sends message to other KERMIT in an error
; packet, as KERMSG does.
define %jsker (msg, label) < ;; Use this immediately following a JSYS.
erjmp [
ifb <msg>,< move t1, [point 7, [asciz/KERMIT-20: /]] >
ifnb <msg>,< move t1, [point 7, [asciz/KERMIT-20: 'msg - /]] >
movem t1, errptr ;; Save pointer to error msg for status.
call %%krms
ttcrlf
tmsg <?KERMIT-20: '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: "
tmsg <
> ;; And a trailing CR.
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
; Support routines for error handling macros.
; JSERR0 synchronizes with terminal i/o in progress before typing the
; JSYS error message.
;
; JSMSG0 just types the JSYS error message.
;
jserr0: movei t1,.priin
CFIBF% ; Clear typeahead.
movei t1,.priou
DOBE% ; Wait for previous output to finish.
tmsg < - > ; Type a dash.
jsmsg0: movei t1,.priou
hrloi t2,.fhslf ; This fork ,, last error.
setz t3,
ERSTR%
jfcl
jfcl
ret
; KERMSG -- Send an error message to the KERMIT on the other side in an
; error packet. Invoked from %JSKER, with T1 pointing at the user-provided
; prefix (if any), to which the JSYS error message is appended.
blanks: repeat <maxpkt/4>,<ascii/ />
%%krms: move t3, [blanks,,%%krbf] ;[40] Fill up the msg buffer with blanks.
blt t3, <%%krbf+<maxpkt/4>-1> ;[40]
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?
idpb t2, t3 ; Deposit the byte.
aoja t4, %%krm1
%%krm2: move t1, t3 ; Put the information into the buffer.
hrloi t2, .fhslf ; Say: this fork ,, last error.
movn t3, spsiz ; Specify the maximum to send as a negative
add t3, t4 ; number
hrlzs t3 ;[74] (ERSTR wants -n,,0)
skipge t3 ;[50] (don't bother if not negative).
ERSTR%
trn
trn
move t2, t1 ; Set up to get the new length.
move t1, [point 7, %%krbf] ; ...
call subbp ; Subtract byte pointers.
skipa ;[40] If there is an error assume this count.
camle t3, spsiz ;[40] Longer than we're supposed to send?
move t3, spsiz ;[40] If so, truncate it.
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.
nop
ret
; Misc macros
; NUMOUT - Type a number in the desired base (decimal by default), free format.
define numout(num,base<^d10>) <
call [ saveac <t1,t2,t3>
move t2, num
movei t1, .PRIOU
movei t3, base
NOUT%
nop
ret ]
>;numout
; OUTCHR - Type a character at the terminal without disturbing any registers.
define OUTCHR(char) <
jrst [ exch t1, char
PBOUT
exch t1, char
jrst .+1 ]
>;OUTCHR
;[126] Write time-stamped file message to the transaction log file.
;
; Macro arguments are a message string and the address of a JFN
; of the filename to write, e.g.
;
; wtlog (<Sending >,filjfn)
;
define wtlog(..msg,..file) <
call [ skipn t1, tlgjfn ;; Transaction log open?
ret ;; No, skip this.
saveac <t2,t3,t4> ;; Yes, save these AC's
seto t2, ;; Start with time stamp, current date/time.
movx t3, ot%nda ;; No date.
ODTIM
hrroi t2, [asciz/: /] ;; Punctuation.
setzb t3, t4
SOUT
hrroi t2, [asciz/..msg/] ;; The given message.
SOUT
ifnb <..file>,<
move t3, [111110,,js%paf]
skiple t2, ..file ; File name.
JFNS
>;ifnb
setz t3,
hrroi t2, crlf
SOUT
ret ]
>;wtlog
; %TABLE - Beginning of COMND/TBLUK keyword table.
;
define %table <
%%tbst== . ;; Plant start of table
exp 0 ;; and leave a hole for %tbend to fill
>
; %TBEND - End of COMND/TBLUK 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 - COMND or TBLUK keyword definition
;
; This macro takes three arguments: an (alphanumerics only!) keyword, the
; data to be associated with the keyword, and an (optional) flag value. It
; creates either a flagless keyword (the normal case), or, if any 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
>
>
define ttcrlf < ;; Output a CRLF if not at left margin.
call [ saveac <t1,t2>
movei t1, .priou
RFPOS%
hrroi t1, crlf
trne t2, -1
PSOUT
ret ]
>;;ttcrlf
subttl Command Line Processing
; RESCAN - Routine to check for command line arguments.
;
;[85] Returns +1 always, with F$EXIT = 0 if no args, nonzero if some args.
;
rescan: setzm f$exit ;[85] Assume no rescan arguments.
movx t1, .rsini ; Now check.
RSCAN% ; ...
erjmp r ;[85] If none return.
movx t1, .rscnt ; Get the size of the rescan.
RSCAN% ; ...
erjmp r ;[85] Return if unsucessful.
jumpe t1, r ;[85] 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.
movei t1, [flddb. (.cmkey,,<[exp <1,,1>,<[asciz/Kermit/],,0>]>)]
call rflde ; Parse it.
ret ;[85] If we don't find it return.
setom f$exit ;[85] Assume we have command line arguments.
movei t1, [flddb. (.cmcfm,cm%sdh)] ; See if we can parse a confirm.
call rflde ; ...
ret ; If not, we have a rescan argument.
setzm f$exit ;[85] Parsed confirmation, so no arguments.
ret ;[85] Done.
subttl KERMIT Program entry, initialization, and exit.
kermit: jrst start ; Start entry.
jrst reen ; Re-entry.
versio: FLD($who,VI%WHO)!FLD($verno,VI%MAJ)!FLD($mnver,VI%MIN)!
FLD($edno,VI%EDN)!VI%DEC ;;[184] Want decimal version numbers
evlen==.-kermit
reen: jrst start ; Nothing special for now...
start: RESET% ; Normal startup: reset everything
setzm monv ; See what monitor version.
move t1, [sixbit/MONVER/] ; This only works in V6 or later.
SYSGT
erjmp .+1
skipe t2 ; Got anything?
movem t1, monv ; Yes, save it.
move p, [iowd pdlsiz,pdl] ; and set up a stack.
setzm ttfork ; Clear connect receive fork handle
setzm netjfn ; and communication line JFN
setzm f$exit ; and exit flag, so we re-init if restarted.
;[78] Set up a JFN stack for 'take' commands.
move t2, [iowd takel, takpdl] ;[78] Construct TAKE jfn stack pointer.
movem t2, takep ;[78]
setzm takdep ;[78] Start 'take depth' out at 0.
setzm takjfn ;[78] And no TAKE file jfn.
; Run KERMIT...
call main ; The actual program.
halt: HALTF% ; Upon return, just halt.
; If continued, fall thru to here...
cont: setzm f$exit ; Turn off the exit flag.
GJINF% ;[184] Load current job line in t4
movem t4, ttynum ;[184] stomp in a possible new line
move t1, ttynum ;[87] Reassign the line we were using.
movem t1, pars3 ;[87] (this is the calling convention...)
call $setln ;[85]
call prsint ; Go to command level.
jrst halt
subttl KERMIT main program
main: setzm local ; Start off running remotely.
call pinit ; Initialize interrupt system.
movei t1, .fhslf ;[176] Read current process capabilities.
RPCAP% ;[176]
movem t2, capas ;[176]
seto t1, ; Get job info for this job.
move t2, [-20,,jobtab] ; Into this job table.
setzb t3, t4
GETJI
%jserr (,.+1)
dmove t3, jobtab ; Get job & terminal numbers.
movem t3, myjob ; Job number of my job.
movem t4, mytty ; Remember this is my controlling terminal.
movem t4, pars3 ; Make believe we parsed terminal number
setz debug, ; And no debugging
call $setln ; Set the line to our own.
panda < call chknbm > ;[181] Determine if we have network binary mode
call cmdini ; Initialize the command package.
call inifil ;[79] Execute commands from KERMIT.INI, if any.
ccl: call rescan ;[85] If no .INI file, look for rescan now.
skipe f$exit ;[85] If there was a rescan argument,
jrst parse ;[85] go do that.
jrst @dfstrt ; No rescan go to default: PROMPT or SERVER.
server: jrst getcom ; Here if starting as server by default.
; Here if starting in command mode by default.
promp: skipe iniflg ;[83] Doing init file?
jrst prsint ;[83] Yes, don't print herald yet.
move q1, [ret] ;[39] Hokey calling convention for routine
call $shver ;[39] to print current program version.
prsint: setzm rcving ; Indicate neither receiving nor sending.
skipe f$exit ; Exit flag set by EXIT command or CCL entry?
jrst clenup ; If so, go clean up and return.
hrroi t1, prompx ;[137] Otherwise, point to prompt text.
call dpromp ;[137] Issue prompt.
parse: setzm pars1 ;[40] Clean out old parse values.
move t1, [pars1,,pars2] ;[40]
blt t1, parsx ;[40]
setzm cjfnbk+.gjgen ; Clear the JFN bits.
movei t1, [flddb. .cmkey,,cmdtab] ; Point to command keyword table.
skipe local ;[68] Running in local mode?
movei t1, [flddb. .cmkey,,cmdtb2] ;[68] Yes, use that table instead.
call rflde ;[78] Parse a keyword.
jrst eoftst ;[78] If error, test for EOF on command file.
hrrz t2, (t2) ; Get the command routine addresses.
movem t2, pars1 ; Save into pars1.
hlrz t1, (t2) ; Get the next level routine.
call (t1) ; Call it.
eval: move t2, pars1 ; Get back data value.
hrrz t1, (t2) ; Get evaluation routine.
call (t1) ; Call it.
jrst prsint ; Go round again.
;[78] EOFTST: Command file EOF handler.
;
eoftst: push p, t2 ; Save this in case we can resume.
movei t1, .fhslf ; Get last process error.
GETER% ; Test for eof on COMND input file.
move t1, t2 ; Move error code from t2 to t1
pop p, t2 ; and restore t2.
hrrzs t1 ; Erase fork handle from this.
caie t1, iox4 ; Was error EOF?
cain t1, comnx9 ; Or this kind of EOF?
jrst eofts2 ;[85] Yes, some kind of EOF.
skipe f$exit ;[85] Parsing rescan line?
jrst [ tmsg <?Not a KERMIT command - > ;[85] Yes, print message
hrroi t1, atmbuf ;[85]
PSOUT ;[85]
ret ] ;[85] And quit.
; Not EOF, and not parsing rescan line, just enter normal parse error handler.
jrst cmderr ; Complain, then resume parsing.
; EOF on command file.
eofts2: call popjfn ; It was EOF. Pop the command file JFN.
jrst [ movei t1, .priin ; On any error, revert parsing to TTY.
call setcsb ; ...
jrst .+1 ]
skipn iniflg ;[83] Just closed init file?
jrst prsint ;[83] No, don't bother with rescan stuff.
;[83] Just closed init file, check for command line (rescan) arguments.
setzm iniflg ;[83] Flag that we're done with init file.
jrst ccl ;[85] And go check for rescan arguments.
; Top-Level command tables.
; Commands available to remote KERMIT.
cmdtab: %table
%key <bye>, [xwd .bye,$bye], cm%inv ;[11]
%key <c>, %conn, cm%inv+cm%abr
%key <clear>, [xwd .clear,$clear], cm%inv ;[162]
%key <close>, [xwd .close,$close]
%conn: %key <connect>, [xwd .conne,$conne]
%key <cwd>, [xwd .ycwd,$ycwd] ;[145]
%key <define>, [xwd .defin,$defin] ;[77]
%key <delete>, [xwd .ydele,$ydele] ;[145]
%key <directory>, [xwd .ydire,$ydire] ;[145]
%key <e>, %exit, cm%inv+cm%abr
%key <echo>, [xwd .echo,$echo]
%exit: %key <exit>, [xwd .exit,$exit]
%key <finish>, [xwd .finis,$finis], cm%inv ;[28]
%key <get>, [xwd .get,$get], cm%inv ;[11]
%key <help>, [xwd .help,$help]
%key <input>, [xwd .input,$input], cm%inv ;[159]
%key <local>, [xwd .local,$local] ;[56]
%key <log>, [xwd .log,$log] ;[125]
%key <output>, [xwd .outpu,$outpu], cm%inv ;[159]
%key <pause>, [xwd .pause,$pause], cm%inv ;[159]
%key <prompt>, [xwd .promp,$promp], cm%inv
%key <push>, [xwd .push,$push] ;[152]
%key <quit>, [xwd .exit,$exit]
%key <r>, %recv, cm%inv+cm%abr ;[56]
%recv: %key <receive>, [xwd .recv,$recv]
%key <remote>, [xwd .remot,$remot], cm%inv ;[56]
%key <run>, [xwd .yrun,$yrun] ;[145]
%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 <space>, [xwd .ydisk,$ydisk] ;[145]
%key <statistics>, [xwd .stat,$stat]
%key <take>, [xwd .take,$take] ;[78]
%key <transmit>, [xwd .trans,$trans],cm%inv ;[165]
%key <type>, [xwd .ytype,$ytype] ;[145]
%tbend
; Commands available to local KERMIT.
cmdtb2: %table
%key <bye>, [xwd .bye,$bye] ;[11]
%key <c>, %conn2, cm%inv+cm%abr
%key <clear>, [xwd .clear,$clear] ;[162]
%key <close>, [xwd .close,$close]
%conn2: %key <connect>, [xwd .conne,$conne]
%key <cwd>, [xwd .ycwd,$ycwd] ;[145]
%key <define>, [xwd .defin,$defin] ;[77]
%key <delete>, [xwd .ydele,$ydele] ;[145]
%key <directory>, [xwd .ydire,$ydire] ;[145]
%key <e>, %exit2, cm%inv+cm%abr
%key <echo>, [xwd .echo,$echo]
%exit2: %key <exit>, [xwd .exit,$exit]
%key <finish>, [xwd .finis,$finis] ;[28]
%key <get>, [xwd .get,$get] ;[11]
%key <help>, [xwd .help,$help]
%key <input>, [xwd .input,$input] ;[159]
%key <local>, [xwd .local,$local] ;[56]
%key <log>, [xwd .log,$log] ;[125]
%key <output>, [xwd .outpu,$outpu] ;[159]
%key <pause>, [xwd .pause,$pause] ;[159]
%key <prompt>, [xwd .promp,$promp], cm%inv
%key <push>, [xwd .push,$push] ;[152]
%key <quit>, [xwd .exit,$exit]
%key <r>, %recv2, cm%inv+cm%abr ;[56]
%recv2: %key <receive>, [xwd .recv,$recv]
%key <remote>, [xwd .remot,$remot] ;[56]
%key <run>, [xwd .yrun,$yrun] ;[145]
%key <s>, %send2, cm%inv+cm%abr
%send2: %key <send>, [xwd .send,$send]
%key <server>, [xwd .serve,$serve], cm%inv
%key <set>, [xwd .set,$set]
%key <show>, [xwd .show,$show]
%key <space>, [xwd .ydisk,$ydisk] ;[145]
%key <statistics>, [xwd .stat,$stat]
%key <take>, [xwd .take,$take] ;[78]
%key <transmit>, [xwd .trans,$trans] ;[165]
%key <type>, [xwd .ytype,$ytype] ;[145]
%tbend
subttl ECHO command [167]
; Help text for ECHO
hecho: asciz |
ECHO text-string
Echoes the given text string at your terminal. Useful in TAKE command files
and with login scripts for reporting progress or telling you what to do.
|
.echo: noise <text at terminal> ; Issue noise words
movei t1, [flddb. .cmtxt] ; Get the string into the atom buffer.
call cfield
ret
$echo: hrroi t1, atmbuf ; Point at the atom buffer.
PSOUT ; Type the string.
hrroi t1, crlf ; And a CRLF.
PSOUT
ret
subttl EXIT and QUIT commands (which are the same)
; Help text for QUIT.
hquit: asciz |
QUIT
Synonym for EXIT.
|
; Help text for EXIT...
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. You can also exit from
KERMIT-20 by typing one or more control-C's, even if it's in the middle of
transferring a file. KERMIT-20 will always restore your terminal to its
original condition, and you will be able to CONTINUE the program to get back
to KERMIT-20> command level. When you EXIT from KERMIT-20, any open files,
including logs, will be closed.
|
; Parse the rest of the EXIT or QUIT command.
.exit: noise <from Kermit>
confrm ; Confirm.
ret
; Execute the EXIT or QUIT command.
$exit: setom f$exit ; Set exit flag.
ret ; (that's all)
; Routine to clean up any open files or devices.
clenup: move t1, netjfn ;[127] Get communication line JFN.
setzm netjfn
setzm local
caie t1, .cttrm ;[127] Previous one was controlling terminal?
skipn t1 ;[127] Close any assigned TTY.
jrst clenu2
CLOSF
erjmp .+1 ; Ignore any error (silently).
clenu2: skipn asgflg ; Did I also assign the TTY?
jrst clenu3 ; No.
move t1, ttynum ; Yes, so I should deassign it.
movei t1, .ttdes(t1)
RELD%
erjmp .+1
setzm asgflg
clenu3: skipn t1, logjfn ; Do we have a debugging log?
jrst clenu4 ; No.
setz t2, ;[144] Yes, any bytes written?
RFPTR ;[144]
nop ;[144]
skipg t2 ;[144]
txo t1, cz%abt ;[144] None, don't bother keeping the log.
setzm logjfn ; Yes, forget about it,
CLOSF ; Close it.
erjmp .+1
clenu4: skipn t1, tlgjfn ;[126] Transaction log was open?
jrst clenu5
wtlog <Closed Transaction Log>
setzm tlgjfn
CLOSF
erjmp .+1
clenu5: skipn t1, filjfn ; Any file transfer JFNs hanging around?
jrst clenu6
setzm filjfn
CLOSF
erjmp .+1
clenu6: skipn t1, sesjfn ; How about a session log?
jrst clenuz
setzm sesjfn
CLOSF
erjmp .+1
clenuz: ret ; Note, we DON'T turn off interrupt system.
subttl HELP command
hsfdb1: flddb. .cmkey,,mactab,<SET macro,>,<summary>,hsfdb2
hsfdb2: flddb. .cmkey,,sethlp,<SET option,>,<summary>
.help: noise <about> ;[18] HELP
movei t1, [flddb. .cmkey,,hlptab,,<kermit>]
call rfield ;[67]
move t2, (t2) ; Get help text address.
movem t2, pars3
hrrzs t2 ;[67]
caie t2, hset ;[67] They want help for SET?
jrst .helpx ;[67] No.
noise <parameter> ;[67] Yes, give guide word.
movei t1, hsfdb1 ;[77] Parse from macro or SET keyword table.
call rfield ;[67] Get SET option they want help for.
hrrzs t3 ;[77] Which function descriptor block was used?
caie t3, hsfdb1 ;[77] The macro table?
move t2, (t2) ;[67] Yes, don't do indirection
movem t2, pars3 ;[67] SET...
.helpx: confrm ;[67]
ret
hlptab: %table ;[18] Table of help commands.
%key <bye>,hbye
%key <clear>,hclear ;[162]
%key <close>,hclose
%key <connect>,hconne
%key <CWD>,hcwd
%key <define>,hdefin ;[77]
%key <delete>,hdele
%key <directory>,hdire
%key <echo>,hecho
%key <exit>,hexit
%key <finish>,hfinis
%key <get>,hget
%key <help>,hhelp
%key <input>,hinput ;[159]
%key <kermit>,hkermi
%key <local>,hlocal
%key <log>,hlog
%key <output>,houtpu ;[159]
%key <pause>,hpause ;[159]
%key <prompt>,hpromp
%key <push>,hpush
%key <quit>,hquit
%key <receive>,hrecei
%key <remote>,hremot
%key <run>,hrun
%key <send>,hsend
%key <server>,hserve
%key <set>,hset
%key <show>,hshow
%key <space>,hspace
%key <statistics>,hstatu
%key <take>,htake
%key <transmit>,htrans
%key <type>,htype
%tbend
sethlp: %table ;[67] Table of HELP SET commands.
%key <break>, hsbrea
%key <block-check>, hsbc
%key <debugging>, hsdeb
%key <delay>, hsdel
%key <duplex>, hsdup
%key <escape>, hsesc
%key <file>, hsfil
%key <flow-control>, hsflo ;[143]
%key <handshake>, hshan ;[76]
%key <incomplete>, hsabf
%key <input>, hsetin ;[160]
%key <ITS-binary>, hsits ;[75]
%key <line>, hslin
%key <parity>, hspar
%key <prompt>, hsprom ;[137]
%key <receive>, hsrcv
%key <retry>, hsrty
%key <send>, hssnd
%key <speed>, hspeed
%key <summary>, hset
%key <TVT-Binary>, hstac ;[129]
%tbend
;...
;...HELP command, cont'd
; Help text for HELP command...
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. To see a list of all the available help commands,
type
HELP ?
or consult the Kermit User Guide.
|
; Execute the help command.
$help: hrrz t3, pars3 ;[77] Special case for help about macro.
cail t3, mactab+1
caile t3, mactbx
jrst $help2
tmsg <
">
hlro t1, (t3)
PSOUT
tmsg <" is a SET macro defined to be:
>
hrro t1, (t3)
PSOUT
tmsg <
>
ret
$help2: hrro t1, pars3 ;[18] Normal help text.
PSOUT
hrroi t1, crlf
PSOUT
ret
subttl INPUT, OUTPUT, and PAUSE added as edit [159].
hinput: asciz |
INPUT interval string
INPUT is useful with OUTPUT and PAUSE for sending connect and login
sequences to a remote host, e.g. over a dialout connection.
On the currently selected communication line, look for the given string
for the specified time interval. If no interval is specified, then wait
for the default interval, which is 2 seconds unless changed by SET INPUT
DEFAULT-TIMEOUT. An interval of 0 or less means no timeout (wait
forever).
Characters coming in from the line will be scanned for the search string,
and when a match is found, the command will terminate successfully; if
the string is not found within the given interval, the command will
terminate unsuccessfully. While the INPUT command is active, all
incoming characters will appear on your screen.
The search string may contain any printable characters. Control or other
special characters may be included by preceding their octal ASCII value
with a backslash, for instance foo\15 is "foo" followed by a carriage
return, \100 is an atsign (@). Alphabetic case is ignored ("a" = "A")
unless you have SET INPUT CASE OBSERVE. If no search string is given,
then the INPUT command will keep operating until it times out.
If the INPUT command fails to find the requested string within the given
interval, it will "fail"; if the INPUT command was issued from a command
file (see TAKE), then the next command will be executed, unless you have
SET INPUT TIMEOUT-ACTION to QUIT, in which case the command file will be
terminated. An INPUT command can by interrupted by typing two ^C's.
Type HELP SET INPUT for further information.
|
.input: noise <interval>
setzm buffer ; Make dynamic default string.
setzm buffer+1
move t1, [point 7, buffer]
move t2, indeft
movei t3, ^d10
NOUT
erjmp .+1
movei t1, [flddb. .cmnum,,^d10,<Number of seconds to wait,>,<5>]
move t2, [point 7, buffer] ; The above default will be overridden
skipe buffer ; if there's anything in this buffer.
movem t2, .cmdef(t1) ; Stuff the pointer into the fdb.
call rfield
setzm buffer
setzm buffer+1
movem t2, pars2
movei t1, [flddb. .cmtxt,cm%sdh,,<Text string to look for,
use \ooo (backslash followed by octal digits) to include control characters,
\\ to include a single backslash>]
call cfield
ret
; INPUT command.
$input: call getss ; Get & decode search string from atom buffer.
skipg pars2
jrst $inpu5 ; Skip timer if interval 0 or negative.
; Set the desired timeout.
movei t1, .fhslf
movx t2, 1b0 ; Turn on channel 0.
AIC
%jserr <Can't turn on timer channel>, <.+1>
move t1, [.fhslf,,.timal] ; Remove all pending timer requests.
setzb t2, t3
TIMER
%jserr <Can't clear pending timers>, <.+1>
movem p, intstk ; The timer interrupt routine needs this.
movei t1, $inpu9 ; Where to go upon timeout
movem t1, intpc ; ...
move t1, [.fhslf,,.timel] ; Our process and time from now.
move t2, pars2 ; The interval we parsed.
imuli t2, ^d1000 ; Make time into milliseconds.
setz t3, ; Channel zero.
TIMER
%jserr <Can't set timer>, <.+1>
; Try to get string from the communication line.
$inp4a: call dobits ; Condition the line for i/o.
ret ; Pass along any failure.
call ttyob ; Put TTY in binary mode for output only.
call ccon ; Turn on ^C trap.
jrst $inpuy ; If ^C typed, go to this place.
$inpu5: move t4, [point 7, strbuf] ; Point to the search string.
$inpu6: skipn strc ; Is there a search string?
jrst $inpu7 ; No, just go forever.
ildb t3, t4 ; Get a character from search string.
jumpe t3, $inpux ; If no more, then success.
;...
;...$INPUT, cont'd
; Get & echo a character, compare with current position in search string.
$inpu7: move t1, netjfn ; Now get a character from the line.
setz t2,
BIN
%jserr (,$inpux)
andi t2, ^o177 ; Strip any parity.
move t1, t2 ; Echo the character.
PBOUT
skiple t1, sesjfn ; Session logging?
jrst [ BOUT ; Yes, record the character in the log.
erjmp .+1
jrst .+1 ]
skipn incase ; Case-sensitive compare?
jrst [ cail t2, "a" ; No, is this a lower case letter?
caile t2, "z"
skipa ; No.
txz t2, 40 ; Yes, convert to upper.
jrst .+1 ]
camn t2, t3 ; Compare OK?
jrst $inpu6 ; Yes, get next from string and comm line.
jrst $inpu5 ; No, rewind search string, get next from line.
; Come here upon input timeout.
$inpu9: hrroi t1, [asciz/
%/] ; % message if proceeding
skipe intima
hrroi t1, [asciz/
?/] ; ? message if quitting (for batch)
PSOUT
hrroi t1, [asciz/KERMIT-20: INPUT timed out looking for "/]
PSOUT
hrroi t1, strbuf ; Tell what string we couldn't find.
PSOUT
hrroi t1, [asciz/", proceeding...
/] ; Say what we're doing, proceeding
skipe intima
hrroi t1, [asciz/", quitting /] ; ...or quitting.
PSOUT
skipn intima
jrst $inpux ; Proceeding, just exit from the INPUT command.
movei t1, .priou ; Quitting, tell which file we're quitting from
move t2, takjfn ; (if any).
setz t3,
JFNS ; If no TAKJFN, this will print nothing.
erjmp .+1
tmsg <
>
$inpuy: call popjfn ; Pop the TAKE file JFN from the TAKE stack.
;...
;...$INPUT, cont'd
; Exit thru here, turning off timer, restore line to previous condition.
$inpux: call ccoff2 ; Turn off ^C trap.
call unbits ; Restore the line
call ttyou ; Restore controlling tty output.
skipg pars2 ; Skip timer stuff if interval 0 or negative.
ret
move t1, [.fhslf,,.timbf] ; Turn off timer interrupts for this fork.
hrloi t2, 377777 ; For all times before this (far in future).
TIMER ;
erjmp .+1
movx t1, .fhslf ; Deactivate the channel.
movx t2, 1b0
DIC
%jserr <Can't DIC>,<.+1>
setzm strbuf ; Leave the string buffer cleanup up
setzm strbuf+1 ; a bit...
setzm strptr
ret
; GETSS - Get & Decode a backslash-decoded search string from the atom buffer.
; Returns +1 with 7-bit ASCIZ string in STRBUF, STRC 0 if null, else nonzero.
;
getss: move t1, [point 7, atmbuf] ; Copy search string from here
move t2, [point 7, strbuf] ; ... to here
movem t2, strptr ; Use this pointer
setzm strc ; and this counter.
getss2: ildb t4, t1 ; Get a character.
getss3: jumpe t4, getssx ; If null, then done.
aos strc ; Got one, count it.
cain t4, "\" ; Backslash?
jrst [ movei t3, ^d8 ; Yes, try to read a number.
NIN
nop ; If error, just keep the backslash.
idpb t2, strptr ; OK, deposit ascii value of number.
ldb t4, t1 ; Account for how NIN overshoots the pointer.
jrst getss3 ]
getss4: skipn incase ; Case-sensitive compare?
jrst [ cail t4, "a" ; No, is this a lower case letter?
caile t4, "z"
skipa ; No.
txz t4, 40 ; Yes, convert to upper.
jrst .+1 ]
getss5: idpb t4, strptr ; Deposit the result of all this.
jrst getss2
getssx: idpb t4, strptr ; Deposit a null at the end.
ret
houtpu: asciz |
OUTPUT string
The given string is sent out the currently selected communication line.
Control characters may be included in \ooo format (backslash followed by
octal representation of ASCII value). Currently selected settings for
DUPLEX, PARITY, and FLOW are used.
Type HELP INPUT for further information.
|
.outpu: noise (string) ; Parse OUTPUT command.
movei t1, [flddb. .cmtxt,cm%sdh,,<Text string to send,
use \ooo (backslash followed by octal digits) to include control characters,
\\ to include a single backslash>]
call cfield
ret
$outpu: move t1, [point 7, atmbuf] ; Do OUTPUT; move chars from here...
move t2, [point 8, strbuf] ; to here.
movem t2, strptr
$outp3: ildb t4, t1 ; Copy them
$out3x: jumpe t4, $outp4 ; up to a null.
cain t4, "\" ; Backslash?
jrst [ movei t3, ^d8 ; Yes, read a number
NIN
movei t2, "\" ; If error, keep the backslash.
move t4, t2 ; Get ascii value into t4.
seto t2, ; Decrement the source byte pointer.
adjbp t2, t1
move t1, t2
jrst .+1 ]
out3a: exch t1, t4 ; Put character in t1, preserve source pointer.
call @parity ; Tack on desired parity.
idpb t1, strptr ; Deposit the result in the output buffer.
move t1, t4 ; Restore the source pointer.
jrst $outp3 ; Go back for next.
$outp4: idpb t4, strptr ; Done, deposit a null.
move t1, netjfn ; Comm line designator.
move t2, [point 8, strbuf] ; Point to string.
setzb t3, t4 ; It's null-terminated.
SOUT ; Send it.
%jserr (<Can't send the string>,<.+1>)
skipn duplex ; Half duplex connection?
ret ; No, host will echo.
movei t1, .priou ; Yes, do it ourselves.
move t2, [point 8, strbuf] ; Point to string again.
setzb t3, t4
SOUT
erjmp .+1
skipn t1, sesjfn ; Session logging?
jrst $outpx ; No.
move t2, [point 8, strbuf] ; Yes, point again.
setzb t3, t4
SOUT
erjmp .+1
$outpx: ret ; Done.
; PAUSE command.
hpause: asciz |
PAUSE interval
Pause for the given number of seconds. Useful with INPUT and OUTPUT.
|
.pause: noise (seconds)
movei t1, [flddb. .cmnum,,^d10,<Number of seconds to pause>,<1>]
call cfield
movem t2, pars2
ret
$pause: move t1, pars2 ; Get the number that was parsed.
imuli t1, ^d1000 ; Convert to millisecs.
DISMS ; Sleep.
erjmp .+1
ret
subttl TAKE command, added as edit 78.
htake: asciz |
TAKE filespec
Execute KERMIT-20 commands from the specified file. The file may contain
contain TAKE commands. Command files may be nested up to a depth of 20.
|
; Parse the rest of the TAKE command.
.take: movx t1, cz%ncl!.fhslf ; Release non-open jfn's.
CLZFF
noise <commands from file>
move t1, [defbk,,cjfnbk] ; Insert our file parsing defaults.
blt t1, cjfnbk+defbkl
movei t1, [flddb. .cmfil]
call cfield
movem t2, pars2 ; Here's the JFN just parsed.
ret
; Execute the TAKE command.
$take: move t1, takdep ; How deep are we?
caile t1, takel ; Too deep?
jrst [ tmsg <?TAKE command file stack overflow> ; Yes, don't do it.
ret ]
move t1, takjfn ; There's room, get current TAKE file jfn.
move t2, takep ; Push it on the stack
push t2, t1 ; ...
movem t2, takep ; ...
aos takdep ; Remember what level we're on.
move t1, pars2 ; Get JFN that was parsed
movem t1, takjfn ; ...
movx t2, fld(7,of%bsz)!of%rd ; 7-bit i/o, read access.
OPENF
%jserr (,$takex)
callret setcsb ; Opened OK, go set up command state block.
; Error opening command file.
$takex: call popjfn ; Remove offending JFN from TAKE stack.
jrst [ tmsg <?TAKE file stack underflow>
ret ]
movx t1, cz%ncl!.fhslf ; Release extraneous JFNs.
CLZFF
erjmp .+1
ret
; Default command filespec fields for .CMFIL:
defbk: gj%old ; Must be existing file.
repeat 4,<0> ; Normal defaults for dev:<dir>name.
point 7, [asciz/CMD/] ; Default extension is .CMD.
0 ; Default protection,
0 ; and account.
defbkl==<.-defbk> ; Length of this GTJFN argument block.
; SETCSB - Set up Command State Block to parse from JFN in t1.
;
setcsb: skipg t1 ; Make sure there's a real JFN.
movei t1, .priin ; If not, revert.
hrlm t1, sbk+.cmioj ; Put the input JFN into the CSB.
movei t2, .priou ; Assume JFN is primary input.
caie t1, .priin ; Is it?
movx t2, .nulio ; No, it's a file, so nullify COMND output.
hrrm t2, sbk+.cmioj ; Put output JFN in CSB.
ret
; POPJFN
; Routine to pop a command file JFN off the JFN stack.
;
; Enter with current command file jfn in TAKJFN.
;
; Returns:
; +1 if stack empty,
; +2 otherwise, with popped jfn in TAKJFN.
;
popjfn: skipg takdep ; Back at top level?
ret ; Yes, return silently.
; Close current command file.
hrrz t1, takjfn ; No, close the current file
CLOSF ; ...
%jserr (,.+1) ; Just print message on error.
; Return to previous one.
move t2, takep ; Get the TAKE stack pointer
pop t2, t1 ; and the previous TAKE file JFN,
movem t2, takep ; restore them,
movem t1, takjfn ; ...
call setcsb ; and also restore the command state block.
sos takdep ; Decrement the depth indicator
retskp ; Return successfully.
;[79] INIFIL -- Process initialization file.
;
;[85] Returns +1 if there was no init file, +2 if there was.
;
inifil: move t2, jobtab+.jiuno
move t1, [point 7, dirbuf, 27] ; Put string here.
DIRST
erjmp r
movei t3, 76 ; Right angle bracket.
idpb t3, t1
move t2, [point 7, [asciz/KERMIT.INI/]] ; File name.
inif2: ildb t3, t2 ; Copy file name.
idpb t3, t1
jumpn t3, inif2
inif3: movx t1, gj%old+gj%sht ; Get JFN on it.
hrroi t2, dirbuf
GTJFN
erjmp r ; If we can't, return silently.
hrrzm t1, pars2 ; Got one, pretend we parsed it.
setom iniflg ;[83] Flag that we're doing init file.
call $take ; Go TAKE the file.
retskp ;[85]
subttl LOCAL and REMOTE commands.
;[56] LOCAL and REMOTE commands added as edit 56
.local: setom lcflg ; -1 = local
movei t1, [flddb. .cmkey,,loctab] ; LOCAL what?
jrst .remo2 ; Go parse the rest.
loctab: %table
%key <cwd>, [xwd .ycwd,$ycwd]
%key <delete>, [xwd .ydele,$ydele]
%key <directory>, [xwd .ydire,$ydire]
%key <run>, [xwd .yrun,$yrun]
%key <space>, [xwd .ydisk,$ydisk]
%key <type>, [xwd .ytype,$ytype]
%tbend
.remot: setzm lcflg ; 0 = remote
movei t1, [flddb. .cmkey,,remtab] ; REMOTE what?
.remo2: call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the command routine addresses.
movem t2, pars2 ; Save into pars2.
hlrz t1, (t2) ; Get the next level routine.
call (t1) ; Call it.
ret
remtab: %table
%key <cwd>, [xwd .xcwd,$xcwd]
%key <delete>, [xwd .rmfil,$xdele]
%key <directory>, [xwd .rmfil,$xdire]
%key <error>, [xwd .xerr,$xerr], cm%inv
%key <help>, [xwd .xhelp,$xhelp] ;[120]
%key <host>, [xwd .xhost,$xhost] ;[105]
;;;* %key <run>, [xwd .???, $???]
%key <space>, [xwd .xdisk,$xdisk]
%key <type>, [xwd .rmfil,$xtype]
%tbend
; LOCAL command help text.
hlocal: asciz |
LOCAL option
Execute a command locally. Options include:
CWD Change Working Directory (connect to directory).
DELETE filespec Delete a file or file group.
DIRECTORY filespec Print a directory listing.
HOST command A command to be executed by the TOPS-20 Exec.
RUN program Run the specified program.
SPACE area Disk usage query.
TYPE filesec Type a local file or file group at the terminal.
For further information, type HELP CWD, HELP DELETE, etc.
|
;[137] LOCAL CWD command parsing.
;
hcwd: asciz |
CWD means CHANGE WORKING DIRECTORY. It is the same as LOCAL CWD, i.e. it is
executed on the local system. The operation is the same as the DEC-20
CONNECT command.
|
.ycwd: setzm pasbuf ; Zero this out.
setzm pasbuf+1 ; ...
noise <to directory> ; Issue guide words.
movei t1, [
flddb. .cmdir,cm%sdh,,<directory name or logical name,
or carriage return to connect back to your login directory>,,[
flddb. .cmcfm,cm%sdh ]]
call rfield ; Parse a directory specification.
ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
cain t3, .cmcfm ; Confirmation?
jrst [ move t2, jobtab+.jilno ; Yes, then use own logged in dir no.
movem t2, pars3
ret ]
movem t2, pars3 ; No, directory number, save it.
confrm ; Get confirmation.
ret
; Execute the LOCAL CWD command.
;
;[171] Rewritten to only prompt for the password when necessary, as
; the Exec CONNECT command does, and to print the name of the directory
; connected to.
;
; First try to connect with no password. This returns immediately on error.
;
$ycwd: move t1, [ac%con!<3>] ; Ask for connect function, arg block length 3.
movei t2, pars3 ; Point to argument block.
setom pars5 ; Specify "this job".
ACCES ; Try to connect.
erjmp $ycwdx ; If error, go prompt for password.
jrst $ycwdz ; Connected OK, exit.
; Handle error by prompting for password and then trying to connect again.
$ycwdx: setzm pars4 ; Assume no password will be given.
call getpas ; Ask for password.
movem t1, pars4 ; Save pointer to (possibly null) string.
move t1, [ac%con!<3>] ; Try to connect again.
movei t2, pars3 ; If this fails, monitor won't return
ACCES ; for about 3 seconds.
%jserr (,.+1) ; On failure, give message and exit.
; Done either way, exit.
$ycwdz: setzm pasbuf ; Connected, clear this out for security.
setzm pasbuf+1
tmsg <[Connected to > ; Print what we're connected to.
seto t1, ; Get this job's connected directory number.
hrroi t2, t3
movei t3, .jidno
GETJI
erjmp r
move t2, t3 ; Convert to string.
movem t2, jobtab+.jidno ; Remember for future reference.
movei t1, .priou
DIRST
erjmp r
movei t1, "]"
PBOUT
ret
; GETPAS -- Get a password from the terminal
;
; Prompts for password, turns off echoing during typein, leaves result in
; PASBUF, with t1 pointing to it.
;
; Uses t1-t4.
;
getpas: skipn takdep ;[178] Do specially for TAKE files
jrst getpa2 ;[178] (here thru ret)
setzm pasbuf
move t1, takjfn ; Read line from the TAKE file
hrroi t2, pasbuf ; Into here
movei t3, pasbfl ; This many chars, max
movei t4, .CHLFD ; terminate on linefeed.
SIN
erjmp getpax
seto t3, ; Decrement the returned byte pointer.
adjbp t3, t2
setz t4, ; Write a zero over the terminating CR.
dpb t4, t3
idpb t4, t3 ; And linefeed.
getpax: move t1, [point 7, pasbuf] ; Return pointer to password.
ret ;[178]
getpa2: hrroi t1, [asciz/ Password: /] ; Issue first prompt.
PSOUT
movei t1, .priin ; Get TTY mode word
setz t2,
RFMOD
erjmp .+1
call [ saveac <t1,t2> ; Save TTY info.
txz t2, tt%eco ; Turn off echoing.
SFMOD
erjmp r
hrroi t1, pasbuf ; Ask for password.
move t2, [rd%crf+rd%bel+pasbfl]
hrroi t3, [asciz/ Password: /]
RDTTY
%jserr (,r)
move t4, t2 ;[169] Remember flag bits that were returned.
setz t2, ; Write a zero over the terminating linefeed.
dpb t2, t1
ret ] ; Restore TTY info.
SFMOD ; Restore TTY to normal echoing.
erjmp .+1
tmsg <
> ; Echo the crlf that wasn't echoed.
txnn t4, rd%btm ; Too long?
jrst [ tmsg <
?Password too long> ;* This doesn't help, must do something better
jrst .+1 ] ;* later on...
move t1, [point 7, pasbuf] ; Return pointer to result.
ret
;[111] LOCAL DIRECTORY
hdire: asciz |
DIRECTORY is the same as LOCAL directory. It produces a directory listing of
the specified files at your terminal.
|
; Default wildcard filespec fields for .CMFIL:
dirbk: gj%old!gj%ifg!gj%flg!.gjall ; Flag bits,,generation number.
.priin,,.priou ; COMND i/o.
repeat 2,<0> ; Normal defaults for dev:<dir> and gen.
repeat 2,<point 7, [asciz/*/]> ; *.* for name and type.
0 ; Default protection,
0 ; and account.
dirbkl==<.-dirbk> ; Length of this GTJFN argument block.
.ydire: movx t1, cz%ncl!.fhslf ; Close any nonopen JFNs.
CLZFF
noise <of files> ; Issue guide words.
move t1, [dirbk,,cjfnbk] ; Insert our file parsing defaults.
blt t1, cjfnbk+dirbkl
movei t1, [flddb. .cmfil]
call cfield
movem t2, pars3 ; Here's the JFN just parsed.
ret
; LOCAL DIRECTORY command execution.
; Set up.
$ydire: setzm ffunc ; Function is "directory".
$ydir1: move t2, pars3 ; Here's the JFN.
setzm filjfn ; Make sure no one thinks this is in use.
call dirhdr ; Do the header first.
; File-listing loop
$ydir2: call dmpbuf ; Get some directory listing.
call dirlst ; Print it.
jumpn t1, $ydir2 ; Go back for more.
ret ; Till done.
; DIRHDR
;
; Put directory listing header in string buffer.
; Initializes buffer pointers, counters, etc.
; Call with t2/ JFN of files to list.
; Returns +1 always.
;
dirhdr: movem t2, ndxjfn ; Save wildcard bits.
hrrzm t2, nxtjfn ; Initialize lookahead
setzm filcnt ; File counter
setom dirfin ; Initialize directory finished flag.
move t1, [point 7, srvbuf] ; Put the listing in the srving buffer.
skipe ffunc ; Directory listing?
jrst dirhdx ; No, skip printing the heading.
setom dirfin ; Assume some error.
move t3, [111110,,js%paf] ; dev:<dir>name.typ.gen
JFNS
erjmp r
hrroi t2, [asciz/
Name Pages Bytes(Size) Creation Date
/]
setzb t3, t4 ; Print heading.
SOUT
dirhdx: setzm dirfin ; No error, so not finished.
movem t1, srvptr ; Preserve string buffer pointer.
ret
; DIRLST
;
; Builds a directory listing in a chunk of memory starting at
; SRVBUF and ending at (or slightly after) SRVBZ, with pointer in SRVPTR.
;
; Returns +1 always, with t1/ -1 if we got some data, t1/ 0 if done.
;
; Keeps global file counter in FILCNT.
;
dirlst: setz t1,
skipe dirfin ; Finished?
ret ; Yes.
move t1, srvptr ; No, there's more to do.
hrroi t2, crlf ; Issue a line break.
setzb t3, t4
SOUT
movem t1, srvptr ; Save the buffer pointer.
call gtnfil ; Get next file.
jrst dirlsz ; If none, done.
aos filcnt ; Got one, count it.
;[133] Get detailed size info from FDB.
hrrzs t1, t1 ; Get rid of any flags.
move t2, [3,,.fbbyv] ; Get size info from FDB.
movei t3, pagcnt ; Put info in PAGCNT,BYTCNT,CRDATE
GTFDB ; which are adjacent in the data area.
erjmp dirlsz
move t2, t1 ; Put JFN in t2 for JFNS below.
;[122] The rest of this routine rewritten to provide nice columnar listing.
move t1, [ascii/ /] ; Fill the filename buffer with blanks.
movem t1, filbuf
move t1, [filbuf,,filbuf+1]
blt t1, filbfz-1
move t1, [point 7, filbuf] ; Now start filling in the fields.
move t3, [001110,,<js%tmp!js%paf>] ; First the filename.
JFNS
erjmp dirlsz
skipe ffunc ; What was the file function?
jrst dirls2 ; Not directory, so skip the rest.
;...
;...DIRLST, cont'd
; For real directory listing, include file size and creation date.
dirlsm: move t4, t2 ; Save file JFN in t4 for a while...
movei t3, 40 ; Put a blank over the null left by JFNS.
idpb t3, t1
hrrz t2, t1 ; Get address from updated pointer.
caige t2, filbuf+4 ; Name stayed within its field?
jrst [ move t1, [point 7, filbuf+4] ; Yes, advance to next field.
movx t3, <no%lfl!no%ast!fld(5,no%col)!fld(^d10,no%rdx)>
jrst dirlsa ] ; Use right-adjusted number format.
movei t2, 40 ; No, do free format.
idpb t2, t1 ; Deposit a blank, advance pointer.
movei t3, ^d10 ; No fixed-field stuff on page count.
;[133] More detailed info about size: pages, byte count, byte size.
dirlsa: hrrz t2, pagcnt ; Number of pages in file.
NOUT
erjmp dirlsz
movei t3, 40 ; A blank
idpb t3, t1
move t2, bytcnt ; Byte count, free format.
movei t3, ^d10
NOUT
erjmp dirlsz
movei t3, "(" ; Byte size, in parens.
idpb t3, t1
ldb t2, [pointr (pagcnt,fb%bsz)]
movei t3, ^d10
NOUT
erjmp dirlsz
movei t3, ")"
idpb t3, t1 ;[133](end) Closing parens.
hrrz t3, t1 ; Same deal to advance to date field.
caige t3, filbuf+11
jrst [ move t1, [point 7, filbuf+11]
jrst dirlsb ]
movei t2, 40 ; Put in a blank to separate.
idpb t2, t1
dirlsb: move t2, t4 ; File JFN again.
movei t3, js%cdr ; Get the creation date.
JFNS
erjmp dirlsz
dirls2: setz t3, ; Done with this line, make it asciz.
idpb t3, t1
;...
; DIRLST, cont'd
; Copy the result into the server sending buffer.
move t4, [point 7, filbuf] ; Source pointer
dirlsc: ildb t3, t4 ; Copy loop
jumpe t3, dirlsx
idpb t3, srvptr
jrst dirlsc
; Still expect to have file jfn in t2 when we get here.
dirlsx: skipe t1, ffunc ; What is the function?
call (t1) ; Not directory, so go do selected function.
move t1, srvptr
hrrz t2, t1 ; See if buffer full.
cail t2, srvbz
jrst [ seto t1, ; Return indicating we have data.
ret ]
jrst dirlst ; Loop
; Done, print summary.
dirlsz: move t1, srvptr ; Get the buffer pointer.
movei t2, " " ; Summary. First a space.
BOUT
move t2, filcnt ; Then the number of files.
movei t3, ^d10
NOUT
erjmp .+1
setzb t3, t4
hrroi t2, [asciz/ files
/]
sosn filcnt ; Do singular or plural right.
hrroi t2, [asciz/ file
/]
SOUT
movem t1, srvptr ; Save pointer.
seto t1, ; Say we're returning data.
setom dirfin ; Set finished flag for next time through.
ret
;[115] DMPBUF
;
; Dump the buffer.
;
; Call with SRVPTR/ current pointer (to end of string to be dumped)
; Returns +1 with t1/ new pointer. Uses t2.
;
; Dumps the buffer starting from SRVBUF thru present position,
; resets pointer SRVPTR to beginning of SRVBUF.
;
dmpbuf: move t1, srvptr ; Get current pointer.
setz t2,
idpb t2, t1 ; Make sure string is asciz.
move t1, [point 7, srvbuf] ; Point to buffer
movem t1, srvptr ; Save new pointer.
skipn srvflg ; Am I a server?
PSOUT ; If not, print it.
setzm srvbuf ; Clear it.
move t1, [srvbuf,,srvbuf+1]
blt t1, srvbzz
move t1, srvptr ; Return pointer in t1.
ret
;[113] LOCAL DELETE
;
; LOCAL DELETE
;
hdele: asciz |
DELETE filespec
DELETE is the same as LOCAL DELETE. It works like the DEC-20 DELETE command,
except that if you SET EXPUNGE ON, then all files that you delete with
KERMIT, whether with interactive DELETE commands, or via REMOTE DELETE
commands when KERMIT-20 is running as a server, will also be automatically
expunged.
|
; Default filespec fields for .CMFIL:
delbk: gj%old!gj%ifg!gj%flg!.gjall ; Flag bits,,generation number.
.priin,,.priou ; COMND i/o.
repeat 6,<0> ; No defaults, except all generations.
delbkl==<.-delbk> ; Length of this GTJFN argument block.
.ydele: movx t1, cz%ncl!.fhslf ; Close any nonopen JFNs.
CLZFF
noise <files> ; Issue guide words.
move t1, [delbk,,cjfnbk] ; Insert our file parsing defaults.
blt t1, cjfnbk+delbkl
movei t1, [flddb. .cmfil]
call cfield
movem t2, pars3 ; Here's the JFN just parsed.
ret
;[118] LOCAL DELETE command execution.
$ydele: movei t2, delfil ; Address of delete-file code.
movem t2, ffunc ; Make it the file function.
callret $ydir1 ; Go do it like a directory.
;[118] DELFIL - Routine to delete a file.
delfil: move t1, t2 ; Put the JFN in the right place.
skipe expung ;[143] Expunging automatically?
txo t1, df%exp ;[143] Yes, set the bit.
DELF ; Try to delete it.
jrst [ move t1, srvptr ; Error, record the message
hrroi t2, [asciz/: /]
setzb t3, t4
SOUT
erjmp .+1
hrloi t2,.fhslf ; This fork ,, last error.
setz t3,
ERSTR
nop
nop
sos filcnt ; "Uncount" this file, it wasn't deleted.
jrst delf2 ]
move t1, srvptr ; Confirmation message.
hrroi t2, [asciz/ [OK]/]
delf2: setzb t3, t4
SOUT
erjmp r
movem t1, srvptr ; Update the string pointer.
ret ; Done
; LOCAL SPACE
hspace: asciz |
SPACE is the same as LOCAL SPACE. It tells the number of disk pages allowed
and used in the current local directory.
|
.ydisk: noise <usage query>
confrm
ret
$ydisk: seto t1, ; local disk usage query.
GTDAL%
%jserr (,r)
dmove q1, t1
cail t1, [^d100000000]
jrst [ tmsg <
Quota: +Inf>
jrst $ydsk3 ]
$ydsk2: tmsg <
Quota: >
numout q1
$ydsk3: tmsg <, used: >
numout q2
tmsg < (pages)>
ret
; LOCAL RUN
hrun: asciz |
RUN [filespec]
RUN is the same as LOCAL RUN. It runs the specified file as a program in a
fork underneath KERMIT-20. The default file type is .EXE. When the program
terminates, you will be back at KERMIT-20 prompt level. If you want to issue
Exec commands without leaving KERMIT-20, you can RUN SYSTEM:EXEC.EXE, and
then type POP to get back to KERMIT. If you have already RUN a program once,
you can run it again without the overhead of fork creation by typing the RUN
command without an argument.
|
; JFN block for RUN command.
runbk: gj%old!gj%ifg!gj%flg ; Flag bits,,most recent generation.
.priin,,.priou ; COMND i/o.
repeat 3,<0> ; No defaults, except
-1,,[asciz/EXE/] ; file type.
repeat 2,<0> ; No defaults, except
runbkl==<.-runbk> ; Length of this GTJFN argument block.
; Parse local RUN command.
.yrun: movx t1, cz%ncl!.fhslf ; Close any nonopen JFNs.
CLZFF
noise <file> ; Issue guide word.
move t1, [runbk,,cjfnbk] ; Insert our file parsing defaults.
blt t1, cjfnbk+runbkl ; Same as for DELETE.
movei t1, [flddb. .cmfil]
skipe rufork ; Already have a fork?
movei t1, [ ; Yes, let them rerun it.
flddb. .cmfil,cm%sdh,,<name of program to run,
or carriage return to re-run the program you ran last time>,,[
flddb. .cmcfm,cm%sdh ]]
call rfield ; Parse a directory specification.
ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
cain t3, .cmcfm ; Confirmation?
jrst [ setom pars3 ; Yes, set "jfn" to -1.
ret ]
hrrzm t2, pars3 ; No, real JFN, save it.
confrm ; Get confirmation.
ret
; Execute local RUN command.
$yrun: skipg pars3 ; Re-run current fork?
jrst $yrun2 ; Yes, do do that.
skiple t1, rufork ; No, do we have a current fork to kill?
KFORK ; Yes, try to kill it.
erjmp .+1
setz t1, ; Take care of capabilities below.
setzm t2
CFORK ; Make a fork.
%jserr <Can't create run fork>,r
movem t1, rufork ; Remember the fork handle.
move t2, capas ;[169] Get our capabilities.
txz t2, sc%log ;[169] Inferior has same ones,
txo t2, sc%gtb ;[169] but with GETAB capability (for Exec),
move t3, t2 ;[169] and no logout!
EPCAP ;[169] ...
erjmp .+1 ;[169] ...
hrlzs t1 ; Move handle into left half.
hrr t1, pars3 ; JFN in right half.
setzm t2 ; Nothing special.
GET ; Get the file to run.
%jserr <Can't GET program to run>,r
move t1, pars3 ; Got the file, now can release its JFN.
RLJFN
erjmp .+1
; Can come straight here to re-run current fork.
$yrun2: skipg t1, rufork ; Get fork handle.
ermsg <No fork to run>,r ; Make sure it's ok.
setz t2, ; Primary start address.
SFRKV ; Start it up.
%jserr <Can't start run fork>,r
WFORK ; wait for the fork to halt.
%jserr <Can't wait for run fork>,r
ret
;[165] TRANSMIT
htrans: asciz |
TRANSMIT filespec [prompt]
For use in local mode only. Sends the specified text file a line at a time
to the remote system, waiting for the specified prompt for each line. Kermit
protocol is not used; the file is sent "raw". The prompt is any string, for
instance the prompt of a line editor in text insertion mode. The prompt
string may include special characters by preceding their octal ASCII values
with a backslash, e.g. \15 for carriage return. Only a single file may be
sent, no wildcards allowed in the filespec.
If a prompt string is supplied, alphabetic case will be ignored in searching
for it unless you SET INPUT CASE OBSERVE. If a prompt string is not
supplied, then linefeed will be used by default, unless you have performed
a SET HANDSHAKE command, in which case the handshake character will be used.
If you really want to send the entire file without looking for any prompts,
specify a prompt of "\0" (ASCII zero, null) (not recommended).
The file will be sent using the current settings for duplex, parity, and flow
control. There are no timeouts on input, as there are with the INPUT
command. The TRANSMIT command waits forever for each prompt to appear. You
may use the following controls during TRANSMIT:
Carriage Return - Send the next line immediately, even if the prompt hasn't
appeared.
Control-P - Resend the previous line.
Control-C - Typed two or three times will cancel the TRANSMIT command
and return you to the Kermit-20> prompt.
|
.trans: noise <file> ; Prompt for file name.
movei t1, [flddb. .cmifi]
call rfield
movem t2, pars2 ; Save the JFN
noise <using prompt> ; Prompt for prompt...
movei t1, [flddb. .cmtxt,cm%sdh,,<Remote system's line input prompt,
use \ooo (backslash followed by octal digits) to include control characters,
\\ to include a single backslash>] ; No default, supplied in action routine.
call cfield ; Get prompt string into atom buffer.
ret
; TRANSMIT command execution.
$trans: move t1, pars2 ; First make sure we can open the file.
movem t1, filjfn
movx t2, fld(7,of%bsz)!of%rd ; 7-bit read access.
OPENF
%jserr (,r)
call getss ; Get & decode prompt (search) string.
skipe strc ; Was there one?
jrst $tran2 ; Yes, use it.
setzm strbuf ; No, then supply an appropriate default.
move t2, [point 7, strbuf]
skipn t1, handsh ; Handshaking?
movei t1, .chlfd ; No, then use linefeed.
idpb t1, t2 ; Deposit what we have
$tran2: call dobits ; Condition the line.
jrst $tranx
call ccon ; Turn on ^C trap
jrst $tranx ; Where to go upon ^C.
call ttyob ; Let controlling tty output binary.
movei t1, $tran3 ; Where to go if ^M typed (send next)
movem t1, cmloc ; ...
movei t1, $tran4 ; Where to go if ^P typed (resend previous)
movem t1, cploc ; ...
call cmpon ; Enable interrupts on ^M, ^P.
tmsg <
[KERMIT-20: Transmitting > ; Tell user we're starting.
movei t1, .priou
move t2, filjfn
setz t3,
JFNS
erjmp .+1
tmsg <
If stuck, type:
Carriage Return to send next line,
^P to resend current line,
^C^C to cancel. Here goes...]
>
;...
; Get a line from the file.
$tran3: skipe cmseen ; ^M typed?
jrst [ tmsg < Sending next...]
> ; Yes, type msg
setzm cmseen ; and unset flag.
jrst .+1 ]
move t1, filjfn ; Input file pointer
move t2, [point 8, strbf2] ; Where to put the line
movei t3, ^d512 ; Maximum characters to read
movei t4, .chlfd ; but preferably terminate on linefeed.
SIN
erjmp [movei t1, .fhslf ; Get last process error.
GETER ; Test for eof.
hrrzs t2 ; Erase fork handle from left half.
caie t2, iox4 ; Was error EOF?
%ermsg (,$tranx) ; No, give message.
tmsg <
[KERMIT-20: Transmit Complete.]
> ; Yes, reassure.
jrst $tranx ]
ldb t4, t2 ; Was last char a LF?
caie t4, .chlfd
ibp t2 ; If not, don't overwrite it.
setz t4, ; Deposit a null, overwriting
dpb t4, t2 ; last char if it was a LF.
;...
; TRANSMIT, cont'd... Echo the string if necessary.
$tran4: skipe cpseen ; ^P typed?
jrst [ tmsg < - Resending...
> ; Yes, type msg
setzm cpseen ; and unset flag.
jrst .+1 ]
move t1, [point 8, strbf2] ; Point to the string.
move t2, t1 ; Here too.
skipn duplex ; Half duplex?
jrst $tran5 ; No.
PSOUT ; Yes, display it at the tty.
movei t1, .chlfd ; Also need to add linefeed.
PBOUT
; Tack on desired parity, in place.
move t2, [point 8, strbf2] ; Point to the string.
$tran5: ildb t1, t2 ; Get a byte.
jumpe t1, $tran6 ; If null, done.
call @parity ; Set parity bit.
dpb t1, t2 ; Put it back.
jrst $tran5 ; Back for more.
; Send the string
$tran6: move t1, netjfn ; ... out the communication line.
move t2, [point 8, strbf2]
setzb t3, t4
SOUT
%jserr (,$tranx)
; Now wait for prompt.
$tran7: move t4, [point 7, strbuf] ; Point to string buffer.
$tran8: ildb t3, t4 ; Get first character of search string.
jumpe t3, $tran3 ; If no more then we have the prompt.
move t1, netjfn ; Get char from line.
setz t2,
BIN
%jserr (,$tranx)
andi t2, ^o177 ; Strip any parity.
movei t1, .priou ; Echo it.
BOUT
skipn incase ; Case sensitive compare?
jrst [ cail t2, "a" ; No, fold.
caile t2, "z"
skipa
txz t2, 40
jrst .+1 ]
camn t2, t3 ; Match?
jrst $tran8 ; Yes, get next.
jrst $tran7 ; No, rewind search string, then get next.
; Done, call terminal restore routines in reverse order.
$tranx: call cmpoff ; ^M, ^P interrupts off.
call ttyou ; Restore controlling tty.
call ccoff2 ; ^C trap off.
call unbits ; Put line back to previous state.
movei t1, .priin ; Flush any junk they may have typed
CFIBF
erjmp .+1
move t1, filjfn ; Close the file.
CLOSF
%jserr (,$tranz)
skipa
$tranz: RLJFN ; Release the JFN.
erjmp .+1
setzm filjfn ; Zero the JFN holder.
ret
;[143] LOCAL TYPE
htype: asciz |
TYPE filespec
TYPE is the same as LOCAL TYPE. It types the specified file or files at your
terminal. Unlike the DEC-20 TYPE command, it will try to do input from each
file based on its byte size. Also, Control-O output suppression applies only
on a per-file basis.
|
typbk: gj%old!gj%ifg!gj%flg ; Flag bits,,most recent generation.
.priin,,.priou ; COMND i/o.
repeat 6,<0> ; No defaults, except all generations.
typbkl==<.-typbk> ; Length of this GTJFN argument block.
.ytype: movx t1, cz%ncl!.fhslf ; Close any nonopen JFNs.
CLZFF
noise <files> ; Issue guide words.
move t1, [typbk,,cjfnbk] ; Insert our file parsing defaults.
blt t1, cjfnbk+typbkl ; Same as for DELETE.
movei t1, [flddb. .cmfil]
call cfield
movem t2, pars3 ; Here's the JFN just parsed.
ret
; LOCAL TYPE command execution.
$ytype: move t1, pars3 ; Get the JFN.
setzm filjfn ; Set up for file stepping.
movem t1, ndxjfn
hrrzm t1, nxtjfn
call ccon ;[169] Allow ^C out of this.
jrst [ move t1, filjfn ;[169] Upon ^C, close the file.
CLOSF ;[169]
erjmp $ytypz ;[169]
jrst $ytypz ] ;[169] And quit
$ytyp2: call gtnfil ; Any more?
jrst $ytypz ; No, done.
push p, t1 ; Yes, save the JFN for a sec.
tmsg <
>
movei t1, .priou ; Turn off any Control-O
RFMOD
txz t2, tt%osp
SFMOD
move t2, (p) ; Say the name.
setz t3,
JFNS
erjmp .+1
tmsg <
>
pop p, t1 ; Restore the JFN.
move t2, [1,,.fbbyv] ; Get bytesize.
movei t3, t4
setz t4,
GTFDB
erjmp .+1
movx t2, of%rd+fld(7,of%bsz) ; Assume 7-bit mode.
ldb t3, [pointr (t4,fb%bsz)] ; Extract the bytesize.
cain t3, ^d8 ; 8 bit?
movx t2, of%rd+fld(^d8,of%bsz) ; Yes, 8-bit.
OPENF ; Open the file in appropriate mode.
%jserr (,$ytyp2) ; Report any errors.
call typfil ; Type the file
move t1, filjfn ; Close the file.
CLOSF
nop
jrst $ytyp2 ; Go back back for another.
$ytypz: tmsg <
>
call ccoff
ret ; No more, done.
; Routine to type a file at the local terminal.
;
; Type the file whose JFN is in FILJFN. Return +1 always.
;
typfil: saveac<t1,t2,t3>
setz t4, ; EOF flag.
typfi2: jumpl t4, r ; EOF yet?
move t1, filjfn ; No, get JFN of the file.
hrroi t2, strbuf ; Get a bufferfull.
movni t3, <strbln-1> ; This many characters, leave room for null.
setz t4,
SIN
erjmp [ setom t4
jrst .+1 ]
movei t1, .priou ; Type what we got.
hrroi t2, strbuf
addi t3, <strbln-1>
movns t3 ; Exactly this many.
SOUT
jrst typfi2 ; Go back for more.
; REMOTE command help text.
hremot: asciz |
REMOTE option
Ask the KERMIT server on the other end of the connection to execute a command
on its own system. This command won't work unless you are running in local
mode (you have SET LINE n) and the KERMIT on the other end is running as a
server.
Options include:
CWD Change Working Directory (connect).
DELETE filespec Delete a file or file group.
DIRECTORY filespec Send a directory listing.
HOST command To be executed by remote system's command processor.
SPACE Disk usage query.
TYPE filesec Type a file or file group at the terminal.
|
$remot: ; REMOTE and LOCAL command dispatcher...
skipe takdep ;[177] OK from TAKE file
jrst $local ;[177]
skipn local
jrst [ tmsg <?Must SET LINE before issuing a REMOTE command>
ret ]
$local: move t2, pars2 ; Get back data value.
hrrz t1, (t2) ; Get evaluation routine.
call (t1) ; Call it.
ret
; REMOTE CWD Parsing
.xcwd: setzm pasbuf ; Zero this out.
setzm pasbuf+1 ; ...
noise <to directory> ; Issue guide words.
movei t1, [
flddb. .cmtxt,cm%sdh,,<directory or area on server file system,
or carriage return for default area>]
call cfield ; Parse a string.
setzm pars3 ; Assume they didn't give an area.
move t2, [point 7, atmbuf] ; Did they give one?
ildb t1, t2
jumpe t1, r ; No, done.
call getpas ; They did, ask for password.
movem t1, pars3 ; Save pointer to it.
ret ; Done.
;[106] REMOTE CWD Execution
$xcwd:
$xcwd2: setzm strbuf ; Zero out old stuff
setzm strbuf+1
move t1, [point 7, atmbuf] ; Copy directory name from here
move t2, [point 7, strbuf] ; to here.
movei t4, "C" ; CWD generic command.
idpb t4, t2
ibp t2 ; Leave room for length.
setz t3, ; Counter.
$xcwd3: ildb t4, t1 ; Copy the directory string.
jumpe t4, $xcwd4
idpb t4, t2
aoja t3, $xcwd3
; Note that lengths here apply to UNPREFIXED values. If a length turns out to
; be the same as a prefix character, it will be quoted itself.
$xcwd4: move t4, [point 7, strbuf, 13] ; Deposit count at head of field.
addi t3, 40 ; Make it printable.
dpb t3, t4
skipn pars3 ; Got a password too?
jrst $xcwdz ; No.
$xcwd5: movem t2, strptr ; Yes. Save current pointer.
ibp t2 ; Save a place for length of this field.
setz t3, ; Reset counter for new field.
move t1, pars3
$xcwd6: ildb t4, t1 ; Get a character.
jumpe t4, $xcwd7 ; If zero, done.
idpb t4, t2 ; Deposit it.
aoja t3, $xcwd6 ; Count it & loop.
$xcwd7: idpb t4, t2 ; Make it asciz.
addi t3, 40 ; Make count printable.
idpb t3, strptr ; Deposit it at head of field.
$xcwdz: move t1, [point 7, strbuf] ; Point to it.
movei t2, "G" ; Packet type is H.
jrst dosrv ; Go send it and handle the reply.
; REMOTE DELETE, DIRECTORY, TYPE parsing -- Parse a remote filespec.
.rmfil: noise <remote files> ; Parse the rest of the command.
movei t1, [flddb. .cmtxt,cm%sdh,,<remote file specification>]
call cfield
ret
; REMOTE DELETE (Erase) execution
$xdele: movei t4, "E" ; Generic command is E.
jrst srvfil
; REMOTE DIRECTORY execution
$xdire: movei t4, "D" ; Generic command is D.
jrst srvfil
; REMOTE TYPE command execution.
$xtype: movei t4, "T" ; Generic command is T.
jrst srvfil
; SRVFIL
;
; Common code to construct a generic one-field command.
; Generic command is single character in t4. Argument is in ATMBUF.
; Puts a 1-character length field at the beginning.
;
srvfil: call sinfo ;[128] Exchange parameters with I packet.
ret ;[133] Failed, give up.
setzm strbuf ; Zero out old stuff
setzm strbuf+1
move t1, [point 7, atmbuf] ; Copy directory name from here
move t2, [point 7, strbuf] ; to here.
idpb t4, t2 ; Deposit generic command.
ibp t2 ; Leave a space
setz t3, ; Initialize counter
srvfi2: ildb t4, t1 ; Get next one.
idpb t4, t2 ; Deposit this one.
skipe t4 ; If null, done.
aoja t3, srvfi2 ; Count it & loop.
;* jumpe t3, [ ; Make sure there was at least one character.
;* tmsg <?No file specified>
;* ret ]
srvfi3: move t1, t3 ; Length
addi t1, 40 ; CHAR of that.
move t2, [point 7, strbuf, 13] ; Deposit count at head of field.
dpb t1, t2
move t1, [point 7, strbuf] ; Point to generic command.
movei t2, "G" ; Packet type is G.
jrst dosrv ; Go do it.
; REMOTE SPACE parsing
.xdisk: noise <usage query>
confrm
ret
; REMOTE SPACE execution
$xdisk: move t1, [point 7, [asciz/U/]] ; U command for data field.
movei t2, "G" ; Packet type is G.
jrst dosrv
; REMOTE HELP parsing
.xhelp: noise <from KERMIT server>
confrm
ret
; REMOTE HELP execution
$xhelp: call sinfo ; Exchange parameters.
ret ;[133] Failed, give up.
move t1, [point 7, [asciz/H/]] ; H command for data field.
movei t2, "G" ; Packet type is G.
jrst dosrv
;[105] REMOTE HOST command.
.xhost: noise <command> ; Parse the rest of the REMOTE HOST command.
movei t1, [
flddb. .cmtxt,cm%sdh,,<command for server's host command processor>]
call cfield
ret
$xhost: skipe takdep ;[176] Allow commands to servers from TAKE file
jrst $xhos2
skipe local ; This only works if local Kermit.
jrst $xhos2
ermsg <Can't use REMOTE commands without prior SET LINE>,r
$xhos2: move t1, [point 7, atmbuf] ; And move them from here
move t2, [point 7, strbuf] ; to here.
$xhos3: ildb t4, t1 ; Copy the string.
jumpe t4, $xhos4
idpb t4, t2
jrst $xhos3
$xhos4: move t3, seolch ; Terminate it with the host's eol character.
idpb t3, t2
idpb t4, t2 ; And a null.
call ccon ;[169] Enable ^C during this bit.
jrst ccoff ;[169] Where to go if ^C happens.
call sinfo ; Exchange params.
jrst ccoff ;[169] Failed, give up, turn off ^C trap.
call ccoff ;[169]
move t1, [point 7, strbuf] ; Point to command.
movei t2, "C" ; Packet type is C.
jrst dosrv ; Go send it and handle the reply.
; REMOTE ERROR -- a secret command to send a null error packet.
.xerr: confrm
ret
$xerr: movei t1, "E" ; Send an error packet.
move t2, pktnum
setzb t3, t4
call spack
nop
ret
; DOSRV
;
; Call this exactly like SRVCMD.
;
; Send a command to a server and dispatch appropriately depending on the reply.
;
dosrv: setzm gotx ; Clear flags: "got X packet",
setzm gots ; "got S packet".
call srvcmd ; Send a generic command.
ret ; Didn't get good response.
cain t1, "Y" ; Was it an ACK?
ret ; Yes, so we're done.
; Come here if we're about to receive a multipacket reply.
caie t1, "X" ; Text header?
jrst dosrv3 ; No
setom gotx ; Yup, flag that we already got it.
movei state, "F" ; State state to file receive.
skipn t3 ;[173](begin) Any contents?
jrst $recvb ; No.
push p, t1 ; Yes, print them.
hrroi t1, crlf
PSOUT
move t1, pktacs+3
PSOUT
erjmp $recvb
hrroi t1, crlf
PSOUT
dosrv2: pop p, t1 ;[173](end)
jrst $recvb ; Go receive whatever is coming.
dosrv3: cain t1, "S" ; Or Send-Init?
jrst [ setom gots ; Yes, flag that we already got it.
movei state, "R" ; Set state to receive init.
jrst $recvb ] ; Go receive what's coming.
ermsg <Unexpected packet type returned by SRVCMD>,r
; SRVCMD
;
; Routine to send a command to a server.
; Call with:
; t1/ Byte pointer to string.
; First character is Generic Command, subsequent chars are arguments.
; t2/ Packet type, e.g. "G" for Generic, "C" for Host Command.
;
; Returns:
; +1 if reply was not received successfully.
; +2 If we got a good response, with
; t1/ packet type of response, "Y", "X", or "S".
; PKTACS/ Block of 4 words containing the data returned by RPACK.
;
; If packet was ACK containing data, this routine prints it.
;
srvcmd: skipe takdep ;[176] Allow commands to servers from TAKE file
jrst srvxx
srvxx: saveac <q1,q2> ; Preserve these work registers.
dmove q1, t1 ; Copy arguments into them.
skipn local ;[177] Local Kermit?
call inilin ;[177] No, set TTY: up for packets.
setzm numtry ; Reset retry counter.
setzm nnak ; Init some statistics counters
setzm ntimou ; ...
setom bctone ; Force 1-char checksum.
move t1, netjfn ; Clear out any stacked-up NAKs
CFIBF% ;
%jserr (,.+1) ; Give warning in case there's a problem.
call ccon ; Let them ^C out gracefully
jrst srvcmx ; and go here if they do.
call setlog ; Set up any debugging log.
nop
; Put the command into the data field of the packet, using the normal
; packet-filling technique, prefixing, etc.
setzm data ; Zero the buffer.
srvcma: movei t1, gtsch ; Indicate routine to be used for getting
movem t1, source ; characters.
movem q1, strptr ; And where it should get them from.
setom next ; Set initial condition.
move t1, maxdat ; Get a buffer full of data.
call getbuf ; ...
jumpn t1, srvcmx ; Clean up if this fails.
setzm source ; Got it, so put GETCH back to normal.
movem t1, gclen ; Save length.
jumpn t1, srvcm2 ; Proceed if we got any.
ermsg <No data for generic command>, srvcmx ; Do this otherwise.
;...
;...SRVCMD, cont'd
; Top of try-again loop.
srvcm2: move q1, numtry ; Too many tries?
caml q1, maxtry
ermsg <Can't send generic command, max tries exceeded>,srvcmx
aos numtry ; Not too many, count this try.
move t1, q2 ; Packet type.
setz t2, ; Make the packet number zero.
move t3, gclen ; Length of data.
move t4, [point 8, data] ; Point to data block.
call spack ; Send it off.
jrst @[exp srvcm2, srvcmx](t1) ; Handle nonfatal & fatal failures.
setzm gotx ; Assume it'll be an ACK.
call rpack ; Look for response.
ermsg <RPACK failed>,srvcm2
caie t1, "X" ; X or Y?
cain t1, "Y"
jrst srvcmz ; Good.
caie t1, "S" ; S or I?
cain t1, "I"
jrst srvcmz ; That's ok too.
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.
jrst srvcmx ] ;[70]
caie t1, "N" ; NAK?
cain t1, "T" ; Or Timeout?
jrst srvcm2 ; One of those, go try again.
ermsg <Invalid response from server>
; Exit point for any kind of error, failure, or interruption
srvcmx: call ccoff ; Turn off ^C trap.
call caxzof ; Turn these interrupts off too.
skiple filjfn ;[135] Any file left open?
jrst [ hrrz t1, filjfn ; Apparently, try to close it.
setzm filjfn
CLOSF
erjmp .+1
jrst .+1 ] ;[135](end)
skipn local ;[177] Put controlling TTY back to normal
call rrsl2 ;[177] ... (entry point to reslin)
setzm source ; Put things back to normal.
seto t1, ; Indicate no good response was received.
ret ; Return +1.
;...
;...SRVCMD, cont'd
; Exit here when response received successfully.
srvcmz: dmovem t1, pktacs ;[112] Save the ACs returned in RPACK
dmovem t3, pktacs+2 ;[112] ...
movem t2, pktnum ; Synchronize packet numbers.
cain t1, "Y" ;[121] Was the reply an ACK?
jrst [ skipg t2, t3 ;[144] Yes, any characters?
jrst .+1 ;[144] No.
movei t1, puttch ;[144] Routine to display decoded characters.
movem t1, dest ;[144] ...
move t1, t4 ;[144] Pointer to data buffer.
call putbuf ;[144] Go decode it.
nop ;[144]
setzm dest ;[144]
jrst .+1 ]
move t1, pktacs ;[112] Get packet type back.
call ccoff ; Turn off ^C trap.
skipn local ;[177] Put controlling TTY back to normal
call rrsl2 ;[177] ... (entry point to reslin)
retskp ; Done.
;[58] SINFO added as part of edit 58.
;
; Call this routine before sending any server command which has a nontrivial
; response. For instance, it should be called before requesting a remote
; directory listing, but need not be called before sending a CWD command,
; which normally responds with a simple ACK.
;
; Action: Sends an info packet with our own parameters, waits for ACK with
; other side's. Uses packet number 0, does not increment the packet number.
; If other side doesn't know about I packets, this routine returns as if a
; an ACK was received containing all default values.
;
; Returns:
; +1 on failure, maximum tries exceeded.
; +2 on "success" getting a reply, even if it was an error packet,
; with other sides parameters set.
;
sinfo: saveac<t3,t4> ;[128] Save these.
setzm numtry ; Give it a try,
setzm pktnum ; starting out with a clean slate.
setom bctone ;[98] Use 1-char checksum.
move t1, netjfn ; Clear out any piled up NAKs.
CFIBF%
%jserr (,.+1)
call setlog ; Set up any debugging log.
nop
movei state, "S" ;[133] This will be a little state switcher.
sinfo2: movei t1, "I" ;[100][133] Packet type.
setom iflg ;[100] Say we're doing I, not S.
call sinit ;[100] Let SINIT send it & get reply.
cain t1, "E" ; Other side doesn't know I packet?
jrst [ setzb t3, t4 ;[133] Then set defaults this way.
call spar ;[133]
jrst sinfoz ] ;[133] And return successfully.
;[133] Keep going if it doesn't get thru the first time.
cain state, "F" ; Switched into F state?
jrst sinfoz ; Yes, so I was ACK'd, done.
cain state, "S" ; Still in S state?
jrst sinfo2 ; So go round again.
sinfox: setzm iflg ; Must have exceeded retry limit.
ret ; Fail.
sinfoz: setzm iflg ;[100] Done with sending I packet.
retskp
subttl SET command
; SET command help text.
hset: asciz |
SET parameter [option] [value]
Establish or modify various parameters for file transfer or terminal
connection. You can examine their values with the SHOW command. The
following parameters may be SET:
BLOCK-CHECK error detection method
BREAK number of nulls at 50 baud for BREAK simulation
DEBUGGING mode or log file
DELAY how long to wait before starting to send
DUPLEX for terminal connection, full (remote echo) or half (local echo)
ESCAPE character for terminal connection
FILE for setting file parameters like name conversion and byte size
FLOW-CONTROL for enabling and disabling XON/XOFF flow control
HANDSHAKE for turning around half duplex communication line
INCOMPLETE what to do with an incomplete file
INPUT desired behavior for INPUT command
ITS-BINARY special format for 8-bit binary files
LINE TTY line to use for terminal connection or file transfer
PARITY character parity to use
PROMPT for changing the KERMIT-20 program prompt
RECEIVE various parameters for receiving files
RETRY how many times to retry a packet before giving up
SEND various parameters for sending files
SPEED set speed (baud rate) of currently selected line
TVT-BINARY binary mode negotiation for Internet virtual terminals
For further information, type "help set" followed by one of these keywords.
Also, type "help define" to see how to define "macros" for SET commands.
|
;[77] Parse SET command. (This routine rewritten for edit 77.)
sfdb1: flddb. .cmkey,,mactab,<SET macro,>,,sfdb2
sfdb2: flddb. .cmkey,,settab
.set: movei t1, sfdb2 ; Normal SET command table.
hlrz t2, mactab ; Anything in macro table?
skipe t2 ; If so, include them too.
skipe definf ; Unless we're defining a macro.
skipa ; Don't allow recursive definitions!
movei t1, sfdb1 ; Macro table is searched first.
call rfield ; Parse a keyword.
;...
;...SET, cont'd
.set2: setzm macrof ; Assume regular SET keyword was parsed.
hrrzs t3 ; See which function descriptor block was used.
cain t3, sfdb1 ; The macro table?
jrst [ hrrz t1, (t2) ; Yes, get the data.
hrli t1, (point 7,) ; This will be a pointer to the macro text.
movem t1, pars2 ; Save it.
confrm ; Get confirmation.
setom macrof ; Set the macro flag.
ret ] ; No more to do.
hrrz t2, (t2) ; Get the command routine addresses.
movem t2, pars2 ; Save into pars2.
hlrz t1, (t2) ; Get the next level routine.
call (t1) ; Call it.
; If doing a DEFINE, loop through SET commands until CR typed.
skipn definf ; Doing DEFINE? If so, allow comma here.
ret
movei t1, [flddb. .cmcma,cm%sdh,,<Comma for another SET parameter>,,[
flddb. .cmcfm]
]
call rfield
ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
cain t3, .cmcma ; Comma?
jrst .set ; Yes, go back & get another SET parameter.
ret ; Confirmation, done.
; SET keyword table.
settab: %table
%key <block-check>, [xwd .setbc,$setbc] ;[98]
%key <break>, [xwd .setbr,$setbr]
%key <debugging>, [xwd .setdb,$setdb]
%key <delay>, [xwd .setdl,$setdl]
%key <duplex>, [xwd .setdu,$setdu]
%key <escape>, [xwd .setes,$setes]
%key <expunge>, [xwd .setex,$setex] ;[143]
%key <file>, [xwd .setfi,$setfi]
%key <flow-control>, [xwd .setfl,$setfl] ;[143]
%key <handshake>, [xwd .setha,$setha] ;[76]
%key <incomplete>, [xwd .setab,$setab]
%key <input>, [xwd .setin,$setrs] ;[160]
%key <ITS-binary>, [xwd .setit,$setit]
%key <line>, [xwd .setln,$setln]
%key <parity>, [xwd .setpa,$setpa]
%key <prompt>, [xwd .setpr,$setpr]
%key <receive>, [xwd .setrc,$setrs]
%key <retry>, [xwd .setre,$setre]
%key <send>, [xwd .setsn,$setrs]
%key <speed>, [xwd .setxp,$setsp]
%key <TVT-Binary>, [xwd .setta,$setta] ;[129]
%tbend
; SET command, cont'd
;[98] SET BLOCK-CHECK (This command added as part of edit 98)
hsbc: asciz |
SET BLOCK-CHECK option
A block check is a quantity formed by arithmetically combining all the
characters in a packet. The sender of the packet appends the block check
to it, the receiver recomputes the block check and compares it with the
one that was received. If they don't agree, the packet is retransmitted.
The SET BLOCK-CHECK command is used to request one of three block check
techniques:
1-CHARACTER-CHECKSUM
The standard KERMIT 6-bit checksum, the most efficient of the three
options, sufficient in almost every case. This is the default.
2-CHARACTER-CHECKSUM
A 12-bit checksum. Adds transmission overhead, but catches more
errors.
3-CHARACTER-CRC
A 16-bit cyclic redundancy check. Adds even more overhead, catches
even more errors. Only use this for very noisy connections.
KERMIT-20 will request the type of block check set by this command be used
for a transfer. If the other KERMIT agrees (not all KERMITs know how to
compute the 2- and 3-character block checks), then the desired block check
type will be used. If not, the single character checksum will be used.
|
.setbc: noise <type to> ; Issue guide words
movei t1, [flddb. .cmkey,,bctab,,<1>] ; Parse keyword, default is "1".
call rfield
hrrz t2, (t2) ; Save the value we parsed.
movem t2, pars3
skipn definf ; In a DEFINE command?
confrm ; No, make them type a carriage return.
ret
bctab: %table
%key <1-character-checksum>, "1"
%key <2-character-checksum>, "2"
%key <3-character-crc>, "3"
%tbend
; SET BLOCK-CHECK command execution.
$setbc: move t1, pars3 ; Get what was parsed.
movem t1, bctr ; Save it as "block check type requested".
ret
; SET command, cont'd
; SET INCOMPLETE
hsabf: asciz |
SET INCOMPLETE options
Specify what to do when a file transfer fails before it is completed.
The options are DISCARD (the default) and KEEP. If you choose KEEP, then if
a transfer fails to complete successfully, you will be able to keep the
incomplete part that was received.
|
.setab: noise <file disposition> ;[42] SET INCOMPLETE (file disposition)
movei t1, [flddb. .cmkey,,[<2,,2>
<[asciz/discard/],,0>
<[asciz/keep/],,1>
],,<discard>]
call rfield ; Parse & confirm.
hrrz t2, (t2)
movem t2, pars3
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
; SET command, cont'd
; SET BREAK
hsbrea: asciz |
SET BREAK n
Specify the number of nulls to be sent at 50 baud to simulate a BREAK
signal when connected to a remote host via SET LINE and CONNECT.
|
.setbr: noise (nulls)
movei t1, [
flddb. .cmnum,,^d10,<Number of nulls at 50 baud to simulate BREAK,>]
call rfield
skipge t2
jrst [ tmsg <?Number must be positive>
jrst cmder1 ]
caile t2, maxnul
jrst [ tmsg <?Too many nulls, maximum is >
numout [maxnul]
jrst cmder1 ]
movem t2, pars3
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
$setbr: move t2, pars3 ; Execute SET BREAK.
movem t2, brk
ret
; SET DEBUG
hsdeb: asciz |
SET DEBUG options
Show packet traffic explicitly on your terminal (if local) or in a file.
Options are:
STATES Show Kermit state transitions and packet numbers (brief).
PACKETS Display each incoming and outgoing packet (lengthy).
OFF Don't display debugging information (this is the default). If
debugging was in effect, turn it off and close any log file.
To record debugging information in a file, use LOG DEBUGGING.
|
.setdb: noise <option> ; SET DEBUGGING
movei t1, [flddb. .cmkey,,dbgtab,,states]
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the value for the keyword.
movem t2, pars3 ; Save into pars3.
.stdbx: skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
dbgtab: %table
%key <off>, 0
%key <packets>, 2 ;[22]
%key <states>, 1 ;[22]
%tbend
dbstab: %table ;[41] (this table)
%key <7>,7
%key <8>,8
%tbend
;...SET command, cont'd
; SET FILE
; Help text...
hsfil: asciz |
SET FILE paramater keyword
Establish file-related parameters:
BYTESIZE keyword or number
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 bytesize (as shown by
the Exec VDIR command) is 8, otherwise use SEVEN. The default is AUTO.
SEVEN or AUTO can be used to send and receive DEC-20 binary files, such as
.EXE or .REL files. EIGHT is only for "foreign" 8-bit binary files.
NAMING UNTRANSLATED or NORMAL-FORM
If NORMAL-FORM the names of incoming or outgoing files will be converted
to contain only uppercase letters, digits, and periods. If UNTRANSLATED,
filenames will be left alone. If conversion is being done, all control
and punctuation characters (other than ".") in filenames will be
translated to "X", and lower case letters will be capitalized.
UNTRANSLATED is the default.
|
; Parse rest of SET FILE
sfitab: %table ; Table of file parameters to SET.
%key <bytesize>,0
%key <naming>,1
%tbend
; The following ruse using chained FDB's allows the old-style command to
; be parsed most of the time, like "SET FILE 8".
sfifd1: flddb. .cmkey,,sfitab,,<bytesize>,sfifd2
sfifd2: flddb. .cmkey,,sfbtab,<DEC-20 file byte size,>,<auto>
.setfi: noise <parameter> ;[84] SET FILE
movei t1, sfifd1
call rfield
hrrz t2, (t2)
hrrzs t3 ;[84] Which function descriptor block was used?
setzm pars3 ;[84] Assume they specified a bytesize.
cain t3, sfifd2 ;[84] They specified a bytesize?
jrst .setfz ;[84] Yes, so don't parse it again.
movem t2, pars3
noise <to>
movei t1, [flddb. .cmkey,,sfbtab,<DEC-20 file byte size,>,<auto>]
skipe pars3 ;[84]
movei t1, [flddb. .cmkey,,fntab,,<untranslated>] ;[84]
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the value for the keyword (0 or 1).
.setfz: movem t2, pars4 ;[84] Save here.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
; file name translation keywords.
fntab: 2,,2
[asciz/normal-form/],,1
[asciz/untranslated/],,0
; file bytesize keyword table.
sfbtab: %table
%key <7-bit>, 0
%key <8-bit>, 1
%key <auto>, 2
%key <eight-bit>, 1
%key <seven-bit>, 0
%tbend
;...SET command, cont'd
; SET PARITY
hspar: asciz |
SET PARITY keyword
If parity is being used 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.
If ODD, EVEN, MARK, or SPACE are selected, binary files will be transferred
using 8th-bit-prefixing if the other side agrees, otherwise they cannot be
be successfully transferred. If NONE is specified, 8th-bit-prefixing will
not be requested.
SET PARITY should be used for communicating with hosts that require
character parity, or through devices or networks (like TELENET) that add
parity to characters that pass through them. Both KERMITs should be set to
the same parity.
The specified parity is used both for terminal connection (CONNECT) and
file transfer (SEND, RECEIVE, GET).
|
.setpa: noise <to> ; SET PARITY
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.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
partab: %table
%key <even>, even
%key <mark>, mark
%key <none>, none
%key <odd>, odd
%key <space>, space
%tbend
;...SET command, cont'd
;[137] SET PROMPT
hsprom: asciz |
SET PROMPT string
Set the KERMIT-20 prompt to whatever character string you like.
This is especially useful when connected to another DEC-20 through a
dialer, using another KERMIT-20 on the remote system. A unique prompt
for each KERMIT-20 will clear up any confusion about which one you're
talking to.
|
.setpr: noise <to> ; Parse the rest of the SET PROMPT command.
movei t1, [
flddb. .cmtxt,,,<KERMIT-20 command prompt>,<x>] ; Phony default.
hrroi t2, [asciz/Kermit-20>/] ; Set up real default
movem t2, .cmdef(t1)
call cfield
ret
; Execute the SET PROMPT command.
$setpr: move t1, [point 7, atmbuf] ; And move the characters from here
move t2, [point 7, prompx] ; to here.
$stpra: ildb t4, t1 ; Copy the string.
jumpe t4, $stprb
idpb t4, t2
jrst $stpra
$stprb: idpb t4, t2 ; And a null.
ret
; SET command, cont'd
; SET RETRY
hsrty: asciz |
SET RETRY option decimal-number
Set the maximum number of retries allowed for:
INITIAL CONNECTION -- How many times to try connecting before giving up.
PACKETS -- How many times to try sending a particular packet.
|
.setre: noise <maximum for> ;[37] SET RETRY
movei t1, [flddb. .cmkey,,[<2,,2>
<[asciz/initial-connection/],,0>
<[asciz/packets/],,1>
],,<packets>]
call rfield
hrrz t2, (t2) ; Get the keyword index
movem t2, pars3
noise <to> ; Prompt for the value
movei t1, [flddb. .cmnum,,^d10,<times to retry before giving up,>,5]
skipn pars3
movei t1, [flddb. .cmnum,,^d10,<times to retry before giving up,>,16]
call rfield
movem t2, pars4
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
offon: %table ; Table for parsing ON or OFF.
%key <off>, 0
%key <on>, 1
%tbend
; SET command, cont'd
;[143] SET FLOW-CONTROL added as edit 143
hsflo: asciz |
SET FLOW-CONTROL option
For communicating with full duplex systems. The DEC-20 system is capable
of regulating the flow of characters on the line using XON/XOFF flow
control. If characters are coming into the DEC-20 too fast, the DEC-20 will
send an XOFF signal, Control-S, to tell the system on the other side to stop
sending characters. After it has finished processing the characters in its
input buffer, it will send a Control-Q to tell the other side to resume
sending. The other system does the same thing when the DEC-20 is sending
data characters. KERMIT-20 will use XON/XOFF flow control on a full-duplex
connection by default, and it will not use it on a half duplex connection.
The options of the SET FLOW-CONTROL command are XON-XOFF and NONE. If you
SET FLOW-CONTROL to anything other than NONE, HANDSHAKE is set to NONE.
|
.setfl: movei t1, [flddb. .cmkey,,flotab,,XON-XOFF] ; SET FLOW-CONTROL
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the value for the keyword (0 or 1).
movem t2, pars3 ; Save into pars3.
skipn definf ; In DEFINE?
confrm ; No, get confirmation.
ret
flotab: %table ; Flow-Control keywords
%key <none>,0
%key <XON-XOFF>,1
%tbend
;[76] SET HANDSHAKE added as edit 76.
hshan: asciz |
SET HANDSHAKE option
For communicating with half duplex systems. This lets you specify the line
turnaround character sent by the half duplex host to indicate it has ended
its transmission and is granting you permission to transmit. When a
handshake is set, KERMIT-20 will not send a packet until the half duplex
host has sent the specified character. The options are:
NONE
XOFF (^S)
XON (^Q)
BELL (^G)
CR (^M, carriage return)
LF (^J, linefeed)
ESC (Escape)
or an octal number specifying any ASCII control character.
If you SET HANDSHAKE to anything other than NONE, FLOW-CONTROL is set to NONE.
|
.setha: movei t1, [flddb. .cmkey,,hshtab,,XOFF,[
flddb. .cmnum,cm%sdh,^d8,<octal value of ASCII control character>]]
call rfield ; Parse a keyword.
ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
caie t3, .cmnum ; Number?
hrrz t2, (t2) ; No, get the keyword's associated value.
caile t2, 37 ; Control character?
cain t2, 177
skipa
jrst [ tmsg <?Must be in ASCII control range, 0-37 or 177>
jrst cmder1 ]
movem t2, pars3 ; Save into pars3.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
hshtab: %table ; Handshake keywords
%key <bell>,7
%key <CR>,15
%key <ESC>,33
%key <LF>,12
%key <none>,0
%key <XOFF>,23
%key <XON>,21
%tbend
; SET command, cont'd
;[160] SET INPUT
hsetin: asciz |
SET INPUT parameter value
Specify how the INPUT command is to behave (see INPUT).
SET INPUT DEFAULT-TIMEOUT n
n is the number of seconds for an INPUT command to time out after
not receiving the requested input, if no interval is explicitly
given in the INPUT command.
SET INPUT TIMEOUT-ACTION PROCEED or QUIT
If the INPUT command comes from a command file (see TAKE command),
then use this command to specify whether processing of the command
file should proceed or quit after a timeout occurs.
SET INPUT CASE IGNORE or OBSERVE
Specify whether alphabetic case should be ignored ("a" matches "A")
or observed ("a" does not match "A").
|
;...
; SET INPUT parsing, like SET SEND/RECEIVE -- an extra level of parsing.
.setin: movei t1, [flddb. .cmkey,,sintab] ; SET INPUT ...
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the command routine addresses.
movem t2, pars3 ; Save into pars3.
hlrz t1, (t2) ; Get the next level routine.
call (t1) ; Call it.
ret
sintab: %table
%key <case>, [xwd .sinca,incase]
%key <default-timeout>, [xwd .sindt,indeft]
%key <timeout-action>, [xwd .sinta,intima]
%tbend
.sinca: noise <for matching> ; SET INPUT CASE
movei t1, [flddb. .cmkey,,castab,,<ignore>]
jrst .sinkp ; Go below & parse rest.
castab: %table ; Case table.
%key <ignore>, 0
%key <observe>, 1
%tbend
.sindt: noise <for INPUT commands> ; SET INPUT DEFAULT-TIMEOUT
movei t1, [
flddb. .cmnum,,^d10,<seconds,
when interval not specified in INPUT command,>]
call rfield
movem t2, pars4
skipn definf ; In DEFINE?
confrm ; No, get confirmation.
ret
.sinta: noise <for command file> ; SET INPUT TIMEOUT-ACTION
movei t1, [flddb. .cmkey,,itatab,,<proceed>]
.sinkp: call rfield ; Parse keyword.
hrrz t2, (t2) ; Get the value for the keyword (0 or 1).
movem t2, pars4 ; Save into pars4.
skipn definf ; In DEFINE?
confrm ; No, get confirmation.
ret
itatab: %table ; INPUT timeout action table
%key <proceed>, 0
%key <quit>, 1
%tbend
; SET command, cont'd
;[75] SET ITS-BINARY (format) ON or OFF
hsits: asciz |
SET ITS-BINARY (format) ON or OFF
Specify whether ITS-Binary file headers are to be recognized or ignored.
ITS binary format is a way (devised at MIT) of storing foreign 8-bit binary
data on a 36-bit machine to allow automatic recognition of these files when
sending them out again, so that you don't have to depend on the file byte
size, or to issue explict SET FILE BYTESIZE commands to KERMIT.
An ITS format binary file contains the sixbit characters "DSK8" left-
adjusted in the first 36-bit word. If ITS-BINARY is ON, then KERMIT-20 will
send any file starting with this "header word" using 8-bit i/o, and will not
send the header word itself, and it will store any incoming file that begins
with that header word with 8-bit bytesize, again discarding the header word
itself. If ITS-BINARY is OFF, then the header word, if any, will be sent,
and i/o will be according to the setting of FILE BYTESIZE.
|
.setit: noise <format> ; Issue guide word.
movei t1, [flddb. .cmkey,,offon,,on] ; SET ITS-BINARY
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the value for the keyword (0 or 1).
movem t2, pars3 ; Save into pars3.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
; SET command, cont'd
; SET LINE
hslin: asciz |
SET LINE octal-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.
You can also select the line directly in the CONNECT command.
|
; Parse rest of SET LINE command.
.setln: noise <to tty> ; SET LINE
movei t1, [
flddb. .cmnum,,^d8,<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.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
.setl1: move t4, mytty ; Get the our terminal number.
movem t4, pars3 ; Make believe we parsed it.
ret
hsdel: asciz |
SET DELAY decimal-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 before packets start arriving.
The normal delay is 5 seconds.
|
.setdl: noise <to> ; SET DELAY
movei t1, [flddb. .cmnum,,^d10,<seconds before sending first packet,>]
call rfield ; Parse a number.
movem t2, pars3 ; Save the number.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
; SET command, cont'd
; SET DUPLEX
hsdup: asciz |
SET 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.
|
; Parse SET DUPLEX
.setdu: noise <to> ;[18] SET DUPLEX
movei t1, [flddb. .cmkey,,duptab,,<full>]
call rfield
hrrz t2, (t2)
movem t2, pars3
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
duptab: %table ;[18] Table of legal duplexes
%key <full>,dxfull
%key <half>,dxhalf
%tbend
;[143] SET EXPUNGE
;
hsexp: asciz |
SET EXPUNGE ON or OFF
Tell whether you want a DELETE command (either the LOCAL DELETE command
or a REMOTE DELETE command sent to a KERMIT-20 server) to expunge files as
it deletes them. On the DEC-20, a deleted file continues to take up space,
and may be "undeleted" at a later time in the same session. To expunge a
deleted file means to remove it completely and irrevocably. EXPUNGE is OFF
(i.e. no automatic expunging of deleted files) by default.
|
.setex: noise <deleted files automatically> ; SET EXPUNGE
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.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
; SET ESCAPE
hsesc: asciz |
SET ESCAPE octal-number
Tell what control character you want to use to "escape" from remote
connections. 34 (Control-Backslash ^\) by default. The number is the octal
value of the ASCII control character, 1 to 37. When you type the escape
character, you must follow it by a single-character "argument":
C Close connection
S Status report
P Push to a new Exec on the local system
Q If you have given a LOG SESSION command, temporarily Quit logging
R Resume logging to session log
B Attempt to send a simulated BREAK signal.
? List available options
or second copy of the escape character to send the escape character itself.
|
; Parse rest of SET ESCAPE command.
.setes: noise <character for connect to> ;[16] SET ESCAPE
movei t1, [
flddb. .cmnum,,^d8,<Value of ASCII control character,>,<34>]
call rfield
caile t2, 37 ; Control character?
cain t2, 177
skipa
jrst [ tmsg <?Must be in ASCII control range, 0-37 or 177>
jrst cmder1 ]
movem t2, pars3
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
; SET command, cont'd
; SET RECEIVE parameters
hsrcv: asciz |
SET RECEIVE parameter
Parameters to request or expect for incoming packets, as follows:
END-OF-LINE octal-number
Carriage return (15) by default. The DEC-20 does not actually need any
line terminator for incoming packets.
PACKET-LENGTH decimal-number
Maximum length packet for the other side to send, decimal number,
between 10 and 9000, 80 by default.
PADDING octal-number, PADCHAR octal-number
Should never be necessary; the DEC-20 needs no padding.
PAUSE floating-point-number
How many seconds to pause before acknowledging a packet.
Setting this to a nonzero value will slow down the rate at which
data packets come in to the DEC-20, which may be necessary for DEC-20's
that have "sensitive" front ends and cannot accept input at a high rate.
QUOTE octal-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.
SERVER-TIMEOUT decimal-numer
When running as a server, how often to send periodic NAKs during server
server command wait. 0 means don't send them at all. 94 seconds maximum.
START-OF-PACKET octal-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.
TIMEOUT decimal-number
How many seconds the other Kermit should wait for a packet before asking
for retransmission. If 0, then no timing out will be done. 94 seconds
maximum.
|
; Parse rest of SET RECEIVE...
.setrc: movei t1, [flddb. (.cmkey,,srtabl,,)] ; SET RECEIVE ...
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the command routine addresses.
movem t2, pars3 ; Save into pars3.
hlrz t1, (t2) ; Get the next level routine.
call (t1) ; Call it.
ret
srtabl: %table
%key <end-of-line>, [xwd .seteo,reolch]
%key <packet-length>, [xwd .setpk,rpsiz]
%key <padchar>, [xwd .setpc,rpadch]
%key <padding>, [xwd .setpd,rpadn]
%key <pause>, [xwd .srpau,rpause] ;[36]
%key <quote>, [xwd .setqu,rquote]
%key <server-timeout>, [xwd .setim,srvtim] ;[137]
%key <start-of-packet>, [xwd .setsp,rsthdr] ;[18]
%key <timeout>,[xwd .setim,rtimou]
%tbend
; SET SEND parameters
hssnd: asciz |
SET SEND parameter
Parameters for outgoing packets, as follows:
END-OF-LINE octal-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. You will only have to use this command for systems
that require a line terminator other than carriage return.
PACKET-LENGTH decimal-number
Maximum packet length to send, decimal number, between 10 and 9000, 80 by
default. Shortening the packets might allow more of them to get through
through without error on noisy communication lines.
PADDING octal-number, PADCHAR octal-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.
PAUSE floating-point-number
How many seconds to pause before sending each data packet. Setting this
to a nonzero value may allow some slow systems enough time to process
a data packet sent by the DEC-20 before the next one arrives. Normally,
no per-packet pausing is done.
QUOTE octal-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 octal-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.
TIMEOUT decimal-number
How many seconds to wait for a packet before trying again.
|
.setsn: movei t1, [flddb. (.cmkey,,sstabl,,)] ; SET SEND ...
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the command routine addresses.
movem t2, pars3 ; Save into pars3.
hlrz t1, (t2) ; Get the next level routine.
call (t1) ; Call it.
ret
sstabl: %table
%key <end-of-line>, [xwd .seteo,seolch]
%key <packet-length>, [xwd .setpk,spsiz]
%key <padchar>, [xwd .setpc,spadch]
%key <padding>, [xwd .setpd,spadn]
%key <pause>, [xwd .sspau,spause] ;[35]
%key <quote>, [xwd .setqu,squote]
%key <start-of-packet>, [xwd .setsp,ssthdr] ;[18]
%key <timeout>,[xwd .setim,stimou]
%tbend
;...SET command, cont'd
; SET PACKET-LENGTH
.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.
cail t2, ^d10 ; Is the number in the right range?
caile t2, ^d9000 ;[179] (was ^d94)
jrst [tmsg <?Illegal packet size>
jrst cmder1 ]
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
.srpau: noise <between packets to> ;[36] SET RECEIVE PAUSE
movei t1, [
flddb. .cmflt,,,<seconds to pause after receiving a packet,>,<0>]
jrst .sxpau ; Join common code.
.sspau: noise <between packets to> ;[35] SET SEND PAUSE
movei t1, [
flddb. .cmflt,,,<seconds to pause before sending a packet,>,<0>]
.sxpau: call rfield ;[36] Common code.
movem t2, pars4
noise <seconds>
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
skipge pars4 ; Is the number in the right range?
jrst [ tmsg <?Must be a positive number>
jrst cmder1 ]
ret
.setpd: noise <to> ; SET SEND/RECEIVE PADDING
movei t1, [
flddb. .cmnum,,^d10,<number of padding characters, positive>,<0>]
call rfield ; Parse the number of padding chars.
movem t2, pars4 ; Save the number.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
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
;...SET command, cont'd
.setpc: noise <to> ; SET SEND/RECEIVE PADCHAR
movei t1, [
flddb. .cmnum,,^d8,<Value of ASCII character, 0 to 37, or 177,>]
call rfield ; Parse the padding character.
movem t2, pars4 ; Save the padding char.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
move t2, pars4 ; Get the padding char we parsed.
cain t2, ^o177 ;[149] Is it a DEL?
ret ;[149] OK.
skipl t2 ; Is it in the control range, 0 to...
caile t2, ^o37 ; ...37 octal?
jrst [tmsg <?Illegal padding character> ; No, give error message
jrst cmder1 ] ; and allow command retry.
ret ; Yes, OK.
.seteo: noise <to> ; END-OF-LINE
movei t1, [
flddb. .cmnum,,^d8,<Value of ASCII control character, 0-37,>,<15>]
call rfield ; 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.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
.setsp: noise <to> ;[18] START-OF-PACKET
movei t1, [
flddb. .cmnum,cm%sdh,^d8,<Octal value of ASCII control character>,<1>]
call rfield
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
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
;...
; More SET commands...
.setqu: noise <to> ; SET SEND/RECEIVE QUOTE
movei t1, [
flddb. .cmnum,,^d8,<Value of printable ASCII character,>,<43>] ;[21]
call rfield ;[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.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
.setim: noise <to> ; SET SEND/RECEIVE TIMEOUT
movei t1, [
flddb. .cmnum,,^d10,<Number of seconds before timing out, 1 to 94,>]
call rfield ; Parse the number.
movem t2, pars4 ; Save the number.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
move t2, pars4 ; Get the number we parsed.
cail t2, 0 ;[94] Is the number in the right range?
caile t2, ^d94 ; Fix to compare correctly.
jrst [tmsg <?Illegal number of seconds>
jrst cmder1 ]
ret
subttl SET command action routines.
; SET ... command dispatcher.
$set: skipe macrof ;[77] Was a macro used?
jrst $set2 ;[77] If so, go handle that.
move t2, pars2 ; Get back data value.
hrrz t1, (t2) ; Get evaluation routine.
call (t1) ; Call it.
ret
;...
;...$SET, cont'd
;[77] SET macro was typed.
$set2: move t1, pars2 ; Pointer to macro text (SET operands)
movem t1, macxp
;* PSOUT ; echo it for debugging...
setzm mdone ; Say macro not done yet.
; Loop to copy one set command into the command buffer.
$set3: move t1, [ascii/set /] ; Fake a SET command
movem t1, cmdbuf
move t2, [point 7, cmdbuf, 27] ; Copy them to after "set "
movem t2, sbk+.cmptr
; Loop for each character.
$set4: ildb t1, macxp ; Get a character from the macro text
aos sbk+.cminc ; Account for it in the CSB
sos sbk+.cmcnt ; ...
jumpe t1, $set5 ; If null, done.
cain t1, "," ; Comma?
jrst [ movei t1, .chcrt ; Yes, substitute a carriage return.
idpb t1, t2
aos sbk+.cminc
sos sbk+.cmcnt
movei t1, .chlfd ; And a linefeed...
idpb t1, t2
aos sbk+.cminc
sos sbk+.cmcnt
setz t1, ; And a null...
idpb t1, t2
jrst $set6 ] ; Go execute this part.
idpb t1, t2 ; Not a comma, copy the character.
jrst $set4
; Get here at end of null-terminated macro body.
$set5: idpb t1, t2 ;[80] Deposit the null.
setom mdone ; Flag that we're done interpreting the macro.
$set6: move t1, sbk ; Zero the CSB flags.
hrrzm t1, sbk ; ...
;* hrroi t1, cmdbuf ; Echo the command.
;* PSOUT ; ...
call .set ; Go parse the string.
call $set ; Go execute what was parsed.
skipn mdone ; Any more?
jrst $set3 ; Yes, go do them.
setzm mdone ; No, all done.
ret
;[42] SET INCOMPLETE
$setab: move t1, pars3 ; Just save what we parsed.
movem t1, abtfil
ret
; SET DEBUGGING
$setdb: skipn t1, pars3 ;[38] See what we got.
jrst [ setz debug, ;[38] Turning debugging off.
skipn t1, logjfn ;[38] Did we have a log?
ret ;[38] No, done.
setz t2, ;[144] Yes, any bytes written?
RFPTR ;[144]
nop ;[144]
skipg t2 ;[144]
txo t1, cz%abt ;[144] None, don't bother keeping the log.
setzm logjfn ;[38] Zero this so we know...
CLOSF ;[38] Close it.
erjmp .+1 ;[144] Ignore errors, may already be closed
ret ] ;[38] by previous EXIT command.
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
; SET SEND/RECEIVE command dispatcher.
$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
; SET DELAY
$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
; SET DUPLEX
$setdu: move t1, pars3 ;[18] DUPLEX. Get what was parsed.
movem t1, duplex
ret
; SET ESCAPE
$setes: move t1, pars3 ;[16] ESCAPE. Get what we parsed.
movem t1, escape
ret
; SET EXPUNGE
$setex: move t1, pars3 ;[143] SET EXPUNGE
movem t1, expung
ret
; SET FILE
$setfi: skipn t1, pars3 ;[84] Which file parameter are we setting?
jrst $setf8 ;[84] Bytesize, go do that.
; ... FILE NAMING
$setfn: sojn t1, [ ;[84] We'll have to get a little fancier
tmsg <?Impossible parse value> ;[84] if more file parameters
ret ] ;[84] are added...
move t1, pars4 ;[84] OK, get the value.
movem t1, xfnflg ;[84] Save it.
ret ;[84] Done.
; ... FILE BYTESIZE
$setf8: move t1, pars4 ; BYTESIZE... Get the value of the flag.
cain t1, 2 ; Is it autobyte?
jrst [ setom autbyt ; If so, say so,
setzm ebtflg ; and say this not so.
ret ]
setzm autbyt ; Say no auto-byte.
movem t1, ebtflg ; Set the flag.
ret
; SET PARITY
$setpa: move t1, pars3 ;[109] What did they say?
caie t1, none ;[109] Was the parity NONE?
jrst [ setom ebqr ;[89] No, so request 8th-bit prefixing.
movei t2, dqbin ;[89] Use the default prefix.
movem t2, ebq ;[89]
tmsg <%Will request 8th-bit prefixing.
%If the other KERMIT doesn't agree,
%binary files cannot be sent correctly.
>
jrst .+2 ] ;[89]
jrst [ movei t1, "Y" ;[95] If none, just say we will do 8th-bit
movem t1, ebq ;[95] prefixing if requested.
setzm ebqr ;[95] But we won't request it ourselves.
jrst .+1 ] ;[95]
move t1, pars3
movem t1, parity
ret
; SET RETRY
$setre: move t1, pars3 ;[37] SET RETRY
move t2, pars4
movem t2, @[exp imxtry, maxtry](t1)
ret
;[143] SET FLOW-CONTROL
$setfl: skipe t1, pars3 ; Get flow control option.
setzm handsh ; If nonzero, turn off handshake.
movem t1, flow
ret
;[76] SET HANDSHAKE
$setha: skipe t1, pars3 ;[143] Get the handshake option.
setzm flow ;[143] If nonzero, turn off flow control.
movem t1, handsh ; Save it.
ret ; Done.
;[75] SET ITS-BINARY
$setit: move t1, pars3 ; Just save the value in the ITS flag.
movem t1, itsflg
ret
; SET LINE
;
;[87] Call with PARS3/ number of line to assign.
;
$setln: move t1, ttynum ; Previous line number, if any.
movem t1, oldnum ; Remember it.
move t1, pars3
movem t1, ttynum ;
move t1, asgflg ; Remember in case we already had another...
movem t1, oasflg ;
move t1, netjfn ;[80]
movem t1, oldjfn ;[80]
setzm local ; Assume we're a remote Kermit.
move t1, ttynum ;[80]
came t1, mytty ; Lines the same?
setom local ; No, so we're local.
call chktvt ;[182] Possibly detect if we're a TVT
$stln1: move t1, ttynum ;[182] Load the line in question
txo t1, .ttdes ;[182] Form device designator.
DVCHR ;
erjmp asser1 ;
hlre t1, t3 ; Who has it?
movem t1, job ; Job number of who has it, or -1 (or -2).
setzm asgflg ; Assume I don't have to assign it.
skipn local ; Own controlling TTY?
jrst [ skipe tvtflg ;[130] Yes, but is it an ARPANET TVT?
jrst $stln2 ;[130] If so, still have to OPENF in 8b mode.
movei t1, .cttrm ; No, so I don't have to assign it.
movem t1, netjfn ; Just use controlling terminal designator.
jrst $stln3 ]
move t3, myjob ; My job number.
camn t3, job ; If I had it assigned already,
jrst $stln2
move t1, ttynum ; Form device designator again,
movei t1, .ttdes(t1) ; and...
ASND ; give it a try.
erjmp asser1 ; Uh oh, can't assign it.
setom asgflg ; Assigned it. Set this flag to remember.
;...
; $SETLN (SET LINE), cont'd
$stln2: move t1, [170700,,filbuf] ; Pointer to file name buffer.
move t2, [ascii/TTY/] ; Build TTYn: filename.
movem t2, filbuf ; Into filbuf.
move t2, ttynum ; TTY number.
movei t3, ^d8 ; Octal.
NOUT%
%jserr <Can't NOUT TTY number>,asserz
movei t2, ":" ; Add a colon.
idpb t2, t1
setz t2,
idpb t2, t1
movx t1, gj%sht!gj%acc ;[183] Now try to get a JFN on the TTY.
hrroi t2, filbuf
GTJFN%
%jserr <Can't get JFN on TTY>,asserz ; Error, probably no such device.
hrrzm t1, netjfn ; Got JFN OK, save it as the "network" JFN.
movx t2, fld(8,of%bsz)!of%wr!of%rd ; 8-bit bytes, read & write access.
OPENF% ; Open the device.
erjmp asserr ; Can't, print informative error message.
setzm setspd ;[161] Flag that speed has not been SET.
$stln3: move t1, oldjfn ;[127] Get JFN of line previously used.
skiple t1 ;[127] No previous one?
cain t1, .cttrm ;[127] Previous one was controlling terminal?
jrst $stlnz ; One of those, nothing to do.
CLOSF% ; Close it.
%jserr (,.+1) ;
setzm oldjfn ; Remember that we did.
skipe oasflg ; Had I also assigned the old one?
jrst [ skipg t1, oldnum ; Yes, did I remember the number?
jrst .+1 ; No...
movei t1, .ttdes(t1) ; Yes, then deassign the old one.
RELD%
%jserr (,.+1)
setzm oldnum ; Set these to zero...
setzm oasflg
jrst .+1 ]
;...
;...SET LINE, cont'd
;[182] Move the TVT detection code to earlier so we side-effect the
;[182] tvtflg variable before we check to see if we should open in 8
;[182] bit mode
;[130] See if line is remote, and if so, if carrier is up.
$stlnz: move t1, netjfn ; Get the line's JFN back.
call chklin ;[134] Check on remote & carrier status.
;* Note, commented out because it seems to take some time for carrier to come
;* up when dialing out. Better not to scare users.
;*
;* hrroi t1, [asciz/
;*%Warning - No carrier on remote line/]
;* skipe mdmlin
;* skipe carier ; Give warning if none.
;* skipa
;* PSOUT
$stlzz: movei t2, .chcrt ; Send a CR down the line to get things going.
BOUT
erjmp r
ret ; Done.
;...
; $SETLN (SET LINE), cont'd
;[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?
%jserr <Can't assign or open TTY>,asserz ; No, something else.
; In use by someone else. Say who.
asser1: tmsg <
?Line >
numout ttynum, 8 ; Line so-&-so...
tmsg < in use by job > ; ...in use by job
numout job ; ...job number
tmsg <, user > ; Tell who the user is.
move t1, job
hrroi t2, t3
movei t3, .jiuno
GETJI
erjmp asserx
movei t1, .priou
move t2, t3 ; User name of who has the line.
DIRST
erjmp asserx
tmsg <
>
jrst asserz
asserx: tmsg <???
>
asserz: move t2, oldnum ; Restore old line.
movem t2, ttynum
move t2, oldjfn ; And line JFN.
movem t2, netjfn
move t2, oasflg ; And the I-assigned-it flag.
movem t2, asgflg
ret
; Check the line whose JFN is in t1.
; Set flags MDMLIN if line is remote, CARIER if line has carrier up.
; SPEED is set to a nonnegative number if known, -1 otherwise.
;
; Returns +1 always, with t1 unchanged, t2-t4 modified.
;
chklin: saveac<t1> ; Save the argument
movei t2, .morsp ; "Read Speed"
MTOPR ; Flag bits are returned in LH(T2)
%jserr (,.+1) ; ...
hrres t3 ; No split speed.
setzm carier ; Assume no carrier.
setzm mdmlin ; Assume line not modem-controlled.
txnn t2, mo%rmt ; Is it?
jrst [ movem t3, speed ; No, it's local, so speed is valid.
ret ] ; Don't have to worry about carrier.
setom mdmlin ; Yes, flag for SHOW LINE, etc.
skipe setspd ;[161] Was speed explicitly SET for this line?
jrst chkli2 ;[161] Yes, so skip next part.
skipe monv ; TOPS-10 V6 or later?
jrst [ movem t3, speed ; Yes, so we can believe the speed.
jrst chkli2 ] ; Go check carrier.
came t3, speed ; Pre-V6. Does this agree with what was set?
seto t3, ; No, so we don't really know the speed.
movem t3, speed ; Save the speed or else -1 for don't know.
; Entry point just to see if we have carrier (assume MDMLIN already -1).
chkli2: setzb t2, carier ; See if we have carrier.
RFMOD ; Get mode word.
erjmp .+1
txne t2, tt%car ; Carrier?
setom carier ; Yes.
ret
;
hspeed: asciz |
SET SPEED n
Set the speed of the currently selected line -- the controlling terminal
by default, or else the line specified in the most recent SET LINE
command -- to the baud rate indicated by n, for example 1200. Under
releases of TOPS-20 prior to 6.0, you must issue this command before you
can send a simulated BREAK signal during CONNECT.
|
.setxp: noise <to>
movei t1, [flddb. .cmkey,,baudtb]
call rfield
hrrz t2, (t2) ; Get the value for the keyword (0 or 1).
movem t2, pars3 ; Save into pars3.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
baudtb: %table
%key <110>,^d110
%key <1200>,^d1200
%key <150>,^d150
%key <1800>,^d1800
%key <2000>,^d2000
%key <2400>,^d2400
%key <300>,^d300
%key <3600>,^d3600
%key <4800>,^d4800
%key <600>,^d600
%key <7200>,^d7200
%key <9600>,^d9600
%tbend
$setsp: move t3, pars3 ; Get the speed that was parsed.
movem t3, speed ; Record it.
move t1, netjfn ; Get the output terminal JFN.
movx t2, .mospd ; Speed to set.
hrl t3, speed ; Input and output speeds the same.
MTOPR ; Attempt to set it.
%jserr (,r)
setom setspd ;[161] Flag that speed was explicitly set.
ret
; $SETTA (SET TVT-BINARY)
;
; Request binary-mode negotion with ARPAnet TAC.
;
;[129] This command added as part of edit 129.
;[182] Help message updated for automatic mode
;
hstac: asciz |
SET TVT-BINARY AUTOMATIC, ON or OFF
Only for users running KERMIT-20 on an Internet DEC-20, signed on
to a DEC-20 TVT (Internet virtual terminal), from either another
Internet host or through a TAC. Without TVT Binary mode, file
transfer through a TVT would not work in most cases.
SET TVT AUTOMATIC causes Kermit to determine your line type. If
you sign on from a TVT, then TVT-Binary mode will be enabled. Any
other type of line wil cause TVT-Binary mode to be disabled.
SET TVT AUTOMATIC is the default.
SET TVT ON overrides the automatic setting and forces KERMIT-20 to
always negotiate TELNET binary mode during a file transfer. This
should ONLY be done on a line that you are sure is a TVT that
KERMIT-20 is not recognizing as such. This can happen on older
pre-Release 7 monitors.
If this happens and you normally use KERMIT-20 through a TVT, you
can put the command SET TVT-BINARY ON into your KERMIT.INI file.
SET TVT OFF overrides the automatic setting and forces KERMIT-20 to
NEVER negotiate TELNET binary mode during a file transfer. This
should ONLY be done on a line that you are sure is NOT a TVT that
KERMIT-20 is mistakenly identifying as a TVT. While such a problem
is indicative of a monitor problem, this will allow you to get
around it until such time as the monitor is fixed.
CAUTION: This facility requires certain facilities in the Release 5
TOPS-20 Internet monitor: TELNET binary negotiations are accepted
(bug fix), and the monitor does NOT double the TELNET attention
character (IAC, octal 377). This program will attempt to use
monitor calls to enable TELNET binary mode. If the calls fail, it
will then send IAC escape sequences to negotiate TELNET binary
mode, and doubles any IACs that appear in data during file
transfer.
Further caution: setting or unsetting binary mode may take up to 8
seconds.
|
.setta: noise <negotiation> ; SET TVT-BINARY
movei t1, [flddb. .cmkey,,tvtkey,,automatic] ;[182]
call rfield ; Parse a keyword.
hrrz t2, (t2) ; Get the value for the keyword (0 or 1).
movem t2, pars3 ; Save into pars3.
skipn definf ;[77] In DEFINE?
confrm ;[77] No, get confirmation.
ret
tvtkey: %table ;[182] Table for parsing TVT keywords
%key <automatic>,[0,,1] ;[182] Figure it out for me
%key <off>, [0,,0] ;[182] Override to never negotiate
%key <on>, [1,,0] ;[182] Override to ALWAYS negotiate
%tbend ;[182] Which will break on LAT, CTERM, etc..
$setta: move t1, pars3 ; Get the value that was parsed.
move t2,(t1) ;[182] De-reference to get values
hrrz t3,t2 ;[182] Right halfword is automatic mode
hlrz t2,t2 ;[182] Left halfword is the TVT-Binary mode
jumpn t3,$sett1 ;[182] Setting automatic mode?
dmovem t2,tvtflg ;[182] No, override both TVT line
ret ;[182] and turn off line discovery
$sett1: exch t3, tvtchk ;[182] Update TVT checking mode, get old mode
jumpn t3,R ;[182] Wants automatic and it was already set?
call chktvt ;[182] Went from override to automatic, check
ret ; Done.
subttl chktvt - check to see if we are using a TVT line
;[182] Begin code addition
;
; NTINF%, which was introduced in 6.0 series Tops-20 and is now known
; to work in 7.0 series PANDA monitor and XKL. I believe there are
; also standard patches to the DEC monitor to make it work.
;
; We use NTINF% when the user sets TVT-Binary mode to automatic which
; is an additional keyword (used to be just on or off). Automatic is
; the default, but we still allow overide.
;
; If the NTINF% failes, then we recover by using STAT% to try to
; indentify whether the line is in the range of TVT's.
;
; PANDA monitor verified to have 400000,,RSKP in NVTDOD (see [129])
;
;passed: nothing, but check to see whether we are in automatic
; mode and if so, we execute our code, otherwise we are
; in override mode and we skip any checks
;
;returns: +1, always, although may complain about Jsyi errors
;
; Expects to be ablt to trash t1,t2 and t3
; tvtflg will be side-effect by our (possible lack of) discovery
chktvt: skipn tvtchk ;[182] Are we supposed to figure out if TVT?
ret ;[182] No, so skip all this cruft
hrrz t1,ttynum ;[182] Load the current line
txo t1,.ttdes ;[182] Convert line to a device designator
movem t1,ntiblk+.NWLIN ;[182] Store requested terminal
dmove t1,[exp ntblen,.NWRRH] ;[182] Requesting remote host information
dmovem t1,ntiblk+.NWABC ;[182] Store length and request type
dmove t1,[exp .NULIO,.NWRRH] ;[182] Output the node name to NUL:
dmovem t1,ntiblk+.NWNNP ;[182] return remote host information
setz t1, ;[182] Everything else is zero
movem t1,tvtflg ;[182] Assume not on a TVT
movem t1,ntiblk+.NWNNU ;[182] Initialize returned node numbers and
move t1,[ntiblk+.NWNNU,,ntiblk+.NWNU1] ;[182] clobber everything else
blt t1,ntiblk+ntblen-1 ;[182] Clear whatever is left in the block
movei t1,ntiblk ;[182] Load the address of the argument block
NTINF% ;[182] finally try to see out what's going on
%jserr <NTINF failed>,chktv0 ;[182] Phooey, try the olde fashioned way
;[182] Load network type and line type
ldb t1,[POINTR(<ntiblk+.NWTTF>,nttype)]
ldb t2,[POINTR(<ntiblk+.NWTTF>,ntline)]
cain t1,NW%TCP ;[182] Is the network type NOT TCP?
caie t2,NW%TV ;[182] or is this NOT a TVT?
ret ;[182] Leave line set as not a TVT
aos tvtflg ;[182] Okay, set TVT-BInary to ON
ret ;[182]
;[182] Begin moved code from before $stlnz:, above
;The following code is not used because a BBN TCP jsys is called.
;Some ARPA sites don't have the BBN jsys's any more. Those that have them
;keep them in different places (MONSYM, TCPSYM, etc). Rather than make the
;program site-dependent, this has been replaced with a SET TVT command until
;the DEC TCP jsys's become standard and widespread, assuming there will be a
;GETAB or other jsys to tell whether a given TTY is a TVT.
chktv0: ;[182] Here to try to grovel over STAT
;[129] The next 10 or so lines of code adapted from MODEM.MAC
movx t1,tcp%nt ;[129] Want aobjn ptr for tvts
STAT% ;[129] Get it
%jserr <STAT failed>,r ;[182] Just give up
hrrz t3,ttynum ;[129] Tty line we're useing
hrrz t1,t2 ;[129] Get first tvt
camge t3,t1 ;[129] Are we less than the first?
ret ;[182] Yes
hlres t2 ;[129] Calculate last tvt
sub t1,t2 ;[129] ...
subi t1,1 ;[129] ...
camg t3,t1 ;[129] Are we .le. last tvt?
aos tvtflg ;[182] Yes, flag for later
ret ;[182]
;[182] End moved code from before $stlnz:, above
subttl STATISTICS command
; Help text for STATISTICS
hstatu: asciz |
STATISTICS
Give statistics about the most recent file transfer.
|
; Parse rest of STATISTICS command.
.stat: noise <about last file transfer> ; STATISTICS
confrm
ret
; Execute STATISTICS command.
$stat: setzm otot ;[180]
tmsg <
Maximum number of characters in packet: >
numout rpsiz
tmsg < received; >
numout spsiz
tmsg < sent
>
skipn t2, stdat ;[36] If no time was spent transferring,
jrst $statx ;[36] skip the rest.
tmsg < Number of characters transmitted in >
idivi t2, ^d3 ; Convert thirds of seconds to 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
addm t2, otot ;[180]
numout t2
tmsg <
Received: >
numout rtot
tmsg < Overhead: >
movei t1, .priou ; Output the number of chars in decimal.
move t2, rtot
sub t2, rtchr
addm t2, otot ;[180]
numout t2
;...
; STATISTICS command, cont'd
tmsg <
Total: >
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, otot ;[180] Get total chars.
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 < bps>
;[180]...
tmsg <
ILDB: >
numout ttildb
tmsg < SIN: >
numout ttisin
tmsg < SIN Max: >
numout ttimax
tmsg < BIN: >
numout ttibin
;...[180]
skipge speed ;[146] Do we know the speed?
jrst $stat4 ; No.
fltr t2, t2 ; Yes, float the effective data rate.
fltr t4, speed ; And the line speed.
fmp t2, [100.0]
fdv t2, t4
tmsg <
Efficiency: >
movei t1, .priou
setz t3,
FLOUT
erjmp .+1
tmsg < per cent>
$stat4: skipn errptr ; Was there an error?
jrst $statx ; If not, done.
tmsg <
Canceled by error: >
move t1, errptr
PSOUT% ; If so output it.
hrroi t1, crlf ;[50]
PSOUT%
;...
; STATISTICS command, cont'd
;[36] Interpacket pause.
$statx: tmsg <
Interpacket pause in effect: >
movei t1, .priou
move t2, pause
setz t3,
FLOUT
nop
tmsg < sec
Timeouts: > ;[54] How many timeouts and NAKs.
numout ntimou
tmsg <
NAKs: >
numout nnak
;[47][132] If debugging, tell most recent JSYS error.
jumpe debug, $statz ;[132] Debugging?
$statj: tmsg <
Last JSYS error: > ; Yes, tell about last error.
movei t1, .priou
hrloi t2, .fhslf
setz t3,
ERSTR
nop
nop
tmsg <
Timer errors: > ;[132] Also, give hints if anything is
numout timerx ; going wrong with timers.
$statz: tmsg <
>
ret
; SHOW command.
; Help text...
hshow: asciz |
SHOW
Display current SET parameters, version of KERMIT-20, or other info:
DAYTIME Current date, time, phase of moon.
DEBUGGING Debugging mode and log file in effect, if any.
FILE-INFO Byte size for DEC-20 file i/o, incomplete file disposition.
INPUT Parameters for INPUT command.
LINE TTY line, parity, duplex, handshake, escape character.
MACROS Definitions for SET macros.
PACKET-INFO For incoming and outbound packets. Items under RECEIVE
column show parameters for packets KERMIT-20 expects
to receive, under SEND shows parameters for outgoing
packets.
TIMING-INFO Delays, retries, server NAK intervals.
VERSION Program version of KERMIT-20.
ALL (default) All of the above.
|
; Parse rest of SHOW command...
.show: noise <parameters> ; SHOW command
movei t1, [flddb. .cmkey,,shotab,,<all>] ;[39]
call cfield ;[39]
hrrz t2, (t2) ;[39]
movem t2, pars2 ;[39]
ret
shotab: %table ;[39] (this whole keyword table)
%key <all>,0
%key <daytime>,$shday
%key <debugging>,$shdeb
%key <file-info>,$shfil
%key <input-info>,$shinp ;[160]
%key <line>,$shlin
%key <macros>,$shmac ;[77]
%key <packet-info>,$shpkt
%key <timing-info>,$shtim
%key <version>,$shver
%tbend
$show: move q1, [ret] ;[39] Return after each piece
skipn t2, pars2 ;[39] unless ALL was selected, in which case
jrst [ move q1, [nop] ;[39] fall thru from piece to piece,
jrst $shtop ] ;[39] starting from top.
tmsg <
> ;[39] Single SHOW item. Emit blank line,
jrst (t2) ;[39] then go show the requested stuff.
$shtop: ;[39] Top of SHOW command.
; SHOW VERSION
$shver: tmsg <TOPS-20 Kermit version >
$shv2: ldb t2, [pointr versio,VI%MAJ] ;[184] major version
numout t2, ^d10 ;[184]
ldb t2, [pointr versio,VI%MIN] ;[184]
skipe t2 ;[95] minor version
call [ movei t1, "." ;[95] Use new decimal notation
PBOUT ;[95]
numout t2, ^d10 ;[184]
ret ]
ldb t3, [pointr versio,VI%EDN] ;[184] edit
skipe t3
call [ movei t1, "("
PBOUT
numout t3, ^d10 ;[184]
movei t1, ")"
PBOUT
ret ]
ldb t4, [pointr versio,VI%WHO] ;[184] who
skipe t4
call [ movei t1, "-"
PBOUT
numout t4, ^d10 ;[184]
ret ]
tmsg < > ;[186] Show version date
hrroi t1, verdate ;[186] (defined at top)
PSOUT ;[186]
tmsg <
>
xct q1 ;[39] return or proceed...
; SHOW DAYTIME
$shday: 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 <
>
xct q1 ;[39] return or proceed...
; SHOW LINE
$shlin: 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%
move t1, netjfn ;[130] Tell about modem control & carrier.
call chklin
skipn mdmlin
jrst $show3
tmsg <
Line has modem control
Carrier: >
hrroi t1, [asciz/On/] ; Say it's on.
skipn carier ; Is it?
hrroi t1, [asciz/Off/] ; No.
PSOUT ; Tell
$show3: tmsg <
Handshake: > ;[76] Handshake
skipn t1, handsh ; Any?
jrst [ tmsg <None>
jrst $shw3a ]
call putc
$shw3a: tmsg <
Flow-Control: > ;[143]
hrroi t1, [asciz/XON-XOFF/]
skipn flow
hrroi t1, [asciz/None/]
PSOUT
$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
;...
;...SHOW LINE, cont'd
tmsg <
Speed: > ; Line speed.
skipl speed ; If negative, we don't really know it.
numout speed
hrroi t1, [asciz/(Unknown)/]
skipge speed ; If not negative, we know it.
PSOUT
$sho4b: skipn local ;[96] Don't confuse them with this
jrst $sho4c ;[96] unless they're local.
tmsg <
Escape: >
move t1, escape
call putc
$sho4c: tmsg <
Break Simulation: >
hrroi t1, [asciz/Enabled/]
skipg speed
hrroi t1, [asciz/Disabled/]
PSOUT
skipg speed
jrst $sho4d
tmsg <, >
numout brk
tmsg < NULs at 50 baud>
$sho4d: tmsg <
TVT Binary: > ;[129] ARPAnet TVT binary mode.
hrroi t1, [asciz/Off/]
skipe tvtflg
hrroi t1, [asciz/On/]
PSOUT
tmsg <
TVT Negotiate: > ;[182] ARPAnet TVT discovery
hrroi t1, [asciz/Override/]
skipe tvtchk
hrroi t1, [asciz/Automatic/]
PSOUT
$sho4e: tmsg <
Log: >
skipg t2, sesjfn ; are we logging?
skipl t2, savjfn ; or toggled off?
skipa
jrst [ tmsg <(none)>
jrst $sho4f ]
movei t1, .priou ; so print the Log file
setzb t3, t4 ; default format, no prefix
JFNS ; output it
erjmp [tmsg <(none)>
jrst $sho4f ]
hrroi t1, [asciz/ (on)/] ; assume toggled on
skipg sesjfn ; is that correct?
hrroi t1, [asciz/ (off)/] ; no, use other message
PSOUT ; output it
$sho4f: ;put next one here...
$sho4x: tmsg <
>
xct q1 ;[39] return or proceed...
; SHOW FILE-INFO
$shfil: tmsg <Byte size for file I/O: >
hrroi t1, [ASCIZ/"Auto"/]
skipn autbyt
jrst [ hrroi t1, [asciz/Seven-Bit/]
skipe ebtflg
hrroi t1, [asciz/Eight-Bit/]
jrst .+1 ]
PSOUT%
tmsg <
File name conversion: > ;[84]
hrroi t1, [asciz/Off/] ;[84]
skipe xfnflg ;[84]
hrroi t1, [asciz/On/] ;[84]
PSOUT ;[84]
tmsg <
ITS-binary-format file recognition > ;[75]
hrroi t1, [asciz/enabled/] ;[75]
skipn itsflg ;[75]
hrroi t1, [asciz/disabled/] ;[75]
PSOUT ;[75]
tmsg <
Disposition for incomplete incoming files: > ;[42]
hrroi t1, [asciz/Discard/]
skipe abtfil ;[42]
hrroi t1, [asciz/Keep (whatever was received)/]
PSOUT% ;[42]
tmsg <
Deleted files are > ;[143]
hrroi t1, [asciz/NOT /]
skipn expung
PSOUT
tmsg <expunged automatically
Transaction log file: > ;[126]
skipn t2, tlgjfn ; Any?
jrst [ hrroi t1, [asciz/ (none)/] ; No.
PSOUT
jrst $shflx ]
movei t1, .priou ; Yes, a real file,
setz t3, ; Say what it is.
JFNS
%jserr (,.+1)
$shflx: tmsg <
>
xct q1 ;[39] return or proceed...
; SHOW DEBUG
$shdeb: tmsg <Debugging: >
hrro t1, [
[asciz/Off/]
[asciz/States/]
[asciz/Packets/]
](debug)
PSOUT%
jumpe debug, $shdbx ;[38]
tmsg <
Debugging log file: > ;[38]
move t2, logjfn ;[38] Any log file?
cail t2, 1 ;[71] 0 or -1 means none.
caile t2, 100 ;[71] 100 or above is .priou or whatever...
jrst [ hrroi t1, [asciz/ (none)/] ;[38] None.
PSOUT ;[38]
jrst $shdbx ] ;[38]
movei t1, .priou ;[38] Yes, a real file,
setz t3, ;[38] Say what it is.
JFNS ;[38]
%jserr (,.+1) ;[38]
tmsg <, bytesize > ;[41]
numout logbsz ;[41]
$shdbx: tmsg <
> ;[39]
xct q1 ;[39] return or proceed...
; SHOW PACKET-INFO
;[100] New headings, less confusing.
;
$shpkt: tmsg <Packet parameters:
Inbound Outbound
Size: >
numout rpsiz,^d10
tmsg < >
numout spsiz,^d10
tmsg < characters
Padding: >
numout rpadn
tmsg < >
numout spadn
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 Prefix: >
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
;[100] New headings for this stuff.
$shpk2: tmsg <
Requested Used
8th-bit Prefix: > ;[88] Begin addition
skipe ebqr ; Did our user request 8th bit prefix?
jrst [ move t1, ebq ; Yes.
call putc ; Say what it is.
tmsg < >
jrst .+1 ]
skipn ebqr
jrst [ tmsg <(none) > ; No, just say we'll do it if asked.
jrst .+1 ]
skipe ebqflg ; Was it used during last transfer?
jrst [ move t1, ebq ; Looks like it, say what prefix.
call putc
jrst .+1 ] ;[88] End addition
skipn ebqflg
jrst [ tmsg <(none)> ; No, just say we'll do it if asked.
jrst .+1 ]
tmsg <
Repeat Prefix: > ;[92] Begin addition
move t1, rptq ; What we use to flag repeat counts.
call putc
tmsg < >
skipe rptflg ; Was it actually used?
jrst [ move t1, rptq
call putc
jrst .+1 ] ;[92] End addition
skipn rptflg
jrst [ tmsg <(none) > ; No, just say we'll do it if asked.
jrst .+1 ]
tmsg <
Block Check: > ;[98] Block check type.
move t1, bctr
call putc
tmsg < >
numout bctu ;[98]
tmsg <
>
xct q1 ;[39] return or proceed...
; SHOW TIME-INFO
$shtim: tmsg <Timing parameters:
Receive Send
Timeout: > ;[45]
numout rrtimo ;[128]
tmsg < >
skipg stimou ;[45]
jrst [ tmsg <(none)> ;[45]
jrst $shpau ] ;[45]
numout stimou
movei t1, "-" ;[6]
PBOUT% ;[6]
numout [maxtim] ;[6]
tmsg < sec>
$shpau: tmsg <
Pause: > ;[36]
movei t1, .priou ;[36]
move t2, rpause ;[36]
setz t3, ;[36]
FLOUT ;[36]
nop ;[36]
tmsg < > ;[36]
movei t1, .priou ;[36]
move t2, spause ;[36]
FLOUT ;[36]
nop ;[36]
tmsg < sec
Delay before sending first packet: >
move t1, delay ;[100]
skipe local ;[100]
setz t1, ;[100]
numout t1 ;[100]
tmsg < sec
Packet retries before timeout: >
numout maxtry
$showc: tmsg <
Number of retries for init packet: >
numout imxtry
skipn srvtim
jrst $shwc2
tmsg <
Server sends NAKs every >
numout srvtim
tmsg < sec while waiting for command.>
$shwc2: 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]
xct q1
;[160] Show INPUT parameters
;
$shinp: tmsg <Parameters for INPUT commands:>
tmsg <
Alphabetic Case: >
hrroi t1, [asciz/Ignored in matching/]
skipe incase
hrroi t1, [asciz/Observed in matching/]
PSOUT
tmsg <
Default Timeout: >
skiple indeft
numout indeft
hrroi t1, [asciz/ sec/]
skiple indeft
PSOUT
hrroi t1, [asciz/Infinite/]
skipg indeft
PSOUT
tmsg <
Timeout Action: >
hrroi t1, [asciz/Proceed with command file
/]
skipe intima
hrroi t1, [asciz/Quit from command file
/]
PSOUT
xct q1
;[77] SHOW MACRO DEFINITIONS
;
$shmac: tmsg <Macro definitions:>
hlrz t4, mactab ; Anything in macro table?
skipg t4 ; Yes, tell what.
jrst [ tmsg < (none)
>
jrst $shmax ] ; No, say so.
tmsg <
> ; Yes, list it/them.
movei t3, 1
$shma2: movei t1, 40 ; Space
PBOUT
hlro t1, mactab(t3) ; Point to macro name.
PSOUT ; Print it.
tmsg < = >
hrro t1, mactab(t3) ; Same deal for macro body.
PSOUT
aos t3 ; Bump index.
sojg t4, $shma2 ; Do for all macros in table.
tmsg <
>
$shmax: ret ;[83] Last one, always want to return.
; PUTC - Routine to print a single character, using ^X notation, DEL, etc.
;
; Call with t1/ character to print.
;
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
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 close any local debugging log file and exit from
the local KERMIT.
|
; Parse rest of BYE command.
.bye: noise (to remote server) ; Parse rest of BYE command.
confrm
ret
; Execute the BYE command.
$bye: move t1, [point 7, [asciz/L/]] ; An "L" for the data field.
movei t2, "G" ; Packet type is G.
call srvcmd ;[121] Send the command.
jrst $byez ; Some error, don't exit.
;[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 <...> ; Maybe there's more, but...
move t1, netjfn ; can't wait forever for it,
CFIBF% ; throw the rest away.
erjmp .+1
setom f$exit ;[38] Set exit flag.
; Error exit
$byez: setzm f$exit ;[70] Don't exit.
ret ;[70]
subttl FINISH command
;[28] The FINISH command is edit 28.
; Help text for FINISH 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.
Also, close any local debugging log file.
|
; Parse rest of FINISH command.
.finis: noise (remote server operation) ; Parse rest of FINISH command.
confrm
ret
; Execute FINISH command.
$finis: move t1, [point 7, [asciz/F/]] ; An "F" for the data field.
movei t2, "G" ; Packet type is G.
call srvcmd ; Go send the command.
nop ; Ignore any failure.
ret ; Done.
hclear: asciz |
CLEAR
Clear the input and output buffers of the currently selected line;
attempt to clear any XOFF condition. Useful in local mode, when the
connection to the remote system appears to be stuck.
|
.clear: noise <line>
confrm
ret
$clear: call ttxon ; Clear output buffer, send XON, etc.
CFIBF ; Also clear input buffer.
erjmp r
ret
hclose: asciz |
CLOSE keyword
Close the specified log file, TRANSACTION, DEBUGGING, or SESSION,
and stop recording to that file.
|
; Parse CLOSE command.
.close: noise (logging of)
movei t1, [flddb. .cmkey,,logtab] ; Parse what kind of log.
call cfield
hrrz t2, (t2)
movem t2, pars2
ret
; Execute CLOSE command.
$close: move t4, pars2 ; Get dispatch table offset.
setz t1, ; Make a zero.
jrst @[exp $clost, $closs, $closd](t4) ; Dispatch.
$clost: exch t1, tlgjfn ; Load transaction log JFN and zero it.
jrst $closx
$closs: exch t1, sesjfn ; Load session log JFN and zero it.
skipg t1 ; Were we using the saved JFN?
move t1, savjfn ; Try that.
setzm savjfn ; Also zero any saved copy.
jrst $closx
$closd: exch t1, logjfn
$closx: skipg t2, t1 ; Move JFN to t2 for JFNS, check for validity.
jrst [ tmsg <
?Logging was not being done>
ret ] ; If no valid JFN, give this message.
movei t1, "[" ; JFN looks OK - opening bracket for message.
PBOUT
movei t1, .priou ; Type the filename.
setz t3,
JFNS
%jserr (,r)
move t1, t2 ; JFN back to t1 for other JSYS's.
move t3, t2 ; Save the JFN here, too.
RFPTR ; Get file position.
seto t2, ; On error, substitute -1.
CLOSF ; Close the file.
erjmp [hrrzs t1 ; If error, check what it was.
caie t1, clsx1 ; Already closed?
%ermsg (,r) ; No, give message.
move t1, t3 ; Yes, get the JFN back.
RLJFN ; Release it.
nop ; Ignore any errors.
jrst .+1 ]
tmsg < Closed, > ; Finish the message,
numout t2 ; including count of bytes written.
tmsg < Byte(s) Written]>
ret
subttl CONNECT command
; Help text for CONNECT...
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, and
logging the session to the file specified in the most recent LOG SESSION
command, if any. Get back to KERMIT-20 by typing the escape character followed
by the letter C. The escape character is Control-Backslash (^\) by default.
When you type the escape character, several single-character commands are
possible:
C -- Close the connection and return to KERMIT-20.
B -- Transmit a BREAK signal.
S -- Show status of the connection.
Q -- Temporarily quit logging.
R -- Resume logging.
P -- Push to a new Exec. POP from the Exec to get back to the connection.
^\ (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.
|
;...
;...CONNECT command, cont'd
; Parse rest of 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
;[151] CONNECT code totally rewritten as Edit 151. Formerly, CONNECT was
; accomplished by running a program TTLINK in a lower fork. Now, the code is
; integrated into this program. This was done for two reasons:
;
; 1. V6 of TOPS-20 doesn't allow multiple JFNs on the same TTY device.
; 2. TTLINK was interrupt-driven and therefore did not work under batch.
;
; This method, similar to that used in Mark Crispin's TELNET program, uses
; separate input and output forks. It works under batch because the "pty"
; is always "hungry".
;
$conne: skipe pars3 ; Did we parse a TTY number?
call $setln ; If so, use that one.
move t4, mytty ; Find our terminal number.
camn t4, ttynum ; Is this number the same as requested one?
jrst [ tmsg <
?You can't CONNECT to your own line.
Please use the SET LINE n command to select another line.>
ret ]
; Set up controlling TTY for talk mode, issue connect message.
call ttyini ; Init controlling TTY.
tmsg <[KERMIT-20: Connecting to remote host over TTY> ; Type message.
numout ttynum,^d8
tmsg <:, type >
movei t1, 74 ; Left pointy bracket...
PBOUT
tmsg <CTRL->
move t1, escape ; (tell escape character)
addi t1, "A"-1
PBOUT
movei t1, 76 ; ...Right pointy bracket
PBOUT
tmsg <C to return.]
>
; Tell about session log, if any.
skipg t2, sesjfn ; Logging?
jrst ttsfrk ; No.
tmsg <[KERMIT-20: Logging to File > ; Yes, tell them now.
movei t1, .priou ; Type the filename.
setz t3,
JFNS
%jserr (,.+1)
tmsg <]
> ; End of message.
; Create and start a fork to get and display input from the remote end.
ttsfrk: movx t1, <cr%map!cr%cap!cr%st!netin> ; Share our map, start at NETIN.
CFORK
%jserr (,r)
movem t1, ttfork ; It's running, save fork handle.
;[151] Keyboard input loop.
ttinch: skipn ttfork ; Have a fork?
jrst $connx ; No, it's gone, so disconnect.
move t1, ttyjfn ; Get a byte from the controlling TTY.
BIN
%jserr (<Can't input from tty>,<.+1>) ; What could happen?
ldb t3, [point 7, t2, 35] ; Make copy without parity.
camn t3, escape ; Is it the escape character?
jrst doesc ; Yes, go process single-char command.
skipe duplex ; Have to echo locally?
call echo ; Yes, do.
move t1, t2 ; Tack on desired parity.
call @parity ; The parity routine wants the character in t1.
move t2, t1
move t1, netjfn ; Output the character to the connected TTY.
BOUT
%jserr (<Can't output to line>,tterr) ; If error, go check.
jrst ttinch ; Go back and do it again.
; Error handler for connected TTY.
tterr: skipn mdmlin ; Modem controlled line?
jrst ttinch ; No, go back.
call chkli2 ; Go check for carrier.
skipn carier ; Still have it?
skipa ; No, close the connection.
jrst ttinch ; Yes, keep plugging away till they disconnect.
; Lost carrier, shut down the connection.
tmsg <
[KERMIT-20: Lost Carrier On Remote Connection -- Returning to DEC-20]
>
jrst $connx
;[151] Code for receive fork. Runs forever, asynchronously, till killed.
netin: move t1, netjfn ; Wait for input
BIN
%jserr (<Can't input from line>,neterr) ; Handle any errors.
txz t2, 200 ; Strip parity.
move t1, ttyjfn ; Display incoming character on screen.
BOUT
%jserr (<Can't output to tty>,<.+1>)
skipg t1, sesjfn ; Logging?
jrst netin ; No, go back for more.
BOUT ; Yes, do that.
%jserr (<Can't write log>,netlgx)
jrst netin ; Loop forever.
; Error handler for session log output.
netlgx: setz t1, ; Go shut down the session log.
call $closs
jrst netin
; Error handler for network TTY.
neterr: skipn mdmlin ; Modem controlled line?
jrst netin ; No, go back.
call chkli2 ; Go check for carrier.
skipn carier ; Still have it?
skipa ; No, close the connection.
jrst netin ; Yes, keep plugging away till they disconnect.
; Lost carrier, shut down the connection.
neterx: tmsg <
[KERMIT-20: Lost Carrier On Remote Connection -- Returning to DEC-20]
>
setzm ttfork ; Zero the fork handle/flag.
HALTF ; Halt this fork.
0 ; Should never get here...
;[151] Escape character was typed -- Get argument.
doesc: move t1, ttyjfn
BIN ; Escape char was typed, get argument.
trz t2, 200 ; Strip any parity bit.
cail t2, "a" ; Uppercase any letter.
caile t2, "z"
skipa
subi t2, 40
cain t2, " " ; The null command.
jrst ttinch ; ...
cain t2, "S" ; Status query
jrst [ move q1, [ret] ; Calling convention for show line.
call $shlin ; Go show line parameters.
jrst ttinch ] ; Go back for more input.
cain t2, "C" ; Close connection.
jrst $connx
cain t2,"B" ; is it a break?
jrst [ call brkin0 ; yes, handle it
jrst ttinch ] ; then continue
cain t2, "Q" ; Quit logging
jrst [ call qlog
jrst ttinch ]
cain t2, "R" ; Resume logging
jrst [ call rlog
jrst ttinch ]
cain t2, "?" ; Help
jrst [ hrroi t1, [asciz\
KERMIT-20 Single-Character CONNECT-Mode Commands:
B - Send BREAK signal
C - Close connection
S - Status
P - Push to Exec
Q - Quit logging
R - Resume logging
? - This message
Type the escape character twice to send one copy of it to the remote host.
Escape character is "\]
PSOUT
move t2, escape ; Type the escape character.
call echo
tmsg <".
>
jrst ttinch ]
;...
;[151]...DOESC, cont'd
camn t2, escape ; Send escape character
jrst [ skipe duplex ; If local echo
call echo ; take care of that.
move t1, t2
call @parity ; Add desired parity to it.
move t2, t1
move t1, netjfn ; Send it out the link.
BOUT ;
%jserr (,tterr)
jrst ttinch ]
cain t2, "P" ; PUSH to Exec
jrst [ call fixtty ; Put TTY in normal mode.
call push ; Do the pushing.
call ttyini ; Put back in talk mode.
tmsg <
[KERMIT-20: Back at remote host]
>
jrst ttinch ]
movei t1, 7 ; Anything else, just beep
PBOUT
jrst ttinch
; Come here to restore things.
;
; Take care of any session log file. We want to close it, but leave the JFN
; around in case the logging is resumed, the program continued, etc.
;
$connx: skipg t2, sesjfn ; Is a log file open?
jrst $conx2 ; No, go do the rest.
tmsg <
[KERMIT-20: Closing Log File >
movei t1, .priou
setz t3,
JFNS
%jserr (,.+1)
tmsg <]
>
move t1, t2 ; Get the JFN back into t1.
hrli t1, (co%nrj) ; Close, but don't release JFN.
CLOSF% ; ...
erjmp [hrrzs t1 ; If error, check what it was.
cain t1, clsx1 ; Already closed?
jrst .+1 ; Yes, ignore.
setzm sesjfn ; Some other error, so JFNs are probably
setzm savjfn ; unusable, zero them out,
%ermsg (,$conx2) ] ; complain, and return.
movei t1, (t1) ; Closed OK, open it again to prevent CLZFF
movx t2, <fld(7,of%bsz)+of%app> ; from stomping on the JFN.
OPENF
erjmp .+1
$conx2: call fixtty ; Put controlling tty back in data mode.
movx t1, .priin ; Flush any pending tty input.
CFIBF
erjmp .+1
skipe t1, ttfork ; Kill receive fork.
KFORK%
erjmp .+1
setzm ttfork ; Remember it's gone.
movei t1, .priou ; Output a CRLF if not at left margin.
RFPOS%
hrroi t1, crlf
trne t2, -1
PSOUT%
tmsg <[KERMIT-20: Connection Closed]> ; Closed message.
ret
;[151] Character echoing routine.
;
; Need to do this because having tty open in binary mode overrides ccoc
; settings. t2 contains character to echo.
;
echo: saveac<t1,t2,t3> ; Must save all ACs.
trz t2, 200 ; Strip any parity.
move t3, t2 ; Make a copy of the character.
cail t3, 40 ;[18] Check most common case first,
caile t3, 126 ;[18] namely, whether it's a printable
skipa ;[18] character.
jrst echo2 ;[18] If so, just go print it.
caig t3, 6 ; Check for control char, null thru ^F.
jrst echo1
cain t3, 13 ; ^K
jrst echo1
cail t3, 16 ; ^N-^Z
caile t3, 32
skipa
jrst echo1
cail t3, 34 ; ^\-^_
caile t3, 37
skipa
jrst echo1
cain t3, 33 ; ESC
jrst [ movei t2, "$" ; Echo as dollar sign
jrst echo2 ]
cain t3, 177 ; DEL
jrst [ seto t3, ; So it echoes as ^? (100-1=77="?")
jrst echo1 ]
move t2, t3 ; Anything else, just type it.
jrst echo2
echo1: skipg t1, ttyjfn ; Echo it on the tty.
movei t1, .priou
movei t2, "^" ; Print an uparrow
BOUT
%jserr (,.+1)
skiple t1, sesjfn ; Logging?
call [ BOUT ; Yes, do that.
%jserr (,qlog) ; Error, print msg, close log, rtn from there.
ret ] ; No error.
movei t2, 100(t3) ; Convert to char to uncontrollified version.
echo2: skipg t1, ttyjfn ; Back to TTY.
movei t1, .priou
BOUT ; Print the character itself.
%jserr (,.+1)
skiple t1, sesjfn ; Logging?
call [ BOUT ; Yes, do that.
%jserr (,qlog) ; Error, print msg, close log, rtn from there.
ret ] ; No error.
ret
;[151] BREAK-sending routine. Simulate by sending some nulls at
; a low baud rate. Originally by Bill Schilit, Columbia.
;
brkin0: saveac <t1,t2,t3,t4> ; save all used registers
skipg speed ; do we know about a speed?
jrst brkin2 ; no, give a message
move t1, netjfn ; get the output terminal jfn
movx t2, .mospd ; set the speed
hrlz t3, speed ; same input speed
hrri t3, ^d50 ; but output is lower (input,,output speeds)
MTOPR
%jserr (,r)
skipg t3, brk ; get count of nulls to send
movei t3, defbrk ; use the default
caile t3, maxnul ; greater than we support?
movei t3, maxnul ; yes, use that
movns t3 ; make negative
move t2, [point 7,nulls] ; point to them
setzm t4 ; no stop char
SOUT
%jserr (,.+1)
movx t2, .mospd ; now reset speed
move t3, speed
hrls t3 ; make input same as output
MTOPR
%jserr (,r)
ret
brkin2: tmsg <
[KERMIT-20: Can't send BREAK, line speed unknown -- use SET SPEED command.]
>
ret
defbrk==3 ; Default number of breaks.
maxnul==100 ; Maximum number of nulls.
nulls: repeat <maxnul/5>+1,<0> ; A string of nulls.
;[151] Quit logging session during CONNECT.
qlog: skipg t1, sesjfn ; Do we have a session log?
jrst [ tmsg <
%KERMIT-20 wasn't logging this session...
>
ret ]
movem t1, savjfn ; Yes, save the JFN elsewhere.
hrli t1, (co%nrj) ; Close the log, but don't release JFN.
CLOSF
erjmp .+1
setom sesjfn ; Signal that we're not logging.
; Open the log file again, to keep the JFN from getting flushed by CLZFF.
movei t1, (t1) ; Clear out bits from left half.
movx t2, <fld(7,of%bsz)+of%app> ; Open for appending.
OPENF
%jserr (, [
setom sesjfn
jrst .+1 ])
tmsg <
[KERMIT-20: Quit logging]
>
ret
;[151] Resume logging session after a hiatus.
rlog: skiple sesjfn ; Check for this...
jrst [ tmsg <
%KERMIT-20 already logging...
>
ret ]
skipg t1, savjfn ; Get the saved log JFN back.
jrst [ tmsg <
%KERMIT-20 wasn't logging...
>
ret ]
; A log was selected, but not active. Just juggle the JFNs.
movem t1, sesjfn ; Put saved JFN back as the log JFN.
setom savjfn ; Flag that there's no saved JFN.
tmsg <
[KERMIT-20: Resume logging]
>
ret
subttl PUSH Command
;[151] Push to Exec
push: seto t1, ; Save subsystem & program names...
move t2, [-2,,pname]
movei t3, .jisnm
GETJI
erjmp .+1
tmsg <
[KERMIT-20: PUSHing to new EXEC.]
[POP from Exec to return.]
>
skipe t1, execf ; Have one already?
jrst [ txo t1, sf%con ; Yes, just continue it.
SFORK
erjmp .+1 ; Unless it disappeared...
jrst push3 ]
movx t1, cr%cap ; No, create a fork.
CFORK
%jserr (,r)
movem t1, execf ; Save its handle.
move t2, capas ; Mask capas with this fork's enabled ones.
txz t2, sc%log ; Turn off logout capability.
txo t2, sc%gtb ; Turn on GETAB capability (must have it...)
skipe jobtab+.jibat ; Under batch?
txz t2, sc%ctc ; If so, don't try to enable ^C capability.
move t3, t2 ; Enable capabilities.
EPCAP
%jserr (,r) ; Fail if can't, since Exec must have them.
movx t1, gj%old+gj%sht ; Get JFN on the Exec.
hrroi t2, [asciz/SYSTEM:EXEC.EXE.0/]
GTJFN
%jserr (,r)
move t4, t1 ; Save the JFN for a sec.
hrl t1, execf ; Get the Exec into the fork.
GET
%jserr (,r)
move t1, t4 ; Release the Exec's JFN, don't need it.
RLJFN
nop
move t1, execf ; Exec fork handle.
setz t2, ; Start up the fork.
SFRKV
%jserr (,r)
push3: WFORK ; Wait for it to halt.
dmove t1, pname ; Restore program/subsys name.
SETSN
nop
REMARK Maybe release terminal during push? Keeps TCB locked
push4: GJINF% ;[183] Load current job line in t4
skipn t1, netjfn ;[183] Load terminal JFN
ret ;[183] Nothing there, so don't bother
DVCHR% ;[183] and find out about it
erjmp r ;[183] make this somebody else's problem
load t1, DV%TYP,t2 ;[183] Pick up the device type byte
caie t1, .DVTTY ;[183] and is this a terminal?
ret ;[183] Nope, nothing to check, then
hrrz t1, t3 ;[183] Load the current TTY line number
came t1, mytty ;[183] Was this different from me?
ret ;[183] Yes, so seperate line was being used
camn t1, t4 ;[183] Otherwise, any change?
ret ;[183] Nope, nothing to do, then
;[183] lifted from cleanup
push5: move t1, netjfn ;[183] Get communication line JFN.
setzm netjfn
setzm local
caie t1, .cttrm ;[183] Previous one was controlling terminal?
skipn t1 ;[183] Close any assigned TTY.
jrst push6
CLOSF ;[183] Also releases a held TCB.
erjmp .+1 ;[183] Ignore any error (silently).
push6: skipn asgflg ;[183] Did I also assign the TTY?
jrst push7 ;[183] No.
move t1, ttynum ;[183] Yes, so I should deassign it.
movei t1, .ttdes(t1)
RELD%
erjmp .+1
push7: setzm asgflg
movem t4, ttynum ;[183] stomp in the new terminal
movem t4, mytty ;[183] stomp in the new terminal
movem t4, pars3 ;[183] fake up a parse
callret $setln ;[183] Go set the line again
; Put TTY in binary mode for output only. Still allows normal input,
; ^C trapping, etc.
;
ttyob: movei t1, .priou ; Get CCOC words
RFCOC
dmovem t2, myccoc ; Save em.
move t2, [525252525252] ; Make all characters output
move t3, [525252525000] ; with no translation.
SFCOC
movei t2, .morxo ; Get tty pause-end-of-page status.
MTOPR%
%jserr (,.+1)
movem t3, ttpau ; Save it.
movei t2, .moxof ; Set the terminal pause end...
movei t3, .mooff ; to no pause on end.
MTOPR%
%jserr (,.+1)
ret
; Restore TTY output to condition before TTYOB was called.
ttyou: movei t1, .priou ; Restore normal tty output.
dmove t2, myccoc
SFCOC
%jserr (,.+1)
movei t2, .moxof ; Set terminal pause end-of-page...
move t3, ttpau ; to what it used to be.
MTOPR%
%jserr (,.+1)
ret
;[151] Set up TTY for linking, and open any logging file.
ttyini: movei t1, .fhslf ; Read current process capabilities.
RPCAP%
movem t3, capas
movei t1, .priin ; Turn off terminal page mode and data mode.
movem t1, ttyjfn
movei t2, ttydim ;[185] Point to controlling terminal block
call savlnw ;[185] Save the terminal length and width
RFMOD ; Get tty mode word.
movem t2, ttymod ; Save it, to be restored later.
; No echo, no data mode, full duplex.
txz t2, <tt%eco!tt%dam!tt%dum!tt%lic> ;[129] Add TT$DUM
; No wakeup stuff, infinite width & length.
txz t2, <tt%wkf!tt%wkn!tt%wkp!tt%wka!tt%wid!tt%len!tt%uoc>
; No formfeed/tab/case interpretation, use XON/XOFF.
txo t2, <tt%mff!tt%tab!tt%lca!tt%pgm>
skipn handsh ;[155] Doing handshake?
skipn flow ;[155] Doing flow control?
txz t2, tt%pgm ; Handshake, or no flow - don't do XON/XOFF.
SFMOD ; Set the bits
%jserr (,r)
STPAR ; ...and the other bits...
%jserr (,r)
movx t1, .fhjob ; Turn off ^C, ^O, ^T interrupts for whole job.
RTIW
movem t2, tiword
tdz t2, [1b<.ticcc>+1b<.ticco>+1b<.ticct>]
move t3, capas ; Do we have ^C capability?
txne t3, sc%ctc ; Can't do STIW if we don't...
STIW
%jserr (,.+1)
call seslog ; Open the session log file.
ret
; Open the session log file.
seslog: skipg t1, sesjfn ; Logging?
ret ; No.
movx t2, <fld(7,of%bsz)+of%app> ; Yes, open for appending.
OPENF
erjmp [hrrzs t1 ; Got an error, get code.
cain t1, opnx1 ; Already open?
ret ; Ignore the error.
setzm sesjfn ; Real error, disable logging.
%ermsg (,r) ]
ret
;[151] Restore TTY parameters, turn off interrupts, and close any log file.
fixtty: move t1, ttyjfn ; Restore mode word.
move t2, ttymod
SFMOD ; Do both of these...
STPAR
movei t2, ttydim ;[185] Point to controlling terminal dimensions
call rstlnw ;[185] Restore length and width
movx t1, .fhjob ; Put tty back the way it was.
move t2, tiword ; put the terminal interrupt word
move t3, capas ; Mask capas with this fork's enabled ones.
txne t3, sc%ctc ; Can't do this if no ^C capability.
STIW ;
%jserr (,r)
ret
;[185] Save and restore terminal lengths (a.k.a., heights) and widths.
;[185] This is necessary because linear dimensions in excess of seven
;[185] bits (127) can not be stored in the JFN mode word as saved by
;[185] SFMOD% and restored by STPAR%
;[185]
;[185] As these are stored in halfwords, this allows for a maximum of
;[185] 262,143 for either a width or a length. As this is two decimal
;[185] orders of magnitude larger than the highest resolution graphics
;[185] cards (4096 in 2006), we probably don't have to worry about
;[185] overflowing the field for the next decade or so. None the
;[185] less, the MTOPR% does return a FULL 36 bit word; so if we ever
;[185] overflow 18 bits, then we should change this code.
;[185]
;[185] Assumes:
;[185]
;[185] t1/ Valid terminal JFN (possibly .PRIOU)
;[185] t2/ Pointer to block to save length and width
;[185]
;[185] Preserves the register file and is completely silent about errors.
savlnw: saveac <t1,t2,t3,t4,q1> ;[185] Do not side-effect the register file!
dmove t4, t1 ;[185] Preserve JFN, dimension block address
;[185]
DVCHR% ;[185] What kind of device is this?
erjmpr r ;[185] it's a bogus device!
load t3, dv%typ, t2 ;[185] Get device type field
caie t3, .dvtty ;[185] Is this a terminal?
ret ;[185] No, better leave it alone
move t1, t4 ;[185] Restore the JFN
;[185] Assume infinite (and therefore useless)
setzb t3, (q1) ;[185] defaults for width and length
movx t2, .morll ;[185] Return the terminal page length
MTOPR% ;[185] Which may be over 127 ...
erjmps .+2 ;[185] Must be a bogus JFN
hrlm t3, (q1) ;[185] Save length
dmove t2,[exp .morlw,0] ;[185] Return the terminal page width.
MTOPR% ;[185] Which may be over 127 ...
erjmps .+2 ;[185] Must be a bogus JFN
hrrm t3, (q1) ;[185] Save length
ret ;[185] Done, restore register file
rstlnw: saveac <t1,t2,t3,t4,q1> ;[185] Do not side-effect the register file!
dmove t4, t1 ;[185] Preserve JFN, dimension block address
;[185]
DVCHR% ;[185] What kind of device is this?
erjmpr r ;[185] it's a bogus device!
load t3, dv%typ, t2 ;[185] Get device type field
caie t3, .dvtty ;[185] Is this a terminal?
ret ;[185] No, better leave it alone
move t1, t4 ;[185] Restore the JFN
;[185]
movx t2, .mosll ;[185] Set the terminal page length.
hlrz t3, (q1) ;[185] Load old width
caie t3, 0 ;[185] Ever get anything? If not, leave
MTOPR% ;[185] it alone; otherwise restore it
erjmps .+1 ;[185] Ignore errors, preserve JFN
movx t2, .moslw ;[185] Set the terminal page width.
hrrz t3, (q1) ;[185] Load old width
caie t3, 0 ;[185] Ever get anything? If not, leave
MTOPR% ;[185] it alone; otherwise restore it
erjmps .+1 ;[185] Ignore errors, preserve JFN
ret ;[185] Done, restore register file
;[185] End code insertion
;[77] DEFINE command, added as edit 77.
;
hdefin: asciz |
DEFINE macroname set-parameters
Define a "SET macro" to allow convenient association of one or more SET
parameters with a mnemonic keyword of your choice. The set-parameters are
a list of one or more SET options, separated by commas. If you use KERMIT-20
to communicate with several different kinds of systems, you may set up a macro
for each, for instance:
DEFINE IBM PARITY MARK, DUPLEX HALF, HANDSHAKE XON, SEND PACKET-LENGTH 80
DEFINE UNIX PARITY NONE, DUPLEX FULL, HANDSHAKE NONE
DEFINE TELENET PARITY MARK
You may then type SET IBM, SET UNIX, and so forth to set all the desired
parameters with a single command. It is convenient to include these
definitions in your KERMIT.INI file.
You may redefine an existing macro in the same manner as you defined it.
You can undefine an existing macro by typing an empty DEFINE command for it,
for instance:
DEFINE IBM
Macro definitions may not include macro names.
|
;...DEFIN, cont'd
.defin: noise <SET macro named> ; Macro definition
movei t1, [
flddb. .cmfld,cm%sdh,,<new macro name for combining SET options>,,[
flddb. .cmkey,,mactab,<old macro name to delete or redefine,>]
]
call rfield ; Get the macro name
; Check on space for name string.
.defi2: move t2, namp ; Get current name buffer pointer.
movei t3, namx ; Is it at the end of the buffer?
caig t3, (t2)
jrst [ tmsg <?Macro name buffer full>
jrst cmder1 ]
; Have room, align pointer to word boundary.
.defi3: hlrz t4, t2 ; Is it on a word boundary?
caie t4, 440700
jrst [ aos t2 ; No, put it on one.
hrli t2, (point 7,)
movem t2, namp
jrst .+1 ]
movem t2, onamp ; Remember pointer to beginning of string.
; Copy the macro name into the macro name buffer.
move t1, [point 7, atmbuf] ; Copy the string out of the atom buffer.
.defi4: ildb t4, t1 ; Get a character.
idpb t4, namp ; Copy it.
jumpn t4, .defi4 ; Everything up to & including the first null.
; Let them type CR here to undefine the macro, or else jump into the SET
; command parser to let them define a new macro, or redefine an old one.
;
.defi5: noise <to SET> ; Prompt with guide words.
move t1, sbk+.cmptr ; Get current pointer from comnd state block.
movem t1, macptr ; Save it as pointer to macro body.
.defi6: setom definf ; Flag that we're doing a DEFINE.
movei t1, [flddb. .cmkey,,settab,,,[
flddb. .cmcfm,cm%sdh,,<Carriage return to undefine this macro>]
]
call rfield ; Parse a keyword or a CR.
ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
setom undeff ; Assume we're undefining?
cain t3, .cmcfm ; Parsed a CR?
ret ; Yes, so done.
setzm undeff ; No, we're defining after all.
callret .set2 ; Go parse SET commands.
; DEFINE command execution.
; Echo back what was typed...
$defin: skipe undeff ; Define or Undefine?
jrst $defi7 ; Undefine, go do that.
;[82] move t1, onamp ; Name
;[82] PSOUT
;[82] tmsg < = >
move t1, macptr ; Text
;[82] PSOUT
; Check for room left in macro text buffer.
move t3, macbp ; Get current macro text buffer pointer.
movei t2, macx ; Is it at the end of the buffer?
caig t2, (t3)
jrst [ tmsg <?Macro text buffer full>
ret ]
; Adjust to word boundary.
$defi2: hlrz t4, t3 ; Is it on a word boundary?
caie t4, 440700
jrst [ aos t3 ; No, put it on one.
hrli t3, (point 7,)
jrst .+1 ]
movem t3, macbp ; This copy is to be used.
movem t3, omacbp ; This points to the beginning of the result.
; Copy the text out of the command buffer.
$defi3: ildb t4, macptr ; Get a character.
idpb t4, macbp ; Copy it.
jumpn t4, $defi3 ; Everything up to & including the first null.
; Add <address of macro name,,address of body> to macro keyword table.
$defi4: movei t1, mactab ; Stick it in the macro table.
hrlz t2, onamp ; Address of keyword,,
hrr t2, omacbp ; argument (address of body)
TBADD ; ...
erjmp $defi5 ; Handle any errors below.
ret ; OK, done.
;...
; DEFINE command, cont'd
; TBADD got an error.
$defi5: movei t1, .fhslf ; What was it?
GETER
hrrzs t2
cain t2, taddx1 ; Table full?
jrst [ tmsg <?Macro table is full> ; Yes, give message.
ret ]
; Duplicate entry?
$defi6: caie t2, taddx2 ; Duplicate?
callret jserr0 ; No, something unforseen. Give message.
; Come here directly to undefine an existing macro.
; First look it up.
;
$defi7: movei t1, mactab ; Yes, look up its address in the kwd table.
move t2, onamp ; Pointer to macro name.
TBLUK
%jserr (,r)
skipn undeff ; Were we undefining?
jrst $defi8 ; No, don't be beastly then...
txnn t2, tl%exm ; Yes, found an exact match?
jrst [ tmsg <%"> ; No, warn.
move t1, onamp
PSOUT
tmsg <" not found in SET macro table>
ret ]
; Using the table index just obtained, delete the entry.
$defi8: move t2, t1 ; The address we just got.
movei t1, mactab
TBDEL ; Delete the old entry.
%jserr (,r)
skipe undeff ; Were we undefining, or replacing?
ret ; Undefining, so done.
; Try to add the new definition again.
$defi9: hrlz t2, onamp ; Address of keyword,,
hrr t2, omacbp ; argument (address of body)
movei t1, mactab ; Stick it in the macro table.
TBADD
%jserr (,r) ; This time really give up on error.
ret
;[125] LOG command
;
; LOG help text..
hlog: asciz |
LOG TRANSACTIONS or SESSION or DEBUGGING (to) filespec
Log files are closed upon exit from KERMIT-20, or explicitly by the CLOSE
command.
TRANSACTIONS:
Direct KERMIT-20 to log transactions, such as files successfully sent or
received, files that could not be successfully sent or received, and so forth,
to the specified file.
SESSION:
Create a transcript of a CONNECT session, when running KERMIT-20 in local
mode and connected to a remote system, in the specified file. Log is closed
when connection is closed. Logging can be toggled by typing the connect
escape character followed by Q (Quit logging) or R (Resume logging).
DEBUGGING:
Log the selected information (STATES or PACKETS, type HELP SET DEBUG for
further information) to the specified file. If log file not specified, then
use TTY if local, DEBUGGING.LOG if remote. If specified, then log STATES by
default. Also allow specification of bytesize for log file, 7 (normal,
default), or 8 (for debugging binary transfers, use FILDDT to inspect the log).
|
logtab: %table
%key <debugging>,2 ;[143]
%key <session>,1
%key <transactions>,0
%tbend
.log: noise <what> ; Give guide word
movei t1, [flddb. .cmkey,,logtab,,<session>] ; Parse what kind of log.
call rfield
hrrz t2, (t2)
movem t2, pars2
skipe t1, pars3 ; Release any piled up JFNs from reparsing
RLJFN
nop
noise <to file> ; Noise
move t2, pars2
move t1, [
[flddb. .cmofi,,,,<TRANSACTION.LOG.-1>] ; transaction log.
[flddb. .cmofi,,,,<SESSION.LOG.-1>] ; Default session log,
[flddb. .cmofi,,,,<DEBUGGING.LOG.-1>] ; & debugging log.
](t2) ; Note index!
call rfield ; Parse log filespec.
movem t2, pars3 ; Stash JFN here.
move t2, pars2 ;[143] Debugging log?
caie t2, 2 ;[143]
jrst [ confrm ;[143] No, get confirmation
ret ] ;[143] and return.
noise <with file byte size> ;[41] Yes, parse the file byte size.
movei t1, [flddb. .cmkey,,dbstab,<log-file bits per byte,>,7] ;[41]
call rfield ;[41] Parse it. Defaults to 7.
hrrz t2, (t2) ;[41] Get result.
movem t2, pars4 ;[41] Save it.
noise <bits> ;[41] Comforting noise...
confrm
ret
; Open the desired log.
$log: move t1, pars2 ; What kind of log?
jrst @[exp $logt, $logs, $logd](t1) ; Dispatch
;[126] Transaction log.
$logt: skipe t1, tlgjfn ; Already had one open?
CLOSF ; Close it
nop
setzm tlgjfn ; In case of failure.
move t1, pars3 ; Open the log
movx t2, of%wr!fld(7,of%bsz) ; Write access, 7-bit bytes.
OPENF
%jserr (,r)
movem t1, tlgjfn ; Save the jfn.
hrroi t2, [asciz/KERMIT-20 Transaction Log File, /]
setzb t3, t4
SOUT
seto t2, ; Write header in log file.
move t3, [ot%ntm!ot%day!ot%fdy!ot%fmn!ot%4yr]
ODTIM
hrroi t2, crlf
setzb t3, t4
SOUT
hrroi t2, crlf
setzb t3, t4
SOUT
wtlog (<Opened Log: >, tlgjfn)
ret
;[126] end of addition.
; Session log.
$logs: move t1, pars3 ; Get JFN we parsed.
setzm savjfn ; Where to put this JFN when not logging.
movx t2, <fld(7,of%bsz)!of%wr> ;[154] 7-bit bytesize, new file.
OPENF ; Open now, avoid being stomped by CLZFFs.
erjmp [movei t1, (t1) ; Got an error, get code.
cain t1, opnx1 ; Already open?
ret ; Ignore the error.
setzm sesjfn ; Real error, disable logging.
%ermsg (,r) ] ;[154](end)
movem t1, sesjfn ; Save the open JFN.
ret
; Debugging log.
$logd: setzm logjfn ;[38] Zero this out.
move t1, pars3 ;[38] Get the JFN we parsed.
move t4, pars4 ;[41] And bytesize we want.
movem t4, logbsz ;[41] Save bytesize for SHOW command.
movx t2, <fld(7,of%bsz)!of%wr> ;[41] Write access, assume 7-bit.
cain t4, 8 ;[41] 8-bit requested?
movx t2, <fld(8,of%bsz)!of%wr> ;[41] Yes, use 8-bit bytes.
OPENF% ;[38]
%jserr <Can't open log file>,r
movem t1, logjfn ;[38] Opened OK, save it.
skipn debug ;[41] Was debugging asked for?
movei debug, 1 ;[41] Not yet, so set default debugging.
ret
; PROMPT command
; PROMPT help text...
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.
|
; Parse the rest of the PROMPT command.
.promp: confrm ; Confirm.
ret
; PROMPT command execution.
$promp: setzm f$exit ; Reset exit flag.
ret
hpush: asciz |
PUSH
Push to a DEC-20 command processor. Get back to KERMIT with all current
settings intact by typing the Exec POP command.
|
; Parse & execute PUSH command.
.push: confrm
ret
$push: jrst push
; SERVER command
; Help text.
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, REMOTE,
FINISH, 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 shouldn't run KERMIT-20 as a
server. 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 must issue the appropriate SET commands before the
SERVER command.
|
; Parse rest of SERVER command.
.serve: confrm ; Confirm.
ret
; Execute the SERVER command.
;[144] Remove test for remote mode operation. KERMIT-20 works fine as a
; server over an assigned line, although the messages may look a bit strange.
;
$serve: call getcom ; Go serve.
;[137] setzm f$exit ;[110] Return to command mode if they ^C out.
ret
; GET remote files
;
;[11] This whole command is part of edit 11
; GET command help text.
hget: asciz |
GET [remote-filespec]
For use only when talking to a remote 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. You may type
Control-A to get a brief status report, ^X to request that the current incoming
file be cancelled, ^Z to request that the entire incoming batch be cancelled.
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.
Syntax: The GET command accepts an arbitrary string, terminated by a
carriage return. The string specifies a file or files in the syntax of the
remote system. The normal DEC-20 command characters for help (?), comment
delimitation (! and ;), and file indirection (@) are enabled at the beginning
of the field, you can only enter filenames starting with one of these
characters by "quoting" it with a Control-V, which is discarded before
sending the string to the remote system.
If you want to store the incoming file name with a different name than the
remote host sends it with, just type GET alone on a line; Kermit-20 will
prompt you separately for the source (remote) and destination (local)
file specification. If more than one file arrives, only the first one will
be stored under the given name; the rest will be stored under the names
they are sent with.
|
;...GET command, cont'd
;[148] Rewritten to allow source & destination files specified separately.
.get: noise <remote files> ; Parse the rest of the GET command.
setzm pars2 ; Make sure these are zero...
setzm pars3
movei t1, [flddb. .cmcfm,cm%sdh,,,,[
flddb. .cmtxt,cm%sdh,,<Remote file specification in remote host's own syntax
(Use CTRL-V to quote otherwise illegal characters like "!", "?", and "@"),
or carriage return to enter source and destination names separately.>]]
call rfield
ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
cain t3, .cmcfm ; Parsed a CR?
jrst .get2 ; Yes, go prompt.
confrm ; No, so go GET the specified file(s).
move t1, [point 7, atmbuf] ; Let $GET know where to find the string.
movem t1, pars2
setzm filjfn
ret
; Prompt separately for source and destination filespecs.
.get2: hrroi t1, [asciz/ Remote Source File: /] ; Prompt for remote filespec
PSOUT
move t1, [point 7, buffer]
setzm buffer
movem t1, pars2 ; Let $GET know where to find the string.
move t2, [rd%crf+rd%bel+<MAXBUF>]
hrroi t3, [asciz/ Remote Source File: /]
RDTTY
%jserr (,r)
setz t2, ; Write a zero over the terminating linefeed.
dpb t2, t1
skipn buffer ; If they typed nothing, then skip next part.
ret
; Now get local filespec for storing the incoming file.
.get3: hrroi t1, [asciz/ Local Destination File: /]
call dpromp
movei t1, [flddb. .cmofi]
call cfield
movem t2, pars3
ret
; GET command execution.
$get: skipe takdep ;[176] Allow commands to servers from TAKE file
jrst $get2
skipe local ; This only works if local Kermit.
jrst $get2
ermsg <Can't GET without prior SET LINE>, r
;[148] Check for and validate local filespec.
$get2: skipn local ;[177] If we're in remote mode...
call inilin
setzm filjfn ; Assume no local file given.
skipn t1, pars3 ; JFN of local file, if any...
jrst $get3 ; If none, skip this.
DVCHR ; Make sure it's on disk.
txne t2, dv%typ ; ...
ermsg <Destination file must be on disk>, r
move t1, pars3 ; Get this back.
movem t1, filjfn ; Save it here.
; Handle the remote filespec.
$get3: setz t3, ; Count the characters...
move t1, pars2 ; And move them from here
move t2, [point 7, strbuf] ; to here.
$get4: ildb t4, t1 ; Now copy the rest. Get a byte.
cain t4, 26 ;[147] Control-V?
ildb t4, t1 ;[147] Yes, it's a quote, get next byte.
idpb t4, t2 ; Deposit the byte.
skipe t4 ; Null?
aoja t3, $get4 ; No, then keep going.
jumpe t3, [ermsg <No remote filespec given>,r] ; Yes, done, any chars?
movem t3, temp2 ; Save this till after next part.
; OK, they gave a remote filespec. Send an info packet in case we want to
; tell them to send with nonstandard parameters, like 8bq or fancy block check.
setom bctone ;[98] Force 1-char checksum.
call sinfo ;[100] Go send Info packet.
ret ;[133] Failed, give up.
setom bctone ;[100] In case sinfo or sinit clears this!
; Parameters exchanged (perhaps), now send the R packet.
$get5: move t3, temp2 ; Restore length.
movei t1, "R" ; Packet type is Receive-Init.
setz t2, ; Packet number is zero.
move t4, [point 7, strbuf] ; Point to remote filespec.
call spack ; Send the packet.
jrst $getx
movei state, "R" ; Sent it ok, go into receive state.
callret $recvb
$getx: ermsg <Can't send Receive-Init>,r
subttl RECEIVE command
; Help text
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, lowercase letters,
control characters, etc) with ^V. (You may also use SET FILE NAMING to have
KERMIT-20 pick out a more conventional name.)
If a file with the same name already exists, KERMIT-20 just creates a new
generation of the same name and type.
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; you can type Control-A during the transfer for a brief status
report.
If you are asking KERMIT-20 to receive binary files from a microcomputer or
other 8-bit system, you must first type SET FILE BYTESIZE 8. Otherwise, the
8th bit of each byte will be lost. For ordinary text files, no special action
is necessary.
If you have SET PARITY, then 8th-bit quoting will be requested. If the other
side cannot do this, binary files cannot be transferred correctly. In all
cases, KERMIT-20 will request the other KERMIT to compress repeated characters;
if the other side can do this (not all KERMITs know how) there may be a
significant improvement in transmission efficiency.
When running locally and receiving files, you can attempt to cancel the
current file by typing Control-X; this sends a cancellation request to the
remote KERMIT. If the remote KERMIT understands this request, it will comply;
otherwise it will continue to send. If a file group is being sent, you can
request the entire group be cancelled by typing Control-Z.
If running as a remote Kermit, you should escape back to your local Kermit and
give the SEND command.
|
; RECEIVE command, cont'd
; Parse a filespec or just confirmation.
.recv: noise <into file> ; First, issue noise word.
movei t1, [
flddb. .cmofi,cm%sdh,,<local output file specification>,,[
flddb. .cmcfm,cm%sdh,,<confirm to use remote 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?
ret ; If not it must be a confirm, so done.
movem t2, filjfn ; Filespec, so save the JFN,
movei t1, [flddb. .cmcfm] ; and parse the confirmation.
call rflde
skipa ; Error, handle it.
ret
; Parse error handler.
skipg t1, filjfn ; Release any JFN.
RLJFN%
erjmp .+1 ; Ignore any errors.
setzm filjfn ; Zero the JFN to indicate we don't have one.
tmsg <?Not confirmed> ; Issue our own parse message
jrst cmder1 ; and get back inside CMD to clean up.
;[57] Resolve debugging status. (This made into a separate routine in edit 57).
;
; Call this routine at the beginning of any packet transaction (send, receive,
; server command, etc).
;
; Returns +1 if there's no debugging going on
; +2 if there is, with the log jfn set up correctly.
;
setlog: jumpe debug, r ; Return nonskip if not debugging.
skipe t1, logjfn ; Yes, has a log file been specified?
jrst [ caie t1, .priou ; Yes, but is it the terminal?
jrst rskp ; No, it's a file, which is always OK.
setzm logjfn ; It's the TTY, so say no log file,
jrst .+1 ] ; and do next bit.
movei t1, .priou ; No log file specified.
skipe local ; If running in local mode,
movem t1, logjfn ; use the terminal.
retskp
; RECEIVE, GET, REMOTE TYPE command execution.
; Initialization -- First, stuff only for when not being a server.
$recv: movei state, "R" ; Start out in receive init state.
; Entry point for server commands.
$recvb: setom $recvf ;[88] Executing RECEIVE command,
setzm $sendf ;[88] not SEND command.
setzm ttildb ;[180] (stats)
setzm ttibin ;[180] (stats)
setzm ttisin ;[180] (stats)
setzm ttimax ;[180] (stats)
call caxzon ;[62] Turn on keyboard interrupts.
hrroi t1, [ ;[61] Tell about terminal interrupts,
asciz/^A for status report, ^X to cancel file, ^Z to cancel batch.
/]
skipe local ;[62] if local.
PSOUT% ;[62]
call inilin ; Initialize the line.
call ccon ; Turn on the ^C trap.
jrst reslin ;[27] On ^C go reset line & return from there.
skipn gotx ; If I don't already have an X packet,
setzm pktnum ; inititialize the packet sequence number.
; Entry point for server.
$recvs: GTAD ; Current date/time for start of transaction.
movem t1, stdat
setzm stot ; Initialize statistics variables.
setzm rtot
setzb schr, stchr
setzb rchr, rtchr
setzm files ;[61] File counter
setom rptot ;[4] Init received-packet counter to -1.
setom sptot
setzm nnak ;[54] Init the number of NAKs
setzm ntimou ;[54] and the number of timeouts.
setzm timerx ;[132] Timer error counter.
setzm errptr ; Zero the error message pointer.
setom bctone ;[98] Force block check type to 1 initially.
skipe autbyt ;[72] Using autobyte?
setzm ebtflg ;[72] If so reset eight-bit-mode flag.
move t1, rpause ;[36] Get the requested receive-pause interval
movem t1, pause ;[36] and make it the current one.
setzm numtry ; Set the number of tries to zero.
$recva: call setlog ;[57] Set up any debugging log.
nop
;...
; RECEIVE command, cont'd
; State Table Switcher
$recv2: cain state, "D" ; Are we in the data receive state?
jrst [ call rdata ; Yes, go read data packets.
jrst $recv2 ]
cain state, "F" ; Are we in the file receive state?
jrst [ 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 [ call rinit ; Call receive initiate.
jrst $recv2 ]
cain state, "C" ; Are we in the receive complete state?
jrst [ movei t1, "C"
move t2, pktnum
call diamsg ;[38]
GTAD% ; Get the time we ended.
subm t1, stdat ; Figure how long it all took.
movei t1, .chbel ;[31] Give a beep
skipe local ;[31] if local
PBOUT ;[31]
jrst $recvz ] ;[88] Done.
cain state, "A" ; Are we in the receive cAncel state?
jrst [ movei t1, "A" ; Print diagnostic message if debugging.
move t2, pktnum ; ...
call diamsg ; ...
GTAD% ; Get the time we ended.
subm t1, stdat ; Figure how long it all took.
call giveup ; Clean up the file if necessary.
jrst $recvz ] ;[88] Done.
movei t1, "U" ; Undefined...
move t2, pktnum
call diamsg
$recvz: call caxzof ;[62] Turn off ^A,^X,^Z traps.
call reslin ;[88] Put the line back the way it was.
setzm $recvf ;[88] RECEIVE command finished.
ret
subttl receive routines
; RINIT -- Receive Initiate; get other side's Send-Init packet.
;
rinit: saveac <q1> ; Save this AC.
skipe gots ; Got the S packet already?
jrst rinit3 ; Yes, don't try to read it.
; Give up if we've tried too many times, otherwise keep trying.
aos q1, numtry ; Increment the number of tries.
caml q1, imxtry ; Have we reached the maximum number of tries?
jrst [ movei state, "A" ; Change the state to cAncel.
kermsg <Can't receive Send-Init>,r ] ;[46]
call rpack ; Try to get a packet.
jrst [ move t2, pktnum ;[53] Failed, NAK the one we want.
callret nak ] ;[53]
; Got a packet. Check the type and take appropriate action.
rinit2: cain t1, "E" ;[32] Error packet?
jrst pxerr ;[82] Yes, print it & cancel.
; Should have the other side's Send-Init packet at this point, with T1-T4
; containing the various pointers, counts, etc.
rinit3: setzm gots ; Clear this flag.
move q1, t1 ; 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.
callret nak ] ; Just NAK the packet we wanted.
movem t2, pktnum ; Yes, synchronize packet numbers.
call spar ; Get what the other side wants us to do.
move t4, [point 8, data] ; Tell the other side what we want
rinit4: call rpar ; it to do, by returning our Send-Init
movei t1, "Y" ; parameters in our ACK to its Send-Init.
move t2, pktnum ; Packet number.
move t4, [point 8, data] ; The address of the data.
call spack ; Send our params in the acknowledgment.
jrst rinitx
rinit5: call rrinit ; Go set things up for receiving.
rinitz: movei state, "F" ; Set the state to file receive.
ret
rinitx: movei state, "A" ; Failed, set state to cAncel.
ret
;[126] Set things up for receiving.
;
; This code is used by RINIT and by XSEND.
;
rrinit: move t2, numtry ; Get the number of tries.
movem t2, oldtry ; Save it.
setzm numtry ; Reset the number of tries.
aos t2, pktnum ; Increment the packet number,
andi t2, 77 ; modulo 100,
movem t2, pktnum ; and save it back.
call ebqmsg ; Maybe print message about 8 bit prefix.
setzm bctone ; Enable fancy block checks.
;[126] Log the beginning of this transaction.
skipe iflg ;[134] Is this an I packet?
ret ;[134] If so, skip logging.
wtlog <-- Receive Begins -->
; The following can be called to log ebq & bct for either send or receive.
rrlog: skipn t1, tlgjfn ; Logging transactions?
jrst rinitz ; No, skip ahead.
hrroi t2, [asciz/ 8th bit prefixing: /]
setzb t3, t4
SOUT
hrroi t2, [asciz/Off/]
skipe ebqflg
hrroi t2, [asciz/On/]
setzb t3, t4
SOUT
hrroi t2, [asciz/
Block check type: /]
SOUT
move t2, bctu
movei t3, ^d10
NOUT
nop
hrroi t2, crlf
setzb t3, t4
SOUT
ret
;[89] EBQMSG
;
;Print warning message if 8th bit prefixing requested but won't be done.
ebqmsg: skipe local ; Local?
jrst [ skipn ebqr ; Yes, wanted 8th bit quoting?
jrst .+1 ; No, so no message will be needed.
hrroi t1, [asciz/
%Warning: Other side won't do 8th-bit prefixing.
%Binary files will not be transmitted correctly.
/] ; Yes,
skipn ebqflg ; will other side do it?
PSOUT ; No, warn.
jrst .+1 ]
ret
; RFILE - Receive File Header
rfile: saveac<q1>
setzm cxseen ;[62] Zero ^X,^Z flags, since they apply
setzm czseen ;[62] on a per-file basis.
setzm bctone ;[99] Can't hurt... (but why do we need it????)
move q1, numtry ; Have we reached the maximum number of tries?
caml q1, maxtry ; ...
jrst [ movei state, "A" ; Yes, change the state to cAncel.
kermsg <Can't receive File-Header>,r ]
aos numtry ; No, count this try.
skipe gotx ;[112] Already got an "X" packet?
jrst rfil3t ;[112] Yes, so don't need to get one.
call rpack ; Try to get a packet.
jrst [ move t2, pktnum ;[53] Failed, NAK the one we want.
callret nak ] ;[53]
rfile1: caie t1, "S" ; Got a packet. What's the type?
jrst rfile2 ; Send-Init? Missed our previous ACK?
rfil1a: move q1, oldtry ; Yes, Send-Init. Get the number of tries.
caml q1, imxtry ; How many times have we tried to ACK this?
jrst [ movei state, "A" ; Too many, change the state to cAncel.
kermsg <Too many Send-Inits>,r ]
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?
ret ; No, fail, stay in this state, keep trying.
setzm numtry ; OK, it's the Send-Init again.
move t4, [point 8, data] ;[50] ...
call rpar ; Put our parameters in it.
movei t1, "Y" ; Send the ACK with our parameters again.
move t2, pktnum ;[47] Not for the current packet,
sos t2 ;[47] but the previous one.
call spack ; ...
jrst @[exp rfil1a, rinitx](t1) ; Handle failures.
ret
;...
; RFILE, Cont'd
rfile2: caie t1, "Z" ; Is the packet an EOF packet?
jrst rfile3 ; No, try something else.
rfil2a: move q1, oldtry ; Yes, EOF. How many ACKs have we sent?
caml q1, maxtry ; Too many?
jrst [ movei state, "A" ; Yes, change the state to cAncel.
kermsg <Can't ACK EOF in RFILE>,r ]
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?
ret ; No, then hold out for right one.
setzm numtry ; OK, it's the previous packet again.
movei t1, "Y" ; Restart count, and re-ACK it.
setzb t3, t4 ; No data.
call spack ; Send the packet.
jrst @[exp rfil2a, rfil2x](t1)
ret
rfil2x: movei state, "A" ; Set state to cAncel.
ret
; Process the remote file header
rfile3: came t2, pktnum ; Packet number OK?
ret ; No, hold out for the right one.
;[104] Begin change for receiving "X" packets.
cain t1, "F" ; Start of file?
jrst rfil3k ; Yes.
caie t1, "X" ; Text header?
jrst rfile4 ; No.
rfil3t: setzm gotx ;[112] Reset this flag.
setom filjfn ; Yes, indicate this way.
skipn local
;[177] jrst [ movei state, "A"
;[177] kermsg <Can't receive screen text in remote mode>, r ]
jrst rfil3c ;[177] Let it come, just don't print it.
; Local, print the file name on the screen.
hrroi t1, [asciz/
/]
PSOUT
move t1, t4
PSOUT
erjmp .+1
hrroi t1, crlf
PSOUT
jrst rfil3c ; Skip past file opening stuff.
;[104] End change.
;...
; RFILE, Cont'd
; Come here with normal file header.
rfil3k: move t1, t4 ; Got the header we want, point to filename.
move t2, t3 ; Get the length of the filename string.
call makfil ; Go get JFN on it.
jrst [ movei state, "A" ; Can't, set state to cAncel.
ret ] ; MAKFIL has already issued appropriate E pkt.
movem t1, filjfn ; All OK, save the JFN.
; Open the file.
setzm itsfil ;[75] Assume not ITS binary file.
setzm itscnt ;[75] Init counter for header char matching.
move t1, filjfn ; Open the file.
movx t2, fld(36,of%bsz)!of%wr ; 36-bit bytes, write access.
OPENF% ; Open the file (fix bytesize later).
%jsker <Can't open file>, rfil3a ;[42] Send this + JSYS error msg.
wtlog <Opened: >,filjfn ;[126]
jrst rfil3b ;[42] Opened OK, skip error handling.
; Come here if the file can't be opened.
rfil3a: skipe t1, tlgjfn ;[126] Log this failure in transaction log.
jrst [ wtlog <Can't Receive >,filjfn
hrroi t2, [asciz/ Because: /]
setzb t3, t4
SOUT
hrloi t2, .fhslf ; Tell why.
setz t3,
ERSTR
nop
nop
hrroi t2, crlf
setzb t3, t4
SOUT
jrst .+1 ]
move t1, filjfn ; Get the output JFN.
RLJFN% ; Release it.
nop ;[33] Ignore any error.
setzm filjfn ; Clear the JFN.
movei state, "A" ; Change state to cAncel.
ret
;...
; RFILE, Cont'd...
;[66] If outputting to a file, set up the mapping page pointers.
rfil3b: skiple filjfn ;[66] JFN on a file?
jrst [ move t1, [point 7, mappag*1000] ;[66] Yes, point to page.
skipe ebtflg ;[66] Eight bit mode?
hrli t1, (point 8,) ;[66] Then use 8-bit bytes.
movem t1, pagptr ;[66] Save it here.
setzm pagno ;[66] Begin at file page zero.
jrst .+1 ]
; If running locally, echo filename to screen.
movei t1, 7 ;[66] Remember file byte size for reporting.
skipe ebtflg ;[66] (this may be revised later because
movei t1, 8 ;[66] of ITS binary headers or similar...)
movem t1, bytsiz ;[66]
setom rcving ;[62] Indicate we're receiving a file.
skipn local ;[12] Local Kermit?
jrst rfil3c ;[12] No, no terminal messages necessary.
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]
nop ;[12]
movei t1, " " ;[12]
PBOUT% ;[12]
; ACK file header, initialize counters and go into Receive-Data state.
rfil3c: movei t1, "Y" ; Acknowledge the packet.
move t2, pktnum ; This packet number.
setzb t3, t4 ; No data.
call spack ; Send the packet.
jrst rfil3x
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.
aos t2, pktnum ; Increment the packet number,
andi t2, 77 ; modulo 100,
movem t2, pktnum ; and save it back.
setz rchr, ;[128] Initialize file character counter.
movei state, "D" ; Set the state to file send.
ret
rfil3x: movei state, "A" ; On fatal errors, set the state to cAncel.
ret
;...RFILE, cont'd
; It wasn't a File Header or EOF packet; check for other possibilities.
rfile4: caie t1, "B" ; End of transmission?
jrst rfile5 ; No.
came t2, pktnum ; Yes, but is it the right packet number?
ret ; No, hold out for the right one.
movei t1, "Y" ; All OK, acknowledge the EOT packet.
setzb t3, t4 ; No data.
call spack ; Send the packet.
skipa state, "A"
movei state, "C" ; Sent ok, set state to Complete.
move t1, netjfn ;[158] Wait until the packet
DOBE ;[158] gets all the way out.
erjmp .+1 ;[158]
skiple filjfn ;[126] Were we writing to a file?
wtlog <Receive Complete> ;[126] Yes, record in transaction log.
ret
rfile5: cain t1, "T" ; Timer interrupt pseudo packet?
jrst [ move t2, pktnum ; Yes, NAK the expected packet.
callret nak ]
cain t1, "E" ;[82] Error packet?
jrst pxerr ;[82] Yes, print it & cancel.
rfilex: ret ;[46] Something else, just hold out...
; RDATA -- Receive Data state.
rdata: saveac <q1,q2> ; Save these
aos q1, numtry ;[42] Too many tries for this packet?
camle q1, maxtry ;[42]
kermsg <Retry count exhausted in RDATA>, rdterr
call rpack ; Get a packet.
jrst [ move t2, pktnum ;[53] Failed, NAK the one we want.
callret nak ] ;[53]
caie t1, "D" ; Got one. Data packet?
jrst rdata3 ;[42] No, go see what it is.
came t2, pktnum ; Yes, but is it the right data packet?
jrst rdata2 ; No.
; Process a normal data packet.
rdok: move t1, t4 ; Got the one we want, point to data.
move t2, t3 ; Get the length of the data.
call putbuf ;[66] Write the buffer to the output file.
kermsg <Can't write to file>,rdterr ; This error is always fatal.
movei t1, "Y" ; No error, acknowledge the packet we got.
move t2, pktnum ; This sequence number.
setzb t3, t4 ; Assume no data.
skipn cxseen ;[62] Was ^X typed?
skipe czseen ;[62] Or ^Z?
jrst [ move t3, [byte(8)"Z",0] ;[62] Yes, put a "Z"
skipn czseen ;[62] or
move t3, [byte(8)"X",0] ;[62] an "X" in the
movem t3, data ;[62] data field of the ACK
movei t3, 1 ;[62] (length of data is 1)
move t4, [point 8, data] ;[62] and point to it.
jrst .+1 ] ;[62]
call spack ; Send the packet.
jrst @[exp r, rdterr](t1) ;[60] Handle fatal & nonfatal errors.
move t2, numtry ; Get the number of tries.
movem t2, oldtry ; Save it.
setzm numtry ; Reset the number of tries.
aos t2, pktnum ; Increment the packet number,
andi t2, 77 ; modulo 100,
movem t2, pktnum ; and save it.
ret
;...
; RDATA, cont'd
; Got a data packet, but it's the wrong one.
rdata2: move q1, oldtry ; Get the number of tries.
caml q1, maxtry ; Have we reached the maximum number of tries?
kermsg <Too many retries in RDATA2>,rdterr ; Yes.
aos oldtry ; Not too many, update 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 it the previous packet?
ret ;[46] No, fail, don't change state, retry.
setzm numtry ; Yes, previous packet; start count over.
movei t1, "Y" ; Acknowledge it again.
setzb t3, t4 ; No data.
call spack ; Send the ACK.
jrst @[exp r, rdterr](t1) ;[60] Handle fatal & nonfatal errors.
ret ; Otherwise return OK.
rdata3: caie t1, "F" ; File header?
jrst rdata4 ; Nope, try something else.
caie t1, "X" ; Text header?
jrst rdata4 ; Not that either.
move q1, oldtry ; Yes, "F" or "X". Get the number of tries.
caml q1, maxtry ; Have we reached the maximum number of tries?
kermsg <Can't ACK file header in RDATA3>,rdterr ; Yes, quit.
aos oldtry ; Not yet, update 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?
ret ;[46] No, fail, don't change state, retry.
setzm numtry ; Yes, so start count over.
movei t1, "Y" ; Acknowledge the file header again.
setzb t3, t4 ; No data.
call spack ; Send the packet.
jrst @[exp r, rdterr](t1) ;[60] Handle fatal & nonfatal errors.
ret ; else try again to get data.
; RDATA, cont'd
; End Of File.
rdata4: caie t1, "Z" ; Is it an EOF?
jrst rdata5 ; No, try next thing...
came t2, pktnum ; Yes, is the packet number correct?
ret ;[46] No, ignore this packet, keep trying.
jumpn t3, [ ; Was there any data in the EOF packet?
ildb t3, t4 ; Yes, see what it is.
caie t3, "D" ; Code for Discard the file?
jrst .+1 ; No, proceed.
call giveup ; Yes, go "close/cancel" this one,
jrst rdat5a ] ; and then proceed normally.
call rdclos ;[42] Not discarding, close the file normally.
jrst rdterr ;[174] If can't give up.
rdat4a: aos files ;[61] Count the file.
hrroi t1, [asciz/[OK]/] ;[19] Closed the file OK, make comforting msg.
skipe local ;[19] Print it if local.
PSOUT% ;[19]
rdat5a: movei t1, "Y" ; Acknowledge the eof packet.
move t2, pktnum
setzb t3, t4 ; normally (no data).
call spack ; Send the ACK.
nop ; On any error, just forge ahead.
addm rchr, rtchr ; Add character count for this file to total.
setz rchr, ; Reset for next file.
move t2, numtry ; Get the number of tries.
movem t2, oldtry ; Save it.
setzm numtry ; Reset the number of tries.
aos t2, pktnum ; Increment the packet number,
andi t2, 77 ; modulo 100,
movem t2, pktnum ; and save it.
movei state, "F" ; Change state to "F"
ret ; and go back to the state switcher.
; Come here if there was a timeout or error.
rdata5: 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 ; Try to send it.
jrst rdterr ;[46] Can't, set state to cAncel.
ret ] ; Return to state switcher.
cain t1, "E" ;[82] Error packet?
call pxerr ;[82] Yes, print it, then fall thru...
;...
;...RDATA (cont'd)
; Handler for fatal errors reading/storing data, cancels the transfer.
rdterr: call giveup ; Go clean up the file.
movei state, "A" ; Change the state to cAncel.
ret
; Come here to close a partially received file. It will be discarded or
; kept, depending on setting of ABTFIL, i.e. SET INCOMPLETE (FILE DISPOSTION).
;
giveup: skipe abtfil ;[134] Do we discard or keep?
jrst [ wtlog <Incomplete File Kept: >, filjfn ;[134] Keep.
hrroi t1, [asciz/[keeping partial file]/]
skipe local
PSOUT
call rdclos ; Go close as much of it as we have.
jrst .+1 ; Discard it if we have some problem.
ret ] ; Closed partial file OK.
wtlog <Incomplete File Discarded: >,filjfn ;[126] Discard.
hrroi t1, [asciz/[discarding]/] ; Say what we're up to.
skipe local ; Print message if local.
PSOUT ;
skipg filjfn ; Real file?
jrst givexx ; If not, done.
call unmapo ; Go unmap the file
nop ; Don't worry if we can't.
hrrz t1, filjfn ; Clear out any junk from left half.
txo t1, cz%abt ; Discarding, so cancel the file.
CLOSF% ; Close it.
erjmp [move t1, filjfn ; On any error,
RLJFN ; at least try to release the JFN.
erjmp givexx ; ...
jrst givexx ]
givexx: setzm filjfn ; Say we have no file.
ret
; UNMAPO - Clean up the file mapping page for an output file.
;
; Returns +1 on failure, +2 on success.
; On failure, an error packet is sent, which cancels the transfer.
;
; Uses t1,t2,t3.
;
; Note that unmapping the memory page also makes it disappear. The next write
; to the page will create a fresh page with all 0's.
;
; The trick at the beginning catches the case where the page has already been
; unmapped because we just filled in the last byte. Since this routine is
; called both by the page filler (PUTCH) and by the file closer (RDCLOS, to
; catch a final partial page), we must worry about files that end on a page
; boundary. Putting an ERJMP after any instruction that references memory will
; catch "illegal memory read" errors, and will thus prevent us from attempting
; to unmap a page that has already been unmapped and still has not been
; written into.
unmapo: move t1, mappag ;[66] Has the page been used at all?
erjmp rskp ;[66] No, done.
movx t1, <.fhslf,,mappag> ; Yes, map them out, our fork,,mapping page
hrl t2, filjfn ; file JFN,,...
hrr t2, pagno ; ...page file page number.
movx t3, pm%rd!pm%wr ; Read and write access.
PMAP% ; Map it out.
%jsker (,r) ; Can't - fail.
retskp
; RDCLOS -- Close the output file, update the FDB, etc...
; Return +1 on error, +2 on success.
rdclos: skipg filjfn ;[103] Output was to a real file?
jrst rdclsz ;[103] No, skip all this.
call unmapo ; First, clean out the PMAPping page.
ret ; Oops, failed, pass it along...
; Now close the file.
rdclsa: movx t1, co%nrj ; Flag for not releasing JFN.
hrr t1, filjfn ; Get the JFN.
CLOSF% ; Close it.
%jsker <Can't close file>,r ; Return error.
; Update FDB information about byte size, number of bytes.
hrli t1, .fbsiz ; OK, now fix FDB. Set the number of bytes
txo, t1, cf%nud ; Don't update disk yet.
hrr t1, filjfn ; Move in the JFN.
seto t2, ; Change all bits in the word.
move t3, rchr ; The number of bytes in the file.
CHFDB%
erjmp .+1 ; Keep going if we get an error.
rdclsb: hrli t1, .fbbyv ; Set the byte size.
hrr t1, filjfn
movx t2, fb%bsz ; Byte size field mask.
movx t3, fld(7,fb%bsz) ; Value
skipn itsfil ;[75] ITS binary file?
skipe ebtflg ; Or eight-bit mode?
movx t3, fld(8,fb%bsz) ; Set it that way, then.
ldb t4, [pointr (t3,fb%bsz)] ; Get the bytesize in t4 as a number.
CHFDB%
erjmp .+1 ; Keep going if we get an error.
;...
;...RDCLOS, cont'd
;[126] Take care of any transaction logging.
skiple filjfn ; Real file?
skipg t1, tlgjfn ; Transaction log?
jrst rdclsc ; No, skip this.
hrroi t2, [asciz/ Written: /] ; Yes, log this info.
push p, t4
setzb t3, t4
SOUT
erjmp .+1
move t2, rchr ; Number of bytes.
movei t3, ^d10
NOUT
erjmp .+1
movei t2, 40 ; A space
BOUT
erjmp .+1
pop p, t2 ; Byte size
NOUT
erjmp .+1
hrroi t2, [asciz/-bit bytes
/]
setz t3,
SOUT
erjmp .+1
; Finish closing the output file by releasing its JFN.
rdclsc: skiple filjfn ;[126]
wtlog <Closed: >,filjfn ;[126] Transaction log message.
hrrz t1, filjfn ; Release the JFN.
RLJFN%
nop
rdclsz: setzm filjfn ; Say we have no more file.
retskp
subttl Utility protocol routines
; SPAR - Get the arguments from a Send-Init packet.
;
;[47] Substitute them for our own unless we have given our own SET commands.
;[47] The way this is done here is less than perfect, but will work most of
;[47] the time (it won't work if the user SETs a value to be the same as the
;[47] default, or if the remote sends different parameters each time, or...
;[47] But it's better than it was before. If it becomes an issue, we can
;[47] add flags for each value saying who changed it, and figure out when
;[47] to set it back to the default, etc...
;
;[50] Call with:
;[50] t3/ Length of Send-Init packet data field (number of parameters)
;[50] t4/ Pointer to Send-Init packet data field.
;[50] The ACs t3-t4 are automatically set up this way upon return from RPACK,
;[50] provided nothing has been done to them before calling SPAR.
;
spar: saveac<q1> ;[48]
; Packet Size
spar1: move t2, spsiz ;[168] Get current setting.
sojl t3, spar1a ;[100] Make sure the field is in packet.
ildb t2, t4 ; It is, get it.
subi t2, " " ; Convert it to a number.
spar1a: move q1, spsiz ;[47] See what we have now.
caie q1, dspsiz ;[47] Has default been changed already?
jrst spar2 ;[47] Yes, probably by SET command, keep that.
caige t2, spmin ;[47] No, check bounds for new value.
movei t2, spmin ;[47] If too small, use our minimum.
caile t2, spmax ;[47] Or if too great,
movei t2, spmax ;[47] use our maximum value.
movem t2, spsiz ; Set the maximum packet size to send.
; Timeout.
spar2: move t2, stimou ;[168] Get current setting.
sojl t3, spar2a ;[100] Got a packet field for this?
ildb t2, t4 ; Yes, get it.
subi t2, " " ; Convert the character to a number.
spar2a: skipge t2 ;[49][168] Make sure it's
setz t2, ;[43] not negative.
move q1, stimou ;[47] Has the default already been changed,
caie q1, dstim ;[47] for instance, by a SET command?
jrst spar3 ;[47] Yes it has, so let that take precedence.
cain t2, rtimou ;[131] Same as other side's timeout?
aos t2 ;[131] If so, make it a little bit different.
movem t2, stimou ; Set the time out interval.
movem t2, otimou ;[26] Here too, in case we want to change it.
;...
; SPAR, cont'd
; Padding
spar3: move t2, spadn ;[100][168] Set up default.
sojl t3, spar3a ;[100] Make sure the field is there.
ildb t2, t4 ; Get the 3rd field.
subi t2, " " ; Convert it to a number.
spar3a: move q1, spadn ;[47][168] Check if default already changed.
caie q1, dspadn ;[47]
jrst spar4 ;[50] It has, don't do this.
skipge t2 ;[50] Make sure the number makes sense.
movem t2, spadn ;[50] OK, set the padding.
; Pad character
spar4: move t2, spadch ;[100][168] Set up default.
sojl t3, spar4a ;[100] Make sure the field is there.
ildb t2, t4 ; Get the 4th field.
addi t2, ^o100
andi t2, ^o177
spar4a: move q1, spadch ;[47][168] Check for default already changed.
caie q1, dspad ;[50]
jrst spar5 ;[50]
cain t2, 177 ;[50] DEL?
jrst spar4a ;[50] Yes, can use it.
cail t2, 0 ;[50] No, some other control character?
caile t2, 37 ;[50] ...
skipa ;[50] Nope, reject it.
movem t2, spadch ; OK, set the padding char.
; End Of Line
spar5: move t2, seolch ;[168] Set up default.
sojl t3, spar5a ;[100] Make sure the field is there.
ildb t2, t4 ; Get the 5th field.
subi t2, " " ; Convert it to a number.
spar5a: move q1, seolch ;[47][168] Default changed already?
caie q1, dseol ;[47]
jrst spar6 ;[50] Yes, so don't do this.
cail t2, 0 ;[50] No, did they give a control character?
caile t2, 37 ;[50] ...
skipa ;[50] Nope, reject it.
movem t2, seolch ; OK, in range, set the EOL character.
; Control Prefix
spar6: move t2, rquote ;[168][132][100] Get current setting.
sojl t3, spar6a ;[100] Make sure the field is there.
ildb t2, t4 ; Get the 6th field.
spar6a: move q1, rquote ;[168][132][47] Default already changed?
caie q1, drquot ;[132][50]
jrst spar7 ;[50] Yes, don't change it again.
caile t2, " " ;[50] No, check for printable character
caile t2, "~" ;[50] other than space.
skipa ;[50] Out of range, reject it.
movem t2, rquote ;[132] OK, set the quote character.
;...
;...SPAR, cont'd
; [88] 8th-bit prefix support added as edit 88.
spar7: sojl t3, spar7x ; Did they give one? If not, do default.
ildb t2, t4 ; They did, get it.
caie t2, "Y" ; Is it WILL?
jrst spar7a ; No, go check for WON'T.
; Other side sent "Y" (WILL).
skipe ebqr ; Did our user request prefixing?
jrst [ move t2, ebq ;[89] Yes, use the specified prefix.
movem t2, ebqfld ; Put it here to be sent to other side.
setom ebqflg ; Flag that we're doing this.
cain t2, "N" ; But did she request NOT to do it?
setzm ebqflg ; In that case, don't.
jrst spar8 ]
jrst spar7x ; Didn't request it, so DON'T.
; Other side sent "N" (WON'T).
spar7a: cain t2, "N" ; Is it WON'T?
jrst spar7x ;[89] Yes, so DON'T.
; Not "Y" or "N". See if it's a valid prefix character.
spar7b: call prechk ; Call the prefix checking routine.
jrst spar7x ; It's not valid.
; Other side sent valid prefix character.
spar7c: skipe $sendf ;[89] Sending?
jrst [ camn t2, ebq ;[89] Yes, matches what we said?
jrst spar7d ;[89] Yes, go ahead.
move q1, ebqfld ;[89] No, but...
caie q1, "Y" ;[89] if this was "Y", then it's still OK.
jrst spar7x ;[89] Otherwise, forget it.
jrst .+1 ] ;[89]
; Got &/Y, Y/&, or &/& combination, so may be OK to do 8-bit prefixing.
spar7d: caie t2, rquote ; Same as one of the control quotes?
cain t2, squote
jrst [ movei t2, "N" ; One of those, must refuse.
jrst spar7y ]
movem t2, ebq ; Unique, so save it as the 8b prefix.
movei t2, "Y" ; Acknowledge that we will use it.
movem t2, ebqfld ; ...
setom ebqflg ; Set the flag saying we must do this.
jrst spar8 ; On to next field.
; Field was none of the above. Take default action.
spar7x: movei t2, "Y" ; What we normally say.
spar7y: movem t2, ebqfld ; Put it where RPAR can find it.
setzm ebqflg ; No 8th-bit prefixing.
; [88] (End of addition) ....
;...SPAR, cont'd
;[98] Block check type. (This section added as part of edit 98)
spar8: movei t2, "1" ;[100] Set default, in case this field omitted.
sojl t3, spar8a ;[100] See if there is one.
ildb t2, t4 ; Here it is...
cail t2, "1" ; Between 1
caile t2, "3" ; and 3?
movei t2, "1" ; No, substitute default value.
skipe $sendf ; I'm sending?
jrst [ came t2, bctr ; Yes, does this match what I requested?
movei t2, "1" ; No, so fall back to default.
jrst .+1]
spar8a: movem t2, bctr ; Save as block check type requested.
subi t2, "0" ; Convert to a number 1-3,
movem t2, bctu ; and save as block check type to be used.
;...SPAR, cont'd
; [92] Repeat count prefix support added as edit 92.
spar9: sojl t3, spar9x ; If they didn't give one, don't do this.
ildb t2, t4 ; They did, see what it is.
; Is it a valid prefix character?
spar9b: call prechk ; Call the prefix checking routine.
jrst spar9x ; It's not valid.
; Other side sent valid prefix character.
spar9c: skipe $sendf ; I'm sending?
jrst [ caie t2, rptq ; Yes, see if theirs matches what I said.
jrst spar9d ; It does, proceed.
jrst spar9x ] ; It doesn't, don't do repeat counts.
; Got a valid prefix, but make sure it's not already in use.
spar9d: caie t2, rquote ; Same as one of the control quotes?
cain t2, squote
jrst spar9y
skipe ebqflg ; Doing 8th-bit prefixing?
caie t2, ebq ; Yes, check that prefix too.
skipa ; It's OK.
jrst spar9x ; It's the same, don't do repeat counts.
; OK, it's valid, it's unique.
spar9e: movem t2, rptq ; Save it as what we'll be using.
movem t2, rptfld ; What we'll reply, in case we're receiving.
setom rptflg ; Set the flag.
jrst spar10 ; Go on to next field.
; Come here if we're not going to do repeat counts.
spar9x: movei t2, " " ; Blank means default which is no repeat count.
spar9y: movem t2, rptfld ; Put it here to reply in case we're receiving,
setzm rptflg ; and flag that we're not going to do it.
; [92] (End of addition)
;...
;...SPAR, cont'd
; [ 179] Capabilities mask, window size (not supported), and long packet size.
spar10: sojl t3, sparx ; [179] This field present?
ildb t2, t4 ; [179] Yes, get it.
subi t2, " " ; [179] Convert it to a number.
trnn t2, 2 ; [179] Long Packets capability on?
jrst sparx ; [179] No, done.
sojl t3, sparx ; [179] Skip Window size
ildb t2, t4 ; [179] ...
sojl t3, sparx ; [179] Big part
ildb t1, t4 ; [179] ...
subi t1, " " ; [179] Convert it to a number.
imuli t1, ^d95 ; [179] ...
sojl t3, sparx ; [179] small part
ildb t2, t4 ; [179] ...
subi t2, " " ; [179] Convert to number
add t1, t2 ; [179] Add to big part
movem t1, spsiz ; [179] New packet length.
; Exit. Set up maximum data field size based on what transpired above.
sparx: move t1, spsiz ; Get the send packet size.
subi t1, 4 ; Deduct the constant overhead,
sub t1, bctu ; and the length of the checksum.
subi t1, 2 ; Room to leave at end: 2 for possible #X,
skipe rptflg ; and if doing repeat counts,
subi t1, 2 ; another 2 for repeat prefix,
skipe ebqflg ; and if doing 8th-bit prefixing,
subi t1, 1 ; another one for that.
movem t1, maxdat ; Save max length for data field here.
ret
; PRECHK - Check if character in T2 is valid prefix character.
; Return +1 if not, +2 if it is.
;
prechk: cail t2, ^d33 ; Is it in the 33-62 range?
caile t2, ^d62
skipa ; No, see if it's in the high range.
retskp ; Yes, it's in range.
cail t2, ^d96 ; Or in the 96-126 range?
caile t2, ^d126
ret ; No, something else, not a valid prefix.
retskp ; Yes, it's valid.
; RPAR
;
; Sets up the data field of an init packet with the our own parameters,
; which we want the other side to honor.
;
; Call with:
; t4/ Pointer to data field for S or I packet, or its ACK.
; EBQFLD contains the character to send in the 8-bit-quote field.
; Returns with:
; t3/ Length of data field (number of elements).
; t4/ Original pointer to data field.
; The ACs t3-t4 are returned suitably for a call to SPACK.
;
rpar: saveac <t1,t2,t4,q1> ; Save temp ACs, and t4 for return.
move q1, rpsiz ; 1 Get the packet size.
caile q1, ^d94 ; Fix to compare correctly.
movei q1, ^d94 ;[179] Yes, make it 94.
addi q1, " " ; Make the char printable.
idpb q1, t4 ; Put it in the data block.
;[128] Tell the other side how to time out, based on the current 15-min ldav.
movei t1, 2 ; Request 15-minute load average.
call ldav
move t2, rtimou ; Other side use this timeout when I'm recving.
cain state, "S" ;[131] But am I sending?
subi t2, 2 ;[131] Make it a little different.
call adjtim ; Adjust based on load average.
movem t2, rrtimo ; Save time for reporting.
addi t2, " " ; Make it printable.
idpb t2, t4 ; Put it in the data block.
; Easy fields...
move q1, rpadn ; 3 Get the padding.
addi q1, " " ; Make the char printable.
idpb q1, t4 ; Put it in the data block.
move q1, rpadch ; 4 Get the padding char.
addi q1, ^o100 ; De-controllify it.
andi q1, ^o177 ;
idpb q1, t4 ; Put it in the data block.
move q1, reolch ; 5 Get the EOL char.
addi q1, " " ; Make the char printable.
idpb q1, t4 ; Put it in the data block.
move q1, squote ; 6 [132] Get the quote char.
idpb q1, t4 ; Put it in the data block.
move q1, ebqfld ; 7 Say what we'll do about 8th-bit quoting.
idpb q1, t4 ; Put in the data block.
move q1, bctr ; 8 Block check type requested.
idpb q1, t4 ; Put in the data block.
move q1, rptfld ; 9 The repeat-count-prefix field.
idpb q1, t4 ; Put in the data block.
; [179] Capabilities mask
movei q1, 2 ; [179] 10 Set long-packet capability bit
addi q1, " " ; [179] Convert to ASCII
idpb q1, t4 ; [179] Deposit in packet
movei t3, ^d10 ; [179] Ten bytes of data so far
move q1, rpsiz ; [179] RECEIVE PACKET-LENGTH
caig q1, ^d94 ; [179] Regular (short) packet?
ret ; [179] Done.
; [179] Long packets requested
movei q1, " " ; [179] Window size is 0 (no sliding windows)
idpb q1, t4 ; [179] Deposit
aos t3 ; [179] Count
move q1, rpsiz ; [179] RECEIVE PACKET-LENGTH
idivi q1, ^d95 ; [179] Big part (quotient)
addi q1, " " ; [179] Convert to ASCII
idpb q1, t4 ; [179] Deposit
aos t3 ; [179] Count
addi q2, " " ; [179] Small part (remainder)
idpb q2, t4 ; [179] Deposit
aos t3 ; [179] Count
ret ; Done
; Miscellaneous small routines for NAKs & Error packets.
; Send a NAK. Expects to find the packet number to NAK in AC2.
nak: stkvar <naktry> ; Counter for NAKs.
setom naktry
nak2: aos t1, naktry ; Count this try.
camle t1, maxtry ; Less than maximum?
jrst nakx ; No, fail.
movei t1, "N" ; Send a NAK.
setzb t3, t4 ; No data.
call spack ; Send the packet.
jrst @[exp nak2, nakx](t1) ; Handle failures.
aos nnak ; Sent the NAK OK, count it.
ret
nakx: movei state, "A" ; If we can't, set state to cancel.
ret
; Print the contents of an error packet, if local.
;
; t1-t4 contain the packet parameters from RPACK.
; Sets state to cAncel.
; Returns +1 always.
pxerr: movei state, "A" ; Set state to cAncel.
skipe iflg ; Doing Info packet?
ret ; Skip this.
movem t4, errptr
hrroi t1, [asciz/?Remote error -- /] ; Yes, print message.
PSOUT%
move t1, errptr ; Get pointer to it,
PSOUT% ; and print it.
;[126] Print the error in the transaction log too.
skipn t1, tlgjfn ; (if any)
ret
wtlog <Transaction Cancelled by Error from Other Kermit:>
move t2, errptr
setzb t3, t4
SOUT
hrroi t2, crlf
SOUT
ret
subttl SEND command
; Help text.
hsend: asciz |
SEND filespec (AS) [target-name]
SEND wild-filespec1 (INITIAL) [initial-file]
Send a file or file group from the DEC-20 to the other host. If the filespec
contains wildcard characters (* or %) then all matching files will be sent, in
alphabetical order by name. If a file can't be opened for read access, it will
be skipped. 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 or similar name.
If a single file is specified, you may optionally specify a diffent name for it
"target-name") to be sent in the file header packet. This name is not parsed;
it is sent to the other system as is, except any lowercase letters are raised
to upper case.
If a wildcard file group is specified, you may optionally specify an initial
file to send. 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 displayed for every 5 data packets
sucessfully sent, and a "%" for every retransmission or timeout that occurs
you may also elect other typeout options with the SET DEBUG command). If you
see many "%" characters, you are probably suffering from a noisy connection.
You can type Control-A at any point during the transfer to get a brief status
report.
When running locally and sending files, you can cancel (stop sending) the
current file by typing Control-X. If sending a file group, Control-X will
cause the current file to be skipped, and KERMIT-20 will go on to the next
file. Control-Z will cancel sending the entire group and return you to
KERMIT-20 command level.
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.
If communication line parity is being used, KERMIT-20 will request that the
other KERMIT accept a special kind of prefix notation for binary files. This
is an advanced feature, and not all KERMITs have it; if the other KERMIT does
not agree to use this feature, binary files cannot be sent correctly. This
includes executable programs, relocatable object modules, files with EDIT line
sequence numbers (as produced by EDIT, SOS, or OTTO), etc.
KERMIT-20 will also ask the other KERMIT whether it can handle a special prefix
encoding for repeated characters. If it can, then files with long strings of
repeated characters will be transmitted very efficiently. Columnar data,
highly indented text, and binary files are the chief beneficiaries.
|
;...SEND command, cont'd
; SEND command parsing.
.send: noise <from files> ; Issue guide words.
move t2, cjfnbk+.gjgen ; Get the JFN flag bits.
txo t2, gj%ifg!gj%old ; Old file(s), allow wild cards.
trz t2, -1 ;[172] Default to most recent generation only.
movem t2, cjfnbk+.gjgen ; Return the JFN flag bits.
setzm cjfnbk+.gjext ;[172] No default extension.
movei t1, [flddb. (.cmfil,cm%sdh,,<input file spec (possibly wild)>,,)]
call rfield ; Parse a file spec or a confirm.
movem t2, pars2 ;[111]
tlnn t2, 770000 ; Any wildcards in it?
jrst [ noise <as> ;[96] No, then let them choose a new name.
movei t1, [ ;[96]
flddb. .cmtxt,cm%sdh,,<Carriage return to send with this name,
or specify file name to use on target system>] ;[96]
jrst .send2 ]
noise <initial> ; Wildcard(s) given, prompt for initial.
movei t1, [flddb. (.cmcfm,cm%sdh,,<Carriage return to send them all>,,[
flddb. (.cmfil,cm%sdh,,<First file to send>)])]
.send2: call rflde ; Parse the field.
jrst .sende ;[63] Handle errors explicitly.
ldb t3, [pointr (.cmfnp(t3),cm%fnc)] ; Get function code.
movem t3, pars3 ;[96] Save it for execution.
cain t3, .cmcfm ; Confirmation?
ret ; Yes, just return.
cain t3, .cmfil ;[96] File?
jrst [ hrrm t2, pars2 ;[117] No, initial filespec - substitute it.
movei t1, [flddb. .cmcfm] ; Get command confirmation.
call rflde
jrst .sende
ret ]
;[96] If they gave an alternate name, copy it out of the atom buffer.
caie t3, .cmtxt ; Text?
jrst .sende ; No, error.
move t1, [point 7, atmbuf] ; Copy the string out of the atom buffer.
move t2, [point 7, buffer]
setzm buffer
call movstu
jumpe t3, [ ; If nothing, act like we parsed a confirm.
movei t3, .cmcfm
movem t3, pars3
ret ]
ret
.sende: move t1, filjfn ; Error - get the JFN.
RLJFN% ; Release it.
erjmp .+1 ; Ignore any errors.
setzm filjfn ; Nullify the JFN.
tmsg <?Not confirmed>
jrst cmder1
; MOVSTU -- Move string routine, uppercasing any lowercase letters.
; Eat any leading whitespace.
; Call with t1/ source pointer
; t2/ destination pointer
; Returns with t1, t2 updated, t3/ character count, t4/ 0.
;
movstu: seto t3, ; Counter, started at -1.
movstx: ildb t4, t1 ; Get a character.
jumpn t3, movsty ; Have we got at least one nonwhitespace?
caie t4, 40 ; No, is this a blank?
cain t4, 11 ; or a tab?
jrst movstx ; One of those, skip it.
movsty: cail t4, "a" ; Convert to upper case if necessary.
caile t4, "z"
skipa
trz t4, 40
idpb t4, t2 ; Copy it.
aos t3 ; Count it.
jumpn t4, movstx ; Everything up to & including the first null.
ret
; SEND command execution.
$send: setom $sendf ;[88] Executing SEND command,
setzm $recvf ;[88] not RECEIVE command.
setzm ttildb ;[180] (stats)
setzm ttibin ;[180] (stats)
setzm ttisin ;[180] (stats)
setzm ttimax ;[180] (stats)
move t1, pars2 ;[111] Get JFN we just parsed.
movem t1, ndxjfn ;[111] Save the wildcard bits here.
hrrzm t1, nxtjfn ;[111] Initialize file lookahead.
call gtnfil ;[111] Get JFN of first file.
ermsg <No files to send>,r ;[111] (if any).
call caxzon ;[59] Turn on ^A,^X,^Z interrupts.
hrroi t1, [ ;[61] Tell about terminal interrupts,
asciz/^A for status report, ^X to cancel file, ^Z to cancel batch./]
skipe local ;[61] (if local).
PSOUT% ;[61]
call inilin ; Initialize the line
call ccon ; and turn on ^C trap.
jrst reslin ;[10] on ^C, go reset line, return from there.
; Entry point for server.
$sends: setzm stot ; Initialize statistics variables.
setzm rtot
setzb schr, stchr
setzb rchr, rtchr
setzm files
setom sptot ;[4] Init the sent-packet counter to -1.
setom rptot
setzm nnak ;[54] Init the number of NAKs
setzm ntimou ;[54] and the number of timeouts.
setzm errptr ; Zero the error message pointer.
setzm timerx ; Timer error counter.
GTAD% ; Get the time we start.
movem t1, stdat ; Save it for statistics.
; Delay to give them time to escape back to other side and say "receive".
skipn srvflg ; Don't delay if server
skipe local ; or if local.
jrst $send1
;...
;...$SEND, cont'd
;[128] Remote, do the requested delay.
move t4, delay ; The specified delay in seconds.
lsh t4, 1 ; Make it half seconds.
$sndxx: sojl t4, $send1 ; Countdown.
movei t1, ^d500 ; Sleep half a second.
DISMS
skipn t1, netjfn ; Got a file transfer jfn?
jrst $sndxx ; No reason why we shouldn't, but...
SIBE ; Anything in input buffer?
skipa
jrst $sndxx
;[128] If user escapes back to micro & types CR to send NAK for packet 0,
; no need to delay any longer -- start sending immediately.
$sndzz: BIN ; Just get first character.
came t2, rsthdr ; Start of packet?
jrst $sndxx ; No, they're probably fumbling w/the keyboard
CFIBF ; Yes, assume it's a NAK for packet 0,
erjmp .+1 ; discard the rest and start sending.
; We can be sending with either a File Header (F) or a Text Header (X).
; XFLG nonzero means X header, XFLG zero means F header.
; If sending with F header, start with the Send-Init, as packet 0.
; If sending with X, we can skip the Send-Init and send X as packet 1.
;
;[124] BUT... If type 2 or 3 block check requested and agreed upon,
;[124] cannot skip Send-Init (even if I packet exchange just occurred).
$send1: movei state, "S" ; Set the state to Send-Initiate.
move t1, bctu ;[124] What kind of block check are we using?
caie t1, 1 ;[124] 2 or 3 character block check?
jrst [ setzm pktnum ;[124] Yes, then must send a Send-Init.
jrst $sendb ] ;[124]
; Type 1 block check. Can obey XFLG.
skipn xflg ; X or F header?
setzm pktnum ; F, so reset packet number.
skipe xflg ; X or F?
movei state, "F" ; If X, go straight into file-sending state.
$sendb: move t1, spause ;[36] Get the requested send-pause interval
movem t1, pause ;[36] and make it the current one.
setzm numtry ; Set the number of tries to zero.
$senda: call setlog ;[57] Set up any debugging log.
nop
; SEND command, cont'd... State Table Switcher:
$send2: cain state, "D" ; Are we in the data send state?
jrst [ call sdata
jrst $send2 ]
cain state, "F" ; Are we in the file send state?
jrst [ call sfile ; Call send file.
jrst $send2 ]
cain state, "Z" ; Are we in the end of file state?
jrst [ call seof
jrst $send2 ]
cain state, "S" ; Are we in the send initiate state?
jrst [ movei t1, "S" ;[100] Packet type for Send-Init.
call sinit ; Call send-initiate routine.
jrst $send2 ]
cain state, "B" ; Are we in the end of send state?
jrst [ call seot
jrst $send2 ]
cain state, "C" ; Are we in the send complete state?
jrst [ movei t1, "C"
move t2, pktnum
call diamsg
call caxzoff ;[59] Turn off keyboard interrupts
call reslin ; Restore the line.
GTAD% ; Get the time we ended.
subm t1, stdat ; Figure how long it all took.
movei t1, .chbel ;[31] Give a beep
skipe local ;[31] if local
PBOUT ;[31]
ret ]
cain state, "A" ; Are we in the send cAncel state?
jrst [ movei t1, "A"
move t2, pktnum
call diamsg ;[38]
call reslin ; Restore the line.
GTAD% ; Get the time we ended.
subm t1, stdat ; Figure how long it all took.
move t1, filjfn ;[134] Last-ditch effort to close the file.
setzm filjfn ;[134]
jumple t1, r ;[134]
CLOSF ;[134]
erjmp r ;[134]
ret ]
movei t1, "U" ; Some undefined state???
move t2, pktnum
call diamsg ;[38]
call caxzof ;[59] Turn off ^A,^X,^Z traps.
call reslin
ret
subttl Send routines
; SINIT: Call with t1/packet type, "S" for Send-Init, "I" for Init-Info.
;
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] Yes.
ermsg <Send-Init not ACK'd>,sinitx
jrst sinitx ] ; Go cancel the transfer
aos numtry ; Save updated number of tries.
movei t4, "Y" ;[88] Say we agree to do 8-bit prefixing.
skipe ebqr ;[88] Did our user explicitly ask for it?
move t4, ebq ;[89] In that case, specify requested prefix.
movem t4, ebqfld ;[88] Put it here.
movei t4, drept ;[92] Want to use this as repeat count prefix.
movem t4, rptfld ;[92] Put it here.
move t4, [point 8, data] ;[50] The address of the data.
call rpar ; Set the information.
move t2, pktnum ; Packet number. T1 already has packet type.
setom bctone ;[98] Force single char checksums.
call spack ; Send the packet.
jrst @[exp r, sinitx](t1) ; Handle errors.
call rpack ; Get a packet.
ret ; Trashed packet don't change state, retry.
sinity: caie t1, "Y" ; Check packet type. ACK?
jrst sinitn ; No, go see if it's a NAK.
came t2, pktnum ; ACK. But is it the right ACK?
ret ; No, don't settle, hold out for right one.
call spar ; Yes, get the information.
setzm numtry ; Reset the number of tries.
aos t2, pktnum ; Increment the packet number,
andi t2, 77 ; modulo 100,
movem t2, pktnum ; and save it.
call ebqmsg ;[89] Go warn if problem w/8-bit prefixing.
setzm bctone ;[98] Finished with initialization.
movei state, "F" ; Set the state to file send.
;[126] Start entry in transaction log.
skipn t1, tlgjfn ; (if any)
ret
skipe iflg ; Not an I packet, is it?
ret
wtlog <-- Send Begins -->
callret rrlog ; Go log details.
sinitn: cain t1, "N" ;[30][54] NAK?
aosa nnak ;[54] Yes, count it & return.
sinitt: cain t1, "T" ; Timer interrupt pseudo packet?
ret ;[30] One of those, just keep trying.
cain t1, "E" ; But also print message if error packet.
jrst pxerr ;[82]
sinitx: movei state, "A" ; Anything else, just cancel.
ret
; SFILE - Send File Header
sfile: setzm bctone ; Don't require single-character checksum.
setzm cxseen ; Zero these here, since they apply on
setzm czseen ; on a per-file basis.
move t1, numtry ; Get the number of tries.
caml t1, maxtry ; Have we reached the maximum number of tries?
jrst [ movei state, "A" ; Change the state to cAncel.
kermsg <Can't send file header>, r ]
aos numtry ; No, count this try.
jumpg t1, sfild3 ; After first try, skip opening file, etc.
sfilea: skipn local ;[12] Local Kermit?
jrst sfileb ;[12] No, skip this.
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, pars3 ;[96] Did we have another name to use?
cain t1, .cmtxt ;[96]
jrst [ tmsg < as > ;[96] Yes, say what it was.
hrroi t1, buffer ;[96]
PSOUT ;[96]
jrst .+1] ;[96]
movei t1, " " ;[12] Leave a space.
PBOUT% ;[12]
;...
; SFILE, cont'd
sfileb: skipn source ; Are we getting data from a file?
jrst sfilb2 ; Yes, go open the file, etc.
movei t1, "X" ; No, so send X packet.
move t2, pktnum ; This packet number.
setzb t3, t4 ; No data.
jrst sfildy ; Skip around all the file name baloney.
sfilb2: move t1, filjfn ;[15] JFN of file
movx t2, fld(^d36,of%bsz)+of%rd ;[15]
OPENF% ;[15]
erjmp sfilec ;[44]
skipn xflg ;[126]
wtlog <Opened File: >,filjfn ;[126]
jrst sfiled ;[44] Opened OK, proceed.
sfilec: cain t1, opnx1 ;[44] Got an error. "File already open"?
jrst sfiled ;[44] Yes, so it's not really an error.
skipe t1, tlgjfn ;[126] Log this failure in transaction log.
jrst [ wtlog <Can't Send >,filjfn
hrroi t2, [asciz/ Because: /]
setzb t3, t4
SOUT
hrloi t2, .fhslf ; Tell why.
setz t3,
ERSTR
nop
nop
hrroi t2, crlf
setzb t3, t4
SOUT
jrst .+1 ]
skipe local ;[15] No, really an error. Local?
call [ hrroi t1, [asciz/ %Not sent because: /]
PSOUT
movei t1, .priou
hrloi t2, .fhslf
setz t3,
ERSTR%
nop
nop
ret ]
call gtnfil ; Try to get the next file.
jrst [ setzm filjfn
movei state, "B" ; No more, break transmission.
ret ]
jrst sfilea ; Got one, go try to open it.
;...
;...SFILE, Cont'd
;[96] See if user wants to send the file with a different name.
sfiled: move t1, pars3 ; Use another name?
caie t1, .cmtxt ;
jrst sfild2 ; No, use the file's actual name.
move t1, [point 7, buffer] ; Yes, copy the string the user gave us,
move t2, [point 7, filbuf] ;[102] converting to upper case.
call movstu ; Returns length in t3.
jrst sfild3 ; Proceed.
; Come here to use the file's actual name.
sfild2: move t1, [point 7, filbuf] ;[102] Put string in file name buffer.
move t2, filjfn ; The file's JFN.
movx t3, js%nam+js%typ+js%paf ; Only name, type, and punctuation.
setzb t4, filbuf
JFNS% ; Get the file name.
erjmp [move t1, [point 7, [asciz/XXXXXX.XXX/]] ; If any error
movei t3, ^d10 ; substitute this string.
jrst sfild4 ]
ldb t3, t1 ;[175] See what the last character is.
cain t3, "." ;[175] Dot?
jrst [ dpb t4, t1 ;[175] Yes, zero it out.
seto t4, ;[175] And remember.
jrst .+1 ] ;[175]
move t2, t1 ; Set up to subtract the byte pointers.
idpb t4, t1 ; Terminate the string
move t1, [point 7, filbuf] ;[102] Get a pointer to our data block.
call subbp ; Subtract the byte pointers, get length in t3.
ret ; Uh oh... this should never happen.
skipe t4 ;[175] Last char was dot?
sos t3 ;[175] Yes, so count one less character.
;...
;...SFILE, cont'd.
;[84] Strip out ^V's, convert filename to "normal form" if requested.
;[102] Do this using normal packet encoding & filling technique, but calling
;[102] an alternate GETCH routine.
sfild3: skipn filjfn ;[128] Really a file?
jrst [ movei t1, "X" ; No, just send an empty X header.
move t2, pktnum ; Current packet number.
setzb t3, t4 ; No data.
jrst sfildy ]
; Really a file.
move t1, [point 7, filbuf] ;[102] Keep file buffer pointer in memory.
sfild4: movem t1, filptr ;[102] ...
movei t1, gtfch ;[102] Address alternate GETCH routine
movem t1, source ;[102] to call while getting characters.
setom fildot ;[102] Initialize filename dot counter.
setom next ;[102] Initialize character lookahead.
move t1, maxdat ;[102] Set up maximum length.
call getbuf ;[102] Fill up the packet with the filename.
jumpn t1, [
movei state, "A" ;[102] Shouldn't be any error here, but...
ret ] ;[102] ...
move t3, t1 ;[102] Set up length for call to SPACK.
; Send the file header packet.
sfildx: setzm source ;[102] Done with alternate GETCH routine.
movei t1, "F" ; Packet type is File Header.
skipe xflg ; Unless it's teXt header...
movei t1, "X" ; ...
move t2, pktnum ; Packet number.
move t4, [point 8, data] ; Get a pointer to our data block.
sfildy: call spack ; Send the file header packet.
skipa state, "A" ; Failed, set state to cAncel & return.
call rpack ; Sent the file header OK, get reply.
ret ; Trashed packet, don't change state, retry.
;...
; SFILE, cont'd
; Got a response, check for & handle ACKs.
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 rcving ; Indicate we're sending a file.
aos rcving ; ...
setzm numtry ; Yes, reset the number of tries.
aos t2, pktnum ; Increment the packet number,
andi t2, 77 ; modulo 100,
movem t2, pktnum ; and save it.
skipn xflg ;[126] Don't log if not sending a real file.
jrst [ skipn t1, tlgjfn ;[126] Logging transactions?
jrst .+1
hrroi t2, [asciz/ Sending As "/] ; Yes, log this.
setzb t3, t4
SOUT
hrroi t2, filbuf
SOUT
hrroi t2, [asciz/"
/]
SOUT
jrst sfil3a ]
jrst sfil3a ;[52] Join common code.
; Check for & handle NAKs.
sfile3: caie t1, "N" ; NAK?
jrst sfile4 ; No.
aos nnak ;[54] Yes, count it.
move t1, pktnum ;[51] Get the expected packet number.
aos t1 ;[51] Figure out what the next one would be,
andi t1, 77 ;[51] mod 64.
caie t1, (t2) ;[51] Is the NAK for the next packet?
ret ; No, so must send this packet again.
setzm numtry ; Yes, for next, same as ACK for this.
movem t1, pktnum ; Save incremented packet number.
;...
; SFILE, cont'd
;[75] Check for ITS binary format file.
sfil3a: setzm itsfil ; Assume this isn't an ITS file.
skipn source ; Skip this if it's not really a file.
skipn itsflg ; Looking for ITS files?
jrst sfil3b ; No.
setz t2, ; Yes, do a 36-bit BIN.
skiple t1, filjfn ; ...
BIN ; ...
erjmp sfil3b ; If there's some error, catch it later.
came t2, [sixbit/DSK8/] ; Is it an ITS binary file?
jrst sfil3b ; No, then handle normally.
setom itsfil ; Yes, flag this file as ITS.
hrroi t1, [asciz/(ITS binary format) /]
skipe local ; Say what happened if local.
PSOUT
; Get first chunk of data.
sfil3b: setzm mapflg ;[52] Say no pages mapped in yet.
setzm eoflag ;[72] Not EOF yet.
setom next ;[63] Initialize input character lookahead.
move t1, maxdat ;[63] Maximum length for data field.
setz schr, ;[128] Init number of file characters sent.
call getbuf ;[63] Fill the first data packet.
jrst [ movem t1, cxseen ;[70] If error, send "discard" in EOF message.
movei state, "Z" ; Get into EOF state.
ret ]
movei state, "D" ; Got data, set the state to file send.
movem t1, size ; Save the length of the data.
ret ; Back to state switcher.
; Catch-all for other states.
sfile4: cain t1, "T" ; Timer interrupt pseudo packet?
ret ; Yes, return without changing state.
cain t1, "E" ;[80] Error packet?
call pxerr ;[82] If so, print remote error message.
movei state, "A" ; Cancel the transaction.
skiple t1, filjfn ;[80] Close the file.
CLOSF ;[80]
erjmp .+1 ;[80]
setzm filjfn ;[80]
ret
; GETCH replacement routine for getting characters from a filename string.
; Uses global FILPTR for input string, FILDOT for counting dots in filename.
; Strips any ^V used as a quote, and if requested converts name to normal form.
;
; Returns:
; +1 never (no reason to fail).
; +2 always, with NEXT containing next character, -1 if no more.
;
gtfch: ildb t1, filptr ;[102] Get next character.
jumpe t1, gtfchz ;[102] If zero, must be done.
cain t1, 26 ;[84] Control-V?
ildb t1, filptr ;[102] Yes, it's just a prefix, get next char.
skipn xfnflg ;[101] Converting to normal form?
jrst gtfchx ;[101] No, skip other conversions.
cain t1, "." ;[84] Yes, is this a period?
jrst [ aose fildot ;[84] Yes, don't put more than one.
movei t1, "X" ;[84] Substitute "X" for any extra dots.
jrst gtfchx ] ;[84] ...
gtfchy: move t1, xfntab(t1) ;[84] Translate it.
; Return with character like GETCH.
gtfchx: movem t1, next ;[102] Put result in NEXT, as GETCH does.
retskp ;[102] Done.
; "EOF" return, like GETCH
gtfchz: setz t1,
setom next
ret
; SDATA - Send a data packet.
sdata: skipn cxseen ;[59] Control-X typed?
skipe czseen ;[59] Or Control-Z?
jrst [ call unmapi ;[59] Yes, must unmap current input file page.
nop ;[59] Ignore any errors.
movei state, "Z" ;[59] Get into EOF state.
ret ] ;[59] Back to state switcher.
saveac <q1> ; ^X/^Z not typed, normal case.
sdatab: move q1, numtry ; Get the number of tries.
caml q1, maxtry ; Have we reached the maximum number of tries?
jrst [ movei state, "A" ; Change the state to cAncel.
ermsg <Too many retries>, r ]
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 data packet.
jrst @[exp sdatab,sdatax](t1) ; Handle errors.
call rpack ; Get a packet.
ret ; Trashed packet, don't change state, retry.
sdatay: caie t1, "Y" ; Got one, check the type. Is it ACK?
jrst sdatan ; No, go check for NAK.
came t2, pktnum ; Yes, but is it the right ACK?
ret ; No, don't settle, hold out for right one.
soje t3, [ ;[62] Any data (interested in one & only char)?
ildb t3, t4 ;[62] Yes, what?
cain t3, "X" ;[62] Is it an "X"?
jrst [ setom cxseen ;[140] Yes, set the C-X flag.
move t3, source ;[140] What's the source of our data?
cain t3, dirch ;[140] A directory listing?
setom czseen ;[140] If so, set C-Z flag, too.
jrst sdaty2 ] ;[140]
cain t3, "Z" ;[62] Is it an "Z"?
setom czseen ;[62] Yes, pretend ^Z was typed...
jrst .+1 ] ;[62] Go thru one more time, then out.
sdaty2: setzm numtry ; Correct normal packet, reset retry counter.
aos t2 ;[51] Increment the packet number,
andi t2, 77 ; modulo 100,
movem t2, pktnum ; and remember it.
jrst sdata2 ;[52] Go get some more data to send.
sdatan: cain t1, "N" ; NAK?
jrst [ move t1, pktnum ;[51] Yes, get the expected packet number.
aos nnak ;[54] Count the NAK.
aos t1 ;[51] Figure out what the next one would be,
andi t1, 77 ;[51] mod 64.
caie t1, (t2) ;[51] Is the NAK for the next packet?
ret ; No, then must send current one again.
setzm numtry ; Yes, a NAK for n+1(mod 64) = ACK for n,
movem t1, pktnum ; so play like we got an ACK,
jrst sdata2 ] ;[52] and go get next packetful of data.
;...
;...SDATA, cont'd
; Handle timeout or unexpected packet types.
sdatat: cain t1, "T" ; Timer interrupt pseudo packet?
ret
cain t1, "E" ;[82] Error packet?
jrst pxerr ;[82] Yes, print it & cancel.
sdatax: movei state, "A" ; Anything else, just cancel..
ret
; Fill up the next buffer of data.
sdata2: move t1, maxdat ;[63] Length to work with.
call getbuf ;[63] Try to get next bufferful.
jrst [ movem t1, cxseen ;[70] If error, tell other side to discard.
movei state, "Z" ; Set state to EOF.
ret ] ; Go back to state switcher.
movem t1, size ; Got more data, save length, and
ret ; return, remaining in state "D".
; SEOF - Send End Of File packet.
seof: move t1, numtry ; No ^X/^Z, get the number of tries.
caml t1, maxtry ; Have we reached the maximum number of tries?
jrst [ movei state, "A" ; Change the state to cAncel.
ermsg <Can't send EOF>, r ]
aos numtry ; Still within our limit, bump retry count.
movei t1, "Z" ; Send a Z (EOF) packet.
move t2, pktnum ; Packet number.
skipn cxseen ;[59] Are we discarding this file?
skipe czseen ;[59]
jrst [ move t3, [point 8, data] ;[59] Yes,
movei t4, "D" ;[59] put a "D" for Discard in data field
idpb t4, t3 ;[59] ...
movei t3, 1 ;[59] Say the data length is 1
move t4, [point 8, data] ;[59] point to it again...
jrst .+2 ] ;[59] Skip next instruction!
setzb t3, t4 ; Normal case -- no data field.
call spack ; Send the packet.
jrst @[exp seof, seofx](t1) ; Handle any errors.
call rpack ; Get a packet.
ret ; Trashed packet, don't change state, retry.
; Got a response. Check for ACK and handle it.
caie t1, "Y" ;[52] Check the packet type. Is it an ACK?
jrst seof2 ;[52] No...
came t2, pktnum ; Yes but, is it the right ACK?
ret ; No, don't settle, hold out for right one.
aos t2, pktnum ; Increment the packet number,
andi t2, 77 ; mod 100,
movem t2, pktnum ; and save it.
jrst seof4 ;[52] Join common code.
; Check for NAK and handle it.
seof2: caie t1, "N" ; NAK?
jrst seof3 ; No.
aos nnak ;[54] Yes, count it.
move t1, pktnum ;[51] What packet were we looking for?
aos t1 ;[51] Is the NAK for the next packet?
andi t1, 77 ;[51] (mod 64)
caie t1, (t2) ;[51]
ret ; No, then must send this one again.
movem t1, pktnum ; Yes, behave like it was an ACK for this one.
jrst seof4 ;[52] Join common code.
; SEOF, cont'd
; Check for other types & handle.
seof3: cain t1, "T" ; Timer interrupt pseudo-packet?
ret ; If so, just keep going.
cain t1, "E" ;[80] Error packet?
call pxerr ;[82] If so, print it.
skiple t1, filjfn ;[80] Close the file.
CLOSF ;[80]
erjmp .+1 ;[80]
setzm filjfn ;[80]
seofx: movei state, "A" ; Otherwise cancel.
ret
; EOF packet was ACK'd OK, close the file, get the next one (if any).
seof4: skipn xflg ;[126] Sending a real file?
jrst [ skipn t1, tlgjfn ;[126] Transaction log?
jrst .+1
hrroi t2, [asciz/ Sent: /] ; Yes, log this info.
setzb t3, t4
SOUT
move t2, schr ; Number of bytes.
movei t3, ^d10
NOUT
nop
movei t2, 40 ; A space
BOUT
movei t2, 7 ; Bytesize
skipe ebtflg
aos t2
NOUT
nop
hrroi t2, [asciz/-bit bytes
/]
setzb t3, t4
SOUT
jrst .+1 ]
setzm numtry ;[52] Reset the retry counter.
addm schr, stchr ; Add the last file's size to the total.
setz schr, ; Zero the present count.
aos files ;[61] Count the file.
skipn source ;[128] Sending a file?
jrst [ skipg t1, filjfn ;[128] Yes, get the JFN of the file just sent.
jrst .+1 ;[128] If no valid JFN, don't bother closing.
txo t1, co%nrj ; Don't release it, GNJFN still needs it.
CLOSF% ; Close the file.
%jserr (,.+1) ;[59] Print msg but continue if error.
jrst .+1 ] ;[121]
;...
;...SEOF, cont'd
; Messages to screen and transaction log.
skiple filjfn ;[127] Transaction log stuff.
skipe xflg ;[126] Don't bother if not a real file.
skipa ;[126]
wtlog <Closed >,filjfn ;[126]
hrroi t1, [asciz/[OK]/] ; Normal comforting message.
skipe cxseen ; But was sending interrupted this way?
hrroi t1, [asciz/[interrupted]/] ; Yes, say so.
skipe czseen ; Or this way?
hrroi t1, [asciz/[group interrupted]/] ; Yes, say so.
move t4, t1 ; Keep for log.
skipe local ; Local use?
PSOUT ; Yes, print selected message.
skipe t1, tlgjfn ;[126] If we have a transaction log, there too.
jrst [ move t2, t4
setz t3,
skipn cxseen
skipe czseen
SOUT
jrst .+1 ]
seof5: skipn source ;[121] Really doing files?
call gtnfil ; If so, get the next file to send.
jrst [ setzm filjfn ; If not, or if no more, zero the JFN,
movei state, "B" ; set state to complete,
ret ] ;[59] and return to state switcher.
movei state, "F" ; OK, switch to File-send state.
ret
; SEOT -- Send End Of Transmission packet.
seot: saveac <q1>
seotb: move q1, numtry ; Get the number of tries.
caml q1, maxtry ; Have we reached the maximum number of tries?
jrst [ movei state, "A" ; Change the state to cAncel.
ermsg <Can't send EOT>, r ]
aos numtry ; Increment number of tries.
movei t1, "B" ; Packet type is Break (EOT).
move t2, pktnum ; Packet number.
setzb t3, t4 ; No data.
call spack ; Send the packet.
jrst @[exp seotb, seotx](t1) ; Handle any errors.
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.
aos t2, pktnum ; Increment packet number
andi t2, 77 ; mod 100
movem t2, pktnum ; save it back.
movei state, "C" ; Complete state.
skipn xflg ;[126] Put message in transaction log,
wtlog <Send Complete> ;[126] if it was a real file transfer.
ret ]
cain t1, "N" ; NAK?
jrst [ aos nnak ;[54] Yes, count the NAK.
move t1, pktnum ;[51] Is the NAK for the next packet?
aos t1 ;[51]
andi t1, 77 ;[51]
caie t1, (t2) ;[51]
ret ; No, must send current one again.
movem t1, pktnum ; Yes, behave like it was an ACK for this one.
setzm numtry ; Reset the number of tries.
movei state, "C" ; Complete state.
ret ]
cain t1, "T" ; Timer interrupt pseudo packet?
ret
cain t1, "E" ;[82] Error packet?
jrst pxerr ;[82] Yes, print it & cancel.
seotx: movei state, "A" ; Otherwise cancel.
ret
;[63] Rewrite file routines.
;
; GETBUF - Get buffer (i.e. packet) full of characters from input file.
;
; Call with
; AC1/ desired number of characters to get (i.e. data buffer size)
; Returns:
; +1, failure, with AC1/ 0 if end of input file, or nonzero if other error.
; +2, success, with AC1/ number of characters actually gotten, and
; the result accessible by [point 8, data].
;
getbuf: saveac<q1,q2,q3,q4>
skipg t1 ; Make sure the number is not 0 or negative.
ret ; This gives the right return code.
caile t1, ^d9000 ; Make sure the number is not too big.
movei t1, ^d9000
move q4, t1 ; Maximum number of characters to return.
setz q2, ; Counter for actual characters returned.
move q3, [point 8, data] ; Where to put the result.
setzm rpt ;[126] Clear leftover repeat counts from last.
getbfa: skipge next ; First time through, get first character.
jrst [ call getch
jumpn t1, r ;[64] Pass along any failure
setz t1, ; Since GETCH puts the character it got in NEXT
exch t1, next ; it has to be moved to CH, just this once.
movem t1, ch
jrst .+1 ]
getbfb: skipl ch ; Do we have one? If not, must be EOF.
caml q2, q4 ; Or buffer full?
jrst getbfx ; If so, return it.
; Get next character for lookahead.
getbfc: call getch ; Get next one.
jumpn t1, r ;[64] Pass along any failure
call encode ; Go do any prefixing.
skipge t1, next ; Set up for next time through.
jrst getbfx ; If no next, we're done.
movem t1, ch ; Otherwise next is now current.
jrst getbfa ; Loop till done.
; Return the buffer.
getbfx: skipg t1, q2 ; Return length of data
ret ; +1 if 0 (= EOF)
retskp ; +2 if greater than zero.
;[63] This routine added as part of edit 63.
;
; ENCODE - Process a character -- do any prefixing, etc, necessary to
; insert the character into a data packet.
;
; Call with character in global CH, global RPTFLG and EBQFLG indicating
; whether repeat and 8th-bit prefixing are to be done.
;
; Returns:
; +1 always, with CH unmodified, q2/ updated packet length.
; Uses t2-t4.
;
encode: move t4, ch ; Get current character.
skipn rptflg ; Doing repeat count prefixing?
jrst enco8 ; No, skip to next part.
; Repeat count processing. Check if this character same as next.
encor: camn t4, next ; Same as next one?
jrst [ aos t2, rpt ; Yes, just count it.
caige t2, ^d94 ; Count within bounds?
ret ; Yes, done.
sos t2 ;[93] No, adjust as though next char different.
jrst encor4 ] ; Go emit a repeat sequence for this much.
; Different, see if there were any repeats.
encor2: skipg t2, rpt ; CH not same as next. Any repeats?
jrst enco8 ; No, on to next part.
caige q2, (q4) ;[93] Yes, near end of buffer?
cain t2, 1 ; Or only repeated once?
jrst [ setzm rpt ;[144] Set all the repeat count back to zero.
call enco8 ;[144] Call self, skipping around this part,
move t4, ch ;[144] and again.
call enco8 ;[144]
ret ] ;[93] and return.
; Repeated more than once -- general case.
encor4: move t3, rptq ; Emit a repeat sequence --
idpb t3, q3 ; the repeat prefix character,
addi t2, <40+1> ;[93] followed by 'tochar(count+1)'
idpb t2, q3 ; because if it's repeated 1x there are 2...
addi q2, 2 ; Account for these prefix characters.
setzb t2, rpt ; Clear repeat count.
;...
;...ENCODE, cont'd
; 8th-bit prefixing.
enco8: setz t2, ; Bit-8 flag.
trzn t4, 200 ; Test & clear parity bit.
jrst encoc ; Not set, on to next part.
seto t2, ; Remember it was on.
skipn ebqflg ; Doing 8th-bit quoting?
jrst encoc ; No, so skip this.
move t3, ebq ; Yes, stick in an 8th-bit prefix.
idpb t3, q3
aos q2 ; Count it.
; Control prefixing.
encoc: cail t4, 40 ; Control character
cain t4, .chdel ; or DEL?
jrst [ xori t4, 100 ; Yes, convert to printable
jrst encoc4 ] ; and go insert a control prefix.
; Prefix prefixing.
encoc1: camn t4, squote ; Control Prefix?
jrst encoc4 ; Yes.
encoc2: skipn rptflg ; Repeat processing?
jrst encoc3 ; No.
camn t4, rptq ; Yes, is the character the repeat prefix?
jrst encoc4 ; Yes, insert a control prefix before it.
encoc3: skipe ebqflg ; Eighth-bit prefixing?
came t4, ebq ; Is the character the 8th-bit prefix?
jrst encocx
encoc4: move t3, squote ; Insert a control prefix.
idpb t3, q3
aos q2 ; Count it.
; Now, finally, insert the character itself.
encocx: skipe t2 ; Was 8th bit on originally?
skipe ebqflg ;[109] Yes, but did we quote it already?
skipa ;[109] In that case, don't put it back.
tro t4, 200 ; It was on & wasn't quoted so put it back.
idpb t4, q3 ; Deposit it.
aos q2 ; Count it.
ret
subttl File routines
;[63] This routine added as part of edit 63.
;
; GETCH - Get a character from the disk file.
; If global SOURCE is nonzero, it is assumed to contain an address of a
; routine to be used instead of this one.
;
; Returns:
; +1 on failure, with t1/0 if EOF, t1/-1 if real error getting character.
; +2 on success, with global NEXT containing the character, -1 if EOF.
;
getch: skipe t1, source ;[102] Alternate routine to call?
jrst (t1) ;[102] Yes, go there instead.
saveac <q1,q2,q3> ; Save permanent ACs.
skipe eoflag ; Is the end of file flag set?
jrst [ setzm eoflag ; Yes, reset EOF flag for next time,
jrst getchz ] ; and return EOF.
skipe mapflg ; Do we have anything mapped in?
jrst getch3 ; Yes, don't have to do mapping.
getch1: move t1, filjfn ; No, must do mapping, here's the JFN.
movx t2, <2,,.fbbyv> ; Get number of pages and bytes
movei t3, pagcnt ; into pagcnt and bytcnt,
GTFDB% ; from the file descriptor block.
%jsker <Can't get file length>,getchx ; Return error.
skipn bytcnt ; Any bytes in the file?
jrst [ setom eoflag ; No, set end-of-file flag.
jrst getchz ] ; And return EOF.
ldb t2, [point 6, pagcnt, 11] ; Get the file byte size.
movem t2, bytsiz ; Save it.
; 7- or 8-bit input from the file? First, check for ITS binary format.
skipe itsfil ;[75] ITS binary format file?
jrst getcha ;[75] Yes, then skip "autobyte" stuff.
; Next, if doing "autobyte", use the file byte size.
skipe autbyt ;[81] Are we using autobyte?
jrst [ setzm ebtflg ; Yes, assume seven-bit bytes.
cain t2, ^d8 ; Really 8-bit?
setom ebtflg ; Yes, act like user requested 8-bit.
jrst .+1 ]
; Now, if we're to do 8-bit input, convert the byte count if necessary.
getcha: skipn itsfil ; ITS binary file?
skipe ebtflg ; Or eight bit mode?
jrst [ cain t2, ^d8 ; Yes, is the byte size 8?
jrst getchb ;[170] If so go adjust byte count if necessary.
movei t3, ^d36 ; Get the size of a word.
idiv t3, t2 ; Divide by the byte size.
move q1, bytcnt ; Get the number of bytes in file.
idiv q1, t3 ; Divide by the bytes/word to get words.
imuli q1, 4 ; Multiply by 4 (as if 8-bit bytes).
movem q1, bytcnt ; Save the new byte count.
jrst getchb ] ;[170] Go adjust byte count.
;...
;...GETCH, cont'd
; Or, if we're to do 7-bit input, fix the byte count for that.
caie t2, 7 ; If the bytesize is not 7 or 8, treat as 7.
cain t2, ^d8 ;[170] (don't do this to 8-bit files!
skipa ;[170] ...)
jrst [ movei t3, ^d36 ; Must convert, get the size of a word.
idiv t3, t2 ; Divide by the byte size.
move q1, bytcnt ; 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, bytcnt ; Save the new byte count.
jrst getch2 ] ; Go map in page.
getchb: skipn itsfil ;[86][170] ITS binary file?
jrst getch2 ;[86] No, proceed.
move q1, bytcnt ;[86] Yes, get byte count.
subi q1, 4 ;[86] Subtract 4 to account for header.
movem q1, bytcnt ;[86] Save it back.
; Byte size figured out, now map in the first page.
getch2: hrlzs t1 ; Form file JFN,, page 0
hrlm t1, pagcnt ; Zero the left half of pagcnt.
call mapi ; Map it in.
jrst getchx ; Pass along any failure.
skipe itsfil ;[75] ITS binary file?
aos pagptr ;[75] Yes, skip first word of it.
setzm pagno ; Present page is zero.
setom mapflg ; Say we've got a page mapped in.
; Come here if/when/after page is mapped in...
getch3: caml schr, bytcnt ; Any more bytes in file?
jrst [ setom eoflag ; No, Set the end of file flag.
call unmapi ; Unmap the input file page.
ret ; Fail if we can't
setzm mapflg ; Say nothing mapped in.
jrst getchz ] ; Return EOF.
ildb t2, pagptr ; There are more; get the next one.
erjmp getch% ;[70] (illegal memory read, hole in file...)
aos schr ;[64] Got it OK, count it.
;...
;...GETCH, cont'd
getch4: hrrz t1, pagptr ; Are we at the end of the page yet?
caige t1, <mappag+1>*1000 ;[64]...
jrst getch5 ; No, go return the character.
call unmapi ; Yes, unmap the input page.
jrst getchx ; Pass along any failure.
move t1, pagno ; Get the present page number.
aos t1 ; Increment it.
caml t1, pagcnt ; Any more pages?
jrst [ setom eoflag ; No, set the end of file flag for next time.
setzm mapflg ; Say nothing mapped in,
jrst getch6 ] ; and return normally with the char we got.
movem t1, pagno ; Save the new number.
hrl t1, filjfn ; <file JFN,, page 0>
call mapi ; Map in the page.
jrst getchx ; Pass along any failure.
ildb t2, pagptr ; Get the next character.
erjmp getch% ;[70] (Illegal memory read, hole in file...)
; Got the character in t2. Worry about bit 35 if doing 7-bit i/o. The trick
; is to set the parity bit ("b8") of every 5th character to the value of b35
; of the PDP-10 word it came from. The same trick is used by TOPS-20 when
; writing ANSI-ASCII tapes. This allows DEC-10/20 .EXE and other 36-bit binary
; files, and SOS-line numbered files, to be sent to 8-bit systems and retrieved
; intact. No adverse effects are suffered by ordinary text files.
getch5: move q1, schr ;[64] Count the character.
skipn itsfil ;[75] ITS binary file?
skipe ebtflg ; Eight bit mode?
jrst getch6 ; One of those, no need to do this.
;
idivi q1, 5 ; No, 7-bit, divide character number by 5.
skipn q2 ; Last character of word if remainder is 0.
jrst [ move q1, pagptr ; In that case, get the entire contents.
move q1, (q1) ;
trne q1, 1 ; Bit 35 on?
tro t2, 200 ; Yes, turn on bit 8 of this character.
jrst .+1 ]
getch6: movem t2, next ; Return the character.
retskp
; EOF return.
getchz: setz t1, ; Return zero error code,
setom next ; and character -1.
ret
;...
;...GETCH, cont'd
; Error return.
getch%: skipe local ;[70]
ermsg <Illegal memory read> ;[70]
getchx: setob t1, next ; Return -1 error code, and character -1.
movx t2, <.fhslf,,mappag> ;[70] Unmap any page that's still mapped in.
setz t3, ;[70]
PMAP% ;[70]
erjmp .+1 ;[70] Ignore errors.
setzm mapflg ;[70]
ret
; MAPI - Map in file page.
;
; Call with
; t1/ jfn,,page number.
;
; Returns
; +1 on failure.
; +2 on success, with PAGPTR adjusted to point back to beginning of page.
;
mapi: movx t2, <.fhslf,,mappag> ; Form 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, fail.
move t3, [point 7, mappag*1000] ; Success, get a pointer to the page.
skipn itsfil ;[75] An ITS binary file?
skipe ebtflg ; Or eight bit access?
hrli t3, (point 8,) ; Yes, then use 8-bit pointer.
movem t3, pagptr
retskp ; Return successfully.
; UNMAPI -- Unmap an input file page.
;
; Returns +1 on error, +2 on success.
; First check to see where we're getting our input from.
;
unmapi: skipn t1, source ;[139] But are we really reading from a file?
jrst unmap3 ;[139] Yes, really unmap.
caie t1, dirch ;[139] No, is it a directory listing?
jrst unmap2 ;[139] No, something else.
; From a directory listing buffer. Clear it & reset pointers for next time.
call dmpbuf ;[139] Yes, directory listing; clear buffer.
setzm source ;[139] Indicate no more alternate source.
ret ;[139] Done.
; From some other source (add others here).
unmap2: ret
; Source is really a file, unmap the current file page.
unmap3: seto t1, ; Indicate unmap.
movx t2, <.fhslf,,mappag> ; This process.
setz t3,
PMAP% ; Unmap the page.
%jsker <Error unmapping page>,r
retskp
;[66] PUTBUF -- Write the contents of the data field of a packet out to a file.
;
; Call with:
; t1/ pointer to data buffer.
; t2/ number of characters.
; pagptr/ output file page byte pointer.
; Returns:
; +1: Failure, Couldn't write the whole buffer, Error packet already sent.
; +2: Success
;
putbuf: saveac <q1,q2> ; Preserve these ACs.
dmove q1, t1 ; Save the arguments.
putbf2: jumple q2, rskp ; Are we done?
ildb t2, q1 ; Not yet, get the next character from the pkt.
call decode ; Go decode and store it.
ret ; Pass along any error.
cain rchr, 4 ;[75] Just finished 4th character?
call itschk ;[75] Yes, see if it was the ITS binary hdr.
soja q2, putbf2 ; Loop.
;[75] ITSCHK -- See if first 4 bytes of file are ITS binary file header.
;
; Uses t1-t3.
; Returns +1 always, with ITSFIL set if the first 4 bytes are the ITS binary
; file header, sixbit/DSK8/, and with the various pointers and counters
; adjusted appropriately. By the way, since this routine sets RCHR back to
; zero, it gets called again 4 characters later -- this should do no harm.
;
itschk: skiple itscnt ; No header characters counted?
skipn itsflg ; Is ITS checking enabled?
ret ; No, forget it.
move t1, itscnt ; We were counting the matching characters...
setzm itscnt ; Reset the counter.
caie t1, 4 ; The four characters matched?
ret ; No, done.
setom itsfil ; Yes, flag it.
move t1, [point 8, <mappag*1000>] ; Set up page pointer for 8 bit.
movem t1, pagptr
setz rchr, ; Rewind the character counter.
movei t1, 8 ; Record file bytesize correctly
movem t1, bytsiz ; ...
hrroi t1, [asciz/(ITS binary format) /]
skipe local ; Say what happened if local.
PSOUT
ret
;[66] DECODE -- Convert data in Kermit packet to its original form.
;
; Call with:
; t2/ Character to decode
; q1/ Buffer pointer
; q2/ Position in buffer
; Returns:
; +1: Failure, if output could not be done.
; +2: Success, with q1,q2 updated.
;
; Note: If the input character is a prefix of any kind, this routine
; will input all further characters necessary to complete the prefixed
; sequence, and update the counts and pointers appropriately.
;
decode: saveac<q4> ; Preserve this one.
decod0: move t3, t2 ; Make a copy with the parity bit intact.
andi t2, 177 ; And without, so comparisons will work.
decod1: setzm rpt ; Reset repeat count.
skipn rptflg ; Repeat count processing?
jrst decod2 ; No.
camn t2, rptq ; Yes. Is this the repeat prefix?
jrst [ ildb t2, q1 ; Yes. Get the count.
andi t2, 177 ; Let's be cautious...
subi t2, 40 ; Convert from character to number.
movem t2, rpt ; Save the repeat count.
ildb t2, q1 ; Get the next character.
move t3, t2 ; Copy with parity (in case it's not a prefix)
trz t2, 200 ; and without...
subi q2, 2 ; Account for the repeat prefix sequence.
jrst .+1 ]
;...
;...DECODE, cont'd
decod2: setzm ebqchr ;[90] Say no 8th-bit prefix on this character.
skipn ebqflg ; Doing 8th-bit quoting?
jrst decod3 ; No.
camn t2, ebq ; Yes, is this the 8th-bit prefix?
jrst [ ildb t2, q1 ; Yes, get the character it is prefix of.
move t3, t2 ; Copy with parity in case not ctl prefix
tro t3, 200 ; ...
trz t2, 200 ; and without (this shouldn't anyway, but...)
setom ebqchr ;[90] Flag that we did this.
sos q2 ; Account for it.
jrst .+1 ]
decod3: came t2, rquote ; Control Prefix?
jrst decod4 ; No...
ildb t2, q1 ; Yes, get its argument.
move t3, t2 ; Copy with parity
trz t2, 200 ; and without...
skipe ebqchr ;[90] Was there an 8th-bit prefix?
tro t3, 200 ;[90] If so, set the 8th bit.
sos q2 ; Account for the ctl prefix.
cail t2, "@" ; Check if the character is in the sequence
caile t2, "_" ; "@ABC...XYZ[\]^_"
skipa ; No, take it literally.
xori t2, 100 ; Yes, controllify.
cain t2, "?" ; Or is it a question mark?
movei t2, 177 ; Yes, then it's really a DEL.
decod4: trne t3, 200 ; 8th bit was on?
tro t2, 200 ; Yes, then put it on in the result.
decod5: skipn q4, rpt ; Repeat Count.
movei q4, 1 ; If zero, make it 1.
decod6: jumple q4, decodz ; Loop for repeat count.
aos rchr ; Count the data character.
; The following check must be done here. We can't look directly at RECPKT,
; because it will contain quoting characters which must be evaluated by this
; routine. We can't do it by looking at the result in MAPPAG after calling
; PUTCH, because we might be writing to MAPPAG with a 7-bit pointer.
caile rchr, 4 ;[75] Check for the ITS header in 1st 4 chars.
jrst decod7 ;[75] If past first 4, don't check.
camn t2, [exp 0, 223, 72, 330, 0](rchr) ;[75] Check this character.
aos itscnt ;[75] If it matches, count it.
decod7: call putch ; Output the character.
ret ; Pass along any failure.
soja q4, decod6 ; Until done.
decodz: retskp ; Success.
;[66] PUTCH -- Output a character to a file.
;
; Call with:
; t2/ Character to output.
; pagptr/ Pointer to where to put it (if disk file).
; Returns:
; +1: Failure (disk full, etc).
; +2: Success, pagptr updated. (Uses t1-t4)
;
putch: skipe t1, dest ; Alternate PUTCH routine?
jrst (t1) ; Yes, go to it.
skiple filjfn ;[177] To file?
jrst putch2 ;[177] Yes, go do that.
skipn local ;[177] No, to screen.
retskp ;[177] But if remote, skip it.
move t1, t2 ; No, then just put it on the screen.
PBOUT ;* Pretty dumb, make this more efficient
retskp ;* later...
; File output. Test to see if page is full.
putch2: move t1, pagptr ; Copy the byte pointer.
ibp t1 ; Increment the copy.
hrrzs t1 ; Clear out the LH.
caig t1, <<<mappag+1>*1000>-1> ; At the end yet?
jrst putch5 ; No, proceed.
; A page is filled up -- map it out.
putch3: move t4, t2 ; Yes, save the character around this.
call unmapo ; Go unmap the current page.
ret ; Pass along any failure.
move t2, t4 ; Get back the character.
aos pagno ; Advance the file page number.
; Rewind the memory page back to word 0.
putch4: move t1, [point 7, mappag*1000] ; Success, make a pointer
skipn itsfil ;[75]
skipe ebtflg ; of the appropriate
hrli t1, (point 8,) ; byte size.
movem t1, pagptr ; Store it.
; Deposit the character into the memory page.
putch5: idpb t2, pagptr ; Put it in the page.
;...
;...PUTCH, cont'd
; Worry about bit 35.
putch6: skipe itsfil ;[75][81] ITS binary file?
retskp ;[75] Yes, don't worry about this.
skipn ebtflg ; Output to 7-bit file?
trnn t2, 200 ; AND parity bit is on?
retskp ; No, done.
putch7: move t3, rchr ; Yes, both, get the char count,
idivi t3, 5 ; modulo 5.
jumpg t4, rskp ; Is this the last char in the word?
putch8: move t3, pagptr ; Yes, get its contents.
move t4, (t3) ; ...
tro t4, 1 ; Turn on bit 35.
movem t4, (t3) ; Put it back.
retskp ; Done.
subttl File Routines
; GTNFIL - Get next file from wild file specification.
; Return +1 with AC1/0 if no more, or +2 with JFN of next file in AC1.
;
;[111] Rewritten to do 1-file lookahead as part of edit 111.
;
gtnfil: move t1, filjfn ; Release the JFN of the previous file.
RLJFN
erjmp .+1
setzm filjfn
; Check to see if we really want to or can get the next file.
setz t1, ; Assume no more files.
skipn czseen ;[59] If CTRL-Z seen, then get no more files.
skipn t1, nxtjfn ; No CTRL-Z. Get next JFN.
ret ; None, so we're done.
; Make a separate JFN for the file so that wildcard stepping won't be wiped
; out by anything we do to it, like deleting it, renaming it, etc.
hrrz t2, t1 ; Get the filename string.
hrroi t1, strbuf
setz t3,
JFNS
erjmp r
movx t1, gj%old!gj%sht ; Get a new JFN on it.
hrroi t2, strbuf
GTJFN
erjmp r
hrrzm t1, filjfn ; Save it here.
setzm strbuf
; Get new next JFN.
move t1, nxtjfn ; Get the JFN again.
hll t1, ndxjfn ; Get wildcard flags into left half.
GNJFN ; Get the next JFN.
setz t1, ; If no more, set this to zero.
movem t1, nxtjfn ; Save result for next time.
; Return with current JFN.
move t1, filjfn ; Return JFN of current file in t1.
retskp ; Return +2 indicating another file was found.
;[119] MAKFIL - Rewritten as part of edit 119.
;
; Construct an output filespec from name given in file header packet.
;
; Call with:
; T1/ Pointer to a file name from packet.
; T2/ Number of characters.
;
; Return:
; +1: Failure
; +2, Success, with JFN in T1.
;
makfil: skipe filjfn ; Do we have a file yet?
jrst [ move t1, filjfn ; If so just return its JFN.
retskp ]
skipg t2 ; Are there at least a few chars?
jrst [ setz t1,
kermsg <File name not specified>, r ]
call decodf ;[141] Decode the file name.
kermsg <Can't decode filename>, r
; Now fix up the name, if desired, and get a JFN on it.
call filfix ; Go check & fix the filename syntax.
movx t1, gj%sht!gj%fou ; Short form.
GTJFN%
erjmp makfix ;[132] On error, go do something else.
retskp
;[132] Despite all efforts, couldn't construct legal name for file.
makfix: movx t1, gj%sht!gj%fou ; Get a JFN for...
hrroi t2, [asciz/-UNTRANSLATABLE-FILENAME-.KERMIT.-1/] ; ...this.
GTJFN
%jsker <Can't get JFN in MAKFIL>,r ; This should never fail, but...
move q1, t1 ; Log what happened.
wtlog <Illegal incoming name changed to >,q1
move t1, q1 ; Get this back.
retskp
;[141] Moved to separate routine as part of edit 141.
;
; Decode a file found in the data field of a KERMIT packet.
; Call with:
; t1/ pointer to data field.
; t2/ number of characters in data field.
;
; Returns:
; +1 on failure,
; +2 on success, with pointer to decoded filename in t1.
;
decodf: saveac <q1> ; Preserve this.
move q1, t1 ; Save argument for a sec.
move t1, [point 7, strbuf] ; Build decoded name here.
movem t1, strptr
setzm strbuf ; Clear out the string buffer
move t1, [strbuf,,strbuf+1] ; so result will be asciz.
blt t1, strbz ; ...
movei t1, putsch ; Routine to deposit decoded characters.
movem t1, dest ; ...
move t1, q1 ; Get argument back.
call putbuf ; Decode the file name string.
ret ; Failed for some reason, pass it along.
setzm dest ; Decoded OK, restore normal destination.
move t1, [point 7, strbuf] ; Return pointer to decoded file name.
retskp ; +2.
; FILFIX - Fix incoming file names by quoting illegal characters with ^V.
;*(Should also make sure length is no greater than 39.39)
;
; Call with t1/ Pointer to filename
; Returns +1 always, with t2 pointing to legal TOPS-20 filename.
;
filfix: skipe xfnflg ;[84] Doing filename conversion?
jrst filcnv ;[84] Yes, then go do that.
move t3, [point 7, filbuf] ; No, but still have to quote funnies.
setzm filbuf ;[174]
setom fildot ; Count dots.
filfx2: ildb t2, t1 ; Get the next character.
jumpe t2, [ ; No more, done.
idpb t2, t3 ; Put the null in.
move t2, [point 7, filbuf] ; Return a pointer to the filename.
ret ]
; Got a character, validate it.
cail t2, "A" ; Upper case letters are legal.
caile t2, "Z"
skipa
jrst filfx4
cail t2, "0" ; Digits are legal.
caile t2, "9"
skipa
jrst filfx4
caie t2, "$" ; Dollar sign is legal
cain t2, "-" ; So is dash.
jrst filfx4
caie t2, "_" ; Underscore is legal.
cain t2, 73 ; Allow semicolon for attributes.
jrst filfx4
cain t2, "." ; Dot?
jrst [ aosg fildot ; Yes, count it.
jrst filfx4 ; First dot, ok to use it.
jrst filfx3 ] ; Not first, go prefix it.
cail t2, "a" ;[153] A lower case letter?
caile t2, "z" ;[153] ...
skipa ;[153] No, something very illegal then.
jrst [ trz t2, 40 ;[153] Yes, convert to upper and
jrst filfx4 ] ;[153] use it.
; Get here with illegal character that must be prefixed with control-V.
filfx3: movei t4, ^o26 ; Control-V.
idpb t4, t3 ; Insert it before the character.
;[174] Deposit the character, but if first and a dot, insert an X before it.
filfx4: skipn filbuf ; Something in buffer already?
caie t2, "." ; No, first character is a dot?
jrst filfxx ; OK to go ahead.
movei t4, "X" ; 1st char would be a dot, so...
idpb t4, t3 ;[174]
filfxx: idpb t2, t3 ; Now deposit the actual character.
jrst filfx2 ; Loop till done.
;[84] Convert incoming filename to "normal form".
; This routine added as part of edit 84.
filcnv: move t3, [point 7, filbuf] ; Where to put new file name.
setzm filbuf ;[174]
movei q1, 1 ; Dot counter.
filcn2: ildb t4, t1 ; Get next character.
jumpe t4, filcnx ;[142] If null, done.
caie t4, "." ; Dot?
jrst filcn4 ; No.
;[174] check for names starting with dot.
skipn filbuf ; Anything in name yet?
jrst [ movei t4, "X" ; No, insert an X.
idpb t4, t3
movei t4, "."
jrst .+1 ] ;[174]
soje q1, filcn4 ; Yes, make sure there's only one dot.
movei t4, "X" ; If more, translate extra dots to X's.
jrst filcn5
filcn4: move t4, xfntab(t4) ; Translate it.
filcn5: idpb t4, t3 ; Put it back.
jrst filcn2 ; Loop till done.
filcnx: setz t2, ; Put a null at the end.
idpb t2, t3
move t2, [point 7, filbuf] ; Return a pointer to the file.
ret
; Translate table to turn funny characters into X's, raise lower case
; letters, leave upper case letters and digits, and periods alone.
; For translating file names to "normal form".
xfntab: repeat <^d46>,<exp "X">
exp ".","X"
exp "0","1","2","3","4","5","6","7","8","9"
repeat <7>,<exp "X">
exp "A","B","C","D","E","F","G","H","I","J","K","L","M","N"
exp "O","P","Q","R","S","T","U","V","W","X","Y","Z"
repeat <6>,<exp "X">
exp "A","B","C","D","E","F","G","H","I","J","K","L","M","N"
exp "O","P","Q","R","S","T","U","V","W","X","Y","Z"
repeat <5>,<exp "X">
0
subttl Line routines
; INILIN -- Initialize the communication line for file transfer.
;
inilin: skipe inited ;[177] Already init'd? Don't do it again.
ret ;[177]
call gtclas ;[130] Check status of class scheduler.
; Set all the terminal mode bits for transparent i/o.
inil2: call dobits ; Go do the bits.
ret ; Pass along any failures.
call doarpa ; Set up any Arpanet stuff.
; Clear the comm line's input buffer.
move t1, netjfn ;[82] Clear the line in case a bunch of NAKs
CFIBF ;[1] have piled up.
erjmp .+1 ;[147] Ignore any errors.
setom inited ;[177] Flag we've done this.
ret
; Get Scheduler Class information.
;
gtclas: setzm class ; Start out assuming scheduler class 0.
movei t1, .skrcv ; Class scheduler on?
movei t2, t3
movei t3, 2 ; Just want 2 words.
SKED%
erjmp gtclsa ; Not R4 or above? Say it's not on.
txnn t4, sk%stp ; Class scheduler on?
skipa ; Yes, it's on - t4 nonzero.
gtclsa: setz t4, ; No, it's off - t4 zero.
movem t4, skdflg ; Set scheduler flag accordingly.
jumpe t4, r ; If no scheduler, go on to next part.
;[130] Scheduler is on, get my scheduler class.
movei t2, skdblk ; Get job's scheduler class. Here's arg block.
movei t1, 5 ; Store length of arg block
movem t1, .sacnt(t2) ; in arg block.
move t1, myjob ; My job number.
movem t1, .sajob(t2) ; Also into arg block.
movx t1, .skrjp ; Function code for getting job class info.
SKED%
erjmp .+2 ; Leap frog
skipa ; to set class to -1 if there was an error.
setom .sajcl(t2) ;
move t1, skdblk+.sajcl ; Now get class.
movem t1, class ; Save it here.
ret
; Set communication line bits for transparent i/o.
; Returns +1 on failure, +2 on success.
;
dobits: move t1, netjfn ; JFN for connection to other system.
movx t2, .mornt ; Read system message status.
MTOPR
%jserr (,dobit2)
movem t3, sysmsg ; Save here for later restoral.
movx t2, .mosnt ; Now refuse system messages.
movx t3, .mosmn
MTOPR
%jserr (,dobit2)
dobit2: movx t1, <tl%cro!tl%cor!tl%sab!tl%sta> ;[147] Clear/Refuse links,
hrr t1, ttynum ;[147] on the line used for file transfer.
txo t1, .ttdes ;[147] (TLINK wants a device designator.)
seto t2,
TLINK
erjmp dobit3 ;[147] Ignore any failure.
dobit3: move t1, netjfn ; JFN for the file transfer line.
movei t2, .morxo ; Get terminal pause end-of-page status.
MTOPR%
%jserr (,r)
movem t3, oldpau ; Save the old pause mode.
movei t2, .moxof ; Now set to...
movei t3, .mooff ; no pause on end.
MTOPR%
%jserr (,r)
movei t2, olddim ;[185] Point to line block
call savlnw ;[185] Save this JFN's length and width
RFMOD% ; Get current mode for this line.
%jserr (,r)
setom carier
setzm mdmlin ;[130] Assume line not modem-controlled.
txne t2, tt%car ;[130] Is it?
setom mdmlin ;[130] Yes, flag.
movem t2, oldmod ; Save the present mode.
;[97] Turn off undesired bits (program echoing, links, translation).
;[97] Turn on desired bits (full duplex; TTY has form feed, tab, lowercase).
;[97] Note that any other settings are left intact, in particular TT%ECM, which
;[97] can cause a TAC to do its own echoing if turned off.
dobit4: ; No echo, no links, no advice, no data mode, full duplex.
txz t2, <tt%eco!tt%alk!tt%aad!tt%dam!tt%dum!tt%lic> ;[129] Add TT$DUM
; No wakeup stuff, infinite width & length.
txz t2, <tt%wkf!tt%wkn!tt%wkp!tt%wka!tt%wid!tt%len!tt%uoc> ;[127]
; No formfeed/tab/case interpretation, use XON/XOFF.
txo t2, <tt%mff!tt%tab!tt%lca!tt%pgm> ;[129] REMOVE TT%DUM!!!
skipn handsh ;[155] Doing handshake?
skipn flow ;[155] Doing flow control?
txz t2, tt%pgm ; Handshake, or no flow - don't do XON/XOFF.
SFMOD% ; Set the bits.
%jserr (,.+1)
STPAR%
%jserr (,.+1)
retskp
;[181] PANDA Network Binary Mode routines
panda < ;[181] Only if doing Panda
;[181] Returns true if we have network binary mode MTOPR%
;[181] Preserves ACs, always returns +1, havnbm: is side-effected
chknbm: saveac <t1,t2,t3> ;[181] Save the registers that MTOPR% trashes
dmove t1,[ exp .CTTRM,.MORLT ] ;[181] Read local status
MTOPR% ;[181] Can the monitor process this request?
erjmp [ setzm havnbm ;[181] No, assume this isn't in the monitor
setzm setlts ;[181] so don't try to use it
ret ] ;[181] and never try to restore status
setom havnbm ;[181] Otherwise, we have winning
ret ;[181] Panda Network Binary Mode!
;[181] Sets network binary mode
;[181] Assumes it can stomp acumulators t1 through t3
;[181] Returns to doarpa's caller on success
;[181] on failure, assumes we don't have network binary mode,
;[181] clears the flag and tries it the old way
setnbm: skipe setlts ;[181] Did we already sucessfully set this?
ret ;[181] Yes, why bother doing it twice?
move t1,netjfn ;[181] Use current line
movx t2,.MORLT ;[181] Read local status
MTOPR%
erjmp nbmerr
movem t3,OLDLTS ;[181] save old terminal status
txo t3,MO%NBI!MO%NBO ;[181] network binary mode (input AND output)
movx t2,.MOSLT ;[181] want to set it
MTOPR%
erjmp nbmerr
movx t2,.MORLT ;[181] now see what actually happened
MTOPR%
erjmp nbmerr
xorx t3,MO%NBI!MO%NBO ;[181] flip binary mode status
txne t3,MO%NBI!MO%NBO ;[181] they should have been BOTH set ...
jrst nbmerr
aos setlts ;[181] flag that we set terminal line status
ret
nbmerr: setzm havnbm ;[181] We don't have network binary mode
callret doarpa ;[181] Maybe the olde fashioned way works?
;[181] un-Sets network binary mode
;[181] Assumes it can stomp acumulators t1 through t3
;[181] Returns to unarpa's caller on success
;[181] on failure, assumes we don't have network binary mode,
;[181] clears the flag and tries it the old way
unsnbm: setz t1, ;[181] whatever the current state is,
exch t1,setlts ;[181] say that it is no longer set
jumpe t1,r ;[181] However: did we ever set nbm??
move t1,netjfn ;[181] Use current line
movx t2,.MOSLT ;[181] Read local status
move t3,OLDLTS ;[181] get former status
MTOPR% ;[181] try to restore it
erjmp [ setzm havnbm ;[181] Use this no longer
callret unarpa ] ;[181] How could this have failed?
ret
> ;[181] End Panda conditional
;[129] Do any required ARPAnet stuff.
;
; Important Note: The ability to send binary mode telnet negotiations
; depends on the monitor NOT doubling IACs on TVT lines. Some versions of
; TOPS-20 (particularly BBN's TCP monitor) will do this.
;
;[181] Use SOUTR% instead of SOUT% to ensure that
;[181] we flush the data to the TAC
;
; Returns +1 always, but prints warning on failure.
;
doarpa: skipn tvtflg ; Are we on tvt?
ret
panda < skipe havnbm ;[181] Does the monitor support network
callret setnbm > ;[181] binary mode?
move t1,netjfn ; Yes, talk binary.
dmove t2,[exp <point 8,[byte(8) iac,will,trnbin]>,-3]
SOUTR% ;[181] This code adapted from MODEM.MAC
%jserr(,doarpx)
movei t1,^d4000 ; Sleep four seconds.
DISMS%
move t1,netjfn ;[181] Tell TVT "do binary".
dmove t2,[exp <point 8,[byte(8) iac,do,trnbin]>,-3]
SOUTR%
%jserr(,doarpx)
movei t1,^d4000
DISMS
ret
doarpx: tmsg <
%KERMIT-20: Warning -- Can't negotiate binary mode with TAC
>
ret
; RESLIN -- Reset/Restore the communications line.
;
; Restore old terminal modes, links, length & width, etc.
; Turn off control-C trap.
;
; CALL RESLIN does nothing if server.
; CALL RRSLIN restores the line even if server.
;
reslin: skipe srvflg ; Server?
ret ; Yes, forget it.
rrslin: call ccoff2 ; REALLY reset the line.
rrsl2: skiple filjfn ; Were we doing something with a file?
jrst [ hrrz t1, filjfn ; If so, try to close it.
setzm filjfn
CLOSF
erjmp .+1
jrst .+1 ]
call unarpa ; Undo Arpanet TAC binary mode.
call unbits ; Restore terminal bits.
call ttxon ; Clear up any XOFF condition.
move t1,netjfn ;[181] TLINK leaves trash in AC1
CFIBF% ; Also clear out any piled up junk.
erjmp .+1
setzm inited ;[177] Flag we're back to normal.
ret
; Undo the effect of DOBITS -- restore all the communication line's
; old bits & modes.
;
unbits: move t1, netjfn ; Get the line.
movei t2, .moxof ; Set the terminal pause on end mode...
move t3, oldpau ; to what it was before.
MTOPR%
%jserr (,.+1)
move t1, netjfn ; Communication line JFN.
move t2, oldmod ; Get the previous mode.
SFMOD%
%jserr (,.+1)
STPAR%
%jserr (,.+1)
movei t2, olddim ;[185] Point to this JFN's dimensions
call rstlnw ;[185] Restore length and width
movx t2, .mosnt ; Restore system msg refuse/accept.
move t3, sysmsg
MTOPR
%jserr (,.+1)
; Restore links and advice if necessary.
setz t1, ; Restore links & advice.
move t2, oldmod ; From old tty mode word.
txne t2, tt%alk ; Was receiving links before?
txo t1, <tl%sab!tl%abs> ; Yes, so receive links.
txne t2, tt%aad ; Was receiving advice before?
txo t1, <tl%sta!tl%aad> ; Yes, so receive links.
jumpe t1, r ; Skip to next part if no bits to set.
hrr t1, ttynum ; Must set bits, form tty designator
txo t1, .ttdes ; ...
setz t2, ; Don't leave garbage in here...
TLINK ; Restore the settings.
erjmp .+1 ; Ignore any errors.
ret
; Turn off Arpanet TAC binary mode.
unarpa: skipn tvtflg ; Are we on a tvt?
ret ; No, skip this.
panda < skipe havnbm ;[181] Does the monitor support network
callret unsnbm > ;[181] binary mode?
move t1, netjfn ;[181] Get the line.
dmove t2, [exp <point 8,[byte(8) iac,wont,trnbin]>,-3]
SOUT% ; Yes, turn off binary mode.
%jserr(,unarpx)
movei t1, ^d4000 ; Wait 4 secs.
DISMS%
move t1, netjfn ; Send the command.
dmove t2, [exp <point 8,[byte(8) iac,dont,trnbin]>,-3]
SOUT%
%jserr(,unarpx)
movei t1, ^d4000 ; Wait another 4 secs.
DISMS%
ret ; Done.
unarpx: tmsg <
%KERMIT-20: Warning -- Can't clear binary mode with TAC
> ;[129] Error message for any of the above.
ret
;[91] Routine to unstop an XOFF'd line, added as edit 91.
ttxon: saveac <t1,t2,t3> ; Save these.
move t1, netjfn ; In case line was XOFF'd, this will
CFOBF% ; turn it back on (see monitor source).
erjmp r
;[157] If we're doing flow control, send a ^Q (XON) to unstick the other side.
skipn flow ; Doing flow control?
ret ; No, done.
RFMOD ; Yes, get terminal mode.
erjmp r
move t3, t2 ; Save it.
txzn t2, tt%dam ; Data mode?
jrst ttxon3 ; No, binary, just send it.
ttxon2: SFMOD ; Put in binary mode.
erjmp r
call ttxon3 ; Send the XON.
move t2, t3
SFMOD ; Put back in data mode.
erjmp r
ret
ttxon3: movei t2, xon ; Send an XON.
BOUT
erjmp r
ret
subttl Packet routines
;[114] DIAMSG
;
; Print packet type and number if debugging "states".
; Enter with:
; t1/ packet type
; t2/ packet number
; t4/ pointer to data
; logjfn/ debugging log file jfn
; Returns +1 always, with all ACs unchanged.
;
diamsg: cain debug, 1 ; Only for protocol debugging.
skipn logjfn ; Got a log JFN?
ret ; Nope, forget it.
saveac <t1,t2,t3> ; Save these.
push p, t1 ; Save this for sec.
move t1, logjfn ; Get debugging log file JFN.
movei t3, ^d10 ; in decimal.
NOUT%
erjmp deberr ;[174]
pop p, t2 ; Pop packet type
BOUT
erjmp deberr ;[174]
cain t2, "G" ; Generic command?
jrst [ move t3, t4 ; Log the first character of the data packet.
ildb t2, t3
BOUT
erjmp deberr ;[174]
jrst .+1 ]
diamsz: movei t2, " " ; A space for delimitation.
BOUT
erjmp deberr ;[174]
ret
;[174] Handle i/o errors writing to debugging log file.
deberr: tmsg <
%KERMIT-20: Error writing debug log file - >
movei t1, .priou
hrloi t2, .fhslf
setz t3,
ERSTR
nop
nop
tmsg <
>
setz t1, ; Close the log file if possible
call $closd ; and turn off debug log.
ret
; SPACK (Send-Packet)
;
; Assembles & sends a packet from the given arguments. Assumes all quoting,
; prefixing, condensing, etc, already done. Sends the fields in the proper
; order, validating the control fields to some extent, adding desired parity
; (if any) to each character, calculates and appends the checksum, appends any
; desired padding or eol characters, and does any required pause or handshake.
;
; Call with:
; AC1 - Type of packet (D,Y,N,S,R,E,F,Z,T,I, or any uppercase letter)
; AC2 - Packet sequence number (binary)
; AC3 - Number (binary) of characters in data field
; AC4 - 8-bit byte pointer to data characters
; Returns: +1 on failure, with:
; AC1 - 0: SOUT failed or timeout on handshake (can retry).
; 1: invalid argument (no point retrying).
; (These values are suitable indexes for a jump table)
; +2 on success, with ACs 1-4 unchanged.
;
spack: saveac <q1,q2,q3> ; Preserve us!
; Set things up.
dmovem t1, actmp ; Save what we were called with in a way that
dmovem t3, actmp+2 ; that they only are restored if we want to.
movem t1, type ; Save the type.
call diamsg ; Print diagnostic if desired.
setz q2, ; Zero the checksum AC.
move q1, [point 8, sndpkt] ; Get a byte pointer to the send packet.
; Start of 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.
; Packet length.
;
;[98] This section changed to allow for different block check types.
movem t3, datlen ; Remember data length for later.
skipe bctone ; Forcing single-character checksum?
aosa t3 ; Yes, then always use type 1.
add t3, bctu ; Otherwise add the block check length.
addi t3, 2 ;[179] Account for SEQ and TYPE.
movem t3, pktlen ;[179] Remember value of packet length field.
;[179] cail t3, 5 ; Does the packet have the minimum length?
camle t3, spsiz ; And is it below the maximum?
kermsg <SPACK: Illegal message length>,spxx2 ; No, fatal.
addm t3, stot ;[22] It's OK, account for the whole packet.
setzm islong ;[179] Assume regular (short) packet
caile t3, ^d94 ;[179] Long packet?
setom islong ;[179] Set flag.
addi t3, " " ;[179] Convert to ASCII.
skipe islong ;[179] Long?
movei t3, " " ;[179] Put a blank here
add q2, t3 ; Add the LEN field to the checksum.
move t1, t3
call @parity ; Call the appropriate parity routine.
idpb t1, q1 ; Put the LEN field into the packet.
;...
; SPACK, cont'd
; Packet sequence number.
skipl t1, t2 ; Is the sequence number valid? (0-64)?
cail t2, ^o100
ermsg <SPACK: Illegal packet sequence number>,spxx2 ; No, fatal.
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.
; Packet type.
move t1, type ; Get the type.
cail t1, "A" ; Check if the type is a capital letter.
caile t1, "Z"
ermsg <SPACK: Illegal message type>, spxx2 ;[60] Not, fatal.
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, datlen ; Is there any data?
jrst spack3 ; No, finish up.
;[179] Extended header for long packet.
skipn islong ;[179] Long packet?
jrst spack2 ;[179] No
move t1, pktlen ;[179] Yes, length
subi t1, 2 ;[179] This time we only count data + checksum
idivi t1, ^d95 ;[179] Big part of length (quotient)
addi t1, " " ;[179] Convert to ASCII
add q2, t1 ;[179] Add to checksum
call @parity ;[179] Tack on parity
idpb t1, q1 ;[179] Deposit in packet
addi t2, " " ;[179] Same deal for small part (remainder)
add q2, t2 ;[179] Add to checksum
move t1, t2 ;[179] Move remainder to t1 for parity routine
call @parity ;[179]
idpb t1, q1 ;[179]
push p, q2 ;[179] Save current packet checksum
move t2, q2 ;[179] Form header checksum
andi q2, ^o300 ;[179] ...
lsh q2, -6 ;[179]
add q2, t2 ;[179]
ldb t1, [point 6, q2, 35] ;[179]
addi t1, " " ;[179]
pop p, q2 ;[179] Restore packet checksum
add q2, t1 ;[179] Include header checksum in it
call @parity ;[179] Add parity to header checksum
idpb t1, q1 ;[179] Put it in the packet
move t3, datlen ;[179] Set t3 as spack2 expects to find it.
; Loop to put each data character in the packet.
spack2: ildb t1, t4 ; Get the next character.
add q2, t1 ; Add it to the checksum.
call @parity ; Call the appropriate parity routine.
idpb t1, q1 ; Put the character into the packet.
sojg t3, spack2 ; Loop for all characters.
;...
; SPACK, cont'd.
;[98] SPACK3-SPAK3X rewritten as part of edit 98.
; Done with the data, now append the appropriate kind of block check.
spack3: skipe bctone ; Doing send-init exchange?
jrst spak3a ; Then always use type 1.
move t1, bctu ; Get block check type,
jrst @[exp spxx2, spak3a, spak3b, spak3c](t1) ; and do it.
; Single-character 6-bit checksum.
spak3a: move t3, q2 ; Make an extra copy of the checksum.
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] ; Take modulo 64.
addi t1, " " ; Add a space so the result is printable.
call @parity ; Call the appropriate parity routine.
idpb t1, q1 ; Put the checksum into the packet.
jrst spak3x ; Done with checksum.
; 2-Character 12-bit checksum.
spak3b: ldb t1, [point 6, q2, 29] ; Get bits 24-29 (high order 6 bits).
addi t1, " " ; CHAR of that.
call @parity ; Do any parity.
idpb t1, q1 ; Deposit this as first character of checksum.
ldb t1, [point 6, q2, 35] ; Get bits 30-35 (low order 6 bits).
addi t1, " " ; CHAR of that.
call @parity ; Do any parity.
idpb t1, q1 ; Deposit this as second checksum character.
jrst spak3x ; Done with checksum.
; 3-character 16-bit CRC CCITT.
spak3c: move t1, datlen ; Length of the data field.
addi t1, 3 ; Plus LEN, SEQ, and TYPE fields.
skipe islong ;[179] Long packet?
addi t1, 3 ;[179] Add length of header.
move t2, [point 8, sndpkt, 7] ; Point to packet starting at LEN field.
call crcclc ; Go compute the CRC.
move q2, t1 ; Here it is.
ldb t1, [point 4, q2, 23] ; Get bits 20-23 (high order 4 bits).
addi t1, " " ; CHAR of that.
call @parity ; Do any parity.
idpb t1, q1 ; Deposit this as first CRC character.
jrst spak3b ; Go back and do other two CRC characters.
;...
; SPACK, cont'd
; Supply requested End-of-Line.
spak3x: 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.
;[36] Do any requested interpacket pausing.
spack5: skipe t1, pause ; Pausing?
jrst [ fmp t1, [1000.0] ; Yes, convert to milliseconds.
fixr t1, t1 ; And then to an integer.
DISMS ; Sleep for that long.
jrst .+1 ]
; Do any requested padding.
spak5a: skipg t4, spadn ;[34] Sending pad characters?
jrst spack6 ;[34] No, just send the packet.
move t1, spadch ;[34] Yes, this is the character.
call @parity ;[34] Tack on desired parity.
move t2, t1 ;[34] Shuffle ACs...
move t1, netjfn ;[34] Where to send the padding.
spak5b: BOUT ;[34] Output the padding character.
%jserr <SPACK: Can't send padding>,spack6 ;[34] Warn about errors.
sojg t4, spak5b ;[34] This many pad characters.
;...
; SPACK, cont'd
;[131] If ARPANET TVT then must double any hex FF's (TELNET IAC).
; Note, since IAC is DEL with parity bit on, we should never see one, right?
;
spack6: move t2, [point 8, sndpkt] ; The address of the packet.
skipn tvtflg ; TVT-Binary mode?
jrst spak6x ; No, just go send it.
move t2, [point 8, sndpkt] ; Yes, must double any IACs.
move t3, [point 8, tvtbuf] ; Copy data field to this place.
spak6a: ildb t1, t2 ; Byte loop. Get one.
jumpe t1, spak6b ; Done?
idpb t1, t3 ; No, copy it.
cain t1, iac ; IAC?
idpb t1, t3 ; Yes, copy it again.
jrst spak6a ; Till done.
spak6b: setz t1, ; Done, make result asciz.
idpb t1, t3 ; ...
move t2, [point 8, tvtbuf] ; Point to result.
;[131] End. Now, finally send the packet.
spak6x: move t1, netjfn ; JFN for sending the packet.
setzb t3, t4 ; Terminate on a null.
SOUT% ; Send the string.
erjmp spxx1 ; JSYS error, go handle.
spak6y: aos sptot ;[4] Count the packet we sent.
skipn debug ;[128] Debugging?
jrst spackb ; No, how about blips?
caie debug, 2 ;[128] Yes, packets?
jrst spackz ; No, states, that's taken care of elsewhere.
; Debugging -- Log the packet.
skipn t1, logjfn ; Yes, but make sure we have a destination.
jrst spackz ; We don't, skip this.
hrroi t2, [asciz/
S,/] ; We do, give a crlf and "S," first.
setzb t3, t4
SOUT
erjmp spkder
seto t2, ; Include time stamp, current date/time.
movx t3, ot%nda ; But no date.
ODTIM
erjmp spkder
spackd: movei t2, "," ; Comma,
BOUT
erjmp spkder
setzb t3, t4
move t2, [point 8, sndpkt] ; Now the packet itself.
SOUT
erjmp spkder
hrroi t2, crlf ; Another crlf
SOUT
erjmp spkder
jrst spackz
;...
;...SPACK, cont'd
;[174] Recover from errors writing to debugging log.
spkder: call deberr
jrst spackz
;[4] Put blips on user's screen if local.
spackb: skipl filjfn ;[106] No blips if output is to TTY.
skipn local ; Not debugging, but still local?
jrst spackz ; Remote, don't make blips.
move t3, type ; Local, am I sending a NAK packet?
movei t1, "%" ; Print a "%" for each one I send.
move t2, numtry ; Or each resend I have to do.
caig t2, 1 ;
cain t3, "N" ;
jrst spackx ;
setz t3, ; Not a NAK, is it time to blip?
move t4, sptot ; Check the absolute packet number.
divi t3, blip ; We do it every "blip" packets.
jumpn t4, spackz ; Not time for a blip.
movei t1, "." ; It's time, here's the blip.
spackx: PBOUT% ; "."
; Common exit point for successful exit.
spackz: dmove t1, actmp ;[60] Restore what we were called with
dmove t3, actmp+2 ;[60]
retskp
; Exit point for nonfatal errors.
spxx1: skipe mdmlin ; Modem line?
jrst [ move t1, netjfn ; Yes, see if we just dropped carrier.
call chkli2
skipn carier ; Still have it?
jrst spxx2 ; No, then fatal.
jrst .+1 ] ; Yes, can continue trying.
setz t1, ;[60] Indicate nonfatal.
ret
; Exit for fatal errors.
spxx2: movei t1, 1 ;[60] Indicate fatal.
ret
; RPACK -- Receive-Packet
;
; This routine waits for a packet to arrive. It reads characters until it
; finds the start-of-packet character, normally SOH. It then reads the packet
; into RECPKT based on the length supplied in the length field (no termination
; character necessary).
;
; Returns:
; +1 failure (if the checksum is wrong or the packet trashed)
; +2 success with:
; t1/ Packet type
; t2/ Packet number
; t3/ Length of data field
; t4/ 8-bit byte pointer to data field
;
rpack: saveac <q1,q2,q3> ; Save these ACs.
stkvar <pktbct> ; Block check type for this packet.
setzm islong ;[179] Assume packet is not long.
cain debug, 2 ; Logging packets?
skipn t1, logjfn ; Yes, make sure there's a log.
jrst rpackb
hrroi t2, [asciz/
R,/] ; "R" for Receive
setzb t3, t4
SOUT
erjmp [call deberr ;[174] Recover from debug log errors.
jrst rpacka ]
seto t2, ; Time stamp, current date/time.
movx t3, ot%nda ; But no date.
ODTIM
erjmp [call deberr ;[174]
jrst rpacka ]
movei t2, "/" ; Current timeout interval.
BOUT
erjmp [call deberr ;[174]
jrst rpacka ]
movei t1, tmout ; Place to go on timeout.
call timeit ; Set the timer
move t1, logjfn
move t2, curtim ; Log current time interval
movei t3, ^d10
NOUT
erjmp [call deberr ;[174]
jrst rpacka ]
rpacka: movei t2, ","
BOUT
erjmp [call deberr ;[174]
jrst rpackb ]
move t1, netjfn ; JFN of the communication line.
jrst rpack0 ; Already set timer...
; Here if not logging packets.
rpackb: movei t1, tmout ; Place to go on timeout.
call timeit ; Time out if it takes too long.
move t1, netjfn ; JFN of the communication line.
;...
;...RPACK, cont'd
; Eat interpacket garbage, read up to start-of-packet character.
rpack0: call inchar ; Get a character from the line.
jrst rperr ; If we can't, go fail.
came t2, rsthdr ;[18] Is the char the start of header char?
jrst rpack0 ; No, go until it is (or we are timed out).
; Now read the packet.
rpack1: move q1, [point 8, recpkt] ; OK, now point to the packet buffer.
idpb t2, q1 ; Put the start character into the packet.
; Packet length field = number of characters to follow the length field,
; up to and including the last block check character.
call inchar ; Get next character from the line.
jrst rperr
camn t2, rsthdr ;[18] Is the char the start of header char?
jrst rpack1 ; Yes, then go start over.
idpb t2, q1 ; Copy character to packet buffer.
move q2, t2 ; Start the checksum.
move q3, t2 ; Save the length here for later.
; Packet sequence number.
call inchar ; Get the next character
jrst rperr
camn t2, rsthdr ;[18] Start of header?
jrst rpack1 ; Yes, go start over.
idpb t2, q1 ; No, put it in the packet.
add q2, t2 ; Add it to the checksum.
subi t2, " " ; Get the real packet number.
movem t2, num ; Save it for later.
; Packet type.
call inchar ; Next character.
jrst rperr
camn t2, rsthdr ;[18] SOH?
jrst rpack1 ; Yes, go back.
idpb t2, q1 ; Not SOH, keep it.
add q2, t2 ; Add it to the checksum.
movem t2, type ; It's the message type, remember it.
;...
;...RPACK, cont'd
;[123] Beginning of change
;
; Now determine block check type for this packet. Here we violate the layered
; nature of the protocol by inspecting the packet type in order to detect when
; the two sides get out of sync. Two heuristics allow us to resync here:
;
; a. An S packet always has a type 1 checksum.
; b. A NAK never contains data, so its block check type is LEN-2.
subi q3, " " ;[179] Convert ASCII length to number.
skipn q3 ;[179] Is it zero?
setom islong ;[179] Yes - long packet.
skipn islong ;[179] Long?
subi q3, 2 ;[179] No, subtract 2 for SEQ & TYPE fields.
move t1, bctu ; Expected block check type.
skipn bctone ; But if type 1 is required,
cain t2, "S" ; or if this is an S packet,
movei t1, 1 ; then force the type to 1.
cain t2, "N" ; But, is this a NAK?
move t1, q3 ; Yes, so this must be the block check type.
movem t1, pktbct ; Save the block check type we have determined.
skipn islong ;[179] Long packet?
jrst rpackc ;[179] No, go get data.
move t1, netjfn ;[179] Set up for inchar.
call inchar ;[179] Get next character.
jrst rperr ;[179]
idpb t2, q1 ;[179] Save it.
add q2, t2 ;[179] Add to checksum.
subi t2, " " ;[179] Convert to number.
move q3, t2 ;[179] Set to make...
imuli q3, ^d95 ;[179] big part of length.
call inchar ;[179] Get next character.
jrst rperr ;[179]
idpb t2, q1 ;[179] Save it.
add q2, t2 ;[179] Add to checksum.
subi t2, " " ;[179] Convert to number.
add q3, t2 ;[179] Add to big part of length.
call inchar ;[179] Get next character (header checksum)
jrst rperr ;[179]
idpb t2, q1 ;[179] Save it.
add q2, t2 ;[179] Add to checksum.
; [179] HERE WE SHOULD CHECK THE HEADER CHECKSUM...
; [179] But no big deal since overall checksum will catch any errors later.
; Now subtract the block check length from the packet length, which gives the
; length of the data field.
rpackc: sub q3, pktbct ; Calculate the data length.
movem q3, datlen ; Save it.
; Take in the data field.
move t1, netjfn ; Get the packet input jfn back again.
;[123] End of change.
movem q1, datptr ; Return pointer to the data buffer.
skipg q3, datlen ; Use character count for loop control.
jrst rpbc ;[99] If none, go get the block check.
; Loop to get the specified number of data characters.
rpack2: hrrz t2, q1 ;[117] Check for buffer overflow.
cail t2, recpkz ;[117] If we're past the end, go back and
jrst rpack0 ;[117] eat characters until a ^A.
call inchar ; Get a character from the line.
jrst rperr ; Oops, can't.
camn t2, rsthdr ; 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.
;...
;...RPACK, cont'd
; Count exhausted, next characters will be the block check.
;
;[98] This section, thru RPACK4, mostly rewritten as part of edit 98.
rpbc: movem q1, bctemp ; Save pointer to block check.
move q3, pktbct ;[123] Length of block check for this packet.
;[123] skipl datlen ;[99] If data len negative, must be type 1 NAK!
;[123] skipe bctone ; or if this flag is set,
;[123] movei q3, 1 ; must look for single-character checksum.
; Get the checksum bytes and add them up.
setz t3, ; Accumulator for 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.
idpb t2, q1 ; Got one, deposit it.
lsh t3, 6 ; Accumulate numeric value
addi t3, -40(t2) ; ...
sojg q3, rpack3 ; Go back and get the rest.
setz t1, ; Make the string ASCIZ.
idpb t1, q1
;[135] If doing handshake, look for that now.
;[135] (This code moved from beginning of SPACK)
rpakh1: skipn handsh ; Doing handshake?
jrst rpakcc ; Nope.
rpakh2: move t1, netjfn ; Try to get a character
call inchar ; from the line.
jrst rpakhx ; If there was an error, try to proceed
andi t2, 177 ; Strip the high bit.
came t2, handsh ; Is it the handshake character?
jrst rpakh2 ; No, keep going till it is.
rpakhx: ;...
;[135](end of change)
;...RPACK, cont'd
; Check the checksum.
rpakcc: skipl datlen ;[99] If negative data length, or
skipe bctone ; explicitly requested to,
jrst rpak3a ; then compute 1 character checksum.
move t1, bctu ; Otherwise get the type which we're using.
jrst @[exp rperr, rpak3a, rpak3b, rpak3c](t1)
; Here for single-character 6-bit checksum.
rpak3a: move q3, q2 ; Make a copy of the arithmetic checksum.
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.
andi q2, 77 ; Get the modulo 64 of the char total.
jrst rpak3x ; Go check it.
; Two-character 12-bit checksum.
rpak3b: andi q2, 7777 ;[100] Mask out all but 12 bits.
jrst rpak3x ; Go compare.
; 3-character 16-bit CRC CCITT.
rpak3c: move t1, datlen ; Get the data length.
addi t1, 3 ; Account for LEN, SEQ, and TYPE fields.
skipe islong ;[179] Long packet?
addi t1, 3 ;[179] Also account for extended header.
move t2, [point 8, recpkt, 7] ; Point to packet starting at LEN field.
call crcclc ; Compute CRC.
ldb q2, [point 16, t1, 35] ;[100] Get exactly 16 bits worth.
;...
;...RPACK, cont'd
; Compare the two block checks.
rpak3x: caie t3, (q2) ; Are they equal?
jrst badbc ; No, bad block check.
; All OK, turn off timer, flush buffer.
rpack4: call timoff ; Got packet OK, turn off the timer.
move t1, netjfn ;[17] Clear out any further junk from input
CFIBF% ;[17] buffer, there should be nothing there
erjmp .+1 ;[17] till after we reply.
; Set up ACs 1-4 with results and return successfully.
rpackx: aos rptot ; Count the packet we received.
move q1, bctemp ; Pointer to first character of block check.
setz t1, ; Terminate the data string, nullifying
idpb t1, q1 ; the block check.
move t1, type ; Return the packet type in T1,
move t2, num ; the sequence number in T2,
call diamsg ; Log the packet type & number if desired.
skipge t3, datlen ; the number of data characters in T3,
setz t3, ;***
move t4, datptr ; and a pointer to the data in t4.
retskp ; Return +2.
; Come here if block checks don't compare.
badbc: skipn t1, logjfn ;[38] No, do we have a debugging log?
jrst rperr ;[38] No, skip messages.
setzb t3, t4 ;[38] Yes, say checksum was bad.
hrroi t2, [asciz/
%chksum /] ;[29]
SOUT
erjmp [call deberr ;[174]
jrst .+1 ]
; Exit thru here upon any kind of error except a timeout.
rperr: call timoff ; Cancel the time out.
move t1, netjfn ;[17] Flush any stacked up packets from the
CFIBF% ;[17] input buffer. If anything's there, we
erjmp .+1 ;[17] don't want it!
ret ; Return unsuccessfully.
subttl Support Routines for RPACK.
; INCHAR - Get a character from the communication line.
;
; Call with:
; t1/ JFN of comm line.
;
; Returns:
; +1 on failure, with state set to "A" if carrier dropped.
; +2 on success with:
; t1/ unchanged
; t2/ character, with parity bit stripped if parity is being used.
;
inchar: saveac <t1> ; Save the JFN.
;[180] Begin buffering communications input change.
skiple tticnt ; Something in buffer?
jrst [ sos tticnt ; Yes, decrement count
ildb t2, ttiptr ; Load next byte.
aos ttildb ; (stats)
jrst inch3 ] ; Go handle byte.
SIBE% ; Buffer empty - see if anything is waiting.
jrst [ caile t2, IOBUF ; Adjust if more than buffer size.
movei t2, IOBUF
movem t2, tticnt ; Remember how many we asked for
movn t3, t2 ; Negative version for SIN
move t2, [point 8, ttibuf] ; Where to put them
movem t2, ttiptr ; Reset buffer pointer
SIN% ; Try to read
erjmp inchxx ; Error...
aos ttisin ; Number of SINs for stats
add t3, tticnt ; How many we got (t3 is negative)
camle t3, ttimax ; Maximum size of a SIN for stats
movem t3, ttimax
movem t3, tticnt ; Save the input byte count
skipg tticnt ; More than zero
jrst inch2 ; Less than one - go do blocking BIN
sos tticnt ; Decrement count
ildb t2, ttiptr ; Load next byte.
aos ttildb ; (stats)
jrst inch3 ] ; Go handle byte.
; Do BIN if SIBE sees nothing waiting or if SIN gets nothing.
;[180] End buffering change.
inch2: setzm tticnt ;[180]
setz t2, ; (in case of error)
BIN% ; Get a character from the line.
erjmp inchxx ;[130] Error, go see what.
aos ttibin ;[180] (stats)
inch3: ;[180] (label added).
cain debug, 2 ; Logging packets?
call [ skipn t1, logjfn ; Yes, make sure there's a log.
ret
BOUT ; Record the character.
erjmp deberr ;[174]
ret ]
aos rtot ; Increment total character count.
move t1, parity ; What type of parity?
caie t1, none ; If none, don't touch the parity.
andi t2, ^o177 ; Else, take out parity.
retskp ; Done, return successfully.
;[130] Error handler to check for carrier dropped.
inchxx: skipn mdmlin ; Modem controlled line?
ret ; No, just return +1 to indicate error.
move t1, netjfn ; Yes, see if we still have carrier
call chkli2 ; ...
skipe carier ; Do we?
ret ; Yes, so some other error, handle normally.
wtlog <Carrier Dropped, Connection Terminated> ; No, lost it. Log.
movei state, "A" ; Cancel this transaction.
setzm carier ; Say no more carrier.
ret
; Come here on timeout, via interrupt handler.
tmout: call rperr ;[46] Clean up timers & buffer...
call ttxon ;[91] Unstop the line in case it was XOFF'd.
movei t1, "T" ; Make believe we got a "Timeout" packet
move t2, pktnum
setzb t3, t4 ; No data.
call diamsg
retskp ; Return successfully as if with real packet.
subttl CRC and Parity Routines
;[66] CRC calculation
;
; This routine will calculate the CRC for a string, using the
; CRC-CCITT polynomial.
;
; The string should be the fields of the packet between but not including
; the <mark> and the block check, which is treated as a string of bits with
; the low order bit of the first character first and the high order bit of the
; last character last -- this is how the bits arrive on the transmission line.
; The bit string is divided by the polynomial
;
; x^16+x^12+x^5+1
;
; The initial value of the CRC is 0. The result is the remainder of this
; division, used as-is (i.e. not complemented).
;
; Contributed by Nick Bush, Stevens Institute of Technology.
;
; Call with
; t1/ length of string
; t2/ 8-bit byte pointer to string
; Returns +1 always, with t1/ 16-bit CRC, t2 unchanged.
;
; AC usage:
; t1/ Accumulated CRC
; q4/ Remaining length
; q3/ Byte pointer to string
; q2/ temp
; q1/ temp
;
crcclc: saveac <q1,q2,q3,q4,t2> ; Save q1-q4, and t2.
dmove q3,t1 ; Get arguments.
setz t1, ; Initial CRC is 0.
move t2, parity ;[136] Get parity.
crcc.1: ildb q1, q4 ; Get a character.
caie t2, none ;[136] Parity = NONE?
andi q1, ^o177 ;[136] No, doing parity, strip parity bit.
xori q1, (t1) ; Add in with current CRC.
ldb q2, [point 4,q1,31] ; Get high 4 bits.
andi q1, ^o17 ; And low 4 bits.
move q1, crctb2(q1) ; Get low portion of CRC factor.
xor q1, crctab(q2) ; Plus high portion.
lsh t1, -^d8 ; Shift off a byte from previous CRC.
xor t1, q1 ; Add in new value.
sojg q3, crcc.1 ; Loop for all characters.
ret ; Done, return +1 with CRC in t1.
; Data tables for CRC-CCITT generation
crctab: oct 0
oct 10201
oct 20402
oct 30603
oct 41004
oct 51205
oct 61406
oct 71607
oct 102010
oct 112211
oct 122412
oct 132613
oct 143014
oct 153215
oct 163416
oct 173617
crctb2: oct 0
oct 10611
oct 21422
oct 31233
oct 43044
oct 53655
oct 62466
oct 72277
oct 106110
oct 116701
oct 127532
oct 137323
oct 145154
oct 155745
oct 164576
oct 174367
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
subttl Server Operation
; GETCOM
;
; We come here if we are in server mode. We just wait for a packet of one of
; the following types:
;
; S Send init - just follow the normal path from here
; R Receive init - like a local "send filespec"
; I Init (all-purpose exchange of parameters)
; G Generic command:
; L Logout - the other side is done, log out this job
; F Finish - exit from Kermit
; U Disk Usage query
; T Type a file
; etc
;
; First, issue a message telling the user what to do.
;
getcom: movei t1, [ ;[157] In case line gets XOFF'd while
call ttxon ;[157] typing the message, unstick it,
jrst getcm2 ] ;[157] and proceed.
call timeit ;[157] Set the timer.
skipe local ;[174] Local mode?
jrst [ tmsg <
Entering server mode on TTY> ;[174] Yes, give appropriate message.
numout ttynum, 8
skipl speed
jrst [ tmsg <, >
numout speed
tmsg < baud>
jrst getcmm ]
jrst getcmm ] ;[174]
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 BYE command to KERMIT on your local machine.>
getcmm: tmsg <
>
getcm2: call timoff ;[157] Turn off timer.
setom srvflg ; Flag that we are serving.
call inilin ; Initialize the line.
call ccon ; Don't let someone ^C without reseting line.
jrst xgfin2 ; On control-C, go "finish".
setzm delay ; No delay in server mode.
setzb t3, t4 ; Set default parameters in case we get some
call spar ; command before first Send-Init or Info.
jrst xxwait ; Go wait for a command packet.
; Server command loop. Server commands should always jrst back to here,
; even upon error, except for those that specify exit from server mode.
;
xxwait: skipe mdmlin ;[130] Modem line?
skipe carier ;[130] Did carrier drop?
skipa ;[130] No.
jrst xgfin2 ;[130] Yes, go clean up.
setom sptot ;[134] Clear packet statistics counters
setom rptot ;[134] ...
setzm xflg ; Clear the server "type" flag.
setzm source ; Ditto for GETCH source.
setzm dest ; Ditto for PUTCH destination.
setzm ffunc ; And for file function.
move t1, srvtim ; Get the default server packet time out.
movem t1, stimou ; Set it so we don't time out as often.
xxwt2: setom bctone ;[98] Set this so we use type 1 checksum.
setzm pktnum ; Initial packet sequence number.
call rpack ; Get a packet.
skipa ; On error, NAK what we're looking for.
cain t1, "T" ; Timer interrupt pseudo packet?
jrst [ move t2, pktnum ; Yes, NAK that "packet".
call nak ;
jrst xxwt2 ; Go round again.
jrst xxwt2 ] ; (no matter what)
cail t1, "A" ;[150] Packet type in range?
caile t1, "Z" ;[150]
kermsg <Packet type out of range>,xxwait ;[150] No.
; Got a real command. Restore the normal timeout interval and do the command.
movem t2, pktnum ; Save packet number.
push p, t1 ; We can't use any normal AC's here...
move t1, otimou ; Put normal timeout back.
movem t1, stimou
pop p, t1
jrst @<xxcmd-<"A">>(t1) ;[150] Go do the indicated command.
;[150] Server command dispatch table and error message routines.
xxcmd: xxinv ; A - Attributes, shouldn't come now
xxinv ; B - EOT, shouldn't come now
xhost ; C - Host Command
xxinv ; D - Data, shouldn't come now
xxwait ; E - Error, just ignore
xxinv ; F - File header, shouldn't come now
xgen ; G - Generic Command
xxunk ; H - Undefined
xinfo ; I - Info Packet
xxunk ; J - Undefined
xxunk ; K - Undefined
xxunk ; L - Undefined
xxunk ; M - Undefined
xxwait ; N - NAK, ignore
xxunk ; O - Undefined
xxunk ; P - Undefined
xxunk ; Q - Undefined
xrecv ; R - Receive (GET), server sends
xsend ; S - Send, server receives
xxwait ; T - (Already handled specially above)
xxunk ; U - Undefined
xxunk ; V - Undefined
xxunk ; W - Undefined
xxinv ; X - Text Header, shouldn't come now
xxwait ; Y - ACK, ignore
xxinv ; Z - EOF, shouldn't come now
0 ; (superstition)
; Routine to issue informative error messages.
xxunk: move t4, [point 7, xxumsg] ; Get "unknown command" message.
movei t3, xxulen ; And its length
jrst xxmsg
xxinv: move t4, [point 7, xxbmsg] ; Get "invalid use of..." message.
movei t3, xxblen ; And its lentgh.
xxmsg: push p, t4 ; Save msg pointer.
ibp t4 ; Point past opening quote.
idpb t1, t4 ; Deposit the packet type.
movei t1, "E" ; Send an Error packet.
move t2, pktnum ; This is the packet number.
pop p, t4 ; Get original pointer back.
call spack ; Send the error packet.
nop
jrst xxwait ; Go back to command wait.
subttl Server commands.
; Server SEND command (i.e. send to me, I'm the server, I receive the files.)
;
; We've just received a Send-Init.
;
xsend: setzm numtry ; Packet retry counter.
movem t2, pktnum ; Synchronize packet numbers.
call spar ; Get the Send-Init parameters.
move t4, [point 8, data] ;[50] Now send back our own,
call rpar ; which we put in the data field of our ACK.
movei t1, "Y" ; Set up the ACK.
move t2, pktnum ; Packet number.
call spack ; Send the packet.
jrst xxwait ;* Give up if we can't.(?)
call rrinit ;[126] Set things up for receiving.
movei state, "F" ; Set the state to file send.
call $recvs ;[42] Go look like we're receiving.
nop ;
jrst xxwait ; Get another command when done.
; Server RECEIVE (or GET) command -- Server sends files.
;
; We've just received a Receive-Init packet, containing a filename.
; (Or a remote TYPE command). T1-T4 contain packet parameters returned
; by RPACK.
;
xrecv: move t1, t4 ;[141] Pointer to encoded filespec.
move t2, t3 ;[141] Number of characters.
call decodf ;[141] Decode it.
kermsg <Can't decode filename>, xxwait ;[141] Can't? Give message.
move t2, t1 ;[141] Decoded OK, point to decoded filespec.
; Entry point when filespec already decoded.
xrecv2: movx t1, gj%sht!gj%old!gj%ifg ; Old file and allow wildcarding.
GTJFN% ; Get a JFN.
%jsker (,xxwait) ; Can't, send error packet and loop.
movem t1, ndxjfn ;[111] Got JFN, save wildcard bits here.
hrrzm t1, nxtjfn ;[111] Initialize file lookahead.
call gtnfil ;[111] Get next (in this case, first) file.
nop ;[111] Could never fail, right?
call $sends ; Go send the file(s).
nop ; (in case it skips for some reason...)
jrst xxwait ; Go back & get another command.
; HOST command.
xhost: kermsg <Host commands not implemented>, xxwait
;[150] Server GENERIC command. Get the subcommand and execute it.
xgen: ildb t1, t4 ; Get the first character of the data field.
cail t1, "A" ; Validate.
caile t1, "Z"
kermsg <Generic command out of range>, xxwait ; Bad.
sos t3 ; Command in range, account for it.
jrst @<xxgcmd-<"A">>(t1) ; Dispatch to it.
;[150] Server generic command dispatch table.
xxgcmd: xgundf ; A - Undefined
xgundf ; B - Undefined
xgcwd ; C - CWD
xgdir ; D - Directory
xgdel ; E - Erase (delete)
xgfin ; F - Finish
xgundf ; G - Undefined
xghelp ; H - Help
xgnyi ; I - Login (not yet implemented)
xgnyi ; J - Journal control (nyi)
xgnyi ; K - Copy (nyi)
xglogo ; L - Logout, Bye
xgnyi ; M - Short message
xgundf ; N - Undef
xgundf ; O - Undef
xgnyi ; P - Program invocation (nyi)
xgnyi ; Q - Server status query (nyi)
xgnyi ; R - Rename (nyi)
xgundf ; S - Undef
xgtype ; T - Type
xgdisk ; U - Disk Usage
xgnyi ; V - Variable Set/Query
xgnyi ; W - Who (Finger)
xgundf ; X - Undef
xgundf ; Y - Undef
xgundf ; Z - Undef
0
xgundf: move t4, [point 7, xxgums] ; Issue message for undefined command.
movei t3, xxguln
jrst xxmsg
xgnyi: move t4, [point 7, xxgnms] ; Issue msg for unimplemented command.
movei t3, xxgnln
jrst xxmsg
; 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.
nop ;[56]
move t1, netjfn ;[158] Wait for the ACK to get there.
DOBE ;[158] ...
erjmp .+1 ;[158] ...
setom f$exit ;[137] Say we want to go back to command level.
xgfin2: call rrslin ;[121] Put line back in interactive 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
skipe t1, logjfn ;[38] If we were logging,
CLOSF ;[38] close the log.
erjmp .+1 ;[38] (Ignore any errors here.)
setzm logjfn ;[38]
ret ; Done
; 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.
nop ;
move t1, netjfn ;[158] Wait for the packet to arrive.
DOBE ;[158]...
erjmp .+1 ;[158]...
call rrslin ; Restore the line for interactive use.
move t1, odelay ; Restore normal delay
movem t1, delay ;
move t1, otimou ; and timout interval
movem t1, stimou ;
setzm srvflg ; and reset the server flag.
wtlog <BYE Received> ;[126] Log the BYE.
call clenup ;[126] Close all logs.
setom f$exit ; Just in case we can't logout, set exit flag.
seto t1, ; -1 = Myself.
LGOUT% ; Log me out.
%jsker (,r) ; If this fails, print msg & go back.
; Command to TYPE a file. Just like sending a file, except must send "X"
; packet instead of file header.
xgtype: call getarg ; Get the argument.
setom xflg ; Send file with X header.
move t2, t4 ;[141] Point to filespec.
jrst xrecv2 ;[141] Do like when we get an R packet.
;[58] Init-Info mechanism added as edit 58.
;
; Get an "I" parameters packet from the user, record the parameters, and send
; our own back in return. This exchange is optional, but should take place
; before any server/user transaction except file transfer, where it is required
; and always takes place via the Send-Init mechanism.
;
xinfo: movem t2, pktnum ; Set the parameters we just got.
call spar
setzm numtry
move t4, [point 8, data] ; Respond with ours.
call rpar
movei t1, "Y"
move t2, pktnum
call spack
nop ; If they don't get it, they'll ask again...
jrst xxwait
; GTSCH -- Get String Character
;
; Alternate GETCH routine for getting a character from an ASCIZ string in
; memory. Uses global STRPTR for input string.
;
; Returns:
; +1 if no more characters left in string.
; +2 always, with NEXT containing next character, -1 if no more.
;
gtsch: ildb t1, strptr ; Get next character.
jumpe t1, gtschz ; If zero, must be done.
; Return with character like GETCH.
gtschx: movem t1, next ; Put result in NEXT, as GETCH does.
retskp ; Done.
; "EOF" return, like GETCH
gtschz: setz t1,
setom next
ret
; PUTSCH
;
; Alternate PUTCH routine. Just writes the character to a string in memory.
; Call with t2/ character to write.
;
putsch: idpb t2, strptr ; Here's the alternate PUTCH routine.
retskp ; It always succeeds.
; PUTTCH
;
; Another alternate PUTCH routine. Writes the character to the terminal.
; Call like PUTCH and PUTSCH.
;
puttch: skipe local ;[177] But only if in remote mode.
retskp ;[177] ...
push p, t1
movei t1, .priou
BOUT
erjmp .+1
pop p, t1
retskp
; GETARG
;
; Decode server command packet, set up pointers, get first argument.
;
; Return +1 with:
; t3/ Length of first argument
; t4/ pointer to first argument
;
getarg: movei t1, putsch ; Address of alternate PUTCH routine.
movem t1, dest
setzm strbuf ; Clear decoding area.
move t1, [strbuf,,strbuf+1]
blt t1, strbz
move t1, [point 7, strbuf] ; Where to put the decoded string.
movem t1, strptr
move t1, t4 ; Pointer to data to decode.
move t2, t3 ; Length.
call putbuf ; Go decode the packet.
jrst [ setzm dest
kermsg <Can't decode server command>, xxwait ]
setzm dest ; Put PUTCH back to normal.
move t4, [point 7, strbuf] ; Point to decoded string.
ildb t3, t4 ; Get CHAR(length) of directory string.
caige t3, 40 ;[128] If null, no need to convert.
movei t3, 40 ;[128] This also catches funny cases.
subi t3, 40 ; UNCHAR of that to make a number.
ret
;[107] CWD server command (Connect to directory in DEC-20 parlance).
;
; Changes Working Directory, sends new directory name back in ACK, or else
; error packet if there's a problem.
;
; Arrive here with t4 containing pointer to argument string of form
; <length><directory><length><password>
; where <length> is a single character (offset by CHAR),
; and t3 containing the length of the string.
;
xgcwd: call getarg ; Get the first argument.
jumpg t3, xgcwd3 ; If positive, go handle string.
jumpe t3, xgcwd5 ; If null, go connect back to own directory.
kermsg <Bad length field in CWD packet>,xxwait ; Negative length???
; Set up argument block for ACCES
xgcwd3: move q1, t4 ; Byte pointer to directory string.
adjbp t3, t4 ; Now point to password.
ildb t4, t3 ; Get its length.
move q2, t3 ; Put pointer in ACCES arg block.
subi t4, 40 ; UNCHAR to make it a number.
skipge t4 ; Normal kind of number?
setz t4, ; No, must have fallen off end, so no pswd.
setz t2, ; Zero the length to make directory asciz.
dpb t2, t3 ; ...
adjbp t4, t3 ; Make sure password is asciz.
idpb t2, t4
; Access the directory. ** Maybe should also mount structure if necessary?
xgcwd4: move t1, [ac%con!<3>] ; Function is Connect, arg block has 2 words.
movei t2, q1 ; Address of argument block.
seto q3, ; Own job.
ACCES
%jsker (,xxwait) ; Send any error message in error packet.
jrst xgcwdz ; Done connecting, go send ACK.
;...XGCWD, cont'd
; Come here to connect to own directory.
xgcwd5: seto t1, ; This job.
hrroi t2, q1 ; Want one word, put it in q1.
movei t3, .jilno ; Logged-in directory number.
GETJI
%jsker (,xxwait)
move t1, [ac%con!<3>] ; Function is connect.
setz q2, ; No password needed
seto q3, ; Own job.
movei t2, q1 ; Address of arg block.
ACCES ; Connect to own directory.
%jsker (,xxwait)
;...
;...XGCWD, cont'd
; Done, send back ACK with directory string in it.
xgcwdz: GJINF
move t1, [point 7, strbuf]
movem t1, strptr
DIRST
%jsker (,xxwait)
movei t1, gtsch ; Indicate routine to be used for getting
movem t1, source ; characters.
setom next ; Set initial condition.
move t1, maxdat ; Get a buffer full of data.
call getbuf ; ...
jumpn t1, xxwait ;
setzm source ; Put GETCH back to normal.
move t3, t1 ; Length
movei t1, "Y" ; Y for Yes (ACK)
setz t2, ; Packet number 0.
move t4, [point 8, data] ; Point to string built by getbuf.
call spack ; Send the ACK.
nop ; Nothing much we can do here...
jrst xxwait ; Done.
;[56] Disk USAGE server query added in edit 56.
;
; Assumes reply will fit in data field of ACK packet; does not use
; text header ("X") protocol. Sends as much of reply as will fit.
;
xgdisk: seto t1, ; Get disk usage of connected directory.
GTDAL%
%jsker <Can't get disk usage>,r
dmove q1, t1 ; Save the numbers in q1,q2.
move t1, [point 7, strbuf] ;[103] String pointer to data field.
movem t1, strptr ;[103]
hrroi t2, [asciz/Quota: /]
setzb t3, t4 ; Source string is null-terminated.
SOUT%
erjmp xgdis2
move t2, q1 ; Quota, or "+Inf"
cail t2, [^d100000000]
jrst [ hrroi t2, [asciz/+Inf/]
SOUT
jrst xgdsk2 ]
movei t3, ^d10 ; in decimal
NOUT%
erjmp xgdis2
xgdsk2: hrroi t2, [asciz/, used: /]
setzb t3, t4
SOUT%
erjmp xgdis2
move t2, q2 ; Pages used,
movei t3, ^d10 ; in decimal
NOUT%
erjmp xgdis2
hrroi t2, [asciz/ (pages)/] ; Specify units
setzb t3, t4
SOUT%
erjmp xgdis2
xgdis2: move t2, strptr ;[103] Check length
exch t1, t2
call subbp
%jsker <subbp foulup>,r
idpb t4, t2 ; Done constructing string, make it asciz
move q1, spsiz ; Is the string bigger than max size to send?
subi q1, 5
caig q1, (t3) ; (it should always fit).
move t3, q1 ; Yes, so cut it off at the limit.
;..
;...XGDISK, cont'd
;[103] Begin Change: Use standard packet filling technique to send this.
movei t1, gtsch ; Indicate routine to be used for getting
movem t1, source ; characters.
setom next ; Set initial condition.
move t1, maxdat ; Get a buffer full of data.
call getbuf ; ...
jumpn t1, xxwait ;
move t3, t1 ; Set up length.
setzm source ; Put GETCH back to normal.
;[103] End Change. Now send the packet.
xgdisz: movei t1, "Y" ; Formulate the ACK
setz t2, ; (Packet number should be 0, right?)
move t4, [point 8, data] ; The data itself
call spack ; Send it off.
nop ;* What if it fails?
jrst xxwait
;[120] HELP server command.
srvhlp: asciz /
The DECSYSTEM-20 KERMIT server is capable of the following:
Command you would normally type to your
Server Function: local KERMIT to invoke the server function:
Receive a file or file group SEND filespec
Send a file or file group GET filespec
Logout BYE
Exit to TOPS-20 FINISH
Delete a file or file group REMOTE DELETE filespec
List file(s) at the terminal REMOTE TYPE filespec
Provide a directory listing REMOTE DIRECTORY filespec
Change working directory REMOTE CWD directory [password]
Report disk usage REMOTE SPACE
Send this message REMOTE HELP
/
srvhz: 0
0 ; This padding seems to be necessary...
xghelp: move t1, [point 7, srvhlp] ; Point to help text.
movem t1, strptr ; Put pointer here, where
movei t1, gtsch ; routine for getting chars from a string
movem t1, source ; can find it.
setom next ; Init char lookahead
setom xflg ; Send with X rather than F header.
call $sends ; Go send the text like a file
nop
setzm source ;[121] Put send source back to normal.
jrst xxwait
;[116] DIRECTORY server command.
; DIRCH
;
; Alternate GETCH routine for getting characters from a directory listing
; in a memory buffer, and for refilling the buffer when it gets empty.
;
dirch: ildb t1, getptr ; Get character.
skipe t1 ; Null?
jrst dirchx ; No, return the character.
; No characters in buffer, try to refill.
dirch2: call dmpbuf ; If so, reset the buffer pointers, etc.
call dirlst ; And try to fill the listing buffer again.
jumpe t1, dirchz ; No more, done.
move t1, [point 7, srvbuf] ; Get new listing buffer pointer.
movem t1, getptr ; Save it for getting characters.
ildb t1, getptr ; Get first character of new buffer.
jumpe t1, dirchz ; This shouldn't happen...
; Return with character like GETCH.
dirchx: movem t1, next
retskp
; "EOF" return, like GETCH.
dirchz: setz t1,
setom next
ret
; XGDIR - Server provides directory listing.
xgdir: call getarg ; Get the first (& only) argument
jumpg t3, xgdir2 ; Got something, go do it.
jumpe t3, [ ; Got nothing, do default directory.
move t4, [point 7, [asciz/*.*.*/]] ;[174] (not hrroi!)
jrst xgdir2 ]
kermsg <Bad length field in DIRECTORY command>,xxwait ; Got junk.
; Get JFN on the string we got, supply normal defaults like Exec does.
xgdir2: move t2, t4 ; Point to filespec
adjbp t3, t4 ; Make it asciz
setz t4,
idpb t4, t3
movei t1, sdirbk ; JFN block containing flags & defaults.
GTJFN ; Do long form GTJFN.
%jsker (,xxwait) ; Send error packet if we can't.
move t2, t1 ; Construct heading in string buffer.
setzm ffunc ; Function is "directory".
call dirhdr
move t1, [point 7, srvbuf] ; Point to beginning of text buffer.
movem t1, getptr ; This is where we'll get characters from.
movei t1, dirch ; And this routine will do the getting.
movem t1, source ; ...
setom next ; Initialize character lookahead.
setom xflg ; This produces some desired effects...
call $sends ; Go send the listing like it's a file.
nop ; Ignore any skipping...
jrst xxwait
sdirbk: gj%old!gj%ifg!.gjall ; Flags,,All generations.
.nulio,,.nulio ; No i/o.
repeat <2>,<0> ; Default device and directory.
repeat <2>,<-1,,[asciz/*/]> ; Default name is "*.*"
repeat <4>,<0> ; Nothing special for the rest.
;[118] XGDEL - Server provides file deletion.
xgdel: call getarg ; Get the first (& only) argument
jumpg t3, xgdel2 ; Got something, go do it.
kermsg <No file specified for deletion>,xxwait
; Get JFN on the string we got, supply normal defaults like Exec does.
xgdel2: move t2, t4 ; Point to filespec
adjbp t3, t4 ; Make it asciz
setz t4,
idpb t4, t3
movei t1, sdelbk ; JFN block containing flags & defaults.
GTJFN ; Do long form GTJFN.
%jsker (,xxwait) ; Send error packet if we can't.
move t2, t1 ; Construct heading in string buffer.
movei t1, delfil ; Routine for deleting a file.
movem t1, ffunc ; Make it the file function.
call dirhdr ; Start things off.
move t1, [point 7, srvbuf] ; Point to beginning of text buffer.
movem t1, getptr ; This is where we'll get characters from.
movei t1, dirch ; And this routine will do the getting.
movem t1, source ; ...
setom next ; Initialize character lookahead.
setom xflg ; This produces some desired effects...
call $sends ; Go send the listing like it's a file.
nop ; Ignore any skipping...
jrst xxwait
sdelbk: gj%old!gj%ifg!.gjall ; Flags,,All generations.
.nulio,,.nulio ; No i/o.
repeat <^d8>,<0> ; No other defaults.
subttl Timer Routines
; Set a timer. Call with t1/ Address of where to go upon timout.
timeit: skipg stimou ;[43] Doing timeouts?
ret ;[43] No, skip this.
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
%jserr <TIMEIT - Can't turn on timer channel>, <.+1>
;[132] Remove any pending timer requests.
timei2: move t1, [.fhslf,,.timal] ; Remove all pending timer requests.
setzb t2, t3
TIMER
aos timerx ; If we get a timer error, just count it.
timei3: setz t1, ;[130] Get 1-minute load average.
call ldav ;[130]
move t2, stimou ;[130] Minimum acceptable.
call adjtim ;[128] Adjust based on load average.
move t1, [.fhslf,,.timel] ; Our process and time from now.
movem t2, curtim ;[131] Remember this for reporting.
imuli t2, ^d1000 ; Make time into milliseconds.
setz t3, ; Channel zero.
TIMER
aos timerx ; If we get an error, count it.
ret
; TIMOFF -- Turn off timer.
timoff: skipg stimou ;[43] Doing timeouts?
ret ;[43] No, skip this.
saveac <t1,t2> ; Yes, save these ACs.
move t1, [.fhslf,,.timbf] ; Turn off timer interrupts for this fork.
hrloi t2, 377777 ; For all times before this (far in future).
TIMER ;
aos timerx ; Count any error.
movx t1, .fhslf ; Deactivate the channel.
movx t2, 1b0
DIC
ret
; TMTRAP -- Timer interrupt handler.
tmtrap: push p, t1 ; Get a work AC.
move t1, intpc ; Get the PC we want.
hrli t1, (1b5) ;[132] Set user mode to escape from any jsys.
movem t1, pc1 ; Restore as if we came from there.
pop p, t1
move p, intstk ; Pop any junk off the stack.
aos ntimou ; Count the timeout.
DEBRK
;[128] Make this a separate routine.
;
; ADJTIM -- Adjust timeout interval based on load average (ldav).
;
; Calculate Timeout = mintim + (ldav-MINLOD)*((MAXTIM-mintim)/MAXLOD)
; If the load is low, this gives the minimum acceptable timeout, mintim.
; If the load is very high, this gives the maximum timeout, MAXTIM.
; In between, the timeout goes up linearly with given load average.
; MINLOD, MAXLOD, and MAXTIM are defined as global symbols.
;
; Call with:
; t1/ 1, 5, or 15 minute ldav, floating point number as returned by GETAB.
; t2/ minimum acceptable timeout (mintim), seconds (integer).
; Returns +1 always, with
; t2/ adjusted timeout interval, in seconds (integer).
;
adjtim: stkvar <mintim> ; Local storage for second argument.
movem t2, mintim ; Save the minimum for later.
fsb t1, [minlod] ; Adjust load by subtracting the minimum.
skipg t1 ; If negative, make it zero.
setz t1,
caml t1, [maxlod] ; If too big, cut it off.
move t1, [maxlod]
movei t2, maxtim ; Maximum timeout, seconds.
sub t2, mintim ; Less specified timeout interval.
fltr t2, t2 ; Floated.
fdv t2, [maxlod] ; Divided by maximum load.
fmp t1, t2 ; Multiplied by actual (adjusted) load.
fixr t2, t1 ; Fixed & rounded.
add t2, mintim ; Add in requested minimum timeout.
ret ; Return with result in t2.
;[130] This routine added as part of edit 130.
;
; LDAV -- Get the current load average. Takes class scheduling into account.
;
; Call with
; t1/ 0 for 1-min, 1 for 5-min, 2 for 15-min ldav.
; SKDFLG/ -1 for class scheduler running, 0 for no class scheduler.
; CLASS/ This job's scheduler class.
;
; Returns +1 always, with requested load average in t1.
;
ldav: saveac <q1> ; Save this.
cail t1, 0 ; Argument in range?
caile t1, 2
setz t1, ; Force to 0.
move q1, t1 ; Save argument here.
skipe skdflg ; Class scheduler on?
jrst ldav3 ; Yes, go do it the special way.
; Class scheduler off, use GETAB for system-wide load average.
ldav2: hrlz t1, q1 ; Desired load average.
add t1, [14,,.systa] ; Scheduler off,
GETAB ; use load avg from SYSTAT monitor table.
erjmp ldavx
ret
; Class scheduler on, get load avg for this class from SKED%.
ldav3: skipge t1, class ; This job's scheduler class.
jrst ldav2 ; Unless there was some error getting it...
movem t1, skdblk+.sacls ; Put it in the SKED% arg block.
movei t1, 10 ; Arg block length
movem t1, skdblk+.sacnt
movei t1, .skrcs ; Function is read class parameters.
movei t2, skdblk ; into this arg block.
SKED%
%jserr (,ldavx)
move t1, skdblk+.sa1ml(q1) ; Return the desired value.
ret
ldavx: move t1, [minlod] ; Return this in case of any error.
ret
subttl Interrupt Routines
; 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
; Turn Control-C trap on. Sets things up so that ^C will return control
; to the instruction FOLLOWING the the call to this routine, with the
; stack fixed up appropriately, e.g.
;
; call ccon ; Turn on ^C trap
; jrst foo ; What to do if ^C is typed.
; move x, y ; Execute this after the call to CCON.
;
; Returns +2 always.
;
$ccn==2 ; Number of ^C's to get out of ^C trap.
ccon: movei t1, .fhslf ; Read current process capabilities.
RPCAP%
;[10] Try to enable ^C capabilities unless under batch.
tloe t3, (sc%ctc) ; Do we have Control-C capas?
jrst ccon2 ; Yes, go on.
EPCAP% ; Nope, try to get them.
RPCAP% ; Did we?
skipn jobtab+.jibat ; Under batch?
tloe t3, (sc%ctc) ; Check the ^C bit.
jrst ccon2 ; If under batch
ermsg <Can't enable ^C capability>,r ; Not under batch, give up.
ccon2: movem t3, capas ; Save them.
movei t1, $ccn ; Initialize ^C count to this.
movem t1, ccn
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: skipe srvflg ;[81] Being a server?
ret ;[81] Yes, so don't turn off the ^C trap.
; Entry point for REALLY turning it off, even if server.
ccoff2: saveac <t1,t2,t3> ; Save these.
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, (1b3) ; for ^C... (^C = ASCII 3 = bit 3)
STIW ; ...
move t3, capas ; Restore capabilities.
EPCAP
erjmp .+1
ret
;[59] ^A, ^X, and ^Z interrupt control added as part of edit 59.
caxzon: Remark - Turn on ^A, ^X, and ^Z interrupts.
setzm cxseen ; Say we haven't seen a ^X yet,
setzm czseen ; nor a ^Z.
setzm caseen ; ...
skipn local ; Only do this if local!
ret
movei t1, .fhslf ; This fork.
movx t2, 1b<cachan>!1b<cxchan>!1b<czchan> ; Turn on the channels.
AIC%
move t1, [.ticca,,cachan] ; Put ^A on its channel.
ATI%
move t1, [.ticcx,,cxchan] ; Put ^X on its channel.
ATI%
move t1, [.ticcz,,czchan] ; And ^Z on its.
ATI%
ret
cmpon: Remark - ^M, ^P interrupts on.
movei t1, .fhslf ; This fork.
movx t2, 1b<cmchan>!1b<cpchan> ; These channels.
AIC ; Activate interrupt system.
move t1, [.ticcm,,cmchan] ; Assign ^M to this channel.
ATI
setzm cmseen
move t1, [.ticcp,,cpchan] ; Assign ^P to this one.
ATI
setzm cpseen
ret
caxzof: Remark - Turn off ^A,^X,^Z interrupts.
setzm cxseen ; Turn off the flags
setzm czseen ; ...
setzm caseen ; ...
skipn local ; Nothing to do if remote, the interrupts
ret ; weren't on anyway.
movx t1, .fhslf ; Turn off ^A,^X,^Z traps.
movx t2, 1b<cachan>!1b<cxchan>!1b<czchan> ; Turn off these channels.
DIC% ; ...
RTIW% ; Fix up the interrupt mask
tdz t2, [<1b1+1b24+1b26>] ; for ^A,^X,^Z
STIW% ; ...
%jserr (,.+1)
ret
; ^M, ^P interrupts off.
cmpoff: setzm cmseen
setzm cpseen
movx t1, .fhslf ; Turn off ^M trap.
movx t2, 1b<cmchan>!1b<cpchan> ; Turn off channels.
DIC ; ...
RTIW ; Fix up the terminal interrupt mask
tdz t2, [<1b13>!<1b16>] ; for ^M, ^P
STIW
%jserr (,.+1)
ret
cctrap: sosle ccn ; Count the ^C's.
DEBRK% ; If they haven't typed enough, just resume.
call timoff ; Turn off any timer.
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.
pop p, t1 ;[80] Don't need it on the stack any more.
DEBRK% ; Resume where stack pointer points.
;[61] Control-A trap handler. Give brief progress report at terminal.
;
catrap: push p, t1 ; Save all ACs we might use.
push p, t2
push p, t3
skipn rcving ; Sending or receiving a file?
jrst catrp1 ; No.
hrroi t1, [asciz/^A
Sending /] ; Yes, one...
skipg rcving
hrroi t1, [asciz/^A
Receiving /] ; ...or the other.
PSOUT%
movei t1, .priou ; Say the filename
setz t3,
skipe t2, filjfn
JFNS%
erjmp .+1
tmsg <, file bytesize > ; File bytesize
numout bytsiz
skipl rcving ; I/O bytesize, only if sending
jrst [ tmsg <, i/o bytesize >
movei t2, 7
skipn itsfil ;[75]
skipe ebtflg
movei t2, 8
numout t2
jrst .+1 ]
tmsg <
> ;[92]
hrroi t1, [asciz/ (ITS binary)/] ;[75]
skipe itsfil ;[75]
PSOUT ;[75]
hrroi t1, [asciz/ (8th-bit prefixing)/] ;[88]
skipe ebqflg ;[88]
PSOUT ;[88]
hrroi t1, [asciz/ (compression)/] ;[92]
skipe rptflg ;[92]
PSOUT ;[92]
hrroi t1, [asciz/ (block check type /] ;[98]
PSOUT
numout bctu ;[98]
movei t1, ")" ;[98]
PBOUT ;[98]
tmsg <
At page > ; What page we're at.
move t2, pagno
aos t2
numout t2
skipl rcving ; Out of how many
jrst [ tmsg < of > ; (which we know only if we're sending)
numout pagcnt
jrst .+1 ]
;...
;...CATRAP, cont'd
catrp1: tmsg <
Files: > ; Say how many files,
numout files
tmsg <, packets: > ; packets,
skipl rcving
numout sptot
skipg rcving
numout rptot
tmsg <, chars: > ; characters,
move t2, stchr
add t2, schr
skipl rcving
numout t2
move t2, rtchr
add t2, rchr
skipg rcving
numout rtot
tmsg <
NAKs: > ; NAKS & timeouts.
numout nnak
tmsg <, timeouts: >
numout ntimou
tmsg <
> ; End up with a CRLF
pop p, t3 ; Restore ACs.
pop p, t2
pop p, t1
DEBRK% ; Resume.
;[59] Control-X trap handler.
cxtrap: setom cxseen ; Just set the flag & echo the character.
push p, t1
move t1, source ;[140] What's the source of our data?
cain t1, dirch ;[140] Is it a directory listing?
setom czseen ;[140] If so, set C-Z flag, too.
cxtrp2: hrroi t1, [asciz\^X// \]
PSOUT%
pop p, t1
DEBRK%
;[59] Control-Z trap handler.
cztrap: setom czseen ; Just set the flag & echo the character.
push p, t1
hrroi t1, [asciz\^Z// \]
PSOUT%
pop p, t1
DEBRK
;[165] Control-M and -P trap handlers
cmtrap: setom cmseen ; Set ^M flag
push p, t1 ; Echo CRLF
tmsg <
>
move t1, cmloc ; Get place to resume.
jrst cmptr2
cptrap: setom cpseen ; Set ^P flag
push p, t1 ; Echo ^P
tmsg <
^P>
move t1, cploc ; Get place to resume.
cmptr2: hrli t1, (1b5) ; Get into user mode.
movem t1, pc2 ; Resume at desired PC.
pop p, t1
DEBRK
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.
;[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.
subttl Pure Data
; 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
; Some other miscellaneous pure data
crlf: asciz/
/ ; A carriage-return-linefeed.
Remark Interrupt storage (pure)
levtab: pc1
pc2
pc3
chntab: phase 0
tmchan: 1,,tmtrap ; Timer trap on channel 0, priority 1.
ccchan: 1,,cctrap ; ^C trap on channel 1, same priority.
cachan: 2,,catrap ; ^A trap on channel 2, lower priority.
cxchan: 2,,cxtrap ; ^X trap on channel 3...
czchan: 2,,cztrap ; ^Y trap .... 4
cmchan: 2,,cmtrap ; ^M trap .... 5
repeat <^d23-.>,<0> ; (Skip reserved area, can't use these)
cpchan: 2,,cptrap ; ^P trap on channel 6
block ^d36-.
dephase
0 ; (superstition)
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: 0 ; PC to restore on timer interrupt.
intstk: 0 ; Stack pointer to restore on timer interrupt.
ccn: 0 ; Number of ^C's typed.
caseen: 0 ; Flag for ^A trap.
psave: 0 ; Stack pointer for ^C interrupt.
psave2: 0 ; Stack top for ^C interrupt.
tsave: 0 ;[132] Same as above, but for timer interrupts.
tsave2: 0 ;[132] ...
cmseen: 0 ;[165] Flag for ^M interrupt seen.
cmloc: 0 ;[165] Where to go on ^M interrupt.
cpseen: 0 ;[165] Flag for ^P interrupt seen.
cploc: 0 ;[165] Where to go on ^P interrupt.
cxseen: 0 ;[59] Flag for ^X interrupt seen.
czseen: 0 ;[59] Flag for ^Z interrupt seen.
capas: 0 ; Process capabilities.
inited: 0 ;[177] inilin/reslin flag.
pars1: 0 ; Data from first parse.
pars2: 0 ; Data from second parse.
pars3: 0 ; Data from third parse.
pars4: 0 ; Data from fourth parse.
pars5: 0 ;[41] ...
srvflg: 0 ; Are we serving? Erase if we go for command.
iflg: 0 ;[100] -1 if sending INFO packet, else 0.
lcflg: 0 ;[56] LOCAL command (-1 = LOCAL, 0 = REMOTE).
definf: 0 ;[77] DEFINE flag nonzero if parsing DEFINE.
undeff: 0 ;[77] UNDEFF flag nonzero if DEFINE x <cr>.
source: 0 ;[102] Source routine for GETCH.
dest: 0 ;[107] Destination routine for PUTCH.
ffunc: 0 ;[118] File function (dir, del, ren, etc).
parsx==.-1 ; For zeroing the above.
dfstrt: PROMP ; Are we to be a SERVER or go to the PROMPT?
; (PROMP not PROMPT, which CMD package uses)
f$exit: 0 ; Exit flag for EXIT command or rescan entry.
ttyjfn: .priin ; JFN for controlling terminal.
logjfn: 0 ;[38] Debugging log file JFN.
tlgjfn: 0 ;[126] Transaction log file JFN.
sesjfn: 0 ;[128] Session log file JFN.
savjfn: 0 ; Place to save session log JFN.
logbsz: 0 ;[41] Log file byte size.
filjfn: 0 ; JFN of file being sent.
ndxjfn: 0 ; Indexable JFN, for wildcard stepping.
nxtjfn: 0 ;[111] JFN of next file to be sent.
netjfn: 0 ; Line for packet transmission.
ttymod: 0 ; Current mode word for controlling tty.
ttydim: 0 ;[185] Current controlling tty dimensions
oldjfn: 0 ; JFN on previous line.
oldmod: 0 ; Previous mode of the line.
olddim: 0 ;[185] Old line dimensions
oldpau: 0 ; Previous terminal pause on end mode.
tiword: 0 ; Terminal interrupt word
sysmsg: 0 ;[82] Accept/refuse system message status.
ttynum: 0 ; 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.
myccoc: 0 ;[161] CCOC words for my tty.
0 ;[161] (two of them)
ttpau: 0 ;[161] Controlling TTY's pause chars.
myjob: 0 ;[7] My job number.
skdflg: 0 ;[130] Nonzero if class scheduler on.
class: 0 ;[130] My scheduler class.
job: 0 ;[7] Number of job that has TTY I want.
;...
; Impure Data, cont'd
pname: 0 ; Name of this process
0 ; (need 2 words)
ttfork: 0 ; Fork number of the connect receive fork.
rufork: 0 ; Fork number for LOCAL RUN program fork.
rujfn: 0 ; JFN for LOCAL RUN program.
execf: 0 ; Fork number of PUSH (to Exec) fork.
errptr: 0 ; Pointer to most recent error string.
atmptr: 0 ; Atom buffer pointer.
xfnflg: 0 ;[84] Flag for file name conversion.
xflg: 0 ;[104] Flag for sending with X header.
ebtflg: 0 ; One if file is to be used in 8-bit mode.
autbyt: 1 ; One if auto-byte is to be used.
handsh: 0 ;[76] Handshake.
flow: 1 ;[143] Flow-Control (nonzero = XON/XOFF)
itsflg: defits ;[75] Flag for handling ITS-binary format files
itsfil: 0 ;[75] Flag for this file is ITS format.
itscnt: 0 ;[75] Counter for ITS header chars matched.
tvtflg: 0 ;[129] Negotiate binary mode on ARPANET TVT.
tvtchk: 1 ;[182] TVT discovery (MUST BE AFTER tvtflg!)
ntiblk: block ntblen ;[182] NTINF% block for TVT
panda < ;[181] PANDA monitor TVT support
havnbm: 0 ;[181] Non-zero if we have network binary mode
setlts: 0 ;[181] set if we set terminal status
oldlts: 0 > ;[181] Old terminal status
incase: defics ;[160] Case conversion flag for INPUT search.
indeft: defito ;[160] Default timeout for INPUT search.
intima: defita ;[160] Timeout action for INPUT search.
asgflg: 0 ;[7] -1 if I asg'd the TTY, 0 if already asg'd.
oasflg: 0 ;[7] Same, but for previous TTY.
actmp: block 20 ;[59] A place for short-term saving of ACs.
pktacs: block 6 ;[112] Place to save RPACK/SPACK ACs.
parity: defpar ; Type of parity to use.
gotx: 0 ; Flag for "already got an X-packet".
gots: 0 ; Flag for "already got an S-packet".
mapflg: 0 ; One if a page is mapped in. (Init to 0.)
mdmlin: 0 ;[130] -1 = modem-controlled line, 0 = not.
carier: 0 ;[130] Flag for carrier dropped.
monv: 0 ;[146] Monitor version (0 if less than 6.0).
speed: 0 ;[130] Ostensible line speed -- input,,output.
setspd: 0 ;[161] Flag speed was explicitly SET.
defbrk==3 ;[16] default nulls to send on break
brk: defbrk ;[16] nulls to send on BREAK key
local: 0 ; -1 = local Kermit, 0 = remote.
rcving: 0 ; -1=actually recving, +1=sending, 0=neither.
$sendf: 0 ; SEND command in progress.
$recvf: 0 ; RECEIVE command in progress.
pagptr: 0 ; Pointer into the page.
;**************
pagcnt: 0 ; Number of pages in the file,
bytcnt: 0 ; and byte count
crdate: 0 ; and creation date (these 3 must be adjacent!)
;**************
bytsiz: 0 ; Byte size of file.
abtfil: 0 ;[42] 0 = discard incomplete file, -1 = keep.
expung: 0 ;[143] Automatically expunge when deleting.
pagno: 0 ; Present page number.
stdat: 0 ; Time taken in transmitting.
size: 0 ; Size of the present data.
spsiz: dspsiz ; Maximum size packet to send.
rpsiz: drpsiz ; Maximum size packet to receive.
maxdat: dspsiz-5 ;[63] Max length for data field.
srvtim: dsrvtm ;[137] Server command wait timeout interval.
stimou: dstim ; Interval for my own timer.
otimou: dstim ;[26] Place to save old timout interval.
rtimou: drtim ; Minimum timeout interval I need.
rrtimo: drtim ;[128] Above, adjusted for 15-min load avg.
ntimou: 0 ;[54] Timeout counter.
curtim: 0 ;[131] Current load-adjusted timeout interval.
timerx: 0 ;[132] Counter for timer errors.
nnak: 0 ;[54] NAK counter.
;...
; Impure Data, cont'd
rpause: drpaus ;[35] Pause before ACKing data packet.
spause: dspaus ;[36] Pause before sending data packet.
pause: 0 ;[36] Pause currently in effect.
spadch: dspad ; Pad char micro wants.
rpadch: drpad ; Pad char I want.
spadn: dspadn ; Number of pad chars for micro.
rpadn: 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: defesc ; 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: 0 ; Total characters received.
stchr: 0 ; ... sent.
rtot: 0 ; Some more counters..
stot: 0 ;
otot: 0
numtry: 0 ; Number of tries on a packet.
oldtry: 0 ; Number of tries for previous packet.
maxtry: dmxtry ; Maximum retries for an ordinary packet.
imxtry: dimxtr ; Maximum retries in send initiate.
pktnum: 0 ; Current packet sequence number.
num: 0 ; Number of packet just received.
type: 0 ; Type of same.
datlen: 0 ; Length of data field of same.
pktlen: 0 ;[179] Packet length.
islong: 0 ;[179] Packet is long.
datptr: 0 ; Pointer to data field of same.
gclen: 0 ; Generic command data field length.
rptot: 0 ;[4] Counter for received packets.
sptot: 0 ;[4] Counter for sent packets.
files: 0 ; File counter.
sec: 0 ; Seconds (for figuring baud rate)
eoflag: 0 ; End of file flag.
temp: 0 ; Temporary location, to be used only for
temp2: 0 ; very brief periods.
ch: 0 ;[63] Current character.
next: 0 ;[63] Next character.
rpt: 0 ;[63] Repeat count of current character.
rptq: drept ;[63] Repeat count prefix.
rptflg: 0 ;[63] Repeat count processing flag.
rptfld: drept ;[92] Repeat count field for Send-Init.
ebq: "Y" ;[63] 8th-bit-on prefix.
ebqflg: 0 ;[63] 8th-bit prefixing flag.
ebqr: 0 ;[88] 8th-bit prefixing requested flag.
ebqfld: "Y" ;[88] 8th-bit prefix field for Send-Init.
ebqchr: 0 ;[90] Current character has 8th-bit prefix.
bctr: "1" ;[98] Block check type requested (character).
bctu: 1 ;[98] Block check type in use (number).
bctone: 0 ;[98] Use type 1 for this packet regardless...
bctemp: 0 ;[98] Place to store incoming block check.
0 ;[98]
; Impure Data, cont'd
xxumsg: asciz/"x" - Unknown server command/ ; Server message (fill in the x)
xxulen=^d28 ; Number of characters in xxumsg.
xxbmsg: asciz/"x" - Not valid as server command/ ; Another.
xxblen=^d33 ; Number of characters in xxbmsg.
xxgums: asciz/"x" - Undefined generic command/
xxguln=^d31
xxgnms: asciz/"x" - Unimplemented generic command/
xxgnln=^d35
dirbuf: asciz/PS:</ ;[79] User's logged-in ID string.
block ^d30 ;[79]
iniflg: 0 ;[83] Init file in progress.
takjfn: 0 ;[78] JFN of current TAKE command file.
takdep: 0 ;[78] Depth of TAKE file JFN stack.
takep: 0 ;[78] TAKE file JFN stack pointer.
takpdl: block <takel+2> ;[78] TAKE file JFN stack itself.
mdone: 0 ;[77] Flag for macro execution done.
macrof: 0 ;[77] Flag on if executing a SET macro.
macbp: point 7, macbuf ;[77] Pointer into macro text buffer.
omacbp: 0 ;[77] Previous MACBP.
macxp: 0 ;[77] Macro execution pointer.
namp: point 7, nambuf ;[77] Pointer into macro name buffer.
onamp: 0 ;[77] Previous NAMP.
macptr: 0 ;[77] Pointer to start of macro text in CSB.
nambuf: block MNBLEN ;[77] Buffer for DEFINE macro name.
namx: block ^d10 ;[77] Some protection against spills.
filptr: 0 ;[102] Pointer into file name buffer.
fildot: 0 ;[102] Counter for dots in filename.
filbuf: block ^d30 ; Buffer for file name building.
filbfz: -1 ; End of same...
filcnt: 0 ; File counter for directory listings.
dirfin: 0 ; Flag for directory listing finished.
;...
; Impure Data, cont'd -- big stuff at end.
jobtab: block ^d30 ; Job info table for GETJI
skdblk: block ^d20 ; Argument block for SKED% jsys.
prompx: asciz/Kermit-20>/ ; Program prompt text (replacable)
block ^d10 ; ...and some padding.
pasptr: 0 ; Pointer into...
pasbuf: block MAXPKT/4+1 ; Buffer for remote password.
pasbfl==.-pasbuf ; Length of above.
0 ; Superstition
ttibuf: block IOBUF/4+1 ;[180] Communications device input buffer
ttiptr: point 8, ttibuf ;[180] Pointer to communications input buffer
tticnt: 0 ;[180] Communications input buffer count
ttisin: 0 ;[180] Statistics counters...
ttibin: 0 ;[180]
ttildb: 0 ;[180]
ttimax: 0 ;[180]
buffer: block MAXBUF/4+1 ; Buffer for file I/O.
block ^d20 ; Superstition
data: block MAXBUF/4+1 ; Data field of packet.
block ^d20 ; Superstition
sndpkt: block MAXBUF/4+1 ; Place for building outbound packets.
block ^d20 ; Superstition
recpkt: block MAXBUF/4+1 ; Place for putting incoming packets.
recpkz: block ^d20 ; Superstition
tvtbuf: block MAXBUF/4+1 ;[131] For doubled-iac version of send packet.
block ^d20 ; Superstition
%%krbf: block MAXPKT/4+1 ;[40] Place for packetized error messages.
block ^d20 ; Superstition
macbuf: repeat <MTBLEN>,<0> ;[77] Macro text buffer.
macx: block ^d20 ;[77] End of macro text buffer, with padding.
;
; Macro table, with one predefined macro, for Columbia's IBM system.
; Users can remove this definition by typing "define ibm", or they can
; replace it. KERMIT-20 maintainers can remove it for their site by replacing
; the contents of MACTAB (first word) with 0,,MACMAX, or can change it to be
; anything they like.
;
mactab: 1,,MACMAX ;[77] Macro keyword TBLUK format table.
[asciz/IBM/],,[asciz/parity mark, duplex half, handshake xon
/] ;[77] Custom IBM mainframe definition.
repeat <MACMAX-1>,<0> ;[77] Macro keyword table.
mactbx: repeat <100>,<0> ; A small reserve tank...
lit ; Expand remaining literals here.
0
strc: 0 ; Counter for, and...
strptr: 0 ; Pointer into...
strbuf: repeat <1000>,<0> ; String buffer for big strings.
strbf2: repeat <1000>,<0> ; More of string buffer for big strings.
strbln=.-strbuf ; Length of whole thing.
strbz: 0 ; Where the padding ends.
getptr: 0 ; Pointer for emptying...
srvptr: 0 ; And pointer for filling...
srvbuf: repeat <1000>,<0> ; Big buffer for server responses.
srvbz: repeat <100>,<0> ; End of buffer, with some padding.
srvbzz: 0 ; Where the padding ends.
end <evlen,,kermit>
;Old Edit history moved to after END statement...
;
;*************** Major Version 4.0 ****************
;PS:<TIMREK>KERMIT.MAC.491, 5-Jan-84 18:49:24, Frank
;[102] Have SFILE call GETBUF to put filename in file header packet with
; full prefixing. This is the first use of GETBUF/ENCODE on non-file data.
;PS:<TIMREK>KERMIT.MAC.487, 3-Jan-84 18:42:38, Frank
;[101] Strip ^V quote characters from outgoing file names.
;PS:<TIMREK>KERMIT.MAC.472, 30-Dec-83 11:29:03, Frank
;[100] More debugging of [98]; got 3-char CRC to work. Also:
;.Make GET command send an I packet before the R packet, to tell other side
; what block check & other parameters to use when sending. Replace SINFO
; with a simple call to SINIT -- they do the same thing.
;.New headings for SHOW PACKET display.
;.If local, say delay is 0 in SHOW TIMING.
;PS:<TIMREK>KERMIT.MAC.469, 29-Dec-83 20:53:36, Frank
;[99] Debugging of [98]; Got 2-character checksum actually working. Also:
;.In RPACK, allow receipt of 1-char checksummed null packet, even if doing
; 2 or 3 char block checks. Other side might have restarted & sent a NAK.
;.Tightened up various much-used loops.
;.Improved packet logging -- now every character sent or received is logged.
;PS:<SY.FDC>KERMIT.MAC.2, 28-Dec-83 09:25:32, Frank
;[98] Added support for 2- and 3-character checksums.
;************* Version 3.4 **************
;PS:<TIMREK>KERMIT.MAC.448, 23-Dec-83 13:59:52, Frank
;[97] In INILIN, preserve TTY mode word settings that don't effect KERMIT, so
; as not to cause undesired side effects with TACs, etc. Fixes(?) bug reported
; by Keith Petersen, diagnosed by Mark Crispin.
;PS:<TIMREK>KERMIT.MAC.442, 20-Dec-83 19:47:03, Frank
;[96] Add SEND (AS) remote-filespec when sending a single file.
; Don't confuse user by displaying escape character in SHOW LINE when remote.
;PS:<TIMREK>KERMIT.MAC.437, 15-Dec-83 19:20:10, Frank
;[95] Remove SET EIGHTH-BIT-PREFIX command, always request it if parity is
; being used. Minor cleanups of help & program text. Change version number
; typeout to agree with the way the Exec now does it: major.minor(edit)-who.
; Get rid of old GTCHR and PTCHR routines, and SET IBM routines.
;PS:<TIMREK>KERMIT.MAC.431, 14-Dec-83 18:21:44, Frank
;[94] Don't allow user to type RECEIVE or SERVER commands when local.
;PS:<TIMREK>KERMIT.MAC.428, 14-Dec-83 15:18:03, Frank
;[93] Minor corrections in ENCODE for off-by-1 errors doing repeat counts.
;PS:<TIMREK>KERMIT.MAC.420, 14-Dec-83 12:39:32, Frank
;[92] Add repeat count processing to SPAR, RPAR, SINIT, RINIT.
; (It was already in the i/o routines, but never used.)
;PS:<TIMREK>KERMIT.MAC.419, 13-Dec-83 18:25:55, Frank
;[91] Add routine TTXON, call it whenever there's a timeout.
; This should unstick the two sides in case of an XOFF deadlock.
;PS:<TIMREK>KERMIT.MAC.415, 12-Dec-83 13:04:35, Frank
;[90] Make 8th-bit prefixing work with PDP-10 36-bit binary files.
;PS:<TIMREK>KERMIT.MAC.405, 9-Dec-83 15:15:39, Frank
;[89] Polish up previous edit. Turn on prefixing if using parity.
;PS:<TIMREK>KERMIT.MAC.400, 8-Dec-83 16:40:28, Frank
;[88] Turn on 8th-bit prefixing in RPAR & SPAR, add SET & SHOW stuff for it.
;****************** Version 3C **********************
;PS:<TIMREK>KERMIT.MAC.394, 2-Dec-83 14:50:55, Frank
;[87] Fix bugs in [85]; make sure line does not change after halt/cont.
;PS:<TIMREK>KERMIT.MAC.382, 1-Dec-83 14:15:24, Frank
;[86] Don't send 4 extra characters if file is ITS binary.
;PS:<TIMREK>KERMIT.MAC.381, 1-Dec-83 13:58:23, Frank
;[85] Make rescan work even if no KERMIT.INI file.
; Make sure line is set up correctly after exit and continue.
;PS:<TIMREK>KERMIT.MAC.379, 25-Nov-83 17:13:16, Frank
;[84] Add SET option to convert file names to "normal form".
; SET FILE-BYTE-SIZE changed to SET FILE BYTESIZE to allow other file
; options, like this new one (SET FILE NAMING).
; Still allow "SET FILE 8", etc, for compatibility with the old way.
;PS:<TIMREK>KERMIT.MAC.361, 25-Nov-83 11:34:54, Frank
;[83] Return properly from SHOW ALL command.
; Allow init file to be taken even when there is a command line argument.
; Init file is always taken before looking at any other commands.
;PS:<TIMREK>KERMIT.MAC.355, 11-Nov-83 19:14:43, Frank
;[82] Clear/refuse links, system messages during file transfer.
; Also, make sure we print the contents of any incoming error packet if
; in local mode. Also, don't echo back DEFINEs any more.
;PS:<TIMREK>KERMIT.MAC.354, 9-Nov-83 18:35:53, Frank
;[81] More miscellaneous fixes:
; . Since CCOFF is called whenever RESLIN is called, have RESLIN call CCOFF.
; . Don't turn ^C trap off between transactions if running in server mode.
; . Fix broken autobyte code (skipn/skipe, sigh...)
; . Fix broken "bit35" code in PUTCH for SOS & PDP-10 binary files.
; . Remove debugging output for DEFINE & SET macro stuff.
;PS:<TIMREK>KERMIT.MAC.338, 8-Nov-83 11:39:11, Frank
;[80] Fix miscellaneous bugs:
; . Communication line JFNs improperly juggled in $SETLN.
; . Control-C trap was leaving an extra entry on the stack.
; . Turn off Control-C trap after ^C out of send, receive, or server mode.
; . Close file we're sending if other side sends an error packet.
; . Time transfer started not always properly initialized.
; . Remove garbage at end of set-macro body string.
; . Clean up code at $SEND and $RECV for server entry.
;PS:<TIMREK>KERMIT.MAC.331, 28-Oct-83 20:35:46, Frank
;[79] Do an implicit TAKE of KERMIT.INI upon initial startup.
;PS:<TIMREK>KERMIT.MAC.309, 28-Oct-83 15:29:45, Frank
;[78] Add TAKE command to allow (nested) command files.
;PS:<TIMREK>KERMIT.MAC.288, 27-Oct-83 18:55:44, Frank
;[77] Add DEFINE command for SET macros. Remove hardwired SET IBM.
;PS:<TIMREK>KERMIT.MAC.268, 26-Oct-83 14:15:23, Frank
;[76] Add SET HANDSHAKE.
;PS:<TIMREK>KERMIT.MAC.251, 12-Oct-83 10:51:56, Frank
;[75] Add ITS binary format file handling, as specified in KRFC #3.
;PS:<TIMREK>KERMIT.MAC.243, 10-Oct-83 13:33:53, Frank
;[74] Fix bug that truncated JSYS error messages in error packet text.
;PS:<TIMREK>KERMIT.MAC.241, 10-Oct-83 13:07:33, Frank
;[73] Make sure old JFN's on assigned TTYs are released properly.
;PS:<TIMREK>KERMIT.MAC.240, 10-Oct-83 11:44:47, Frank
;[72] Fix bug that made any file sent after a null file also null.
; Fix bug in which last send from server sets byte size for next receive.
;PS:<TIMREK>KERMIT.MAC.237, 7-Oct-83 16:47:24, Frank
;[71] Fix SHOW DEBUG not to foul up if log JFN is .PRIOU.
;PS:<TIMREK>KERMIT.MAC.230, 7-Oct-83 14:02:35, Frank
;[70] Catch illegal memory references when mapping in a nonexistent page.
; If i/o error sending a file, don't cancel, tell other side to discard.
; This allows wildcard sends to proceed after a memory access error.
; Also, allow ^C's to interrupt a nonworking FINISH or BYE command gracefully.
;PS:<TIMREK>KERMIT.MAC.224, 6-Oct-83 18:56:09, Frank
;[69] Fix bug that prevented interrupts from working after EXIT & continue.
;PS:<TIMREK>KERMIT.MAC.219, 6-Oct-83 15:13:33, Frank
;[68] Separate local and remote mode top-level command tables.
; Make remote commands invisible in local mode & vice versa.
; Move command keyword tables to where they are used.
;PS:<TIMREK>KERMIT.MAC.212, 6-Oct-83 10:18:30, Frank
;[67] Remove REMOTE & LOCAL commands for now -- these will be added later.
; Update help text to reflect changes since last release, mainly ^A,^X,^Z.
; Rename SET ABORTED-FILE to SET INCOMPLETE to avoid emotionally toned word.
; Rename SET IBM-FLAG to SET IBM (flags are for programmers).
; Break up help text for SET command.
; Move help text for each command to same area as command itself.
;PS:<TIMREK>KERMIT.MAC.202, 4-Oct-83 19:16:37, Frank
;[66] Same deal as [63], but for file output routines.
; Old PTCHR replaced by PUTBUF, DECODE, and PUTCH.
; Also, include Nick Bush's CRC routine, but don't use it yet.
;PS:<TIMREK>KERMIT.MAC.199, 30-Sep-83 19:48:52, Frank
;[65] Clean up SEND command parsing, don't parse for initial filespec if no
; wildcards given.
;PS:<TIMREK>KERMIT.MAC.196, 29-Sep-83 19:13:45, Frank
;[64] Debug the previous edit for basic service.
;PS:<TIMREK>KERMIT.MAC.184, 28-Sep-83 18:53:21, Frank
;[63] Rewrite file input routines to separate i/o from packet formation.
; New routines are GETBUF to fill a packet buffer,
; GETCH to get an input character,
; ENCODE to process the character, performing control quoting, prefix quoting,
; and, if selected, 8th-bit quoting and repeat count processing.
; GTCHR is still present, but not used at all.
;PS:<TIMREK>KERMIT.MAC.169, 19-Sep-83 17:56:27, Frank
;[62] Add ^X and ^Z to interrupt receiving a file or a batch, respectively.
; Required insertion of data ("D") in ACK for data packet.
;PS:<TIMREK>KERMIT.MAC.163, 16-Sep-83 19:19:13, Frank
;[61] Put brief status report on ^A, like NFT has.
;PS:<TIMREK>KERMIT.MAC.156, 16-Sep-83 15:45:56, Frank
;[60] Add return code to SPACK to distinguish different kinds of failures.
;PS:<TIMREK>KERMIT.MAC.151, 15-Sep-83 19:32:57, Frank
;[59] Add ^X and ^Z to interrupt sending a file or a batch, respectively.
; Required addition of data ("X" or "Z") to Z packet.
;PS:<TIMREK>KERMIT.MAC.146, 15-Sep-83 16:18:26, Frank
;[58] Add sending of "I" packets before server commands.
;PS:<TIMREK>KERMIT.MAC.137, 8-Sep-83 20:20:28, Frank
;[57] Add debugging log capability to server commands as well as file xfer.
;PS:<TIMREK>KERMIT.MAC.130, 8-Sep-83 18:55:05, Frank
;[56] Begin adding new server commands. First, add LOCAL and REMOTE
; top level commands, with operands like DELETE, TYPE, DISK, etc.
; Implement DISK first, that's the easiest test of sending back info in
; the data field of an ACK. Also, catch a couple places where the nonskip
; return from SPACK was not being accounted for (oops!).
;**************** Version 3B *******************************
;PS:<TIMREK>KERMIT.MAC.126, 8-Sep-83 15:14:37, Frank
;[55] Add CFIBFs in BYE and FINISH; all commands to servers should do this.
;PS:<TIMREK>KERMIT.MAC.123, 8-Sep-83 14:02:38, Frank
;[54] Report number of NAKs and timeouts in STATISTICS command.
;PS:<SY.FDC>KERMIT.MAC.7, 2-Sep-83 17:56:19, Frank
;[53] When receiving a file, NAK a trashed packet immediately, don't just wait
; for it to come again and only NAK after timeout. This should result in a
; major speed improvement over noisy lines. The book has always said to do it
; this way. Fix is in RINIT, RFILE, RDATA. Other KERMITs may need this too.
;PS:<SY.FDC>KERMIT.MAC.4, 2-Sep-83 16:43:22, Frank
;[52] Combine some common code in the send routines, and improve comments.
;PS:<KERMIT>20KERMIT.MAC.40, 25-Aug-83 15:28:36, Frank
;[51] Fix packet number compares for mod 64 in SFILE, SDATA, SEOF, SEOT.
; This eliminates canceling whenever a retransmission of packet 0 occurs.
;CU20D::PS:[SY.FDC]KERMIT.MAC.32, 29 June 1983, 5:39PM, Frank
;[50] Change and document the calling conventions of RPAR & SPAR to eliminate
; the mess from the last few edits. Do even more validation in SPAR.
;PS:<TIMREK>KERMIT.MAC.118, 29-Jun-83 14:31:52, Frank
;[49] Fix another bug in SPAR, change method of incrementing packet numbers.
;PS:<TIMREK>KERMIT.MAC.114, 28-Jun-83 16:43:09, Frank
;[48] Point to data buffer correctly in SPAR & RPAR. This was lost in some
; previous edit.
;PS:<TIMREK>KERMIT.MAC.110, 28-Jun-83 15:10:26, Frank
;[47] Fix bad checksum reporting, again. Print most recent JSYS err in STAT.
; Don't let other side's Send-Init parameters override any local SET commands.
;PS:<TIMREK>KERMIT.MAC.104, 27-Jun-83 17:37:54, Frank
;[46] CFIBF after timeout in RPACK. Be more consistent about how errors
; are handled in receive routines. Clean up server command loop a little.
;[PS:<TIMREK>KERMIT.MAC.101, 24-Jun-83 20:18:42, Frank
;[45] Fix SHOW command for timing info.
;[PS:<TIMREK>KERMIT.MAC.99, 24-Jun-83 17:54:07, Frank
;[44] In SFILE, don't give up if OPENF failed because file already open.
;PS:<TIMREK>KERMIT.MAC.92, 24-Jun-83 16:55:38, Frank
;[43] Don't do timeouts if STIMOU is 0, as protocol says. Kermit-65 was
; sending a space (which translates to 0) in this field of the send-init by
; mistake, and Kermit-20 was doing rapid-fire timeouts.
;CU20D::PS:[SY.FDC]KERMIT.MAC.19, 22 Jun 83 17:12:33, Frank
;[42] Release any piled up log jfns. Issue KERMSGs any time we cancel.
; Add SET ABORTED-FILE (DISPOSITION) DISCARD | KEEP
;PS:<TIMREK>KERMIT.MAC.89, 17-Jun-83 11:48:26, Frank
;[3A(41)] Clean up listing & help messages, declare minor version "A".
;************************ Version 3A ******************************
;PS:<TIMREK>KERMIT.MAC.83, 16-Jun-83 16:10:47, Frank
;[41] Add bytesize selection option for debugging log file (7 or 8 bit),
; for use when debugging binary file transfers. Force debugging on
; when log file requested.
;PS:<TIMREK>KERMIT.MAC.75, 16-Jun-83 12:32:34, Frank
;[40] Remove the last remaining long lines. Get rid of hairy %CLEAR macro.
; Don't send an error packet longer than the other side's maximum packet size.
; Always blank out the error message packet buffer before filling.
;PS:<TIMREK>KERMIT.MAC.71, 16-Jun-83 11:36:51, Frank
;[39] Change STATUS to STATISTICS, give optional arguments to SHOW command.
; Print program version upon startup.
;CU20D::PS:<SY.FDC>KERMIT.MAC.13, 15-Jun-83 18:12:37, Frank
;[38] Allow debugging output to go to a file. Thus can even get debugging
; information when running remotely. Suggested by Dave King at CMU.
;CU20D::PS:<SY.FDC>KERMIT.MAC.6, 15-Jun-83 14:34:19, Frank
;[37] Add SET RETRY, fix FLDDB's so none are more than 80 chars wide.
;PS:<TIMREK>KERMIT.MAC.68, 15-Jun-83 11:47:19, Frank
;[36] Add SET SEND PAUSE, and include pause info in SHOW & STATUS commands.
;PS:<TIMREK>KERMIT.MAC.64, 14-Jun-83 19:25:45, Frank
;[35] Add SET RECEIVE PAUSE, suggested by Dave King at CMU.
;PS:<TIMREK>KERMIT.MAC.61, 14-Jun-83 18:40:48, Frank
;[34] In SPACK, send padding if requested.
;PS:<KERMIT>20KERMIT.MAC.34, 10-Jun-83 12:55:42, Frank
;[33] Cancel correctly if the output file can't be opened.
; Enclose checksum characters in quotes in debugging messages.
;*********** Version 3(40) Shipped to over 100 sites May 5 ************
;PS:<TIMREK>KERMIT.MAC.56, 4-May-83 09:01:16, Frank
;[32] Report bad checksums correctly when debugging.
; Report error message from server & cancel 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 da Cruz
;[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.
;[181]
; Local Modes:
; Mode:MACRO
; Comment Column:32
; Comment Start:;[185]
; Auto Fill Mode: 0
; End: