Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_SRC_3_19910112
-
stanford/ftp/ftp.mac
There are 5 other files named ftp.mac in the archive. Click here to see a list.
;[SRI-NIC]SRC:<STANFORD.FTP>FTP.MAC.265, 31-Aug-87 17:15:38, Edit by MKL
; use GTDOM% instead of GTHST%
;<FTP>FTP.MAC.289, 3-May-85 19:34:19, Edit by LOUGHEED
; Alternate sockets capability (F%ALTS) is now always on by default.
; Easier than guessing which hosts can't cope.
;<FTP>FTP.MAC.288, 30-Apr-85 00:03:40, Edit by LOUGHEED
; More from SRA:
; - Send "anonymous" instead of "ANONYMOUS" for UNIX systems.
; - Make SET NO ANONYMOUS-LOGIN work
;<FTP>FTP.MAC.287, 29-Apr-85 03:19:00, Edit by LOUGHEED
; From Rob Austein (SRA@XX):
; Fix initialization of FRECOR so that NLST (etc.) works
;<FTP>FTP.MAC.286, 20-Apr-85 14:45:38, Edit by LOUGHEED
; Reset all defaults if switching from one operating system to another.
; Prevents nonsense like TOPS-20 paged transfers to UNIX systems.
;<FTP>FTP.MAC.285, 12-Feb-85 21:50:59, Edit by LOUGHEED
; From Rutgers:
; - Print out file's protection when doing a retrieve operation
; - RLOGIN code uses TMPHST to avoid clobbering TEMP.
;<FTP>FTP.MAC.284, 29-Oct-84 18:39:52, Edit by LOUGHEED
; Somehow STTXT8 got lost in the last shuffle
;<FTP>FTP.MAC.283, 29-Oct-84 18:20:29, Edit by LOUGHEED
; Add SITE as invisible synonym for QUOTE command
; From Rutgers: Try to use RHOSTS file, if any, to default logins
;<FTP>FTP.MAC.282, 16-Sep-84 14:52:24, Edit by LOUGHEED
; STTEXT routine for setting Multics defaults correctly
;<FTP>FTP.MAC.281, 4-Sep-84 01:46:18, Edit by LOUGHEED
; Support the SET [NO] ANONYMOUS-LOGIN command
;<FTP>FTP.MAC.280, 31-Aug-84 15:28:04, Edit by SATZ
; Make transfer defaults protocol dependent
;<FTP>FTP.MAC.279, 29-Aug-84 16:10:05, Edit by SATZ
; Parse for quoted strings too when getting Unix file names
;<FTP>FTP.MAC.278, 28-Aug-84 14:43:04, Edit by LOUGHEED
; On continue after a fancy quit, don't set connected directory
; if it wasn't set before.
;<FTP>FTP.MAC.277, 27-Aug-84 16:21:23, Edit by LOUGHEED
; Fix help message in QUOTE command parse
;<FTP>FTP.MAC.276, 25-Aug-84 16:15:07, Edit by LOUGHEED
;<FTP>FTP.MAC.275, 25-Aug-84 15:30:58, Edit by LOUGHEED
;<FTP>FTP.MAC.274, 25-Aug-84 14:14:39, Edit by LOUGHEED
; Add support for a QUOTE command
;<FTP>FTP.MAC.273, 23-Aug-84 17:00:25, Edit by SATZ
; Make Unix systems use a default byte size of 8.
;<FTP>FTP.MAC.272, 20-Aug-84 23:28:45, Edit by SATZ
; Use a single asterisk for the default file spec. for Unix
;<FTP>FTP.MAC.271, 15-Aug-84 19:14:50, Edit by LOUGHEED
; For TOPS-20 filename bizarreness:
; - Make FFLBUF stack variable NAMSTL words long instead of just 10.
; - Make STKLEN be 512. words long so that FFLBUF fits.
;<FTP>FTP.MAC.270, 31-Jul-84 13:26:26, Edit by LOUGHEED
; Set MULTIPLE GET default strategy to HEURISTIC. This works around the
; problem of hosts such as SU-STAR and MIT-MC who claim to use NLST, but
; lie and hang us up during a single file GET command.
;<FTP>FTP.MAC.269, 16-May-84 12:16:55, Edit by KRONJ
; Clean up GTJFN block in file parse for OUTPUT subcommand of DIR
; Fix PRMCNF to really index through AC1
;<FTP>FTP.MAC.268, 10-May-84 16:25:42, Edit by KRONJ
; PUT is another synonym for SEND
;<FTP>FTP.MAC.267, 26-Apr-84 19:58:25, Edit by KRONJ
; OPNSTO checks FB%DIR!FB%NEX so we don't need to duplicate that
;<FTP>FTP.MAC.265, 26-Apr-84 14:26:27, Edit by KRONJ
; Move OPNSTO out to FTPDEF so can use common code with PUPPNT and PUPFSV
; (and so printing files can call CKSPAR to set everything nicely)
;<FTP>FTP.MAC.264, 23-Apr-84 14:57:30, Edit by KRONJ
; 36-bit files with type unspecified are assumed to be text
;<FTP>FTP.MAC.263, 19-Apr-84 22:04:28, Edit by KRONJ
; Separate-line GET local file parse forgot to default generation
;<FTP>FTP.MAC.262, 31-Mar-84 17:37:22, Edit by LOUGHEED
; Remove GENAUT and GENPRO extern definitions - not used by TCP code
; Define SETWDT here instead of in PUPFTP.MAC
SEARCH FTPDEF
VMAJOR==3 ; Major version (not protocol version)
VMINOR==0 ; Minor version
VEDIT==277 ; Edit version
VWHO==0 ; Who last edited (4 = Stanford)
PTITLE(FTP, -- Pup and Internet FTP user program)
SUBTTL David Eppstein / Stanford University / 1-Oct-83
;; Largely based on the PUPFTP module written in 1976
;; by Ed Taft at Xerox PARC, Copyright 1979 Xerox Corp.
;;
;; Copyright (C) 1984 Board of Trustees, Stanford University
;; The information in this software is subject to change without
;; notice and should not be construed as a commitment by Stanford
;; University. Stanford assumes no responsibility for the use or
;; reliability of this software.
.REQUIRE FTPUTL ;Yoyos
.REQUIRE FTPPRO ;Protocols (will require any necessary files)
.REQUIRE FTPDIR ;Directory listing subroutine
.REQUIRE HSTNAM ;Host name parsing routines
.REQUIRE FTPLUD ;Postlude
EXTERN STRCMP,CHKDSK,.SFUST,KILFIL,SETPLT,.JBSYM,.JBUSY,JFNVRS
EXTERN NXTFIL,$GTNAM,$GTPRO,$RMREL,PROTS,GETNMB,SKPDIR,SHXDEF
EXTERN FILPRP,DEFPRP,TMPPRP,SETPRP,ZDATPA,TYPBUF,PRTDSP,OPNSTO
SUBTTL Parameters, storage, and macros
STKLEN==:^D512 ; Length of stack
IPDLEN==10 ; TAKE file maximum nesting level
DEFINE KFLS (NAME,FLG) <LS FLG>
KFLAGS(KFLS) ; Define permanent storage for KEEP flags
; Macros for building command tables
; Use DEFTAB to build a command-table macro
DEFINE DEFTAB (TNAME,BODY) <
DEFINE TNAME (PREF) <
DEFINE T (CMD,SYN,FLG) <
IFB <SYN>,<KEY CMD,DOT(PREF,CMD),FLG>
IFNB <SYN>,<KEY CMD,DOT(PREF,SYN),FLG>
>;DEFINE T
TABLE
BODY
TEND
>;TNAME
>;DEFTAB
DEFINE DOT (PREF,CMD) <PREF'.'CMD>
DEFINE TI (CMD,SYN,FLG) < T (CMD,SYN,CM%INV) >
DEFINE TA (CMD,SYN) < T (CMD,SYN,CM%INV!CM%ABR) >
; COMND JSYS support data.
CMDBLK::0 ; Reparse address.
0 ; Input, Output JFNs.
0 ; Ctrl-R text.
-1,,CMDBUF ; Pointer to start of text buffer.
-1,,CMDBUF ; Pointer next input to be parsed.
CMDBFW*5 ; Space left in buffer.
CMDBFW*5 ; Number of characters left in buffer.
-1,,ATMBUF ; Pointer to atom buffer.
ATMBFW*5 ; Size of atom buffer.
CMDGTJ ; Pointer to GTJFN% argument block.
CMDBFW==^D50 ; Size in words of command buffer.
ATMBFW==^D50 ; Size in words of atom buffer.
LS CMDBUF,CMDBFW ; Command buffer.
LS ATMBUF,ATMBFW ; Atom buffer.
LS CMDGTJ,20 ; COMND JSYS GTJFN% block.
; Username and remote filename break mask.
REMBRK: 777777,,777760 ; All controls are breaks (?)
400000,,000020 ; Space and question marks are breaks
000000,,000000 ; Everything else
000000,,000020 ; except DEL is not a break.
; Host name break mask
HSTBRK::777777,,777760 ; All controls are breaks
737644,,001760 ; Digits, -, #, +, . not breaks
400000,,000260 ; Alphabetics and square brackets
400000,,000760 ; are not breaks
; Macros
; Get a keyword.
DEFINE KEYWRD (TABLE) <
MOVEI B,[FLDDB. .CMKEY,,TABLE]
CALL .COMND
ERMSG <Invalid subcommand>
>
; Assemble command dispatch tables
DEFTAB COMMANDS,<
TA B,BY
TA BY
DOT(PREF,BY):
T BYE
TA C,CO
TI CD,CONNECT ; Lots of ways to connect to directories
TI CHDIR,CONNECT
TI CLOSE,DISCONNECT
DOT(PREF,CO):
T CONNECT
TI CPATH,CONNECT
TI CWD,CONNECT
TI DDT
T DELETE
TA DI
DOT(PREF,DI):
T DIRECTORY
TI DISCONNECT
TI DISPLAY
T EXIT
T GET
TA H
TI HALT
DOT(PREF,H):
T HELP
TI HOST
TA I
TA IN,I
TI INFORMATION
DOT(PREF,I):
T INSTALL
TA L
TI LIST,DIRECTORY
DOT(PREF,L):
T LOGIN
TI MULTIPLE
T OPEN
T PRINT
TA PU
DOT(PREF,PU):
T PUSH
TI PUT,SEND
TA Q
DOT(PREF,Q):
T QUIT,HALT
T QUOTE
TA R
TA RE,R
DOT(PREF,R):
TI RECEIVE,GET
T RENAME
TI RESTORE,GET
TI RETRIEVE,GET
TA S
TI SAVE,SEND
TA SE,S
DOT(PREF,S):
T SEND
T SET
TI SHOW,DISPLAY
TI SITE,QUOTE
TA ST
DOT(PREF,ST):
T STATUS,STS ; Don't conflict with SET STATISTICS
TI STORE,SEND
TA T
T TAKE
DOT(PREF,T):
T TYPE
T UPDATE
TI VDIRECTORY
>
CMDDSP: COMMANDS(C)
SUBTTL Main loop and user command handling
; Start of program
START:: RESET% ; Initialize the world
PCLEAR (DATA,[.FHSLF]) ; Clear local word storage.
PCLEAR (GDATA,[.FHSLF]) ; Clear global word storage.
PCLEAR (DATPAG,[.FHSLF]) ; Clear local page storage.
MOVE P,[IOWD STKLEN,STACK] ; Setup stack
MOVE IOP,[IOWD IPDLEN,IPDL] ; and TAKE file JFN stack.
MOVX F,F%INIC!F%ALTS ; Initial flags
MVI. ZDATPA+1,FRECOR ; Set free storage pointer to top of core
MVI. VB.NRM,VRBSTY ; Normal verbosity
MVI. ^D10,SHXDEF ; Start with ten pages per hash mark
MVI. MG.HEU,MULGET ; Default MULTIPLE GET strategy is heuristic
GJINF% ; Set up local user name.
HRLI A,500000
MOVE B,A
HRROI A,LCLUSR
DIRST%
ERJMP .+1
SETZM B
IDPB B,A
CALL INIKEP ; Initialize kept atributes
CALL INIPSI ; Initialize psi system
CALL CMDFIL ; Read input from command file
; (if that returned, we didn't have one)
TXOA F,F%TEMP ; We want to print the header
REENTR:: TXZ F,F%TEMP ; We don't want to print the header
MOVE IOP,[IOWD IPDLEN,IPDL] ; Reset TAKE file JFN stack.
MVI. <.PRIIN,,.PRIOU>,CMDBLK+.CMIOJ ; Set command JFNs
MOVX A,.RSINI
RSCAN% ; Read JCL input.
ERJMP COMHDR ; Couldn't, assume none.
JUMPE A,COMHDR ; If none, go start up normally
MOVE C,A ; Move count to AC 3
MOVEI A,.PRIIN ; From the terminal,
MOVEI B,.NULIO ; to the bit bucket,
MOVEI D," " ; until out of JCL or a space reached,
SIN% ; read those bits!
JUMPE C,COMHDR ; All gone, go start normally.
HRRM B,CMDBLK+.CMIOJ ; Set null JFN as command output (input TTY)
JRST COMINI ; Go read a command.
DEFINE MOVKF (NAME,FLG) <MOVEM KF,FLG>
INIKEP: MOVX KF,K%INIT ; Get initial attributes
KFLAGS(MOVKF) ; Set in each command's KEEP word
RET
; Main command loop
COMHDR: IFXN. F,F%TEMP ; If we still want a header
HRROI A,VERTXT
TYPE <Stanford TOPS-20 FTP %1S, type HELP if you need it.%/>
ENDIF.
COMLP:: SKIPN A,CMDBLK+.CMIOJ ; Get I/O JFNs.
JRST REENTR ; If none set, go back and read JCL etc.
CAME A,[.PRIIN,,.NULIO] ; Was input from JCL?
JRST COMINI ; No, go on.
MOVEI A,.PRIOU ; Get terminal output JFN
HRRM A,CMDBLK+.CMIOJ ; and restore it as command output JFN.
CALL FQUIT ; Close connection if open and stop program
COMINI: SETZM ABTLOC ; No aborts left hanging around
CALL KILFIL ; Flush input or output file if one got left
PROMPT [ASCIZ/FTP>/]
CALL SETCMD
MOVE P,[IOWD STKLEN,STACK] ; Fix stack
CALL FLTFIL ; Flush temporary parse files
HLLZS F ; Clear temporary flags
MOVE B,MULGET ; Get MULTIPLE GET state
CAIE B,MG.TMP ; Temporarily on?
IFSKP. <MVI. MG.OFF,MULGET> ; Yes, turn off again
CAIE B,MG.THE ; Temporarily on from heuristic?
IFSKP. <MVI. MG.HEU,MULGET> ; Yes, set back to heuristic
MOVEI B,[FLDDB. .CMKEY,,CMDDSP,<
Type HELP for a brief example of how to use FTP.
Type HELP <command> for a detailed explanation of a particular command.
Now type an FTP command,>,,[
FLDDB. .CMKEY,CM%SDH,SETDSP,,,[
FLDBK. .CMFLD,CM%SDH,,<type a network host name or number>,,HSTBRK]]]
CALL .COMND
ERMSG <Unrecognized command>
LOAD D,CM%FNC,(C) ; Get FDB parsed
CAIE D,.CMKEY ; Is it a command?
IFSKP.
HRRZ A,(B) ; Yes, get handler routine
ELSE.
CALL VALFLD ; Make sure we have a real field
ERMSGX <Null command or host name given>
MOVEI A,C.OPNM ; Set up with net num handler
ENDIF.
CALL (A) ; Dispatch to command handler
JRST COMLP ; Back to top
SUBTTL MULTIPLE command
; see also S.MULT (SET MULTIPLE-GET)
H.MULT: ASCIZ/There are two ways of retrieving files over TCP connections:
one can do a MULTIPLE GET, in which case FTP first asks the remote
server for a list of files to retrieve and then asks to retrieve each
of the file names returned; or one can do a non-MULTIPLE GET in which
FTP merely asks the server for the filename you specify. In the
latter case the file name must refer to only one file.
FTP has various options for which style of GET to use:
- ALWAYS always tries to use MULTIPLE GET
- NEVER always uses non-MULTIPLE GET
- HEURISTIC (the default) uses MULTIPLE GET only if there are wildcard
characters (i.e. "*" or "%") in the remote filename.
You can set these options with SET MULTIPLE-GET; you can temporarily
override them with the MULTIPLE command. If FTP thinks the remote
host can not do MULTIPLE GETs it will stop until a new connection is
made; either of the above commands forces it to try again. If smart
directories are available then they will always be used instead of
MULTIPLE GETs (see SET SMART-DIRECTORIES).
/
DEFTAB MULCMD,<
T GET
TI INSTALL
TI PUT,SEND
TI RECEIVE,GET
TI RESTORE,GET
TI RETRIEVE,GET
TI SAVE,SEND
TI SEND
TI STORE,SEND
TI UPDATE
>
T.MULT: MULCMD(C)
LS MULGET ; MULTIPLE GET state
; LH: 0/Ok, -1/Not ok for this host
; RH: MG.XXX normal MULTIPLE GET state
C.MULT: HRRZ B,MULGET ; Get state, forget if host can handle
MOVE B,[ MG.ON ; MG.ON stays that way
MG.TMP ; MG.OFF becomes temporarily on
MG.TMP ; MG.TMP stays that way
MG.THE ; MG.HEU becomes temporarily on
MG.THE ](B) ; MG.THE stays that way
MOVEM B,MULGET ; Save new MULTIPLE GET state
MOVEI B,[FLDDB. .CMKEY,,T.MULT,<file transfer command,>,<GET>]
CALL .COMND ; Parse command
ERMSG <Invalid MULTIPLE subcommand>
HRRZ B,(B) ; Get routine to call
CALLRET (B) ; Go run the command, GET or SEND
SUBTTL HELP command.
HLPTXT: ASCIZ/FTP transfers files between computers on the Ethernet or the
ARPAnet. The first thing you should do when using PUPFTP is to type the
name of the machine you are transferring files to, and your username there:
FTP>SCORE ; The computer to connect to
< SCORE Pup FTP Server 1.30 16-Apr-82 ; It will reply something like this
FTP>LOGIN CSD.KRONJ ; Your username there
Password: ; Your password (not echoed)
Then use the SEND command to send a file to the other machine, or the
GET command to get a file from the other machine to this machine:
FTP>SEND FOO.FAH (to remote file) BAR.BAZ ; Give SEND command
FOO.FAH.3 => BAR.BAZ.-1 !! [OK] ; The computer types this
FTP>GET BAR.BAZ (to local file) FOO.FAH ; Give GET command
BAR.BAZ.3 => FOO.FAH.2 !! [OK] ; The computer types this
When you are done with FTP, use the EXIT command to return to the EXEC.
Type ^G to abort any subcommand parse or multiple-file transfer.
/
CMDHLP: COMMANDS(H)
H.HELP: ASCIZ/Use the HELP command for general information about FTP,
or for a detailed explanation of a FTP command.
FTP>HELP <command>
describes a particular command, e.g. HELP HELP prints this text.
FTP>HELP
gives an introduction to FTP, with examples of common commands.
/
C.HELP: NOISE <on FTP command>
MOVEI B,[FLDDB. .CMCFM,,,,,[
FLDDB. .CMKEY,,CMDHLP,<FTP command,>,,[
FLDDB. .CMKEY,CM%SDH,SETHLP]]]
CALL .COMND
ERMSG <Invalid FTP command>
LOAD C,CM%FNC,(C)
CAIE C,.CMCFM ; Bare return?
IFSKP.
HRROI A,HLPTXT ; Main help, point to general examples
PSOUT%
RET
ENDIF.
HRRZ D,(B) ; Get pointer to string
CAIE D,H.SET ; Was it SET?
IFSKP.
NOISE <subcommand>
MOVEI B,[FLDDB. .CMCFM,,,,,[
FLDDB. .CMKEY,,SETHLP,<SET subcommand,>]]
CALL .COMND
ERMSG <Invalid SET subcommand>
LOAD C,CM%FNC,(C)
CAIN C,.CMCFM ; Bare return?
JRST C.HLP1 ; Yes, go give main SET help
HRRZ D,(B) ; Else get subcommand help text
ENDIF.
CALL CONFRM ; Confirm parse
C.HLP1: HRRO A,D
PSOUT%
RET
SUBTTL TAKE command.
H.TAKE: ASCIZ/The TAKE command tells FTP to read commands from a file.
When the end of the file is reached, FTP will once again
read commands from the terminal.
While reading commands from a file, double confirmation is not required
for any command; e.g. DELETE. Passwords (e.g. for the LOGIN command)
are always read from the terminal. Any error encountered will terminate
command file execution.
The file FTP.INIT in the user's home directory is automatically
read when FTP is started if it exists.
/
C.TAKE: HRLOI B,2-IPDL-IPDLEN(IOP)
JUMPGE B,[ERMSGX <TAKE files nested too deeply>]
NOISE <commands from file>
SETZM CMDGTJ
MOVE B,[CMDGTJ,,CMDGTJ+1]
BLT B,CMDGTJ+20-1 ; Zero GTJFN command block.
MOVEI B,[FLDDB. .CMIFI]
CALL .COMND ; Parse input file.
ERMSG <Invalid TAKE file>
MOVEM B,TMPJFN ; Save JFN for reparse
CALL CONFRM ; Finish command parse.
MOVE A,TMPJFN ; Get JFN back
SETZM TMPJFN ; Don't lose it at end of command
TAKFIL: MOVX B,FLD(7,OF%BSZ)!OF%RD
OPENF% ; Open the file.
ERMSG <Couldn't open TAKE file>
PUSH IOP,CMDBLK+.CMIOJ ; Save old I/O JFNs.
MOVSS A ; Put JFN in left half
HRRI A,.NULIO ; and get null output JFN for right half.
MOVEM A,CMDBLK+.CMIOJ ; Save as command input and output JFNs.
RET
CMDFIL: HRROI B,LCLUSR ; Point to our user name
HRROI A,TEMP ; Into temporary space
WRITE (PS:<%2S>FTP.INIT.0) ; Finish off filename.
MOVX A,GJ%SHT!GJ%OLD
HRROI B,TEMP
GTJFN% ; Get a JFN on the file
RET ; No such file, return now.
SETZM CMDBLK+.CMIOJ ; When file execution ends read JCL etc.
CALL TAKFIL ; Set up to read commands from the file.
JRST COMLP ; Go start reading commands (fixes stack).
ENDTAK: HLRZ A,CMDBLK+.CMIOJ ; Get command file JFN.
CAIN A,.PRIIN ; If it's the terminal, just return +2.
RETSKP
JUMPE A,RSKP ; If it's not set yet, just return +2.
CLOSF% ; Else close it,
NOP ; but don't care if the close fails.
POP IOP,CMDBLK+.CMIOJ ; Restore old input and output pointers.
RET
FLSTAK::CALL ENDTAK ; Close this TAKE file
JRST FLSTAK ; More left, go back for them
MOVEI A,.PRIOU
DOBE% ; Wait for all typeout to finish.
MOVEI A,.PRIIN
CFIBF% ; Then clear typeahead.
RET
; Save some parse parameters
; Must *not* be called in the middle of a parse! Trashes reparse address...
PUSHIO::EXCH A,(P) ; Save an accumulator, get caller's address
EXCH A,CMDBLK+.CMFLG ; Save caller addr, get reparse address
EXCH A,(P) ; Restore AC, save reparse address
PUSH P,CMDBLK+.CMIOJ ; Save command I/O JFNs
PUSH P,CMDBLK+.CMRTY ; Save prompt
PUSH P,A ; Save accumulator
HRRZ A,CMDBLK+.CMIOJ ; Get command output JFN.
CAIN A,.PRIOU ; If anything other than primary output
IFSKP.
MOVE A,[.PRIIN,,.PRIOU] ; Get canonical input/output pointers
MOVEM A,CMDBLK+.CMIOJ ; and set them in command block.
ENDIF.
POP P,A ; Restore accumulator again
CALL @CMDBLK+.CMFLG ; Call caller in this strange way
IFSKP. <AOS -3(P)> ; Propagate skip return.
POP P,CMDBLK+.CMRTY ; Restore prompt
POP P,CMDBLK+.CMIOJ ; Restore command I/O JFNs.
POP P,CMDBLK+.CMFLG ; Restore reparse address
RET ; Return to caller's caller.
SUBTTL EXIT and QUIT commands.
H.EXIT: ASCIZ/The EXIT command closes any open connection and returns
to the EXEC. If FTP is continued a new foreign host name
will have to be given before any file transfers can occur.
/
C.EXIT: TXNN F,F%COPN ; Connection open?
JRST C.HAL0 ; No, just exit
NOISE2 <and close connection>,<to EXEC>
CALL CONFRM
CALL @.CLOSE(V) ; Close it
JRST EXEUNT
; HALT command.
H.HALT: ASCIZ/The QUIT command returns to the EXEC without closing any open
connection. FTP can be continued without having to specify
the foreign host name again. If SET FANCY-QUIT is in effect, FTP
will actually close the connection and then re-open it after it
is continued.
/
C.HALT: TXNN F,F%COPN ; Connection open?
JRST C.HAL0 ; No, give simple noise word
IFXE. F,F%QUIT ; Fancy quit?
NOISE2 <without closing connection>,<to EXEC>
JRST C.HAL1
ENDIF.
NOISE2 <temporarily closing connection>,<to EXEC>
CALL CONFRM ; Confirm fancy quit
FQUIT: JE F%QUIT,F,EXEUNT ; If got here with no conn, don't try to close
CALL @.CLOSE(V) ; Disconnect
HALTF% ; Stop the program
TXO F,F%STYO ; Suppress terminal output for rest of command
CALL @.OPEN(V) ; And re-open
RET ; Ignore errors
CALL @.LOGIN(V) ; Log in again
RET ; Ignore errors
SKIPE CONNAM ; Skip if no connected directory
CALL @.CWDIR(V) ; Else, set working directory appropriately
RET ; Ignore errors
RET ; All done
C.HAL0: NOISE <to EXEC>
C.HAL1: CALL CONFRM
EXEUNT: HALTF% ; Exit FTP
RET ; Back to command loop if resumed
SUBTTL PUSH command.
LS XECFRK ; Fork handle of the pushed EXEC
H.PUSH: ASCIZ/The PUSH command creates an inferior EXEC to FTP and runs it.
To return to FTP use the POP command from the EXEC.
/
C.PUSH: NOISE <to EXEC>
CALL CONFRM
SKIPE A,XECFRK ; Do we have a fork already?
IFSKP.
MOVX A,GJ%OLD!GJ%SHT
HRROI B,[ASCIZ /SYSTEM:EXEC.EXE/]
GTJFN% ; Get JFN on the EXEC
JERMSG <Can't find EXEC!>
MOVEM A,TMPJFN ; Save the JFN
MOVX A,CR%CAP ; With our capabilities
CFORK% ; Make a new fork
JERMSG <Couldn't make a new fork>
MOVEM A,XECFRK ; Save fork handle
MOVSI A,(A) ; Get fork,,jfn
HRR A,TMPJFN ; JFN in right half (will go away eventually)
GET% ; Get file into fork
HLRZ A,A ; Now just get bare fork handle
ENDIF.
SETZ B, ; Entry point 0
SFRKV% ; Start fork
WFORK% ; Wait for it to terminate
RET ; Resume program
SUBTTL DISCONNECT command
H.BYE:
H.DISC: ASCIZ/The BYE command breaks the connection to the other computer.
A new connection will have to be specified by typing the foreign
host name or with the OPEN command before any more files can
be transferred.
/
C.BYE: NOISE <break connection with remote host>
JRST C.DIS1 ; Join common code
; DISCONNECT and CLOSE (synonyms for BYE) come in here
C.DISC: NOISE <connection with remote host>
C.DIS1: CALL CONFRM
TXNN F,F%COPN ; Is there a connection open now?
RET ; No, nothing to do.
CALLRET @.CLOSE(V) ; Yes, go run handler routine
SUBTTL STATUS command
H.INFO:
H.STS:
H.DISP: ASCIZ/The STATUS command types various information about the state
of the FTP program, including the version, connected host,
logged in user name, and parameters changed with the SET command.
There are various subcommands to list only part of the status
information available; the default is to display it all.
/
C.STS: NOISE <of>
JRST C.DSP1
C.INFO: NOISE <about>
JRST C.DSP1
C.DISP: NOISE <status of>
C.DSP1: MOVEI B,[FLDDB. .CMKEY,,STSTBL,,<ALL>]
CALL .COMND ; Parse keyword
ERMSG <Invalid STATUS subcommand>
CALL CONFRM ; Finish parse
HRRZ B,(B) ; Get bare keyword
CALLRET 0(B) ; Jump to it
STSTBL: TABLE
KEY ALL,DSPALL
KEY CONNECTION,DSPCON
KEY LOGIN,DSPLGN
KEY PROGRAM,DSPPRG
KEY SETTINGS,DSPSET
TEND
; Here to display all status settings
DSPALL: CALL DSPPRG ; Display program version
CALL DSPSET ; And parameter settings
CALL DSPLGN ; And login parameters, drop into DSPCON
; Here to display connection setting
DSPCON: IFXE. F,F%COPN
TYPE <No connection is open%/>
RET
ENDIF.
HLRO A,V ; Get network type
HRROI B,HSTSTR ; And host name buffer
TYPE <Connected to %1S host %2S%/>
CALLRET @.STAT(V) ; Type protocol-dependant status
; Here to display program version
DSPPRG: HRROI A,VERTXT
MOVE B,VERDAT
HRROI C,VERWHO
TYPE <Stanford TOPS-20 FTP user process
Version %1S, compiled %2T by %3S>
HRROI B,VERHST
SKIPE VERHST
TYPE < at %2S>
TYPE <%/> ; Add CRLF to finish off
HLRZ A,CMDBLK+.CMIOJ
CAIE A,.PRIIN
TYPE <Reading commands from file %1F%/>
RET
; Here for login parameter status
DSPLGN: TRVAR <OLGDEF> ; Storage for last-typed username
SKIPN USRNAM
IFSKP.
HRROI A,USRNAM
TYPE <Remote username is %1S>
HRROI A,USRACT
SKIPE USRACT ; Is there an account too?
TYPE <, remote account is %1S>
TYPE <%/>
ENDIF.
HRROI A,DEFPRP+P.DIRE
SKIPE DEFPRP+P.DIRE
TYPE <Default directory for file transfers is %1S%/>
SKIPN B,OLDLGN ; Non-default old-login action?
IFSKP.
HRROI B,[ ASCIZ/always/
ASCIZ/never/ ]+1(B)
TYPE <Old logins are %2S kept for new hosts%/>
ENDIF.
MOVE D,ULGDEF ; Get top of default login list
SETZM OLGDEF ; No default yet
DO.
JUMPE D,ENDLP. ; If zero, done
CALL S1DLGN ; Type one
HRRZ D,(D) ; Get next in list
LOOP. ; Go back for it
ENDDO.
CALLRET PCRIF ; Finish with a new line
; subroutine for default login display
S1DLGN: SKIPGE (D) ; Is there a default there?
RET ; No, skip it
MOVE C,ULGDEF ; Get top of list again
DO.
CAMN C,D ; If the address we already had
EXIT. ; Then we have gone through all prev, exit loop
MOVE A,1(C) ; Get protocol info
CAME A,1(D) ; Same as before?
IFSKP. ; If not, then these two are different
MOVE A,2(C) ; Get host number
CAMN A,2(D) ; Same as this host address?
RET ; Then duplicate, forget it
ENDIF.
HRRZ C,(C) ; Else get next in the list
LOOP. ; And go back to check it.
ENDDO.
HRROI B,3(D) ; Point to the string
SKIPE A,OLGDEF ; Get old pointer
CALL STRCMP ; Same as what we just typed?
IFSKP.
TYPE <, > ; Yes, just type comma
ELSE.
HRROI B,3(D) ; Get pointer to user name again
MOVEM B,OLGDEF ; Save as last typed
TYPE <%_Login defaults to %2S on >
ENDIF.
HRROI A,TEMP ; Into temporary storage
MOVE B,2(D) ; With host number
MOVEI C,1(D) ; Pointing to protocol info
CALL $GTNAM ; Get host name
NOP ; Can't fail
HRROI A,TEMP ; Point to temporary again
CALL $RMREL ; Remove ugly relative domains
HRROI A,TEMP ; And host name
PSOUT% ; Type out the name we got
RET
; Here for random parameter settings
DSPSET: CALL SHKPAR ; Show kept parameters
CALL SHTTYP ; Show transfer type parameters
SKIPN A,MULGET ; Strange multiple-get state?
IFSKP.
IFL. A
TXNE F,F%COPN ; If "remote file server" meaningful
TYPE <Remote file server does not understand MULTIPLE GET%/>
ELSE.
HRRO A,[ [ASCIZ/never/] ;MG.OFF
[ASCIZ/never/] ;MG.TMP
[ASCIZ/heuristically/] ;MG.HEU
[ASCIZ/heuristically/] ]-1(A) ;MG.THE
TYPE <Using MULTIPLE GET %1S%/>
ENDIF.
ENDIF.
MOVE A,SHXDEF ; Get hash mark interval
CAIN A,^D10 ; Is it something different?
IFSKP.
IFE. A
TYPE <Hash marks are not displayed in file transfers%/>
ELSE.
TYPE <Hash marks are displayed every %1D pages in file transfers%/>
ENDIF.
ENDIF.
CALL TYPCNF ; Show confirmations required
MOVE A,VRBSTY ; Get verbosity
HRRO B,[[ASCIZ/super-terse/]
[ASCIZ/terse/]
[ASCIZ/normal/]
[ASCIZ/verbose/]
[ASCIZ/extra-verbose/]
[ASCIZ/debugging/]](A)
CAIE A,VB.NRM ; If normal then be quiet
TYPE <Verbosity level is set to %2S%/>
MOVSI C,-NFLAGS ; Make AOBJN pointer
DO.
HRRO A,FLGDSP(C) ; Point to string for flag
HLRZ B,FLGDSP(C) ; Get the flag there
TLNE F,(B) ; Set in flags?
TYPE <%1S%/> ; Yes, type string for it
AOBJN C,TOP. ; Back for the next
ENDDO.
RET
FLGDSP: F%NSMD![ASCIZ/Smart directory listings for TCP are disabled/]
F%MUNG![ASCIZ/Generation numbers of remote file specs are included/]
F%NCSM![ASCIZ/Data connections are not checksummed/]
F%QUIT![ASCIZ/Connections are invisibly closed and re-opened on QUIT/]
F%STAT![ASCIZ/Statistics of transfer rates are collected/]
F%LOWR![ASCIZ/Wildcard filenames are translated to lower case/]
F%ANON![ASCIZ/Automatic ANONYMOUS logins are in effect/]
NFLAGS==.-FLGDSP
; Show confirmations required
TYPCNF: TYPE <Confirmation required for>
MOVE B,F
ANDX B,F%ALLC ; Isolate just these bits.
IFE. B
TYPE < no commands%/>
RET
ENDIF.
TXO B,F%TEMP ; Say no typeout done.
IFXN. B,F%DELC
TXZ B,F%TEMP ; Say we've typed one.
TYPE < DELETE>
ENDIF.
IFXN. B,F%GETC
TXNN B,F%SENC!F%UPDC ; Any following this?
TXNE F,F%TEMP ; No, have we typed any?
IFSKP.
TYPE < and GET> ; Yes, make conjunctive
JRST TYPCN0
ENDIF.
TXZN F,F%TEMP
TYPE <,>
TYPE < GET>
ENDIF.
IFXN. B,F%UPDC
TXNN B,F%SENC ; Any following this?
TXNE F,F%TEMP ; No, have we typed any?
IFSKP.
TYPE < and UPDATE> ; Yes, make conjunctive
JRST TYPCN0
ENDIF.
TXZN F,F%TEMP
TYPE <,>
TYPE < UPDATE>
ENDIF.
IFXN. B,F%SENC
HRROI A,[ASCIZ/ and/]
TXNN F,F%TEMP ; Typed anything?
PSOUT% ; Yes
TYPE < SEND>
ENDIF.
TYPCN0: TYPE < file operations%/>
RET
; Here to show transfer type parameters
SHTTYP: MOVE C,DEFPRP+P.TYPE
HRRO C,[ [ASCIZ/unspecified/]
[ASCIZ/text/]
[ASCIZ/binary/]
[ASCIZ/paged/]
[ASCIZ/directory/]
[ASCIZ/paged/]
[ASCIZ/ebcdic/]
[ASCIZ/image/] ](C)
TYPE <Transfer type is %3S>
SKIPE C,DEFPRP+P.BYTE
TYPE <, byte size %3D>
SKIPN C,DEFPRP+P.TFRM ; Get format
IFSKP.
HRRO C,[ [ASCIZ/non-print/]
[ASCIZ/TELNET/]
[ASCIZ/carriage control/] ]-1(C)
TYPE <, %3S format>
ENDIF.
SKIPN C,DEFPRP+P.TMOD ; Get mode
IFSKP. ; If non-default
HRRO C,[ [ASCIZ/stream/] ;MD.STR
[ASCIZ/block/] ;MD.BLK
[ASCIZ/compressed/] ]-1(C) ;MD.CMP
TYPE <, %3S mode>
ENDIF.
TYPE <%/> ; Finish line
SKIPN D,DEFPRP+P.EOLC ; Get end of line convention
RET ; None, done
MOVEI C,EOLDSP ; Find its name
CALL TABLUK
TYPE <End-of-line convention is %4S%/>
RET
; Show kept parameters
DEFINE SHK(NAME,FLG) <
SKIPN FLG ;;Anything in that flag?
IFSKP.
CAME KF,FLG ;;Same as previous?
IFSKP.
TYPE <, NAME> ;;Yes, say so
ELSE.
MOVE KF,FLG ;;Else get new flag
CALL OUTKF ;;Type out set bits
TYPE < for NAME> ;;Say what this is for
ENDIF.
ENDIF.
>
SHKPAR: SETZ KF, ; Clear "previous flag" for start
TXZ F,F%TEMP ; No CRLF needed yet
KFLAGS(SHK) ; Chain list of kept flags
CALLRET PCRIF ; Finish with a CRLF if necessary
OUTKF: TYPE <%_Keeping >
CAIE KF,K%ALL ; All flags?
IFSKP.
TYPE <all properties>
RET
ENDIF.
SAVEAC <KF> ; Don't mung - must be kept for SHKPAR
TXZN KF,K%VERS ; Keep VERSION?
IFSKP.
TYPE <file versions>
CALL KFCOMA
ENDIF.
TXZN KF,K%AUTH ; Keep USERNAME?
IFSKP.
TYPE <author names>
CALL KFCOMA ; Maybe a comma
ENDIF.
TXZN KF,K%PROT ; Keep PROTECTION?
IFSKP.
TYPE <protections>
CALL KFCOMA
ENDIF.
CAIE KF,K%DATE ; Keep all date fields?
IFSKP.
TYPE <dates>
RET
ENDIF.
TXZN KF,K%RDAT ; Keep READ-DATE?
IFSKP.
TYPE <read dates>
CALL KFCOMA
ENDIF.
TXZN KF,K%CDAT ; Keep CREATION-DATE?
IFSKP.
TYPE <creation dates>
CALL KFCOMA
ENDIF.
TXZN KF,K%WDAT ; Keep WRITE-DATE?
RET
TYPE <write dates>
RET
KFCOMA: JUMPE KF,R ; If no flags left, no comma
TYPE <, >
RET
; Look up a name in a table
; call with C/table, D/value to look up
; returns with d/string pointer
TABLUK: HLRZ B,(C) ; Get length of table
MOVNS B ; Turn into AOBJN pointer left half
AOS C ; Point to next entry
HRL C,B ; and merge left half in to make full pointer
DO.
HRRZ A,(C) ; Get value of that table entry
CAME A,D ; Same as target?
IFSKP.
HLRZ A,(C) ; Get right half of table entry
MOVE A,(A) ; Word pointed to
TXC A,CM%FW ; Complement FW bit for easier testing
IFXN. A,<-1B7> ; If not FW word
HLRO D,(C) ; Point to string
RET ; Just return with it
ENDIF.
IFXE. A,CM%INV!CM%ABR ; Ignore funny keys
HLRO D,(C) ; Point to string
AOJA D,R ; Skip over flag word and return with it
ENDIF.
ENDIF.
AOBJN C,TOP. ; Else go back for the next
ENDDO.
HRROI D,[ASCIZ/*INVALID*/]
RET
SUBTTL SET command
H.SET: ASCIZ/The SET command changes various parameters of the FTP program.
For more information type HELP SET <subcommand>, as in
FTP>HELP SET CONFIRMATION
For a list of available subcommands type SET ? to the FTP> prompt.
You can also run SET subcommands from the FTP> prompt, rather than
having to type the SET command first.
/
C.SET: KEYWRD SETDSP
HRRZ B,(B)
CALLRET (B) ; Dispatch off to command.
DEFTAB SETTAB,<
T ALTERNATE-SOCKETS,ALTS
T ANONYMOUS-LOGIN,ANON
TI BYTE-SIZE,BYTE
TA C
T CHECKSUMS
DOT(PREF,C):
T CONFIRMATION
TA D,SD
TI DEBUG
DOT(PREF,SD):
T DIRECTORY,SDIR
T END-OF-LINE,EOL
T FANCY-QUIT,FQUI
T HASH-MARK,HASH
T INCLUDE-VERSIONS,MUNG
T KEEP
T LOWERCASE
T MODE
T MULTIPLE-GET,MULT
T NO
T OLD-LOGIN,OLDL
TI PRESERVATION
TA S,SST
T SMART-DIRECTORIES,SMDR
DOT(PREF,SST):
T STATISTICS
T TYPE,STYP ; Don't conflict with TYPE command
T USER
T VERBOSITY
>
SETDSP: SETTAB(S)
SETHLP: SETTAB(H)
; Parse confirmation options for SET BYTE and SET TYPE
; Leaves flags in FX (which must be saved by callers).
S%LOCL==1B32 ; Use for local end of transfer
S%REMT==1B33 ; Use for remote end of transfer
S%CURX==1B34 ; Use for this transfer
S%DEFX==1B35 ; Use for default transfers
TYPOPT: SAVEAC <A,B,C>
NOISE <for>
MOVEI B,[FLDDB. .CMKEY,,TOCETB,<connection end,>,<BOTH>]
CALL .COMND ; Parse keyword
ERMSG <Invalid connection end>
HRRZ FX,(B) ; Get flags
NOISE <transfer>
MOVEI B,[FLDDB. .CMKEY,,TOTXTB,<transfer to set type for,>,<ALL>]
CALL .COMND ; Parse keyword
ERMSG <Invalid transfer specification>
HRRZ B,(B) ; Get flags
TRO FX,(B) ; Set them
CALLRET CONFRM ; Finish parse
TOCETB: TABLE
KEY BOTH,S%LOCL!S%REMT
KEY LOCAL,S%LOCL
KEY REMOTE,S%REMT
TEND
TOTXTB: TABLE
KEY ALL,S%CURX!S%DEFX
KEY CURRENT,S%CURX
KEY DEFAULT,S%DEFX
TEND
; SET [NO] ALTERNATE-SOCKETS - make different socket #s for new data conns
H.ALTS: ASCIZ/Normally when talking to a TCP server FTP uses the same socket
for its data and TELNET connections. When combined with the default
MULTIPLE GET action or when transferring several files, this can
lead to rapid opening and closing of the same local and remote
socket connection.
Some hosts do not treat this situation very well, and work much
better with a different socket number for each data connection.
If this is the case you can use SET ALTERNATE-SOCKETS to force FTP
to use a different socket number every time. Rather than guess which
hosts require this treatement, this option is by default always on.
/
S.ALTS: NOISE <for data connections>
MOVX D,F%ALTS ; Get flag to (re)set
JRST SETFLG ; Join common code
; SET BYTE -- supply byte size for unknown cases
; invisible keyword, normally used as subroutine of SET TYPE BINARY
H.BYTE: ASCIZ/SET BYTE-SIZE changes the number of bits per word FTP
expects the transferred file to have. Typical values for the
size are 7, 8, and 36. If the byte size is 0 (the default), the
byte size will be decided separately for each file.
/
S.BYTE: NOISE <for binary transfers>
CALL SETPRP ; Set up property list
TXO F,F%PSET ; Remember we did that
SAVEAC <FX> ; Don't mung this flag register we use
CALL SETBYT ; Do actual work
CALLRET NOHALT ; Now don't stop on JCL
SETBYT: MOVEI B,[FLDDB. .CMNUM,CM%SDH,^D10,<number between 1 and 36
or zero to leave the default byte size unspecified>,<0>]
CALL .COMND
ERMSG <Invalid bytesize>
SKIPL B ; Ensure in range (0 = unspecified is Ok)
CAILE B,^D36
ERMSGB <Bytesize not between 1 and 36>
CALL TYPOPT ; Finish parse
BYTSET: IFXN. FX,S%CURX ; If current transfer
MOVEI A,FILPRP ; Get file property list
CALL BYTSE0 ; Set properties
ENDIF.
TXNN FX,S%DEFX ; If not default transfer
RET ; Then done now
MOVEI A,DEFPRP ; Get default transfer property list
BYTSE0: TXNE FX,S%LOCL ; Local?
MOVEM B,P.BYTE(A) ; Yes
TXNE FX,S%REMT ; Remote?
MOVEM B,P.XBYT(A) ; Yes
RET
; SET [NO] CHECKSUMS -- turn checksum suppression bit in BSP conn on or off
H.CHEC: ASCIZ/SET CHECKSUMS makes FTP take advantage of whatever checksumming
facility the protocol in use might offer. With checksums enabled file
transfers may be somewhat slower but they will be less likely to
change the data in the files transferred. SET NO CHECKSUMS turns
checksumming off. The default is for checksums to be enabled.
/
S.CHEC: NOISE <for connections>
CALL CONFRM
TXNN F,F%NPRF ; (Can't use common code, flag parity is wrong)
TXZA F,F%NCSM ; "No", allow checksumming
TXO F,F%NCSM ; Else disallow it
TXNE F,F%COPN ; If a connection is open
CALL @.CFLAG(V) ; Then set up checksumming or no
CALLRET NOHALT ; Handle JCL
; SET [NO] CONFIRMATION -- specify which commands are to be confirmed.
H.CONF: ASCIZ/If confirmation is not required for the SEND or GET commands, FTP
will use the same filename on both machines rather than asking for the
other filename. If confirmation is set for the DELETE command, FTP
will ask to make sure you really want to delete the file or files.
If confirmation is required for UPDATE, then FTP will ask before
transferring any files in the UPDATE and INSTALL commands.
Confirmation is initially required for all commands.
/
S.CONF: NOISE <required for>
KEYWRD CNFRMS
HRLZ D,(B) ; Get the flag to be (re)set (in left half).
IFE. D ; Is this OLD-LOGIN stuff?
TXNN F,F%NPRF ; Yes, was NO given?
TDZA D,D ; No, assume confirmation
MOVEI D,1 ; NO CONF LOGIN, equiv to SET OLD-LOGIN NEVER
CALLRET OLLSET ; Go join OLD-LOGIN code
ENDIF.
SETFLG: CALL CONFRM
TXNE F,F%NPRF ; Prefixed with NO?
TDZA F,D ; Yes, clear flags
TDO F,D ; Else set them
CALLRET NOHALT ; Don't stop for JCL
DEFINE T (NAME,VAL,FLG) <KEY NAME,(VAL),FLG>
CNFRMS: TABLE
T ALL,F%ALLC
T DELETE,F%DELC
T GET,F%GETC
TI INSTALL,F%UPDC
TI LOGIN,0 ; Make work for old PUPFTP users
KEY R,CNFREC,CM%INV!CM%ABR ; Abbreviation - TA doesn't seem to work
KEY RE,CNFREC,CM%INV!CM%ABR
CNFREC: TI RECEIVE,F%GETC
TI RESTORE,F%GETC
TI RETRIEVE,F%GETC
KEY S,CNFSND,CM%INV!CM%ABR
TI SAVE,F%SENC
CNFSND: T SEND,F%SENC
TI STORE,F%SENC
T UPDATE,F%UPDC
TEND
; SET [NO] DIRECTORY -- set a default directory for file transfers
H.SDIR: ASCIZ/SET DIRECTORY sets a default directory for file transfers.
Files given without a directory will be assumed by the other
machine to be in the given directory.
Note that this does not give you any special access to the
given directory. To get that effect use the CONNECT command.
Directory defaults set with SET DIRECTORY will automatically
go away if you make a connection to a different machine.
/
S.SDIR: CALL NOHALT ; Don't stop for JCL
IFXN. F,F%NPRF ; Prefixed with "No"?
NOISE <default>
CALL CONFRM ; Yes, just confirm the parse
ZDIRDF: SETZM DEFPRP+P.DIRE ; clear default directory
SETZM FILPRP+P.DIRE ; and current transfer directory.
RET
ENDIF.
NOISE <default to>
SETDIR::MOVEI B,[FLDDB. .CMCFM,CM%SDH,,<return to clear default>,,[
FLDBK. .CMFLD,CM%SDH,,<remote directory>,,REMBRK]]
CALL .COMND
ERMSG <Invalid remote directory>
LOAD C,CM%FNC,(C) ; Get FDB parsed
CAIN C,.CMCFM ; Was it confirm?
JRST ZDIRDF ; Yes, clear default
CALL CONFRM ; else finish parse.
MOVE A,[POINT 7,TEMP]
CALL CPYATM ; Copy atom buffer
CAILE D,USRSTL ; Was it too long?
ERMSGB <Directory string too long>
MOVE A,[TEMP,,DEFPRP+P.DIRE]
BLT A,DEFPRP+P.DIRE+<USRSTL/5>
MOVE A,[TEMP,,FILPRP+P.DIRE]
BLT A,FILPRP+P.DIRE+<USRSTL/5>
RET
; SET END-OF-LINE -- set EOL convention.
H.EOL: ASCIZ/SET END-OF-LINE (convention to) <convention> tells FTP to translate
the end-of-line delimiters of local files (CRLF) to some other form
that the other machine is better equipped to send or receive.
Acceptable values for <convention> are:
CR -- carriage return only
CRLF -- carriage return and line feed
TRANSPARENT -- no translation by either machine
This is currently useful only for Pup transfers - TCP transfers have
no particular concept of an end of line convention.
/
S.EOL: CALL NOHALT ; Don't stop now
NOISE <convention to>
SETEOL::KEYWRD EOLDSP
HRRZ B,(B) ; Get the matching parameter.
CALL CONFRM
MOVEM B,DEFPRP+P.EOLC ; Set default eol convention
MOVEM B,FILPRP+P.EOLC ; Set current eol convention
RET
EOLDSP: TABLE
[ASCIZ /CR/],,EC.CR
[ASCIZ /CRLF/],,EC.CRL
[ASCIZ /TRANSPARENT/],,EC.TRN
TEND
; SET [NO] FANCY-QUIT -- close connection and re-open during QUIT
H.FQUI: ASCIZ/SET FANCY-QUIT changes FTP's behavior in the QUIT command.
Normally, QUIT will simply exit to the EXEC without changing any
of FTP's state. However, if you want to keep a FTP fork lying
around for a long time, the server is likely to time out your connection.
This command makes FTP close your connection when you QUIT, and re-open
it when you continue. This will all happen invisibly to you; it should
appear as though your old connection remained open during the QUIT.
/
S.FQUI: MOVX D,F%QUIT ; Get flag to (re)set
JRST SETFLG ; Join common code
; SET [NO] HASH-MARK - control display of excls on file transfers
H.HASH: ASCIZ/Normally FTP will print an exclamation mark every ten disk pages
sent or received to show that the connection is still active.
This command lets you set the number of pages between these
"hash marks" to be some other number; by setting it to zero or by
using SET NO HASH-MARK you can disable their typeout altogether.
If the verbosity level is set to DEBUGGING then this count will be
ignored and one hash mark will always be typed per page.
/
S.HASH: IFXE. F,F%NPRF ; NO typed?
NOISE <display interval>
MOVEI B,[FLDDB. .CMNUM,,^D10,<decimal number of pages>]
CALL .COMND ; Parse how many
ERMSG <Invalid number of pages>
ELSE.
NOISE <display on file transfers> ; NO, use appropriate noise
SETZ B, ; No count
ENDIF.
CALL CONFRM ; Finish parse
MOVEM B,SHXDEF ; Save count
CALLRET NOHALT ; Don't stop if JCL
; SET [NO] INCLUDE-VERSIONS - hack up escape-completed generation strings
H.MUNG: ASCIZ\The TOPS-20 command completion system automatically includes a
file generation when completing a file name. Some operating systems
will interpret this generation as merely another part of the file name,
leaving incautious users with the string ".-1" at the end of their file
names. FTP goes to great lengths to make this unwanted completion not
happen, but in cases where the filename is longer than 6 characters or
the extension longer than 3, there is no way to avoid it. Because of this,
if escape completion includes a generation in a filespec then FTP will
automatically edit it out.
If the user really wants a ".-1" or other such generation at the end of
the filename, he can type it out without using escape completion, or if he
is particularly paranoid he can enclose the whole filename in doublequotes.
To make this editing never happen, use SET INCLUDE-VERSIONS. Perhaps an
example is needed to make this clearer. In the following, the user typed
an escape immediately after each "(to remote file)".
FTP>SEND FINGER.PLAN (to remote file) FINGER.PLAN.-1
FINGER.PLAN => /csd/kronj/FINGER.PLAN !! [OK]
FTP>SET INCLUDE-VERSIONS
FTP>SEND FINGER.PLAN (to remote file) FINGER.PLAN.-1
FINGER.PLAN => /csd/kronj/FINGER.PLAN.-1 !! [OK]
\
S.MUNG: NOISE <on escape completion of remote files>
MOVX D,F%MUNG ; Get flag to (re)set
JRST SETFLG ; Join common code
; SET [NO] ANONYMOUS-LOGIN -- do ANONYMOUS login if no username is specified
H.ANON: ASCIZ\If you give a command that requires that you be logged in
and you are not already logged in, FTP will normally prompt you for a
username and password. The command SET ANONYMOUS-LOGIN will cause FTP to
instead try to automatically log you in on the remote system as ANONYMOUS,
password GUEST. If that fails, FTP will go ahead and prompt you for another
username.
\
S.ANON: NOISE <if username not specified>
MOVX D,F%ANON ; Get flag to (re)set
JRST SETFLG ; Joing common code
; SET [NO] KEEP -- keep or don't keep various parameters in file xfers
H.KEEP: ASCIZ\SET KEEP tells FTP to attempt to preserve various attributes
of the files it transfers with different commands, or with
all commands together.
Usage is SET KEEP <attribute> <command>. Possible attributes are:
ALL - keep all the following attributes
CREATION-DATE - when the file was first written
DATES - CREATION-DATE, READ-DATE, and WRITE-DATE
PROTECTION - who can access the file in what ways
READ-DATE - when the file was last looked at
USERNAMES - the name of the writer and creator
VERSION - the generation number of the file
WRITE-DATE - when the file was last written
Commands that SET KEEP is applicable to are GET, SEND, and RENAME.
Not all flags are applicable to RENAME. SET parameters also apply
to INSTALL, and likewise GET parameters apply to UPDATE. You can
type ALL to specify all of the above commands. Some attributes
require special capabilities to be kept - if an attempt to keep an
attribute fails FTP will go on with the transfer after warning you.
FTP initially keeps all attributes except VERSION.
\
DEFINE T (NAME,VAL,FLG) <KEY NAME,VAL,FLG>
KEPTBL: TABLE
TA A,K.A
K.A: T ALL,K%ALL
TI AUTHOR,K%AUTH
T CREATION-DATE,K%CDAT
T DATES,K%DATE
TI GENERATION,K%VERS
T PROTECTION,K%PROT
T READ-DATE,K%RDAT
T USERNAMES,K%AUTH
T VERSION,K%VERS
T WRITE-DATE,K%WDAT
TEND
KEPCMD: TABLE
T ALL,0 ; Luckily ALL is before all other flag names
KFLAGS(T) ; Make table entry for each flag name
TEND
DEFINE IORKF (NAME,FLG) <IORM KF,FLG>
DEFINE ANDKF (NAME,FLG) <ANDCAM KF,FLG>
S.KEEP: CALL NOHALT ; Fix JCL
NOISE <attribute>
MOVEI B,[FLDDB. .CMKEY,,KEPTBL,,<ALL>]
CALL .COMND ; Get attribute flags
ERMSG <Illegal SET KEEP atribute>
HRRZ KF,(B) ; Keep them
NOISE <in command>
MOVEI B,[FLDDB. .CMKEY,,KEPCMD,,<ALL>]
CALL .COMND
ERMSG <Illegal command to KEEP attributes in>
HRRZ B,(B) ; Get address or 0 in B
CALL CONFRM ; Finish parse
IFE. B ; If zero, set all flag sets
KP.ALL: IFXE. F,F%NPRF ; "No" typed?
KFLAGS(IORKF) ; Want to turn on flags, IORM into each cell
RET
ENDIF.
KFLAGS(ANDKF) ; Else want to turn them off, ANDCAM each
RET
ENDIF.
IORM KF,(B) ; Turn on flag
TXNE F,F%NPRF ; "No" typed?
ANDCAM KF,(B) ; Yes, turn it off
RET
; SET [NO] PRESERVATION -- shorthand for SET [NO] KEEP VERSION
H.PRES: ASCIZ/SET PRESERVATION preserves version numbers across systems. Normally
files are created with the next highest generation, but with this set
the generation of the old file is kept if possible.
SET PRESERVATION is a synonym for SET KEEP VERSION ALL.
/
S.PRES: NOISE <of version numbers during transfers>
CALL CONFRM ; Finish parse
MOVEI KF,K%VERS ; Preserving versions
JRST KP.ALL ; Go set the flags
; SET [NO] LOWERCASE -- fill wildcard names with lowercase
H.LOWE: ASCIZ\SET LOWERCASE will make the names of files filled out from
wildcards get filled out in lowercase instead of the normal
upper case. This is useful for sending files to machines
running UNIX (tm) or some similar operating system in which
filenames are typically kept in lower case. Example:
FTP>SEND FINGER.PLAN *.*
FINGER.PLAN => /csd/kronj/FINGER.PLAN !! [OK]
FTP>SET LOWERCASE
FTP>SEND FINGER.PLAN *.*
FINGER.PLAN => /csd/kronj/finger.plan !! [OK]
\
S.LOWE: NOISE <file names for UNIX sites>
MOVX D,F%LOWR ; Get flag to (re)set
JRST SETFLG ; Join common code
; SET MODE - low level format for TCP data transfers
H.MODE: ASCIZ/SET MODE tells FTP in what format to send bits across a data
connection.
STREAM mode merely sends the bits and bytes as is. This has the
advantage of simplicity, but the disadvantage that it requires
the data connection to be opened and closed for each file
transfer. Most FTP servers support only this mode.
BLOCK mode is a more structured format which allows one data
connection to remain open throughout a file transfer session.
COMPRESSED mode is like stream mode except that if there are
repetitions of some byte in the file, it will send only one
copy of the byte along with a repetition count. This is
useful for sending files across a very slow connection.
AUTO-BLOCK mode (the default) tries to use block mode, but if
the remote server can't handle that it quietly reverts to
stream mode rather than prompting for a new mode.
This is only applicable to TCP transfers; Pup file transfers have no
concept of a data mode and ignore this parameter.
/
S.MODE: CALL NOHALT ; Don't stop if this is JCL
NOISE2 <for data connections to>,<is>
SETMOD::KEYWRD MODTAB ; Get mode type
CALL CONFRM ; Finish parse
HRRZ B,(B) ; Just the value
MOVEM B,DEFPRP+P.TMOD ; Save in file properties
MOVEM B,FILPRP+P.TMOD
RET
MODTAB: TABLE
KEY AUTO-BLOCK,MD.ABK
KEY BLOCK,MD.BLK
KEY COMPRESSED,MD.CMP
KEY STREAM,MD.STR
TEND
; SET [NO] MULTIPLE-GET - when to use multiple or non-multiple receive
; Help is with MULTIPLE comand
S.MULT: IFXN. F,F%NPRF ; No prefix?
CALL CONFRM ; Yes, finish parse
MVI. MG.OFF,MULGET ; Turn off multiple gets
CALLRET NOHALT ; That's all
ENDIF.
MOVEI B,[FLDDB. .CMKEY,,MLGTAB,,<HEURISTIC>]
CALL .COMND ; Parse multiple state
ERMSG <Invalid MULTIPLE-GET state>
CALL CONFRM ; Finish parse
HRRZ B,(B) ; Get value
MOVEM B,MULGET ; Save state
CALLRET NOHALT ; That's all
MLGTAB: TABLE
KEY ALWAYS,MG.ON
KEY HEURISTIC,MG.HEU
KEY NEVER,MG.OFF
TEND
; SET NO -- Prefix set option with NO.
H.NO: ASCIZ/SET NO <parameter> turns a SET parameter off. Parameters that can be
turned off are ALTERNATE-SOCKETS, ANONYMOUS-LOGIN, CHECKSUMS, CONFIRMATION,
DIRECTORY, FANCY-QUIT, INCLUDE-VERSIONS, KEEP, LOWERCASE, SMART-DIRECTORIES,
STATISTICS, and USER.
/
C.NO: CALL NOHALT ; Don't stop if this is JCL
S.NO: KEYWRD NOOPTS
TXO F,F%NPRF ; Show a no prefix.
HRRZ B,(B) ; Dispatch to the routine.
CALLRET (B)
DEFTAB SNOCMD,<
T ALTERNATE-SOCKETS,ALTS
T ANONYMOUS-LOGIN,ANON
TA C,NC
T CHECKSUMS
DOT(PREF,NC):
T CONFIRMATION
TI DEBUG
T DIRECTORY,SDIR
T FANCY-QUIT,FQUI
T HASH-MARK,HASH
T INCLUDE-VERSIONS,MUNG
T KEEP
T LOWERCASE
TI MULTIPLE-GET,MULT
TI PRESERVATION
TA S,SN
T SMART-DIRECTORIES,SMDR
DOT(PREF,SN):
T STATISTICS
T USER
>
NOOPTS: SNOCMD(S)
; SET OLD-LOGIN - what to do with old username when open a new connection
H.OLDL: ASCIZ/SET OLD-LOGIN tells FTP what to do when you open a connection
to another computer after having logged in to one computer.
The default, CONFIRM, makes FTP ask for confirmation before
logging in as the same user. ALWAYS makes FTP log in without
asking for confirmation. NEVER makes FTP never log in.
If you log in while you are not connected to any computer,
FTP will always keep that login information without requiring
any confirmation.
/
LS OLDLGN ; Where to keep OLD-LOGIN status
S.OLDL: NOISE (action to)
MOVEI B,[FLDDB. .CMKEY,,OLLTAB]
CALL .COMND ; Parse a keyword
ERMSG <Invalid OLD-LOGIN setting>
HRRE D,(B) ; Get keyword contents
IFE. D ; CONFIRM gets different noise
NOISE (before using old user name)
ELSE. ; than do ALWAYS and NEVER
NOISE (use old user name)
ENDIF.
OLLSET: CALL CONFRM ; Finish parse
MOVEM D,OLDLGN ; Save for later
CALLRET NOHALT ; Fix JCL
OLLTAB: TABLE
KEY ALWAYS,-1
KEY CONFIRM,0
KEY NEVER,1
TEND
; SET [NO] SMART-DIRECTORIES - use STAT for dirs if possible
H.SMDR: ASCIZ/SET SMART-DIRECTORIES makes FTP try to get a formatted directory
listing in the directory command at times when this may be difficult.
With the TCP file transfer protocol there is no general way to do this
but for most TOPS-20 and TENEX hosts the output from certain listing
commands is regular enough that it can be parsed by FTP and used to
create a formattedlisting.
It may be useful for debugging purposes, or in cases where a host is
not obeying FTP's expectations, to turn this behavior off. This can
be done with SET NO SMART-DIRECTORIES.
/
S.SMDR: NOISE <for TCP listings>
TXC F,F%NPRF ; Parity of this flag is opposite from normal
MOVX D,F%NSMD ; Get flag to (re)set
JRST SETFLG ; Join common code
; SET [NO] STATISTICS -- enable/disable statistics reporting.
H.STAT: ASCIZ/SET STATISTICS tells FTP to remember information about how long
each file transfer took. After the transfer, the time (CPU and real),
file size, and baud rates of the transfer will be typed.
/
S.STAT: NOISE <gathering>
MOVX D,F%STAT ; Get flag to (re)set
JRST SETFLG ; Join common code
; SET TYPE -- supply transfer type when FTP can't figure it out itself
H.STYP: ASCIZ/SET TYPE (of transfer to) <transfer-type> specifies the format to send
data across the net. Possible values of <transfer-type> are BINARY,
EBCDIC, IMAGE, PAGED, TEXT, and UNSPECIFIED. PAGED is the most efficient,
but only works from one TOPS-20 or TENEX site to another. If UNSPECIFIED
(the default for machines that don't handle PAGED transfers) is set,
FTP will decide which type of transfer is correct for each file.
If BINARY or IMAGE types are given, FTP will also want to know a byte
size to use and will parse it after the file size. The default, zero,
makes FTP choose an appropriate byte size for each transferred file.
If ASCII or EBCDIC types are given, FTP will then prompt for a format.
This tells some sites what style of carriage control to use when printing
the file. The default is to treat the file as a simple text stream.
You can give various options after the type, byte size, and format,
to tell FTP whether to use the setting for the next transfer or for
all other transfers, and to make FTP use different settings on the
local and remote ends of the data connection.
/
; Here when STYCHG detects an error, string in A
STYBAD::TYPE <%1S%/> ; Type error message from CKSPAR
; Drop into SETTYP
; Here when protocol handler or someone notes a need to get a new type
; returns +1/lost, +2/won
SETTYP::SAVEAC <A,B,C,D> ; Don't mung registers
CALL PUSHIO ; Make sure talking to the terminal
PROMPT [ASCIZ/SET TYPE (of transfer to) /]
SETABORT (R) ; Set abort during transfer type prompt
CALL SETCMD ; Set prompt and start parsing
MOVE P,SAVPDL ; Fix stack if necessary
CALL STYPSB ; Set file type
CLRABORT ; Finished parse, forget abort
;; Now make sure opened file is opened w/correct parameters
SKIPN A,FILJFN ; Get input or output file
RETSKP ; None, give up
HRRZS A ; Right half only
GTSTS% ; Get file status
TXNE B,GS%NAM ; Is the JFN ok?
TXNN B,GS%OPN ; Is it open?
RETSKP ; No, so don't touch it
TXO A,CO%NRJ!CZ%ABT ; Aborting output, keeping JFN
CLOSF% ; Close the file
JERMSG <Unexpected JFN close error>
JN GS%RDF,B,OPNSTO ; If SEND, go re-open for that
CALLRET RECYES ; This must be GET, fix up file
S.STYP: NOISE <of transfer>
CALL SETPRP ; Set up property list
TXO F,F%PSET ; Remember we did that
CALL STYPSB ; Call subroutine to do work
CALLRET NOHALT ; Fix JCL
STYPSB: SAVEAC <FX> ; Don't mung this register
KEYWRD TYPDSP
HRRZ B,(B)
CALL (B) ; Dispatch by type
TYPSET: IFXN. FX,S%CURX ; Setting for this time?
MOVEI A,FILPRP ; Yes, get plist
CALL TYPSE0 ; Set it
ENDIF.
TXNN FX,S%DEFX ; Want defaults set?
RET ; No
MOVEI A,DEFPRP ; Yes, use them
TYPSE0: TXNE FX,S%LOCL ; Want local setting?
MOVEM B,P.TYPE(A) ; Yes
TXNE FX,S%REMT ; Remote?
MOVEM B,P.XTYP(A) ; Yes
RET
TYPASC: CALL SETFMT ; Set format too - this is a text type
MOVEI B,TT.TXT ; Text transfer type
RET
TYPBIN: NOISE <byte size> ; Noise words
CALL SETBYT ; Set byte size too
MOVEI B,TT.BIN ; Binary type
RET
TYPIMG: NOISE <byte size> ; Noise words
CALL SETBYT ; Set byte size too
MOVEI B,TT.IMG ; Image type
RET
TYPEBC: CALL SETFMT ; Set format too - this is a text type
MOVEI B,TT.EBC ; EBCDIC transfer type
RET
TYPPAG: SKIPA B,[TT.PAG] ; TENEX data type
TYPMEI: MOVEI B,TT.MEI ; MEIS data type
CALLRET TYPOPT
TYPUNS: MOVEI B,TT.UNS ; Unspecified data type
CALLRET TYPOPT
; Here for ASCII or EBCDIC transfer type, also want printing format
SETFMT: NOISE <format>
MOVEI B,[FLDDB. .CMKEY,,FMTDSP,<format for printing>,<UNSPECIFIED>]
CALL .COMND ; Parse format name
ERMSG <Illegal text format name>
HRRZ B,(B) ; Get actual format
CALL TYPOPT ; Get options to set
TXNE FX,S%CURX ; Set current transfer?
MOVEM B,P.TFRM+FILPRP ; Yes
TXNE FX,S%DEFX ; Set default transfer?
MOVEM B,P.TFRM+DEFPRP ; Yes
RET
DEFINE T (NAME,VAL,FLG) <KEY NAME,VAL,FLG>
TYPDSP: TABLE
TI ASCII,TYPASC
T BINARY,TYPBIN
T EBCDIC,TYPEBC
T IMAGE,TYPIMG
TI LOGICAL-BYTE,TYPBIN
T PAGED,TYPMEI
T TEXT,TYPASC
T UNSPECIFIED,TYPUNS
TEND
FMTDSP: TABLE
T CARRIAGE-CONTROL,FM.ASA
T NON-PRINT,FM.NPR
T TELNET,FM.TEL
T UNSPECIFIED,FM.UNS
TEND
; SET [NO] USER - say who to log in as on new computer
H.USER: ASCIZ/SET USER (default for login at) site (to) user-name
makes FTP automatically log you in as that user whenever
you open a connection to the given site. The password is
not remembered, so you will have to give it each time.
This command is useful for including in a FTP.INIT file,
so you can specify your username on any other machines you
may have an account on.
SET NO USER (default for login at) site
clears any defaults previously set with SET USER.
If you use the LOGIN command before opening a connection to a host,
the login defaults for that host are not checked. If you can connect
to the same site using more than one protocol you will have to specify
a user login default for each protocol you use.
/
; The format of a user login default block is:
; LH[0]: 0 if a default, -1 if cancelling a default
; RH[0]: pointer to next default block
; [1]: copy of appropriate V, i.e. protocol information
; [2]: host number as returned by HSTNAM
; rest: ASCIZ/user/ then ASCIZ/account/
;
S.USER: NOISE <default for login at>
MOVEI B,[FLDBK. .CMFLD,CM%SDH,,<host name>,,HSTBRK]
CALL .COMND ; Parse site name
ERMSG <Invalid host name>
CALL VALFLD ; Make sure valid field
ERMSGX <Null host name given>
HRROI A,ATMBUF ; Point to name we just parsed
MOVEI C,PROTS ; And list of protocols
CALL $GTPRO
ERMSG <No such host>
MOVE D,FRECOR ; Get address to stuff all this
MOVE C,(C) ; Get protocol info
MOVEM C,1(D) ; Save it
MOVEM B,2(D) ; Save host number
MOVEI A,3(D) ; Point to next word
IFXE. F,F%NPRF ; "NO" typed?
NOISE <to>
MOVEI B,[FLDBK. .CMFLD,CM%SDH,,<user name at remote site>,,REMBRK]
CALL .COMND ; Parse user name
ERMSG <Invalid remote user name>
HRROI A,3(D) ; Point to where user name goes
HRROI B,ATMBUF ; And atom buffer
SETZ C, ; Ending on null
SOUT% ; Copy across
HRROI A,1(A) ; Now for account
PUSH P,A ; Save pointer
NOISE <account>
MOVEI B,[FLDBK. .CMFLD,CM%SDH,,<account string>,,REMBRK]
CALL .COMND ; Parse account
ERMSG <Invalid account string>
POP P,A ; Get destination pointer back
HRROI B,ATMBUF ; And pointer to atom buffer
SETZ C, ; Ending on null
SOUT% ; Copy across
ENDIF.
CALL CONFRM ; Finish parse
MOVEI A,1(A) ; Point to next word
MOVEM A,FRECOR ; Save as place to save next default
HRRZ B,ULGDEF ; Get previous default
TXNE F,F%NPRF ; "No" typed?
TXO B,.LHALF ; Yes, set flag saying so
MOVEM B,0(D) ; Save start word
MOVEM D,ULGDEF ; Save new login default
CALLRET NOHALT ; Done
; SET VERBOSITY - say how much typeout to do
H.VERB: ASCIZ/SET VERBOSITY tells FTP how much information to type on your
terminal. There are several possible settings of this parameter:
SUPER-TERSE means almost nothing will be typed on your terminal.
TERSE types very little on the screen, but will type some error messages.
NORMAL typeout mode types everything you need to see but not much more.
VERBOSE typeout mode displays more text, such as positive server
replies that might not normally be shown.
EXTRA-VERBOSE types the machine-readable part in displayed server replies.
DEBUGGING displays all interactions with the FTP server. This may display
the password you use to log in to the remote site, so be careful.
/
S.VERB: NOISE <level to be>
KEYWRD VRBTAB ; Parse a verbosity level name
CALL CONFRM ; Finish parse
HRRZ B,(B) ; Get value
MOVEM B,VRBSTY ; Save as new verbosity
CALLRET NOHALT ; Done
LS VRBSTY ; Where to keep verbosity level
VRBTAB: TABLE
KEY DEBUGGING,VB.DEB
KEY EXTRA-VERBOSE,VB.EVB
KEY NORMAL,VB.NRM
KEY SUPER-TERSE,VB.SRV
KEY TERSE,VB.TRS
KEY VERBOSE,VB.VRB
TEND
H.DEBU: ASCIZ/SET DEBUG is shorthand for SET VERBOSITY DEBUGGING.
SET NO DEBUG is shorthand for SET VERBOSITY NORMAL.
/
S.DEBU: NOISE <mode>
CALL CONFRM ;Finish parse
IFXE. F,F%NPRF ;No?
MVI. VB.DEB,VRBSTY ;SET DEBUG = SET VERBOSITY DEBUGGING
CALLRET NOHALT
ENDIF.
MVI. VB.NRM,VRBSTY ;SET NO DEBUG = SET VERBOSITY NORMAL
CALLRET NOHALT
SUBTTL OPEN command -- initiate connection to foreign port
H.HOST:!
H.OPEN: ASCIZ/The OPEN command opens a FTP connection to another machine.
you can also type the host name to the FTP> prompt without the OPEN
command in front of it, if the host name is different from any FTP
command. The machine you open a connection to will type a welcome
message when you successfully connect, the transfer type may be set
automatically based on the remote host's operating system (see SET TYPE)
and FTP will prompt for a default login if you have set one (see SET USER).
FTP>OPEN SIERRA ; User wants to open connection to Sierra
< Sierra Pup FTP Server 1.30 16-Apr-82
Setting default transfer type to paged.
Default login as Kronj ; Previously set default with SET USER
Password: ; Now type password for Kronj@Sierra
To specify a specific network protocol, give it after the host name,
as "OPEN SIERRA PUP". You may also specify a socket name or number
after the host number; the format of this may vary according to protocol.
/
C.OPEN: NOISE <connection to> ; Make noise words
CALL OPNSUB ; Do the actual OPEN command
RET ; On error and JCL still want to halt
CALLRET NOHALT ; All done, keep going if JCL
C.HOST: NOISE <name> ; Different noise words for this command
CALL OPNSUB ; Do the actual OPEN command
RET ; On error and JCL still want to halt
CALLRET NOHALT ; All done, keep going if JCL
C.OPNM: CALL OPNSB1 ; Here with host name already parsed
RET ; On error and JCL still want to halt
CALLRET NOHALT ; All done, keep going if JCL
; Handler subroutine for OPEN command
; Enter at OPNSUB for a subroutine call so blank line reprompts etc
; returns +1/connection attempt failed, +2/connection open
OPNSUB: MOVEI B,[FLDBK. .CMFLD,CM%SDH,,<host name>,,HSTBRK]
CALL .COMND ; Parse host name as a field
ERMSG <Invalid host name>
CALL VALFLD ; Make sure it was parsed
ERMSGX <Null host name given>
OPNSB1: MOVE A,[POINT 7,TEMP+100] ; Point to a somewhat safe place
CALL CPYATM ; Copy host name
;; Host name is parsed, find which protocol to use.
;; First see which is our preferred protocol for that host.
HRROI A,TEMP+100 ; Point to name we just parsed
MOVEI C,PROTS ; And list of protocols
CALL $GTPRO
ERMSG <No such host> ; Not listed in any protocol, give up.
;; Now use preferred as default in parsing protocol name.
PUSH P,C ; Save dispatch
NOISE <protocol>
MOVE A,[[FLDDB. .CMKEY,,PRTDSP,,<X>],,TEMP]
BLT A,TEMP+.CMBRK ; Copy whole FDB into scratch
POP P,C ; Get dispatch back
HLRO A,(C) ; Copy protocol parsed
MOVEM A,TEMP+.CMDEF ; Set default
MOVEI B,TEMP ; With hacked up FDB
CALL .COMND ; Parse protocol name
ERMSG <Invalid protocol name>
;; Got a protocol name, match host name in that protocol.
MOVE C,B ; Point to protocol we just parsed
MOVE D,B ; Copy for comparison later
HRROI A,TEMP+100 ; With host name again
CALL $GTPRO ; Try it with this protocol
ERMSG <No such host with that protocol>
CAME C,D ; Same protocol parsed?
ERMSG <No such host with that protocol>
MOVE C,(C) ; Get protocol name and vector pointers
;; Protocol all parsed, get socket if protocol wants and finish parse.
CALL @.PARSK(C) ; Parse socket
CALL CONFRM ; Finish parse
;; Now we have parsed host, see if we already have a connection.
IFXN. F,F%COPN ; If we have a connection open
PROMPT TEMP,A ; Start making prompt
HRROI D,HSTSTR ; Point to host name (can't mung B or C)
WRITE <Connection already open to %4S [Confirm] >
CALL DOCONF ; Attempt double confirmation
IFNSK.
SKVERB VB.NRM ; If less than normal typeout mode
RET ; Don't type this message
TYPE <Not confirmed, old connection kept%/>
RET
ENDIF.
CALL @.CLOSE(V) ; Else close old connection
ENDIF.
;; Everything ok, open the connection.
MOVE V,C ; All confirmed, get new protocol vector
MOVEM B,HSTNUM ; Save new host number
HRROI A,HSTSTR ; Point to host string
MOVEI C,V ; Point to protocol again
CALL $GTNAM ; Get host name
NOP ; Can't fail
HRROI A,HSTSTR ; Point to string again
CALL $RMREL ; Remove ugly relative domains
CALL @.OPEN(V) ; Call open routine for protocol
RET
CALL @.OPSYS(V) ; Look up operating system, return in A/
SKIPN OPSYS ; Did we already have an operating system?
IFSKP.
CAMN A,OPSYS ; Yes, was it the same type as the new one?
ANSKP.
SETZM DEFPRP ; No, clear default properties
MOVE B,[XWD DEFPRP, DEFPRP+1] ; So we don't do bizarre things
BLT B,DEFPRP+PLSIZE-1 ; ...
ENDIF.
MOVEM A,OPSYS ; Update operating system type
CALL OPTTYP ; Set default transfer types
;; Connection opened, now handle old and default logins.
CALL OLDUSR ; Have an old user name to use?
CALL GETUDF ; Get user default login
RETSKP ; Kept old login or no default, done now
IFVERB VB.NRM ; If we're being noisy...
HRROI A,3(B) ; Point to string
TYPE <Default login as %1S%/>
ENDIF.
SETZM CONNAM ; No connected directory
HRROI A,USRNAM ; Point to where user name lives
HRROI B,3(B) ; Point to start of string.
SETZ C, ; Until null
SOUT% ; Copy string
SETZM USRACT ; Be careful in case no account
HRROI A,USRACT ; Now point to where account lives
HRROI B,1(B) ; Point to rest of default string
SOUT% ; Copy that too
SETZM USRPSW ; No password yet
SETZM LGNUNC ; Login is connected
CALL @.LOGIN(V) ; Try logging in
NOP ; Don't care about failures here
RETSKP
; Old user name is left around from previous connection, confirm
; that user wants to keep it.
LS LGNUNC ; Nonzero = last login was while unconnected
OLDUSR: SKIPN LGNUNC ; Logged in unconnected
SKIPG OLDLGN ; Or confirming old login?
SKIPN USRNAM ; Have user name?
JRST CLROLG ; No user name or flush old login, done
SKIPN LGNUNC ; Previous login was connected
SKIPE OLDLGN ; And we have to ask?
IFSKP.
PROMPT TEMP,A ; Start making a prompt
HRROI B,USRNAM ; First the user name
WRITE <Logged in as %2S>
HRROI B,USRACT ; Then the account
SKIPE USRACT ; If there is an account set
WRITE <, account %2S>
WRITE < [Confirm] > ; Finish prompt
CALL DOCONF ; Confirm it all
JRST CLROLG ; Not confirmed, clear all old defs
ENDIF.
SETZM LGNUNC ; Now if we remain logged in it's connected
CALL @.LOGIN(V) ; Finish logging in (don't ask for psw)
JRST CLROLG ; Failed, stop now
AOS (P) ; After that we always skip return
SKIPN CONNAM ; Is there a connected directory?
JRST CLRODR ; No, clear out default dir
PROMPT TEMP,A ; Else start making a prompt
HRROI B,CONNAM ; Point to the dir name
WRITE <Connected to %2S [Confirm] >
CALL DOCONF ; See if we want to stay connected
JRST CLRODR ; No, clear old directory
CALL @.CWDIR(V) ; Yes, try connecting
RET ; Don't care about failure
RET
CLROLG: SETZM USRNAM ; No user name
SETZM USRACT ; or account
CLRODR: SETZM CONNAM ; No connected directory
SETZM DEFPRP+P.DIRE ; No default directory
RET
; Here with HSTINF set up for new connection
; Set transfer type according to operating system
; Returns +1/always
LS OPSYS ; Operating system
OPTTYP: MOVE A,OPSYS ; Get host info pointer
MOVE B,DEFPRP+P.TYPE ; Get transfer type
MOVE C,DEFPRP+P.BYTE ; and byte size
CAIE B,TT.PAG ; If neither this paged
CAIN B,TT.MEI ; nor this paged
IFSKP.
CAIE C,^D36 ; Not paged, if bytesize other than 36
JUMPN B,R ; and type specified, don't change setting
ENDIF. ; Otherwise unspecified or 36-bit, need to set
CALLRET @.SDEFS(V) ; Set default transfer types
STTXT8::HRROI A,[ASCIZ/ascii, byte size 8/]
MOVX B,TT.TXT ; Type text
MOVX D,^D8 ; Byte size 8
JRST STIMAG ; Go set it
STPAGE::HRROI A,[ASCIZ/paged/]
MOVEI B,TT.MEI ; Use efficient type unless asked otherwise
MOVEI C,"P" ; Paged for TCP too
MOVEI D,^D36 ; Default byte size is 36
JRST STMSG ; Go set it
ST36BN::HRROI A,[ASCIZ/binary, byte size 36/]
MOVEI B,TT.BIN ; Not paged but can't tell us file types
MOVEI D,^D36 ; Host is 36 bit, use that and binary transfers
JRST STIMAG ; Go set it
STNOPG::HRROI A,[ASCIZ/unspecified/]
SETZB B,D ; Other hosts can decide on a per-file basis
STIMAG::MOVEI C,"I" ; Image mode for TCP
JRST STMSG ; Go set it
STTEXT::HRROI A,[ASCIZ/text/] ; Primarily for MULTICS
MOVEI B,TT.TXT ; Type is ASCII text
MOVEI C,"S" ; TCP Mode is stream
SETZ D, ; Default the byte size
JRST STMSG ; Go set default parameters
STMSG: SAVEAC <FX> ; Save flag register
SETO FX, ; Setting all possible combinations
IFVERB VB.NRM ; If not quiet
CAMN B,DEFPRP+P.TYPE ; then if transfer type
CAME D,DEFPRP+P.BYTE ; or byte size is changed
TYPE <Setting default transfer type to %1S.%/>
ENDIF.
CALL TYPSET ; Set the transfer type
MOVE B,D ; Get byte size
CALLRET BYTSET ; Set that too
; Get pointer to user for default login
GETUDF: MOVE B,ULGDEF ; Get user-login defaults.
MOVE C,HSTNUM ; Get host number to look for
DO.
JUMPE B,R ; If no more, return
CAME V,1(B) ; Same as current protocol?
IFSKP.
CAMN C,2(B) ; Yes, same host number?
EXIT. ; Yes, all done
ENDIF.
HRRZ B,(B) ; Didn't match, get the next one
LOOP. ; And go back to try it
ENDDO.
SKIPL (B) ; Is this a real default?
AOS (P) ; Yes, set up success return
RET
SUBTTL LOGIN command
; LOGCMD routine can be called as a subroutine (as from PROCNO in PUPFTP)
; it will return +1 on success or repeat parse on failure
H.LOGI: ASCIZ/The LOGIN command tells the foreign host your username and
password. Depending on the protocol in use they may either be
checked immediately, or not until you do a file transfer.
The password is prompted for on a separate line, and is not echoed.
See also the SET USER command for a way to specify in an FTP.INIT
usernames to log in as whenever you connect to a given host.
/
C.LOGI: NOISE <user> ; Give noise words
CALL NOHALT ; Don't stop if JCL
LOGCMD::CALL CLRTMP ; Clear temp page
MOVEI B,[FLDDB. .CMCFM,CM%SDH,,,,[
FLDBK. .CMFLD,CM%SDH,,<user name at remote site>,,REMBRK]]
CALL .COMND
ERMSG <Invalid remote username>
LOAD C,CM%FNC,(C) ; Get function parsed
CAIE C,.CMCFM ; Carriage return?
IFSKP.
SETZM USRNAM ; Yes, no username
ELSE.
MOVE A,[POINT 7,TEMP] ; Copy the string to there.
CALL CPYATM ; copy from atom buffer into TEMP
CAILE D,USRSTL ; Was it too long?
ERMSGB <Username too long>
NOISE <account>
MOVEI B,[FLDDB. .CMCFM,CM%SDH,,,,[
FLDBK. .CMFLD,CM%SDH,,<remote account string>,,REMBRK]]
CALL .COMND
ERMSG <Invalid account string>
LOAD A,CM%FNC,(C) ; Get FDB that won.
CAIN A,.CMCFM ; Did user confirm command here?
IFSKP.
MOVE A,[POINT 7,TEMP+400] ; No, point to halfway through temp space
CALL CPYATM ; Copy account string there
CAILE D,USRSTL ; Was it too long?
ERMSGB <Account string too long>
CALL CONFRM ; Finish the parse
ENDIF.
MOVE A,[TEMP,,USRNAM] ; Ok, remember all parameters
BLT A,USRNAM+USRSTL/5 ; Copy user name
MOVE A,[TEMP+400,,USRACT]
BLT A,USRACT+USRSTL/5 ; and account name
ENDIF.
;; All parsed - now figure out what to do with it
IFXE. F,F%COPN ; Have a connection open?
SKIPN USRNAM ; No, if just wanted no user name
RET ; Then don't ask for the password
HRROI A,USRPSW ; Point to where to put password
MOVEI B,USRNAM ; And location to clear on abort
CALL GETPSW ; Get password from user
JRST .ERMSX ; Aborted (must have been top level)
SETOM LGNUNC ; Login is not connected
ELSE.
SETZM USRPSW ; No password yet
SETZM LGNUNC ; Login is connected
CALL @.LOGIN(V) ; Check login against protocol handler
JRST .ERMSX ; Failed, back to top of same parse
ENDIF.
RET
SUBTTL CONNECT command.
; CONSUB can be called analogously to LOGCMD
H.CONN: ASCIZ/The CONNECT command gives FTP the name of a directory
on the foreign machine to connect to, and the password for
that directory.
As with the LOGIN command, the directory name and password are not
checked until a file transfer is attempted.
Note that most machines will require a password for directories connected
to with this command. If you want to simply set a default without
requiring full access to the directory, use the SET DIRECTORY command.
/
C.CONN: NOISE <to directory>
CALL NOHALT
CONSUB::CALL CLRTMP ; Clear temp page
MOVEI B,[FLDDB. .CMCFM,CM%SDH,,,,[
FLDBK. .CMFLD,CM%SDH,,<remote directory>,,REMBRK]]
CALL .COMND
ERMSG <Unable to parse remote directory specification>
LOAD C,CM%FNC,(C) ; Get FDB parsed.
CAIE C,.CMCFM ; Was it carriage return?
IFSKP.
SETZM CONNAM ; Yes, clear directory.
ELSE.
MOVE A,[POINT 7,TEMP] ; Copy the string to temp buffer.
CALL CPYATM
CAILE D,USRSTL ; Was it too long?
ERMSGB <Remote directory name too long>
CALL CONFRM ; Finish parse
MOVE A,[TEMP,,CONNAM] ; Ok, remember all parameters
BLT A,CONNAM+USRSTL/5
ENDIF.
;; All parsed - now figure out what to do with it
IFXE. F,F%COPN ; Have a connection open?
SKIPN CONNAM ; No, if just wanted no dir name
RET ; Then don't ask for the password
HRROI A,CONPSW ; Point to where to put password
MOVEI B,CONNAM ; And location to clear on abort
CALL GETPSW ; Get password from user
JRST .ERMSX ; Aborted (must have been top level)
ELSE.
SETZM CONPSW ; No password yet
CALL @.CWDIR(V) ; Check dir against protocol handler
JRST .ERMSX ; Failed, back to top of same parse
ENDIF.
RET
SUBTTL DDT command
H.DDT: ASCIZ/The DDT command enters DDT on FTP's core image.
This command is mostly useful for debugging the FTP program.
Return with R$G or RET$X.
/
C.DDT: NOISE <self>
CALL CONFRM
MOVE A,[.FHSLF,,770] ; This process, starting at 770000
RMAP% ; Read page status.
TXNE B,RM%PEX ; Page exists?
JRST 770000 ; Yes, don't bother re-mapping
MOVEI A,.FHSLF ; For this process
GEVEC% ; get entry vector
PUSH P,B ; and save it.
MOVX A,GJ%SHT!GJ%OLD ; Short form, old file
HRROI B,[ASCIZ/SYS:UDDT.EXE/]
GTJFN% ; Get handle on DDT program.
ERMSGX <Couldn't get JFN for UDDT>
HRLI A,.FHSLF ; On ourself again
GET% ; Map in DDT
HRRZS A ; Get JFN alone again
RLJFN% ; and flush it
ERNOP ; but don't care if it refuses to leave.
MOVEI A,.FHSLF ; Get process handle back
POP P,B ; and saved entry vector
SEVEC% ; to reset our entry vector to normal.
CALL NOHALT ; Don't stop if this was JCL
MV. .JBSYM,@770001 ; Set symbol table location
MV. .JBUSY,@770002 ; And undefined symbol pointer
JRST 770000 ; Start up DDT, return from command
SUBTTL TYPE command to GET file to TTY:
H.TYPE: ASCIZ/The TYPE command retrieves a file to the terminal.
Except in that it doesn't ask for the local filename and that
it doesn't type exclamation marks or such, it is very much like
the GET command with a local filename of TTY:.
/
C.TYPE: NOISE (remote file)
SETZ A, ; No file default
HRROI B,TMPPRP+P.SFIL ; Into this file
CALL FRNFIL ; Parse foreign filename
ERMSGX <Null remote filename specified>
CALL CONFRM ; Finish parse
TXZ F,F%UPDA ; Not checking against local file date
TXO F,F%STYO ; Suppress typeout
CALL SETPRP ; Get a property list
TXO F,F%PSET ; Don't do it again within SET command
MVI. TT.TXT,FILPRP+P.TYPE ; Set text mode transfer
MVI. TT.TXT,FILPRP+P.XTYP ; Set text mode transfer remotely too
SETZM RCDDEV ; Only one part of device
MVI. <ASCIZ/TTY:/>,RCDDEV+1 ; With terminal as default device
SETZM RCDDIR+1 ; No directory
SETZM RCDNAM+1 ; No filename
SETZM RCDEXT+1 ; No extension
MVI. GJ%FOU,RCDFLG ; Set flag so we don't ask for each file
JRST C.RET1 ; Go join GET command
SUBTTL GET and UPDATE commands
LS RCDDEV,10 ; Device name
LS RCDDIR,10 ; directory name
LS RCDNAM,10 ; filename
LS RCDEXT,10 ; and extension
LS RCDFLG ; and flags/generation for GTJFN block.
H.GET: ASCIZ/The GET command copies a file or files from the foreign host
to the local host. The directory, filename, and extension of the
local filename may each contain one "*", which if given is filled in
with the appropriate part of the remote filename. If confirmation is
required for GET (see SET CONFIRMATION) and no local filename is given,
FTP will prompt for a local file individually for each remote file.
FTP>GET *.TXT SCORE-*.TXT ; GET command with wildcards
MAIL.TXT.1 => SCORE-MAIL.TXT.1 !! [OK]
NOTES.TXT.23 => SCORE-NOTES.TXT.1 !! [OK]
FTP>GET FOO.* ; GET command with no local file given
FOO.FAH (to local file) ^G
Ok, ignoring that file. ; Didn't want FOO.FAH, type ^G
FOO.FOO (to local file) BAR.BAZ ; Name of file to transfer to
FOO.FOO.3 => BAR.BAZ.2 !! [OK] ; System types this out
If the LOGIN or CONNECT commands have been used incorrectly,
FTP will ask for a corrected user name or connected directory.
To return to top level from this type ^G.
/
H.UPDA: ASCIZ/The UPDATE command is the same as the GET command, except
that files with a write-date earlier than that of the latest
local copy will not be retrieved. If confirmation is required
for update then FTP will ask the user whether to go ahead with
a transfer after it has checked the write date.
/
C.UPDA: TXO F,F%UPDA ; UPDATE not GET
NOISE2 <from remote file>,<remote file>
JRST C.GET0 ; jump into GET code
C.GET: TXZ F,F%UPDA ; GET not UPDATE
NOISE <remote file>
C.GET0: MOVE KF,KF.GET ; Set up keep flags
SETZ A, ; No default
HRROI B,TMPPRP+P.SFIL ; Into this file
CALL FRNFIL ; Parse foreign filename
ERMSGX <Null remote filename specified>
;; Parsed remote filename, now try for local file
;; First set up GTJFN block for nice filename defaults
SETZM RCDFLG ; No one-liner defaults yet.
SETZM CMDGTJ ; Start setting up GTJFN defaults
MOVE B,[CMDGTJ,,CMDGTJ+1]
BLT B,CMDGTJ+20-1 ; Zero command GTJFN block
HRROI B,TMPPRP+P.SFIL ; Pointer to filename string
CALL SKPDIR ; Skip over directory name
MOVX A,GJ%SHT!GJ%FOU!GJ%OFG
GTJFN% ; Turn into a JFN
IFNJE.
MOVE B,A ; Move JFN to a new register
CALL GTJDFT ; Set defaults from it.
MOVE A,B
RLJFN% ; Get rid of temporary JFN
NOP
ELSE.
HRROI A,[ASCIZ/*/] ; Couldn't get defaults, just use * instead
MOVEM A,CMDGTJ+.GJNAM
MOVEM A,CMDGTJ+.GJEXT
ENDIF.
;; Defaults all set up, now try parsing file
NOISE <to local file>
MOVX A,GJ%FOU!GJ%OFG!GJ%FLG
TXNE KF,K%VERS
HRRI A,.GJALL ; If preserving versions, default "*"
MOVEM A,CMDGTJ+.GJGEN ; Save flags in GTJFN block.
MOVEI B,[FLDDB. .CMCFM,,,,,[
FLDDB. .CMFIL,CM%SDH,,<local filename>]]
TXNN F,F%GETC ; Confirming GETs?
LOAD B,CM%LST,(B) ; No, accept carriage return as default file
CALL .COMND ; Do the parse
JRST CNFERR
LOAD C,CM%FNC,(C) ; Find out which FDB parsed
;; Have parsed filename, now check it over (JFN in B)
TXO F,F%DSKF ; Assume disk if we don't have a file yet
CAIN C,.CMCFM ; Was it carriage return?
JRST C.RET1 ; Yes, all parsed
MOVEM B,TMPJFN ; Save in case of reparse or command error
CALL OUTWLD ; Make sure wildcards are normal, set names
MOVE A,TMPJFN ; Get JFN back
CALL CHKDSK ; See if it is on disk or not for protocol.
CALL JFNVRS ; Get version number of JFN spec.
HRLI B,(GJ%FOU)
MOVEM B,RCDFLG ; Save it and other flags
RLJFN% ; Flush the JFN
ERNOP
SETZM TMPJFN ; JFN flushed, don't flush it twice
;; Finish parse, check if confirmation needed for wildcarding
CALL CONFRM ; Finish parse
IFXE. F,F%TEMP ; If no wildcards
CALL WLDRET ; See if there were wildcards in remote spec
ANSKP.
HRROI A,TMPPRP+P.SFIL ; Point to filename
TYPE <Remote spec "%1S" is wildcard but local destination is not.
Multiple remote files may be sent to the same local file.%/>
PROMPT [ASCIZ/Using specification as is [Confirm] /]
CALL DOCONF ; Save user from possible lossage
RET ; Not confirmed, give up command
ENDIF.
; Here to generate "Retrieve" command to server
C.RET1: CALL SETPRP ; Now get a new property list
HRROI A,FILPRP+P.SFIL ; Point to filename there
HRROI B,TMPPRP+P.SFIL ; And what we have
WRITE <%2S> ; Copy
ABTSET ; Set up so we can tell we were aborted
CALL CHKCON ; Make sure we have a connection.
RET ; Didn't want one, stop
TXZ F,F%ABTD ; Haven't typed abort message yet
CALLRET @.RECV(V) ; Go do the transfer
; Check remote filespec for wildcarding
; returns +1/no wildcards, +2/wildcard character found
WLDRET: MOVE A,[POINT 7,TMPPRP+P.SFIL] ; Point to parsed filename
DO.
ILDB B,A ; Get next char of spec
CAIE B,"*" ; Is it this wildcard
CAIN B,"%" ; Or this wildcard?
RETSKP ; Yes, found a wildcard
JUMPN B,TOP. ; Else try again until wild or end of string
ENDDO.
RET ; No wildcards found, all done
; Check output filespec for appropriate wildcarding.
; Call with B/JFN (flags should be included), returns +1
; Directory, filename, and extension may only have one * (position is saved).
; Sets F%TEMP if any wildcard chars are seen
OUTWLD: TXZ F,F%TEMP ; No wildcards seen yet
MOVX C,FLD(.JSSSD,JS%DEV)
MOVEI D,RCDDEV ; Save device if it was given
CALL CHKWLD
MOVX C,FLD(.JSSSD,JS%DIR)
MOVEI D,RCDDIR ; Save directory if it was given
CALL CHKWLD
MOVX C,FLD(.JSAOF,JS%NAM)
MOVEI D,RCDNAM ; Save filename always
CALL CHKWLD
MOVX C,FLD(.JSAOF,JS%TYP)
MOVEI D,RCDEXT ; Save extension always
; CALLRET CHKWLD
CHKWLD: SETZM 1(D) ; No string yet
HRROI A,1(D) ; Into place to store string
TXO C,JS%PAF ; Punctuating
JFNS% ; get string for file part
ERJMP R ; Allow errors to mean null string
SETZM (D) ; No pointer yet
MOVEI A,1(D) ; Point to start again
HRLI A,(POINT 7) ; Make into a byte pointer
DO.
ILDB C,A ; Get next char
CAIN C,"*" ; If star
EXIT. ; Go process
CAIN C,"%" ; If percent
ERMSGB <Illegal to use "%" in wildcard filename>
JUMPN C,TOP. ; If not null, back for the next
RET ; Else done
ENDDO.
TXO F,F%TEMP ; Star, remember we had wildcard
SETZ C, ; Get null
DPB C,A ; Drop in over star
MOVEM A,(D) ; Save pointer to second half
SKIPN 1(D) ; If nothing in the string
HLLOS 1(D) ; Make it at least not zero
DO.
ILDB C,A ; Get next char
CAIE C,"*" ; If star
CAIN C,"%" ; or percent
ERMSGB <Multiple wildcard chars in filename field>
JUMPN C,TOP. ; Neither, if not null back for next
ENDDO.
RET ; Else all done
; Here when protocol retrieve routine asks for a JFN to retrieve into
; assumes FILPRP has the specific file properties being retrieved
LS PRTSTR,4 ; Where to put string for file protection
RECFIL::SAVEAC <A,B,C,D> ; Don't mung caller's ACs
ABTSKIP ; If abort has been typed
IFSKP.
TXON F,F%ABTD ; Remember we've done this before
TYPE <[Aborting multiple-file retrieval]%/>
RET ; If already typed, don't say so twice
ENDIF.
SETZM CMDGTJ ; Clear out GTJFN defaults
MOVE B,[CMDGTJ,,CMDGTJ+1]
BLT B,CMDGTJ+20-1 ; Zero command GTJFN block
MOVX A,GJ%FOU!GJ%MSG
TXNE KF,K%VERS ; Preserving versions?
HRR A,FILPRP+P.VERS ; Yes, include new version in GTJFN block
MOVEM A,CMDGTJ+.GJGEN ; (used for all but one-liner filename fill)
SKIPL B,FILPRP+P.PROT ; Protection given?
TXNN KF,K%PROT ; and keeping protection?
IFSKP.
HRROI A,PRTSTR ; Yes, get pointer to buffer space
MOVEM A,CMDGTJ+.GJPRO ; Save as file default protection
MOVEI C,^D8 ; In octal
NOUT% ; Type out the number
JFATAL
ENDIF.
SKIPN A,RCDFLG ; Did user do this as a one-liner?
JRST RFPARS ; No, go ask for filename
MOVEM A,CMDGTJ+.GJGEN ; Save RCDFLG in GTJFN block.
HRRZS A ; Get only right half
CAIE A,.GJALL ; Wildcard?
IFSKP.
SKIPN A,FILPRP+P.VERS ; Yes, get version from file props
MOVX A,.GJNHG ; or next highest file if none given
HRRM A,CMDGTJ+.GJGEN ; and use that instead.
ENDIF.
MOVX A,GJ%OFG!GJ%SHT ; Get parse-only JFN for server filespec
CALL GETNMB ; from name-body of remote file.
GTJFN%
TDZA B,B ; Couldn't, clear it
MOVE B,A ; Got one, put in correct register
HRROI A,TEMP ; Start building filename in temp register
HRROI C,FILPRP+P.DEVI ; Use device
MOVEI D,RCDDEV
CALL RCDOUT ; Process device name
HRROI C,FILPRP+P.DIRE
MOVEI D,RCDDIR
CALL RCDOUT ; and directory
MOVX C,FLD(.JSAOF,JS%NAM)
MOVEI D,RCDNAM
CALL RCDOUT ; and filename
MOVX C,FLD(.JSAOF,JS%TYP)
MOVEI D,RCDEXT
CALL RCDOUT ; and extension
SKIPE A,B ; Did we have a JFN to default with?
RLJFN% ; Yes. Flush it
ERNOP ; and ignore any errors in doing so.
MOVE A,CMDGTJ+.GJGEN ; Get generation
TXO A,GJ%SHT ; Short form
HRROI B,TEMP ; From string we just made
GTJFN% ; Get JFN for destination file.
IFSKP.
MOVE B,A ; Got it, put it where we want it
JRST C.RET7 ; Go check UPDATE and send it off
ENDIF.
HRROI A,TEMP ; Get string we tried to use
TYPE <%% %J, bypassed - "%1S"%/>
RET ; Return failure to .RECV(V)
; Here to fill in one field of file name being built
; A/pointer to file name, B/JFN to default with,
; C/-1,,string or JFNS% bits, D/where default lives
RCDOUT: SKIPN 1(D) ; If no string
RET ; Then all done with this one
PUSH P,B ; Save register
HRROI B,1(D) ; Get string
WRITE <%2S> ; and add it in
POP P,B ; Get JFN back
SKIPN D,0(D) ; Get second part if any
RET ; None, done now
IFL. C ; If we had a string
WRITE <%3S%4S> ; Write it
RET ; all done
ENDIF.
CALL .JFNS ; Else add wild part of filename
WRITE <%4S> ; and then add second part
RET
; Here when user needs to give a specific filename to retrieve into
RFPARS: SETZM CMDGTJ ; Clear GTJFN block
MOVE A,[CMDGTJ,,CMDGTJ+1]
BLT A,CMDGTJ+20-1
MOVX A,GJ%OFG!GJ%SHT ; Get parse-only JFN for server filespec
CALL GETNMB ; from name-body of remote file.
GTJFN%
IFNJE.
MOVE B,A ; Save JFN we just got
CALL GTJDFT ; Set up GTJFN defaults from it
MOVE A,B ; Get JFN back
RLJFN% ; and flush it
NOP
ENDIF.
SKIPLE A,FILPRP+P.VERS ; Look at file version if we have one
TXNN KF,K%VERS ; Want to keep versions?
MOVX A,.GJNHG ; No version or not keeping, use next highest
TXO A,GJ%FOU ; This is for output
MOVEM A,CMDGTJ+.GJGEN ; Save as default generation and flags
PROMPT TYPBUF,A ; Set prompt avoiding file defaults
HRROI B,FILPRP+P.SFIL
WRITE <%2S (to local file) >
SETABORT (GETABT)
CALL SETCMD
MOVE P,SAVPDL
CALL FLTFIL ; Flush JFN on reparse
MOVEI B,[FLDDB. .CMFIL,CM%SDH,,<local filename>]
CALL .COMND
ERMSG <Invalid local filename>
MOVEM B,TMPJFN ; Save for reparse or abort
CALL CONFRM
CLRABORT
SETZM TMPJFN ; Parse complete, don't flush JFN
; Now we have JFN for the local file in B.
; Open it and tell server to send file
C.RET7: MOVEM B,FILJFN ; Save the JFN
TXNN F,F%UPDA ; Is this UPDATE command?
JRST RECYES ; No, always want the file
SKIPN FILPRP+P.WDAT ; Do we have a write date?
JRST UPDCNF ; No, always copy file across
HRROI A,TEMP ; Into temp buffer
MOVX C,FLD(.JSAOF,JS%DEV)!FLD(.JSAOF,JS%DIR)!FLD(.JSAOF,JS%NAM)!FLD(.JSAOF,JS%TYP)!JS%PAF
JFNS% ; get filename, flush generation.
ERJMP UPDCNF ; Failed, always transfer the file
MOVX A,GJ%OLD!GJ%SHT ; Looking for an old file
HRROI B,TEMP ; With name we just got
GTJFN% ; Get the JFN
JRST UPDCNF ; Failed, give up
MOVX B,<1,,.FBWRT> ; Want write date
MOVEI C,C ; Into C
GTFDB% ; Get FDB word
ERNOP
RLJFN% ; Now flush useless JFN
ERNOP
;; Should do IDCNV/ODCNV to canonicalize date here. Instead...
ADDI C,3 ; Fudge thirds of seconds in date number
CAMGE C,FILPRP+P.WDAT ; Greater than before?
JRST UPDCNF ; No, want that file
UPDNO: MOVE A,FILJFN ; Get JFN back
SETZM FILJFN ; Don't have anything there now
RLJFN% ; Flush it since it is useless
ERNOP
RET ; Tell .RECV(V) not to use it
; Here when we want the file, maybe ask the user for confirmation
UPDCNF: TXNN F,F%UPDC ; Confirm for updates?
IFSKP.
PROMPT TEMP,A ; Set prompt to temp area, get ptr to start
MOVE B,FILJFN ; Get JFN back
WRITE <Updating %2F [Confirm] >
CALL DOCONF ; Confirm action
JRST UPDNO ; Didn't want it, give up
ENDIF.
RECYES: MOVE A,FILJFN ; Get JFN again
CALL CHKDSK ; Now see if it is a disk file
MOVE A,FILPRP+P.TYPE ; Get desired transfer type
JRST @[ RTYUNS ; Unspecified
RTYTXT ; Text
RTYBIN ; Binary
RTYPAG ; Tenex-Paged
RTYDIR ; Directory
RTYPAG ; MEIS-Paged
RTYTXT ; EBCDIC
RTYBIN ](A) ; Image
; Here when user types ^G to "FOO (to local file) " parse
GETABT: TYPE <Ok, ignoring that file.%/>
ABTSET ; Set so we still prompt for other files
RET
; Here to try opening the file depending on the transfer type
RTYUNS: HRROI A,FILPRP+P.SFIL ; Transfer type not given, get file name
TYPE <?Transfer type unspecified, skipping %1S%/>
JRST UPDNO ; Give up on the file
RTYDIR: HRROI A,FILPRP+P.SFIL ; Transfer type not given, get file name
TYPE <%% %1S is a directory, not transferred%/>
JRST UPDNO ; Give up on the file
RTYPAG: IFXN. F,F%DSKF ; Paged, device disk?;
MOVEI B,^D36 ; Byte size is 36
JRST RTYPG2 ; (may be changed later by transfer code)
ENDIF.
MOVE A,FILJFN ; Paged transfer for non-disk file
TYPE <?%1F is not a disk file, paged transfers illegal%/>
JRST UPDNO
RTYBIN: SKIPA B,FILPRP+P.BYTE ; Binary, use specified byte size
RTYTXT: MOVEI B,7 ; Text, use byte size 7
RTYPG2: MOVE A,FILJFN ; Get JFN back
ROT B,-6 ; Position byte size for OPENF%
TXO B,OF%WR
OPENF%
JRST RFNOPN ; Couldn't open, go complain
RETSKP ; Else return success
; Here when really retrieving data, types file names and calls TIMEIN.
FILEIN::SKTERS VB.DEB ; Debugging?
JRST TIMEIN ; Yes, will see later
SKVERB VB.NRM ; Terse?
JRST TIMEIN ; Yes, done now.
HRROI A,FILPRP+P.SFIL ; Point to remote filename
MOVE B,FILJFN ; and local filename
TYPE ( %1S => ) ; Print remote filename
MOVX A,.PRIOU ; To the TTY
MOVE B,FILJFN ; Local filename
MOVX C,<211111000000!JS%PAF> ; Optional device, force up to protection
JFNS% ; Print local filename, including protections!
TYPE ( ) ; Finish up message
CALLRET TIMEIN ; Go set up timers
; Here when trying to open the file failed
RFNOPN: HRRZ A,FILJFN ; Release the JFN
SETZM FILJFN ; Don't think we still have it
ETYPE <Couldn't open %1F - %J>
RLJFN%
NOP
TXNE F,F%GETC
JRST RFPARS ; Ask for new filename
TYPE <, transfer aborted.%/>
RET ; Not asking user, just give up on that xfer
; Here when a transfer is finished, to finish timing and close the file
; note that if the transfer is abnormally terminated then the transfer
; routine should worry about cleaning up, and not call this routine.
FILOUT::SAVEAC <A,B,C> ; Don't mung registers
HRRZ A,FILJFN ; Get JFN of file we just retrieved
MOVE B,FILPRP ; Get file properties
CALL SETPLT ; Remember if a plot file
TXO A,CO%NRJ
CLOSF% ; Close local file but keep JFN
JERMSG <Unlikely CLOSF% error>
HRRZ A,FILJFN
CALL TIMOUT ; Finish statistics (must be after file closed)
CALL SETKEP ; Set kept parameters
MOVE A,FILJFN
SETZM FILJFN
RLJFN% ; Flush the now-useless JFN
NOP
RET
; Set various kept fields of the destination file
DEFINE UNSETK (NAME) <
ERCAL [ TYPE <Couldn't set NAME of %1F - %J%/>
RET ]
>
SETKEP: TXNN F,F%DSKF ; Only if it's a disk file...
RET
IFXN. KF,K%AUTH ; Keeping author fields?
HRRZ A,FILJFN ; Yes, get JFN, set up for creator (.SFAUT = 0)
HRROI B,FILPRP+P.OAUT ; Point to creator string
SKIPN (B) ; If none,
HRROI B,FILPRP+P.AUTH ; Point to last writer instead
SKIPE (B) ; If we have something
CALL .SFUST ; Then set it
HRROI B,FILPRP+P.AUTH ; Now point to author for sure
HRLI A,.SFLWR ; Set up for last writer
SKIPE (B) ; If we have something
CALL .SFUST ; Then set it
ENDIF.
HRRZ A,FILJFN ; Get JFN back again
SETO B,
TXNE KF,K%CDAT ; Keeping creation date?
SKIPN C,FILPRP+P.CDAT ; And date present in property list?
IFSKP.
HRLI A,.FBCRV
CHFDB%
UNSETK <creation date>
ENDIF.
TXNE KF,K%WDAT ; Keeping write date?
SKIPN C,FILPRP+P.WDAT ; And write date present?
IFSKP.
HRLI A,.FBWRT
CHFDB%
UNSETK <write date>
ENDIF.
TXNE KF,K%RDAT ; Keeping read date?
SKIPN C,FILPRP+P.RDAT ; Read date seen?
RET
HRLI A,.FBREF
CHFDB%
UNSETK <read date>
RET
SUBTTL PRINT file on remote lineprinter
H.PRIN: ASCIZ/The print command sends a file or files to the lineprinter of
another system. Typically this merely means sending to file LPT:.
/
C.PRIN: NOISE <local file>
MOVE KF,KF.SND ; KEEP doesn't matter but use SEND flags
SETZM CMDGTJ
MOVE A,[CMDGTJ,,CMDGTJ+1]
BLT A,CMDGTJ+20-1
MVI. <GJ%OLD!GJ%IFG!.GJDEF>,CMDGTJ+.GJGEN ; Old, wild
MOVEI B,[FLDDB. .CMFIL,CM%SDH,,<local filename>]
CALL .COMND
ERMSG <Invalid local filename>
MOVEM B,TMPJFN ; Save for reparse
CALL CONFRM ; Finish parse
CALL CHKCON ; Make sure we have a connection
RET
MOVE B,TMPJFN ; Confirmed, get JFN back
SETZM TMPJFN ; Don't flush next time through command loop
MOVEM B,FILJFN ; Save JFN for file transfer
CALLRET @.PRINT(V) ; Go print it
SUBTTL STORE command.
H.SEND: ASCIZ/The SEND command sends a file from the local machine, storing
on the other machine. Example:
FTP>SEND FOO.* ; The name of the local file
FOO.FAH (to remote file) ^G ; Don't want to send that one, type ^G
Ok, ignoring that file.
FOO.FOO (to remote file) BAR.BAZ ; Name of file on other machine
FOO.FOO.3 => BAR.BAZ.-1 !! [OK] ; System types this
Wildcards may be used to fill in the filename, extension, and version
of the local file somewhere within the remote filename. If more than
one of the above is given they must each have exactly one character
between them. Example:
FTP>SEND FINGER.PLAN "GUEST2;* *"
FINGER.PLAN => DSK:GUEST2;FINGER PLAN !! [OK]
If the LOGIN or CONNECT commands have been used incorrectly,
FTP will ask for a corrected user name or connected directory.
To return to top level from this type ^G.
/
H.INST: ASCIZ/The INSTALL command is the same as the SEND command, except
that files with a write-date earlier than that of the latest
remote copy will not be stored. Confirmation for UPDATE also
applies to INSTALL; see the help on UPDATE for details.
/
C.INST: TXOA F,F%UPDA ; INSTALL not SEND
C.SEND: TXZ F,F%UPDA ; SEND not INSTALL
MOVE KF,KF.SND ; Set up keep flags
NOISE <local file>
SETZM CMDGTJ
MOVE A,[CMDGTJ,,CMDGTJ+1]
BLT A,CMDGTJ+20-1 ; Clear out previous cruft from GTJFN block
MVI. <GJ%OLD!GJ%IFG!GJ%FLG>,CMDGTJ+.GJGEN ; Old, wild
MOVEI B,[FLDDB. .CMFIL,CM%SDH,,<local filename>]
CALL .COMND
ERMSG <Invalid local filename>
MOVEM B,TMPJFN ; Save for later or reparse
NOISE <to remote file> ; Always give noise word.
;; Local file parsed, now parse name of file to send it to
SETZM SFPREF ; No prefix yet
SETOM SFECHR ; Flag nothing seen yet
SETZM SFVCHR ; Don't even think about a version
SETZM SFSUFF ; No suffix yet either
MOVE A,TMPJFN ; Set up default for remote file parse.
HRROI B,FILPRP+P.SFIL ; Into this place
CALL NFRNFL ; Parse remote filespec for wildcarding
JRST SDFPAR ; None, finish parse
; Here with remote filespec in one piece, break up for later reassembly
; Syntax is firstpart ["*" [delim "*" [ delim "*"]] secondpart].
; So DEV:*.*;*[PRJ,PGR] for FOO.BAR.3 would expand to DEV:FOO.BAR;3[PRJ,PGR].
; Firstpart and secondpart are (possibly null) strings of non-wildcards.
; Delim can be any character except "%" or "*" (even space is ok).
MOVE A,[POINT 7,FILPRP+P.SFIL] ; Point to server filename
MOVE B,[POINT 7,SFPREF] ; and to remote file prefix string
DO.
ILDB C,A ; Get next char
IDPB C,B ; Drop it in
JUMPE C,SDFPAR ; If null, got everything
CAIN C,"%" ; Percent?
ERMSGX <Invalid use of wildcards>
CAIE C,"*" ; Star for first part of filename?
LOOP. ; No, normal character, go back for the next
ENDDO.
;; Prefix found, now see what we have for the wildcard part
SETZB C,SFECHR ; Get null, assume no extension
DPB C,B ; Drop null in over star
ILDB D,A ; Get delimiter
JUMPE D,SDFPAR ; If null, done
CAIE D,"*" ; Star
CAIN D,"%" ; and percent are illegal here
ERMSGX <Invalid use of wildcards>
ILDB C,A ; Get char after delimiter
CAIE C,"*" ; If asterisk
IFSKP.
MOVEM D,SFECHR ; Save delimiter
ILDB D,A ; Get next delimiter
JUMPE D,SDFPAR ; If null, done
CAIE D,"*" ; Star
CAIN D,"%" ; and percent are illegal here
ERMSGX <Invalid use of wildcards>
ILDB C,A ; Get char after delimiter
CAIE C,"*" ; If asterisk
ANSKP.
MOVEM D,SFVCHR ; Save version delimiter
MOVE B,[POINT 7,SFSUFF] ; Point to suffix
ILDB C,A ; Get next char after that
ELSE.
MOVE B,[POINT 7,SFSUFF] ; No extension or version, get pointer
IDPB D,B ; Drop in delimiter
ENDIF.
;; Now we have everything except suffix, next char in C
DO.
CAIE C,"*" ; If asterisk
CAIN C,"%" ; or percent
ERMSGX <Invalid use of wildcards> ; then complain
IDPB C,B ; Drop it in
JUMPE C,SDFPAR ; If null, done
ILDB C,A ; Else get next char
LOOP. ; and go back with it
ENDDO.
; Finish SEND parse and set up one-time info for multiple file send
; Here to add *.* to end of filename (jumped to from within SDFPAR)
SNDWLD: MOVEI A,"." ; No filename, get a dot
MOVEM A,SFECHR ; Then treat as if it were "*.*"
JRST STONXT ; Go finish file handling
; Here when remote file parsed, finish parse and start sending files
SDFPAR: SETOM SFEPRT ; Assume starting at filename part
SKIPGE SFECHR ; Doing any wildcarding?
IFSKP.
MOVE A,TMPJFN ; Yes, get the file we are wildcarding from
SKIPE SFECHR ; Do we have two stars?
SKIPN SFVCHR ; Three?
TXNE A,GJ%NAM ; Less than three, is it a wildcard fn1?
ANSKP. ; Full wildcard or wildcard fn1, leave alone
HRROI B,SFPREF ; No, get what went before it
CALL SKPDIR ; Skip over directory part
DO.
ILDB A,B ; Get next byte
JUMPE A,ENDLP. ; Null, * must really be filename part
CAIE A,"." ; Is it a period?
LOOP. ; Nothing we're interested in, go get more
AOS SFEPRT ; Was a period, skip over fn1
ENDDO.
ENDIF.
;; Finished munging wildcards, now finish parse
CALL CONFRM ; Finish the parse
CALL SETPRP ; Init property list for first time through
CALL CHKCON ; Make sure we have a connection.
RET ; Didn't want one, done with SEND command
MOVE A,TMPJFN ; Now that we're all parsed, get local file
SETZM TMPJFN ; Don't do a random RLJFN sometime later
MOVEM A,FILJFN ; Save for subsequent iterations
HRRZS A ; Clear flag bits
CALL CHKDSK ; Set up F%DSKF flag for later
ABTSET ; Be able to check later if abort was given
;; Check existence and wildcarding of remote filenames we set up
SKIPL SFECHR ; Do we include local filename anywhere?
JRST STONXT ; Yes, don't need any of this checking
SKIPE SFPREF ; No, do we have a filename at all?
IFSKP.
TXNN F,F%SENC ; No, if user doesn't want to be asked
JRST SNDWLD ; Go treat as *.*
JRST STONXT ; Else go ask individually for each file
ENDIF.
;; Here when the filename the user gave has no wildcards in it.
;; For hosts other than SAIL, make sure it has a filename part
;; at all, and if not act as if there was a *.* after the dir.
MOVE A,OPSYS ; Get operating system
CAIN A,OS.DEC ; Normal file conventions?
IFSKP.
HRROI B,SFPREF ; Yes, point to filename
CALL SKPDIR ; Skip past directory part
ILDB A,B ; Get first char of filename part
JUMPE A,SNDWLD ; If no filename, add *.* to end
ENDIF.
;; Has a non-wild filename or is SAIL, confirm if local file is wild
MOVE A,FILJFN ; Get JFN of local file
TXNN A,GJ%NAM!GJ%EXT ; Is it wildcard?
JRST STONXT ; No, let non-wild storage spec slide by
HRROI B,SFPREF ; Else point to filename user gave
TYPE <%1F is wildcard but "%2S" is not.
Multiple local files may be sent to the same remote file.%/>
PROMPT [ASCIZ/Using specification as is [Confirm] /]
CALL DOCONF ; Save user from possible lossage
RET ; Not confirmed, give up command
; JRST STONXT ; One-time info all set up, go do first file
; Loop here for each local file designated by JFN
; (also falls in from previous page)
STONXT: ABTSKIP ; See if an abort was hit
IFSKP.
TYPE <[Aborting multiple-file store]%/>
HRRZS FILJFN ; Disable indexing
JRST STONFL ; Go finish up
ENDIF.
; Here to parse remote file on separate line
; if we find that autofill has been set up, go do that instead
SKIPN SFPREF ; Do we have a prefix
SKIPL SFECHR ; Or a wildcard filename?
JRST SFAUTO ; Yes, autofill it
PROMPT TYPBUF,A ; Start making prompt, avoid GTJDFT confusion
HRRZ B,FILJFN ; Point to our local file
WRITE <%2F (to remote file) > ; Make prompt
SETABORT (SNDABT) ; Set parse abort
CALL SETCMD ; Start parse
MOVE P,SAVPDL ; Fix stack if necessary
CALL FLTFIL ; Flush any JFNs FRNFIL may have made
HRRZ A,FILJFN ; Default to local file
SETZ B, ; Into FILPRP
CALL NFRNFL ; Parse file
NOP ; Use default we gave on return
CALL CONFRM ; Finish parse
CLRABORT ; Disable our abort
JRST STOCHK ; Go send it off
SNDABT: TYPE <Ok, ignoring that file.%/>
ABTSET ; Don't abort whole multiple send
JRST STONFL ; Go on to the next file
; Here to fill filenames from broken up wildcard info parsed earlier
LS SFPREF,20 ; File name prefix
LS SFECHR ; Char to separate extension
; 0 for no extension, -1 for no filename
LS SFVCHR ; Char to separate vers (0 for no extension)
LS SFSUFF,20 ; File name suffix
LS SFEPRT ; Whether to start with fn1 or fn2
; Table of printer routines for different parts of a wildcard filename
SFEPTT: SFEPT1 ; FN1 printer
SFEPT2 ; FN2 printer
SFEPTV ; Version printer
[FATAL <More than 3 wildcard parts to fill out>]
; FN1 printer
SFEPT1: HRRZ B,FILJFN ; Point to file JFN
MOVX C,FLD(.JSAOF,JS%NAM) ; Just outputting FN1
CALLRET .JFNS ; Send name off
; FN2 printer
SFEPT2: HRRZ B,FILJFN ; Point to file JFN
MOVX C,FLD(.JSAOF,JS%TYP) ; Just outputting FN2
CALLRET .JFNS ; Send name off
; Version printer
SFEPTV: PUSH P,A ; Save string pointer
HRRZ A,FILJFN ; Get JFN again
CALL GTVERS ; Get generation of JFN
SETO B, ; Couldn't, send to new version
POP P,A ; Restore pointer
WRITE <%2D> ; Write version
RET
SFAUTO: HRROI A,FILPRP+P.SFIL ; Now point to where to put filename
HRROI B,SFPREF ; Point to prefix
SKIPE (B) ; If we have anything there
WRITE <%2S> ; Copy it in
SKIPGE D,SFECHR ; If we also want wildcarding
JRST STOCHK ; Then go on else done with file name
;; Have wildcards, fill them out
PUSH P,SFEPRT ; Save for next run
AOS B,SFEPRT ; Get which part to use
CALL @SFEPTT(B) ; Print that part
SKIPG B,SFECHR ; Get extension delim again. If we want it
IFSKP.
IDPB B,A ; Drop delimiter in
AOS B,SFEPRT ; Get which part to use
CALL @SFEPTT(B) ; Print that part
SKIPG B,SFVCHR ; If we want version as well
ANSKP.
IDPB B,A ; Drop delimiter in
AOS B,SFEPRT ; Get which part to use (always version here)
CALL @SFEPTT(B) ; Print it
ENDIF. ; End if have extension
POP P,SFEPRT ; Now restore saved value
HRROI B,SFSUFF ; Point to suffix
SKIPE (B) ; If we have anything there
WRITE <%2S> ; Copy it in
; JRST STOCHK ; Now that we have filled filename, go send
; Here to send file off after remote filename has been agreed upon
; (also falls in from previous page)
STOCHK: HRRZ A,FILJFN ; Get local JFN
TXNE KF,K%VERS ; Keeping version?
CALL GTVERS ; Yes, get file version
SETO B, ; Not keeping or not disk, use version -1
MOVEM B,FILPRP+P.VERS ; Save version number to send off
CALL OPNSTO ; Open local file
JRST STONOP ; Failed, bypass file
CALL @.SEND(V) ; Send the file
HRRZS FILJFN ; Permanent failure, disable indexing
; Here when done with a file, go on to transfer the next
STONFL: CALL NXTFIL ; Step filespec
RET ; All done, return
JRST STONXT ; More, go back and do it again
; Here when OPNSTO fails
STONOP: TYPE <%_%% %1S%/> ; Print error message as a warning
JRST STONFL ; On to the next file
; Here to check on whether install is Ok
; call with D/property list pointer
; returns +1/local copy more recent or not confirmed, +2/ok to store
; need only be called for INSTALL
SNDCNF::TXNN F,F%UPDA ; Updating?
RETSKP ; No, always copy file across
SAVEAC <A,B,C> ; Don't mung registers
HRRZ A,FILJFN ; With source JFN
MOVX B,<1,,.FBWRT> ; Want write date
MOVEI C,C ; Into C
GTFDB% ; Get FDB word
IFNJE.
SUBI C,3 ; Fudge thirds of seconds in date number
CAMG C,P.PWDT(D) ; Is local version more recent than remote?
RET ; Yes, don't send it
ELSE.
HRRZ A,FILJFN ; GTFDB failed, get JFN again
TYPE <%% Couldn't get FDB for %1F, assuming it is more recent%/>
ENDIF.
TXNN F,F%UPDC ; Want to install - need confirmation?
RETSKP ; No, just go send it
PROMPT TEMP,A ; Start making a prompt
HRROI B,P.SFIL(D) ; Point to destination filename
WRITE <Installing %2S [Confirm] > ; Make prompt
CALLRET DOCONF ; Go confirm it
SUBTTL DELETE command
H.DELE: ASCIZ/The DELETE command is used to delete files on the other system.
For each file that matches the given specification, you will be
asked whether to delete it. If you still want to delete it, just
type return; otherwise type NO. Example:
FTP>DELETE FOO.* ; File name to delete
Deleting PS:<CSD.KRONJ>FOO.FAH.3 [Confirm] NO ; Don't want to delete this
Not confirmed, delete aborted.
Deleting PS:<CSD.KRONJ>FOO.FOO.2 [Confirm] ; Type return to delete it
There is (currently) no way to expunge a directory with FTP.
/
C.DELE: NOISE <remote file>
SETZB A,B ; No default, normal destination
CALL FRNFIL ; Parse remote filename.
ERMSGX <Null remote file specified>
MVI. .GJALL,FILPRP+P.VERS ; Set wildcard default version
CALL CONFRM ; Confirm the parse.
CALL CHKCON ; Make sure we have a connection.
RET
CALLRET @.DELFL(V) ; Call protocol handler to delete file
; Here with property list in FILPRP, confirm file deletion
DELCNF::TXNN F,F%DELC ; Delete confirmation required?
RETSKP ; No, return now
PROMPT TEMP,A ; Build prompt
HRROI B,FILPRP+P.SFIL ; Get string for filename
WRITE <Deleting %2S [Confirm] >
CALLRET DOCONF ; Confirm action
SUBTTL RENAME command.
H.RENA: ASCIZ/The RENAME command gives a file on the other machine a new
name. The file is not transferred across the network. Example:
FTP>RENAME FOO.BAR ; Old remote filename
FOO.BAR.3 (to be) FOO.BAZ ; New name for old file
< Rename to <KRONJ>FOO.BAZ successful ; Computer tells you it worked
/
LS RENSTR,20 ; Where to put second remote filename
C.RENA: NOISE <remote file>
MOVE KF,KF.REN ; Flags for RENAME (not usually useful)
SETZB A,B ; No default, normal dest.
CALL FRNFIL ; Parse remote filename.
ERMSGX <Null remote file specified>
NOISE <to be>
HRROI A,FILPRP+P.SFIL ; Default to other file
HRROI B,RENSTR ; into string where we want second filename
CALL NFRNFL ; read destination file.
IFSKP.
CALL CONFRM ; If got a filename, finish parse
ELSE.
CALL CONFRM ; Else finish that line of parse
PROMPT TYPBUF,A ; Set prompt, avoid GTJDFT confusion
HRROI B,FILPRP+P.SFIL ; Using first filename
WRITE <%2S (to be) > ; Make prompt
SETABORT (RENABT) ; Let user abort out of parse
CALL SETCMD ; Start parsing second line
MOVE P,SAVPDL ; Fix stack if necessary
HRROI A,FILPRP+P.SFIL ; Default to other file,
HRROI B,RENSTR ; sending into RENSTR,
CALL NFRNFL ; parse foreign filename.
NOP ; If return, keep filled with default
CALL CONFRM ; Finish parse
CLRABORT
ENDIF.
CALL CHKCON ; Make sure we have a connection
RET ; Didn't want one, stop now
HRROI A,RENSTR ; Point to file to rename to
CALLRET @.RENAM(V) ; Go rename it
; Here when user types ^G to rename
RENABT: TYPE <Ok, rename aborted.%/>
RET
SUBTTL DIRECTORY and VDIRECTORY commands.
H.VDIR: ASCIZ/The VDIRECTORY command is equivalent to the DIRECTORY command
with the VERBOSE option.
/
H.DIRE: ASCIZ/The DIRECTORY command lists information about files on the other
system matching the given specification.
Type a comma at the end of the filename to give subcommands to the
DIRECTORY command. If no comma is given, only the file names will
be listed. When you are done typing subcommands, leave a blank line
to tell FTP to do the directory. To list available options type
HELP to the subcommand prompt ("FTP>>").
Example:
FTP>DIRECTORY FOO.*, ; File spec, comma to enter subcommands
FTP>>VERBOSE ; Include author, read, write, type
FTP>> ; Blank line to finish subcommands
Type Prot Write Read Author
<CSD.KRONJ>
FOO.FAH.1 B(36) 775202 25-Aug-82 --- CSD.KRONJ
FOO.FOO.1 Text 775202 12-Jun-82 --- CSD.KRONJ
/
HH.DIR: ASCIZ/Directory options are:
AUTHOR - type the username of each file's creator
CREATION - type the creation date of each file
EVERYTHING - include all optional fields
HELP - output this text
NO - negate any option (except QUIT or HELP)
ORIG-AUTHOR - the name of the user who created the file
OUTPUT - send the information to a file rather than the terminal
PROTECTION - the file's protection
QUIT - abort the DIRECTORY command
READ - type the date each file was last examined
SIZE - type the number of bytes in each file
TIMES - include times along with read, write, or creation dates
TYPE - type the type (binary or text) and bytesize of each file
VERBOSE - type the author, read and write dates, protection, and type
WRITE - type the date each file was last changed
/
; Parse DIRECTORY and VDIRECTORY commands
LS DIRJFN ; JFN for output
C.DIRE: TDZA FX,FX ; Clear list flags
C.VDIR: MOVX FX,L%VERB ; Or initialize flags to "Verbose"
MVI. .PRIOU,DIRJFN ; Assume output to TTY
NOISE <of remote files>
SETZB A,B ; No default, into FILPRP
CALL FRNFIL ; parse a remote filename.
SETZM FILPRP+P.SFIL ; If user typed bare return let him have it.
MVI. .GJALL,FILPRP+P.VERS ; Set wildcard default version
;; Remote file parsed, see if it ended with a comma
MOVE A,[POINT 7,FILPRP+P.SFIL]
DO.
ILDB B,A ; Get the next character
JUMPE B,ENDLP. ; No comma, go on with parse
CAIE B,"," ; Is it a comma?
LOOP. ; No, go back for more.
MOVE B,A ; Yes, get copy of byte pointer
ILDB B,B ; and read char from it.
JUMPN B,TOP. ; If non-null, false alarm - go back for more.
DPB B,A ; Else drop the null where the comma was
JRST DIRSUB ; and go start parsing subcommands
ENDDO.
;; No comma in filespec already, try parsing it separately
MOVEI B,[FLDDB. .CMCMA,CM%SDH,,<comma to enter subcommands>,,[
FLDDB. .CMCFM]]
CALL .COMND ; Parse comma or carriage return
JRST CNFERR
LOAD C,CM%FNC,(C) ; Get FDB parsed.
CAIE C,.CMCFM ; Was it confirmation?
JRST DIRSUB ; No, go read subcommands
; Here when command and subcommand parsing complete, run directory command
DIRCHK: CALL CHKCON ; Make sure there is a connection.
RET ; Didn't want one, done now
ABTSET ; From now on we handle aborts more carefully
CALL @.DIREC(V) ; Go call handler routine
MOVE A,DIRJFN ; Get source JFN
CAIN A,.PRIOU ; If was to a file
IFSKP.
ABTSKIP ; If aborted
IFSKP. <TXO A,CZ%ABT> ; then abort the file
CLOSF% ; Else close it normally
TYPE <%% Couldn't close directory output file - %J%/>
ENDIF.
ABTSKIP ; If aborted
TXNE FX,L%HDR ; or something was typed
RET ; then all done
TYPE <%% No files match that specification%/>
RET
; Loop to gather subcommands.
DIRSUB: CALL CONFRM ; Finish command line parse
PROMPT [ASCIZ/FTP>>/] ; Set subcommand prompt
SETABORT (R) ; On abort, return from directory command
DIRSCM: CALL SETCMD ; Start parse for subcommands
MOVE P,SAVPDL ; Fix stack if necessary
CALL FLTFIL ; Flush temporary file if any
TXZ F,F%NPRF ; No NO prefix typed yet
DIRSNO: MOVEI B,[FLDDB. .CMCFM,,,,,[
FLDDB. .CMKEY,,LSUBTB]]
TXNE F,F%NPRF ; NO typed?
HRRZ B,(B) ; Yes, don't allow confirmation
CALL .COMND ; Parse subcommand
ERMSG <Invalid subcommand>
LOAD C,CM%FNC,(C) ; Get function code that won.
CAIN C,.CMCFM ; Done here with subcommands?
JRST DIRSDN ; Yes, finish up
HRRZ D,(B) ; Get format flags for this keyword.
TXNE D,L%NO ; NO command?
JRST DIRNO ; Yes, go handle
TXNE D,L%HELP ; HELP command?
JRST DIRHLP ; Yes, go handle
TXNE D,L%QUIT ; QUIT command?
JRST DIRQIT ; Yes, go handle
TXNE D,L%OUTF ; Output to file?
JRST DIROUT ; Yes, go handle
CALL CONFRM ; Otherwise must be a flag, finish parse
TXNN F,F%NPRF ; NO given?
TROA FX,(D) ; No, set flags
TRZ FX,(D) ; Else clear them
JRST DIRSCM ; Back for another subcommand
; Here for QUIT
DIRQIT: TXNE F,F%NPRF ; NO given?
ERMSGB <Illegal keyword with NO prefix>
NOISE (from DIRECTORY command)
CALL CONFRM
CLRABORT ; Flush abort we may have had
RET
; Here for NO
DIRNO: TXOE F,F%NPRF ; Yes, set flag for later
ERMSGX <Illegal to type NO twice in same line>
JRST DIRSNO ; Go parse a second command
; Here for return to FTP>> parse
DIRSDN: CLRABORT ; Clear our abort
MOVE A,DIRJFN ; Get destination JFN
CAIN A,.PRIOU ; If the terminal
JRST DIRCHK ; Then go do the directory now
MOVX B,FLD(7,OF%BSZ)!OF%WR
OPENF% ; Else open it for write
ERMSG <Couldn't open output file>
HRROI B,FILPRP+P.SFIL ; Point to file we parsed
HRROI C,HSTSTR ; and host we're talking to
WRITE <Files matching %2S from %3S at %T%/%/> ; Start header
JRST DIRCHK ; Succeeded, go do the directory
; DIRECTORY subcommand handlers and command table
DEFINE T (NAME,VAL,FLG) <KEY NAME,VAL,FLG>
LSUBTB: TABLE
T AUTHOR,L%AUTH
T CREATION,L%CDAT
T EVERYTHING,777777-<L%OUTF!L%QUIT!L%HELP!L%NO!L%HDR>
T HELP,L%HELP
T NO,L%NO
T ORIG-AUTHOR,L%OAUT
T OUTPUT,L%OUTF
T PROTECTION,L%PROT
T QUIT,L%QUIT
T READ,L%RDAT
T SIZE,L%SIZE
T TIMES,L%TIME
T TYPE,L%TYPE
T VERBOSE,L%VERB
T WRITE,L%WDAT
TEND
; Here for HELP (with the DIRECTORY command)
DIRHLP: TXNE F,F%NPRF ; NO given?
ERMSGB <Illegal keyword with NO prefix>
NOISE (with the DIRECTORY command)
CALL CONFRM ; Finish parse
HRROI A,HH.DIR ; Get list of subcommands
PSOUT% ; Send it off to the terminal
JRST DIRSCM ; Done with that keyword, on to next
; Here for OUTPUT (to file)
DIROUT: NOISE (to file)
SETZM CMDGTJ
MOVE B,[CMDGTJ,,CMDGTJ+1]
BLT B,CMDGTJ+20-1 ; Zero GTJFN command block.
HRROI B,[ASCIZ/LST/] ; Make an extension
MOVEM B,CMDGTJ+.GJEXT ; Set it as the default
MOVEI B,[FLDDB. .CMOFI,CM%SDH,,<file to send listing to>,,[
FLDDB. .CMCFM,CM%SDH,,<carriage return to send to terminal>]]
TXNE F,F%NPRF ; No given?
HRRZ B,(B) ; Yes, only allow carriage return
CALL .COMND ; Parse CR or filename
ERMSG <Invalid filename>
LOAD C,CM%FNC,(C) ; Get FDB parsed
CAIE C,.CMOFI ; File?
IFSKP.
MOVEM B,TMPJFN ; Yes, save for reparse flush
CALL CONFRM ; Finish the parse
MOVE A,TMPJFN ; Get JFN back
SETZM TMPJFN ; Parse is over, file is safe
ELSE.
MOVEI A,.PRIOU ; Carriage return, use terminal
ENDIF.
EXCH A,DIRJFN ; Get old dir JFN, save new
CAIE A,.PRIOU ; If old was not the terminal
RLJFN% ; Then release the JFN
ERNOP ; But don't care if it is lost
JRST DIRSCM ; Go back for next subcommand
SUBTTL QUOTE command.
H.QUOT: ASCIZ/The QUOTE command passes an arbitrary command string to the
remote FTP server. The command string must be enclosed in double quotes,
for example:
FTP>quote "STAT"
/
LS QUOTES,ATMBFW ;Storage for QUOTE command argument
C.QUOT: NOISE <command to server> ;Some noise
MOVEI B,[FLDDB. .CMQST,CM%SDH,,<server command, in double quotes>]
CALL .COMND ;Parse an unquoted string
ERMSG <Unable to parse command for remote server>
SETZM QUOTES ;Clear first word in case of null string
MOVE A,[POINT 7,QUOTES] ;Set up pointer to argument buffer
CALL CPYATM ;Copy from atom buffer into QUOTES
CALL CONFRM ;Wait for confirmation
CALL CHKCON ;Check for a connection
RET ;Didn't want one, done now
MOVE A,[POINT 7,QUOTES] ;Set up pointer to quote string
CALL @.QUOTE(V) ;Call protocol dependent quote routine
RET ;Return to caller
SUBTTL Remote filespec parsing
; Parse a foreign filename.
;
; Enter at FRNFIL for existing file name, NFRNFL for new file.
; Call with A/JFN or -1,,Text pointer for defaults (if 0 then uses *.*)
; B/String to store filename, or zero for standard file props.
; KF/K%VERS set or cleared (only checked for NFRNFL)
; Returns +1/Null string parse, +2/User typed something
;
; Preserves case of command buffer even if a TOPS-20 filespec is parsed
LS FFLDEF ; Space to store foreign file default string
LS FFLJFN ; Place for default JFN
LS FFLSTR ; Where to save the completed string
LS FFLPTR ; Place to save old command pointer
LS FFLPRS ; Place to store ptr to COMND% function blocks
NFRNFL: TXOA F,F%TEMP ; New foreign file, set flag
FRNFIL: TXZ F,F%TEMP ; else clear it.
MOVEM B,FFLSTR ; Save place to save completed string.
SETZM FFLDEF ; No default string yet.
SETZM FFLJFN ; No JFN yet.
SETZM CMDGTJ
MOVE B,[CMDGTJ,,CMDGTJ+1]
BLT B,CMDGTJ+20-1 ; Zero GTJFN command block.
IFXN. F,F%TEMP ; New file?
HLLOS CMDGTJ+.CMFLG ; Yes, set version -1 instead of 0
MOVX B,.GJALL ; Get wildcard version
TXNE KF,K%VERS ; Keeping versions?
HRRM B,CMDGTJ+.CMFLG ; Yes, set in default version
ENDIF.
SKIPE A ; If no default
IFSKP.
MOVE A,OPSYS ; Use default, get operating system type
CAIE A,OS.UNX ; Is it Unix?
IFSKP.
HRROI A,[ASCIZ/*/] ; Use this default
ELSE.
HRROI A,[ASCIZ/*.*/] ; Then use this default (wildcard or -1 gen)
ENDIF.
ENDIF.
TLC A,-1 ; Flip some bits
TLCN A,-1 ; Test default - can it be a JFN?
IFSKP.
TXNE F,F%TEMP ; New file?
TXNN KF,K%VERS ; And keeping versions?
IFSKP.
IFXE. A,GJ%DEV!GJ%UNT!GJ%DIR!GJ%NAM!GJ%EXT!GJ%VER
PUSH P,A ; If not wildcard, save JFN
HRRZS A ; and clear left half bits.
CALL GTVERS ; Find file version.
CAIA ; Not disk file.
HRRM B,CMDGTJ+.CMFLG ; Else set version same as file.
POP P,A ; Get unmunged JFN back
ENDIF.
ENDIF.
STKVAR <<FFLBUF,NAMSTL>> ; Declare some local storage
MOVE B,A ; Copy JFN
HRROI A,FFLBUF ; Point to our new buffer
MOVEM A,FFLDEF ; Save string as default
MOVX C,FLD(.JSAOF,JS%NAM)!FLD(.JSAOF,JS%TYP)!JS%PAF
CALL .JFNS ; Make string default from file name
ELSE.
MOVEM A,FFLDEF ; Save string as default
MOVE B,A ; copy into B
CALL SKPDIR ; and skip over directory terminators.
MOVX A,GJ%SHT!GJ%OFG!GJ%FLG
GTJFN% ; Make a JFN for the file (released on reparse)
IFJER.
MOVEI B,[FLDBK. .CMQST,CM%SDH,,<remote file, optionally quoted>,0,REMBRK,[
FLDBK. .CMFLD,CM%SDH]]
MOVEM B,FFLPRS ; Save it back, remove file parse
HRR B,B ; Point to second item
MOVE A,FFLDEF ; Get default file ptr
MOVEM A,.CMDEF(B) ; Save it in function block
JRST FFLPAR ; Go on with parse.
ENDIF.
MOVE B,A
MOVEM B,FRNJFN ; Save for reparse etc
ENDIF.
MOVEM B,FFLJFN ; Save JFN in a different cell.
CALL GTJDFT ; Set up defaults from filename.
MOVEI A,[FLDDB. .CMCFM,CM%SDH,,,,[
FLDDB. .CMQST,CM%SDH,,<remote file, optionally quoted>,,[
FLDDB. .CMFIL,CM%SDH]]]
MOVEM A,FFLPRS ; Save it for COMND%
; Now that we've set up our defaults and arguments, do the actual parse.
; We only parse a file and quoted string for now, but if we get a filename
; that ends on some break char other than space we will try the parse
; again as an unquoted string (falls in from previous page).
FFLPAR: CALL SKPSPC ; Skip over spaces in parse
MOVX A,GJ%OFG!GJ%XTN ; Parse-only, using extended flag word
HLLM A,CMDGTJ+.GJGEN ; Set parse-only flag.
MOVX A,G1%NLN ; Trying to avoid the generation
MOVEM A,CMDGTJ+.GJF2 ; Set in secondary flag word
MV. CMDBLK+.CMPTR,FFLPTR ; Save command pointer for later
MOVE B,FFLPRS
CALL .COMND ; Try this parse first
TXOA F,F%TEMP ; Failed, remember that we have to mung vers
JRST FFLFLP ; Succeeded, go on
SETZM CMDGTJ+.GJF2 ; Didn't, try a normal file
MOVEI B,[FLDDB. .CMFIL,CM%SDH,,<remote file, optionally quoted>]
CALL .COMND ; Try quoted string or normal file
JRST FFLUQS ; Failed, do unquoted string instead
TXNE A,CM%ESC ; Unless user typed an escape
TXNE F,F%MUNG ; Or if user doesn't want versions munged
FFLFLP: TXZ F,F%TEMP ; Don't mung versions
CALL FFLFFJ ; Flush temporary file
LOAD C,CM%FNC,(C) ; Succeeded, find out what we got
;; We might have parsed a carriage return to cause the default
;; to happen if user typed a bare CR to the start of the line.
CAIE C,.CMCFM ; Carriage return?
IFSKP.
CALL FFLBKP ; Yes, back up pointer
JRST FFILZ ; And go use default
ENDIF.
;; Check other possibilities for parse
CAIE C,.CMQST ; Was it a file?
JRST FFLFIL ; Yes, handle it specially
AOS (P) ; No, quoted string. Set up for success return
CALL FFLDES ; Point to where to put the string
CALLRET CPYATM ; Copy atom buffer there and return
; Here on successful .CMFIL parse of remote filespec
; check it to make sure there's nothing after the file name
; that COMND% mistakenly broke on.
FFLFIL: SKIPE A,B ; Parsed file, copy into appropriate register
RLJFN% ; to flush it
ERNOP
MOVE A,CMDBLK+.CMPTR ; Get pointer to next input
ILDB A,A ; and look at the char there.
CAILE A," " ; Space or control character?
JRST FFLNBL ; No, need to redo parse as unquoted string
MOVE B,FFLPTR ; Yes, file parse Ok, so get old command ptr
CAMN B,CMDBLK+.CMPTR ; Got any text?
JRST FFLUQS ; No, need to parse something more
FFIL3: AOS (P) ; Yes, set up for success return
JRST FFIL4 ; Go copy parsed text and return
; File parse succeeded but then we see these non-blank characters
; immediately following the file name. Fudge the CSB to look like
; we never did the file parse and then do it as an unquoted string.
FFLNBL: CALL FFLBKP ; Back up pointer
; JRST FFLUQS ; Go parse as unquoted string
; Here to attempt to parse an unquoted string. Either the file parse
; failed, or it succeeded but terminated on a non-space char.
; (falls through from previous page)
FFLUQS: CALL SKPSPC ; Skip over spaces at start of buffer
MV. CMDBLK+.CMPTR,FFLPTR ; Save pointer again
TXZ F,F%TEMP ; Not munging versions
CALL FFLFFJ ; Flush file default JFN we made.
MOVEI B,[FLDDB. .CMUQS,CM%SDH,REMBRK,<remote file, optionally quoted>]
CALL .COMND ; TOPS-20 filespec failed, try unquoted string
ERMSG <Unable to parse remote filename>
MOVE B,FFLPTR ; Get old COMND pointer
CAME B,CMDBLK+.CMPTR ; Any text parsed?
JRST FFIL3 ; Yes, go win with it
FFILZ: SKIPN B,FFLDEF ; End of buf, if there's no default
RET ; Then give up in disgust
MKPTR (B) ; Make sure it's a byte pointer.
FFIL4: CALL FFLDES ; Get destination string into A.
DO.
CAMN B,CMDBLK+.CMPTR ; Was that the end of the command text?
TDZA C,C ; Yes, get a zero
ILDB C,B ; Else get the next character.
IDPB C,A ; Drop the char into the destination string.
CAIN C,"." ; If possibly the start of a version
MOVEM A,FFLSTR ; Save pointer for version munging
JUMPN C,TOP. ; Maybe go back for more
ENDDO.
; Brian K Reid memorial crock. This implements SET NO INCLUDE-VERSIONS...
TXNE F,F%TEMP ; If munging versions
DPB C,FFLSTR ; Drop a null in our saved pointer
RET
; Various subroutines for FRNFIL
; Skip over spaces in the COMND% buffer. This is done to make
; comparison against the command block pointer work better.
SKPSP0: SOS CMDBLK+.CMINC ; One less char unparsed
SOSA CMDBLK+.CMCNT ; One less char left in command buffer
SKPSPC: MOVE A,CMDBLK+.CMPTR ; Get command block pointer
MOVEM A,CMDBLK+.CMPTR ; Put it back
SKIPN CMDBLK+.CMINC ; Any unparsed chars?
RET ; No, done
ILDB B,A ; Get next char
INSET B,<.CHSPC,.CHTAB>,JRST SKPSP0
RET ; If non-blank just return
; Here to get string pointer to store remote file name we just parsed into.
; Returns +1/always with A: pointer to string buffer
FFLDES: SKIPN A,FFLSTR ; Is there a string to save into?
IFSKP.
MKPTR (A) ; Yes, make sure it's a real byte pointer
RET ; and return with it.
ENDIF.
CALL SETPRP ; Else init file property list
MOVE A,[POINT 7,FILPRP+P.SFIL] ; and set dest to server-filename.
RET
; Here from FRNFIL to clear out default
FFLFFJ: SKIPN A,FRNJFN ; Did we have a file JFN to clear out?
RET ; No, just return
RLJFN% ; Else clear it
ERNOP
SETZM FRNJFN ; Clear out so we don't do it again
RET
; Here to back up pointer to previous mark
FFLBKP: MOVE B,FFLPTR ; Get old pointer
SETZ A, ; and clear a counter.
DO.
CAMN B,CMDBLK+.CMPTR ; Is it up to new pointer?
EXIT. ; Yes, done with loop
IBP B ; No, increment it
AOJA A,TOP. ; and A, and go back for more.
ENDDO.
ADDM A,CMDBLK+.CMINC ; Use count to set num unparsed chars
ADDM A,CMDBLK+.CMCNT ; and space left in command buffer.
MV. FFLPTR,CMDBLK+.CMPTR ; Put command pointer back
RET ; All done
SUBTTL Subroutines
; Do JFNS call, perhaps lowercasing.
; Call with A,B,C/set up for JFNS%, returns +1 always
.JFNS: STKVAR <JFSPTR> ; Need an extra variable
MKPTR(A) ; Make sure we have a real byte pointer
MOVEM A,JFSPTR ; Save start of destination buffer
JFNS% ; Translate the JFN into a string
ERJMP R ; On error, don't try lowercasing nothing
PUSH P,A ; Save returned pointer
SETZ C, ; Get a null
IDPB C,A ; To make sure string is terminated
POP P,A ; Restore pointer
TXNN F,F%LOWR ; Lowercasing UNIX files?
RET ; No, all done
IFXN. F,F%COPN ; Connection open?
MOVE C,OPSYS ; Yes, get operating system
INSET C,<OS.T20,OS.10X,OS.DEC,OS.ITS>,RET ; Don't downcase for these
ENDIF.
EXCH A,JFSPTR ; Get start ptr and save end
DO.
CAMN A,JFSPTR ; Up to where JFNS% left off?
RET ; Yes, stop
ILDB C,A ; Get next character of new string part
CAIL C,"A" ; Below
CAILE C,"Z" ; or above range?
LOOP. ; Yes, pass it by
TRO C,40 ; It's a letter, lowercase it
DPB C,A ; Drop back in
LOOP.
ENDDO.
; Copy B into A, smashing C
CPYSTR: MKPTR(A) ; Make sure we have real byte pointers
MKPTR(B)
DO.
ILDB C,B ; Get a byte
JUMPE C,R ; If null, done
IDPB C,A ; Else drop it in
LOOP.
ENDDO.
; Initialize PSI system
; Returns +1
; Clobbers A, B
INIPSI: MOVEI A,.FHSLF ; Initialize psi system
MOVE B,[LEVTAB,,CHNTAB]
SIR%
EIR%
MOVX B,ACTCHN ; Activate channels
AIC%
MOVX A,<.TICCG,,ABTCHN> ; ^G interrupt on channel 1
ATI%
RET
; PSI channel definitions
DEFINE PSI(CH,LEV,DISP) <
ACTCHN==ACTCHN!1B<CH>
RELOC CHNTAB+^D<CH>
LEV ,, DISP
>
ACTCHN==0 ; Bit mask of active channels
ABTCHN==:1 ; ^G abort channel
CHNTAB::PSI(ABTCHN,2,ABTINT) ; Channel 1: ^G abort
RELOC CHNTAB+^D36 ; That's all for now
LS CH1PC ; PSI return locations
LS CH2PC
LS CH3PC
LEVTAB::CH1PC ; Level 1 - fatal errors
CH2PC ; Level 2 - ^G command abort interrupt
CH3PC ; Level 3 - normal wakeups, eof, etc.
; Fatal errors
; Routine to call if an impossible error occurs
; Does not return
SCREW:: HRRZ A,0(P) ; Get return pc
SUBI A,1 ; Backup to call
ETYPE <%2S at %1O - %J%/> ; Type message, address, and error
CALL FLSTAK
MOVX A,<CZ%ABT!.FHSLF> ; On ourself, aborting so we don't hang
CLZFF% ; close all our files.
ERNOP ; This is in error handler, so ignore errors.
DO.
HALTF% ; Stop the program
ETYPE <Can't continue> ; Complain if continued
LOOP. ; and go back to stop again
ENDDO.
; Handler for ^G command abort
LS ABTLOC ; Place to hold abort setting
; ABTLOC <= 0 -- no action, set to 0
; ABTLOC > 0 -- clear abort, jump to @ABTLOC
ABTINT: PUSH P,A ; Don't mung this register
HLRZ A,CMDBLK+.CMIOJ ; Get command file JFN.
CAIN A,.PRIIN ; If it's the terminal, don't say anything
IFSKP.
TYPE <%_[Command files aborted]%/> ; Tell user what he just did
CALL FLSTAK ; Clear out any command files we were running
HRRZ A,CH2PC ; Get return location
CAIE A,$COMND+1 ; Are we in COMND?
IFSKP.
MOVEI A,NPARSE ; Yes, get NPARSE instead
MOVEM A,CH2PC ; and save as new PC (may be overridden later)
ENDIF.
TXO F,F%ABTC ; Make sure .COMND knows to abort parse
ENDIF.
SKIPLE A,ABTLOC ; Is there an abort set?
IFSKP.
MOVEI A,.CHBEL
PBOUT% ; Beep
POP P,A ; Restore saved register
ELSE.
MOVEM A,CH2PC ; Return to abort loc from interrupt
TYPE <^G%/> ; Uparrow G, beep
CLRABORT ; Restore the previous abort and stack
ENDIF.
SETZM ABTLOC ; Canonicalize for ABTSKIP
DEBRK% ; Return from interrupt
; Here to try running the next abort after one has been hit.
; If no more aborts, returns +1
NXTABT: SKIPG A,ABTLOC ; Get abort if any
IFSKP.
CLRABORT ; Got one, pop a level beyond it
JRST (A) ; and go to next handler
ENDIF.
SETZM ABTLOC ; None, canonnicalize abort location
RET ; and return normally
; Here to start setting an abort
; call with JSP CX,.SETAB then set appropriate value in ABTLOC
.SETAB::PUSH P,ABTLOC ; Save old abort if any
PUSH P,SAVPDL ; And old saved stack pointer
SETZM ABTLOC ; Avoid timing races
MOVEM P,SAVPDL ; Save stack
JRST (CX) ; Return
; Here to clear current abort
; call with JSP CX,.CLRAB, returns +1 always
.CLRAB::MOVE P,SAVPDL ; Restore saved stack
SETZM ABTLOC ; Avoid timing races
POP P,SAVPDL ; Restore saved saved stack
POP P,ABTLOC ; Restore saved abort
JRST (CX) ; Return
; Parsing support routines.
; .COMND - do a COMND% JSYS.
; Called with B/ Pointer to FLDDB list.
; Returns: +1, error has occurred (CM%NOP)
; +2, successful, ACs are as returned by COMND%.
.COMND::TXZE F,F%ABTC ; Command parse aborted?
JRST NPARSE ; Yes, go retry
MOVEI A,CMDBLK ; With normal command state block
$COMND: COMND% ; Do the parse
IFNJE.
TXNN A,CM%NOP ; Was it parsed?
AOS (P) ; Yes, set up for skip return
RET
ENDIF.
MOVEI A,.FHSLF ; Error, get pointer to self
GETER% ; to find out what it was
HRRZS B ; Don't worry about our fork handle.
CAIE B,COMNX9 ; End of file?
CAIN B,IOX4 ; or this kind of end of file?
IFNSK.
CALL ENDTAK ; Yes, try popping a level
JRST NPARSE ; And go restart parse if we succeeded
ENDIF.
FATAL <Fatal error in command parse>
; VALFLD - make sure field just parsed is non-null
; returns +1/null, +2/not
VALFLD::SAVEAC <A> ; Don't mung register
MOVE A,[POINT 7,ATMBUF] ; Point to atom buffer
ILDB A,A ; Get char there
JUMPN A,RSKP ; If non-null, then we parsed a real field
RET ; Else blank, return +1
; .ERMSJ - called for JSYS errors
.ERMSJ::MOVE P,[IOWD STKLEN,STACK] ; Setup stack
TYPE < - %J%/> ; Type error string
CALL FLSTAK ; Flush any TAKE files.
JRST COMLP ; Go get the next command.
; .ERMSG - Routine to do error message stuff for parse failures.
.ERMSG::MOVE B,[POINT 7,ATMBUF]
ILDB B,B ; Get first char in atom buffer.
JUMPE B,.ERMSX ; Null? Then go on.
HRROI A,ATMBUF
TYPE < - "%1S"%/>
.ERMSX::CALL FLSTAK ; Flush TAKE files
; CALLRET NPARSE
; CMINI functions
NPARSE: SKIPN A,CMDBLK+.CMIOJ ; Get I/O JFNs
JRST REENTR ; None, go back to top-level parse.
CAME A,[.PRIIN,,.NULIO] ; If not reading JCL,
JRST INICMD ; go restart parse.
MOVEI A,.PRIOU ; (assume this was from top level)
HRRM A,CMDBLK+.CMIOJ ; Reset command output JFN.
CALL FQUIT ; Stop, reparse if continued.
CAIA ; Skip into...
SETCMD:: POP P,CMDBLK+.CMFLG ; SETCMD -- do a CMINI (setting reparse)
INICMD: MOVEI B,[FLDDB. .CMINI] ; Assumes caller is careful with SAVPDL.
CALL .COMND ; Re-initialize parse.
JERMSG <Impossible error initializing COMND jsys>
MOVE B,CMDBLK+.CMFLG ; Get reparse address
CALLRET (B) ; And go to it.
; Pretend not reading JCL input so program won't halt at command loop
NOHALT: MOVE A,CMDBLK+.CMIOJ ; Get command input and output JFNs
CAME A,[.PRIIN,,.NULIO] ; Are we reading from JCL?
RET ; No, stop now
MOVEI A,.PRIOU ; Yes, get normal output JFN.
HRRM A,CMDBLK+.CMIOJ ; Don't HALTF back at command loop.
RET
; Here to get rid of any JFNs left over from reparsing
; This should only be called on reparses of parses that can parse files.
; E.g. CHKCON is relied on not to call it.
FLTFIL: SKIPN A,TMPJFN ; Did we have a parse JFN left over?
JRST FLFIL3 ; No, go try for foreign file
FLFIL2: RLJFN% ; Yes, release it
ERNOP ; Ignore errors - message would confuse parse
SETZB A,TMPJFN ; Don't have a parse JFN now
FLFIL3: EXCH A,FRNJFN ; Clear FRNFIL jfn, get what was there
JUMPN A,FLFIL2 ; Got a JFN, release it
RET
; CPYATM - Copy from atom buffer to destination in A, counting chars in D
CPYATM::MKPTR (A) ; Make sure it's a real byte pointer.
MOVE B,[POINT 7,ATMBUF]
SETZ D,
DO.
ILDB C,B
IDPB C,A
JUMPE C,R
AOJA D,TOP.
ENDDO.
;CLRTMP - zero the temporary buffer page
CLRTMP: SETZM TEMP
MOVE A,[XWD TEMP, TEMP+1]
BLT A,TEMP+777
RET
; Subroutine to turn off echoing before password input
NOECHO: PUSH P,A
PUSH P,B
MOVEI A,.CTTRM
RFMOD% ; Read teletype mode word
TXZ B,TT%ECO ; No echoing
JRST ECHOST ; Join common code
; Subroutine to turn on echoing after password input
DOECHO: PUSH P,A
PUSH P,B
MOVEI A,.CTTRM
RFMOD% ; Read teletype mode word
TXO B,TT%ECO ; Turn echoing back on
ECHOST: SFMOD% ; Set TTY mode word
STPAR% ; And the other way
POP P,B
POP P,A
RET
; Parse a password. Call with A/pointer to password, B/where to clear on abort
; Returns +1/aborted, +2/Ok (with password 0,,-1 if user typed return)
LS PSWPTR,2 ; Where to put pointer to password for later
GETPSW::CALL PUSHIO ; Make sure we are talking to the terminal.
SAVEAC <A,B,C,D> ; Save all accumulators
DMOVEM A,PSWPTR ; Save pointer to put password into
MOVEI A,.CTTRM
RFMOD% ; Read TTY mode.
TXNE B,TT%DUM ; Skip if full duplex, otherwise long prompt.
aSKIPAdA,[POINTW7,[ASCIZ/WWWW XXXXXXXXXXXXXXXXXXXX
HRROI A,[ASCIZ/Password: /]
MOVEM A,CMDBLK+.CMRTY ; Set ^R text.
SETABORT (PASABT)
CALL SETCMD ; Start parsing a command
MOVE P,SAVPDL ; Make sure stack is straight
CALL NOECHO ; Turn off echoing
MOVEI B,[FLDDB. .CMCFM,CM%SDH,,,,[
FLDDB. .CMTXT,CM%SDH,,<remote password>]]
CALL .COMND
ERMSGX <Unable to parse password string>
MOVE A,PSWPTR ; Get pointer to password string back
LOAD C,CM%FNC,(C) ; Get FDB parsed
CAIE C,.CMCFM ; Was it bare carriage return?
IFSKP.
SETZM (A) ; Clear it out
HLLOS (A) ; Set right half -1 so we know psw was parsed
ELSE.
CALL CPYATM ; Copy the new password to where it should go
CAILE D,USRSTL ; Was it too long?
ERMSGX <Password too long>
CALL CONFRM ; Finish parse
ENDIF.
CLRABORT ; Turn off our abort now that parse is over
CALL DOECHO ; We want echoing on
AOS (P) ; Set up for skip return
CALLRET PCRIF ; Make sure we have a blank line
PASABT: CALL DOECHO ; Make sure echoing is turned back on
SETZM @1+PSWPTR ; Clear out location we were supposed to
CALLRET NXTABT ; Try dropping another level of aborts
; CONFRM - wait for a user to type RETURN
CONFRM: SAVEAC <A,B,C> ; Don't mung caller's ACs
MOVEI B,[FLDDB. .CMCFM]
CALL .COMND
IFSKP. <RET> ; Return on success
CNFERR: ETYPE <Not confirmed - ">
MOVE B,CMDBLK+.CMPTR
DO.
ILDB A,B ; Get a char
INSET A,<.CHSPC,.CHTAB>,LOOP. ; If space/tab then back for real char
ENDDO.
DO.
JUMPE A,ENDLP. ; If null, done
CAIE A,.CHCRT ; If CR
CAIN A,.CHLFD ; or LF
EXIT. ; Likewise done
PBOUT% ; None of the above, send off the character
ILDB A,B ; Get another
LOOP. ; And go back to process it
ENDDO.
TYPE <"%/> ; Finish error message
JRST .ERMSX ; Finish error processing
; CONFRM, return +1 if not confirmed, +2 confirmed
; always returns +2 if taking commands from a file.
PRMCNF::PROMPT 0(A) ; First prompt with AC1
DOCONF::SAVEAC <A,B,C> ; Don't mung caller ACs
HLRZ A,CMDBLK+.CMIOJ ; Get input JFN.
CAIE A,.PRIIN ; If reading from a TAKE file, return now.
RETSKP
CALL PUSHIO ; Be careful with JCL input.
SETABORT (PCRIF) ; ^G means not confirmed - newline and +1 ret
CALL SETCMD
MOVE P,SAVPDL
MOVEI B,[FLDDB. .CMCFM]
CALL .COMND
IFSKP.
CLRABORT ; Confirmed, undo abort setting
RETSKP ; And finish up
ENDIF.
CLRABORT ; Not confirmed, clear the abort
; CALLRET PCRIF ; and make sure we have a blank line
PCRIF: TYPE <%_> ; Make sure we have a blank line
RET
; Statistics routines.
; Call TIMEIN
; initialize the clock for a later call to TIMEOUT
; smashes registers A B and C.
LS STTCPU
LS STTCON
TIMEIN::TXNN F,F%STAT ; Statistics turned on?
RET ; No, just return.
MOVEI A,.FHSLF ; On ourself
RUNTM% ; read console and CPU time.
MOVEM A,STTCPU ; Save CPU millisecs used
MOVEM C,STTCON ; and console time used.
RET ; All done.
; Call TIMOUT
; A/JFN of disk file
; If statistics turned on, uses info set by TIMEIN to show
; statistics about transfer rate.
; A is not smashed.
LS STTJFN
TIMOUT::TXNN F,F%STAT ; Statistics turned on?
RET ; No, just return.
MOVEM A,STTJFN ; Save the JFN for later
MOVEI A,.FHSLF ; On ourself
RUNTM% ; read console and CPU time.
SUB A,STTCPU ; Take difference between old cpu time and now
SUB C,STTCON ; and old console time and now
MOVEM A,STTCPU ; and save them again.
MOVEM C,STTCON
HRRZ A,STTJFN ; Now get that JFN back again
CALL CHKDSK ; If it is not a disk file, can't get size...
TXNN F,F%DSKF ; is it a disk?
JRST STNDSK ; No, go say how long we took.
MOVE B,[2,,.FBBYV] ; 2 words starting at .FBBYV (includes .FBSIZ)
MOVEI C,B ; into registers B and C.
GTFDB% ; Get pages and number of bytes.
ERJMP STNDSK ; couldn't, go say something else.
LOAD A,FB%BSZ,B ; Get byte size
HRRZS B ; and page count and n bytes in individual ACs.
TYPE <Transferred %3D %1D-bit bytes (%2D pages) in >
IMUL A,C ; Get total number of bytes
PUSH P,A ; and save it on the stack.
CALL SHOTIM ; Say how much time was used.
POP P,A ; Get time back
IDIV A,STTCON ; Divide by console time to get bps.
TYPE <%/for a total transfer rate of %1D kilobaud.%/>
MOVE A,STTJFN ; Get the JFN back for caller.
RET
; Routines for displaying calculated statistics
; Here when file is not a disk file, just say how long it took
STNDSK: TYPE <Completed transfer in >
CALL SHOTIM ; type CPU and console used
TYPE <.%/>
MOVE A,STTJFN ; Get the JFN back.
RET
; Here with disk file, we know how long it is so we can give real stats
SHOTIM: MOVE A,STTCON ; Get connection time
TXZ F,F%TEMP ; Clear flag for later use
IDIVI A,^D100 ; Only keep tenths of seconds
IDIVI A,^D60*^D60*^D10 ; Get hours
IFN. A ; If we have hours
TYPE <%1D:> ; Type them
TXO F,F%TEMP ; and remember we need both digits of minutes
ENDIF.
IDIVI B,^D60*^D10 ; Get minutes
TXNN F,F%TEMP ; If we haven't seen hours
JUMPE B,SHOSEC ; and there are no minutes, just do seconds
PUSH P,C ; Otherwise save seconds
CALL TWODIG ; Show minutes
POP P,C ; Restore seconds
MOVEI A,":" ; and type a colon to separate
PBOUT%
SHOSEC: IDIVI C,^D10 ; Get seconds and tenths
MOVE B,C ; Copy seconds
CALL TWODIG ; Type them out
TYPE <.%4D seconds, > ; Finish with tenths of seconds
MOVE A,STTCPU
IDIVI A,^D1000 ; CPU into secs and msecs
TYPE <%1D.> ; Type the seconds
MOVEI A,.PRIOU ; then to the terminal
MOVX C,NO%LFL!NO%ZRO!FLD(3,NO%COL)!FLD(^D10,NO%RDX)
NOUT% ; Type the msecs as 3 digits
NOP
TYPE < CPU> ; Finish off message
RET
; Here to type out part of a time - hours, minutes etc.
; if F%TEMP is set, we have been called before, so use two columns
TWODIG: MOVEI A,.PRIOU ; To the terminal
MOVEI C,^D10 ; Radix decimal
TXOE F,F%TEMP ; Remember called. If called before,
TXO C,NO%LFL!NO%ZRO!FLD(2,NO%COL) ; make sure we use both columns
NOUT% ; Type out the number in B
NOP
RET
; Get generation number of a file.
; Call with A/JFN
; Returns +1/Not a disk file, +2/Generation in B.
GTVERS: CALL CHKDSK ; Set F%DSKF appropriately
TXNN F,F%DSKF ; Is local file on disk?
RET ; No, can't get version.
MOVE B,[XWD 1,.FBGEN] ; One word, generation (JFN still in A).
MOVEI C,B ; Put it into B again.
GTFDB%
ERJMP R ; If failed, just return +1
HLRZS B ; Put in RH
RETSKP
; Make sure there is an Ethernet connection.
; Returns +1/No connection, +2/Connection open
CHKCON: TXNE F,F%COPN ; Is there a connection open?
RETSKP ; Yes, done now.
CALL PUSHIO ; Make sure talking to the terminal
TYPE <No connection has been opened yet%/>
PROMPT [ASCIZ/OPEN (connection to) /]
SETABORT (R)
DO.
CALL SETCMD ; Set up command parser.
MOVE P,SAVPDL
CALL OPNSUB ; Parse host-name and open connection.
LOOP. ; Failed, try once more.
ENDDO.
CLRABORT
RETSKP ; Done, return.
; Check if we should do automatic ANONYMOUS login
; Returns +1 if the login was attempted
; +2 if no login was attempted
DOANON::SKIPE USRNAM ; Do we already have a user name?
RETSKP ; Yes, forget this
SETZM USRPSW ; Clear password, rhost will set user
SETZM USRACT
CALL RHOST ; Try rhosts
IFSKP. ; If it got something
MOVX A,<POINT 7,USRNAM>
TYPE <[Automatic login to %1S]%/>
CALL @.LOGIN(V) ; Try the login
IFSKP. <RET> ; It worked
ENDIF.
SETZM USRNAM ; Clear any user name that got set
SETZM USRACT ; And any account
TXNN F,F%ANON ; Do we want ANONYMOUS logins by default?
RETSKP ; No, take skip return
HRROI A,USRNAM
HRROI B,[ASCIZ/anonymous/] ; Lowercase for UNIX. Everyone else copes.
WRITE <%2S> ; Set up a username
HRROI A,USRPSW
HRROI B,[ASCIZ/guest/] ; A lowercase password as well.
WRITE <%2S> ; Set up a password
CALL @.LOGIN(V) ; Do protocol dependent stuff
RETSKP ; Some failure
RET ; Possible success, take a single return
;RHOST - Try to set up USRNAM based on the user's RHOSTS file
;Returns +1 if found something
; +2 error
RHOST: STKVAR <RHTJFN> ; Declare local storage
;construct name of user's magic file
HRROI B,LCLUSR ; Point to our user name
HRROI A,TMPHST ; Into temporary space
WRITE (PS:<%2S>RHOSTS) ; Finish off filename.
MOVX A,GJ%SHT!GJ%OLD
HRROI B,TMPHST
GTJFN% ; Get a JFN on the file
RET ; No such file, return now.
MOVEM A,RHTJFN ; Save JFN in case OPENF% bombs
MOVX B,<7B5!OF%RD> ; Open file for ead
OPENF%
IFJER.
MOVE A,RHTJFN
RLJFN%
NOP
RET
ENDIF.
;now scan the file - main loop
BIN% ;prime the pump
ERJMP RHOSTF ;stop at end of file
DO.
MOVE C,[POINT 7, TMPHST] ; First thing in a line is host
SETZM TMPHST
;host name
DO.
CAIE B,40
CAIN B,11
EXIT.
IDPB B,C
BIN%
ERJMP RHOSTF ;stop at end of file
LOOP.
ENDDO.
SETZ D, ;make asciz
IDPB D,C
;skip whitespace
DO.
CAIE B,40
CAIN B,11
IFSKP. <EXIT.>
BIN%
ERJMP RHOSTF ;eof
LOOP.
ENDDO.
;user name
MOVX C,<POINT 7,USRNAM>
DO.
CAIE B,40
CAIN B,11
EXIT.
CAIN B,"/"
EXIT.
CAIE B,12
CAIN B,15
EXIT.
IDPB B,C
BIN%
ERJMP RHOSTF
LOOP.
ENDDO.
SETZ D,
IDPB D,C ;make asciz
;skip whitespace
DO.
CAIE B,40
CAIN B,11
IFSKP. <EXIT.>
BIN%
ERJMP RHOSTF ;eof
LOOP.
ENDDO.
;see if account. Anything except 12, 15, or / must be account
DO.
CAIN B,"/"
EXIT.
CAIE B,15
CAIN B,12
EXIT.
MOVX C,<POINT 7,USRACT>
DO.
CAIE B,40
CAIN B,11
EXIT.
CAIN B,"/"
EXIT.
CAIE B,12
CAIN B,15
EXIT.
IDPB B,C
BIN%
ERJMP RHOSTF
LOOP.
ENDDO.
SETZ D,
IDPB D,C ;make asciz
ENDDO.
; skip to end of line, checking for switch
DO.
;see if switch
CAIE B,"/"
IFSKP.
BIN%
ERJMP RHOSTF
TRZ B,40 ;upper case it
CAIE B,"O" ;if not /O
SETZM TMPHST ;then ignore this entry
ENDIF.
CAIE B,15
CAIN B,12
EXIT.
BIN%
ERJMP RHOSTF ;Eof
LOOP.
ENDDO. ;End of skip
;skip end of lines
DO.
CAIE B,12
CAIN B,15
IFSKP. <EXIT.>
BIN%
IFJER.
MOVEI B,0
EXIT.
ENDIF.
LOOP.
ENDDO.
;now see if we can use this user name
PUSH P,A
PUSH P,B
MOVX A,.GTHSN ;name to number
HRROI B,TMPHST ;it's here
GTDOM% ;get number of host in file
IFJER.
POP P,B
POP P,A
JRST TOP. ;can't, next line
ENDIF.
POP P,B
POP P,A
CAME C,HSTNUM ;is it the host we want?
JRST TOP. ;no, next line...
CLOSF% ;yes, is what we done. Done with file
JFCL
RETSKP ;good return
ENDDO.
;here if something goes wrong
RHOSTF: MOVE A,RHTJFN ;Get back JFN
CLOSF% ;Close file
NOP ;Ignore an error
RET ;Return to caller
; Handle quota exceeded or disk full
; given error number in B
OVRQTA::ETYPE <Quota exceeded - EXPUNGE some files and continue%/>
HALTF% ; Stop the program
RET ; Try again
; Handle unexpected end of connection
DISCON::ETYPE <Connection closed by remote host>
EDISC:: TXNE F,F%COPN ; Connection still open?
CALL @.CLOSE(V) ; Yes, close it
CALL KILFIL ; Abort input or output file
CALL FLSTAK ; Flush take files
JRST COMLP ; Restart command parse
; Here to set watchdog timer to avoid idle timeouts
SETWDT::RET ; Don't need to do anything in user program
; Set up filename and extension defaults from TEMP space for long GTJFN
; Call with B/JFN
GTJDFT: CALL CLRTMP
HRROI A,TEMP
HRROI D,[ASCIZ/*/]
IFXE. B,GJ%NAM ; Wildcard name?
MOVEM A,CMDGTJ+.GJNAM
MOVX C,FLD(.JSAOF,JS%NAM)
CALL .JFNS ; Set up default filename
HRROI A,2(A) ; Set at word boundary with plenty of margin
ELSE.
MOVEM D,CMDGTJ+.GJNAM
ENDIF.
IFXE. B,GJ%EXT ; Wildcard extension?
MOVEM A,CMDGTJ+.GJEXT
MOVX C,FLD(.JSAOF,JS%TYP)
CALLRET .JFNS ; Set up extension.
ENDIF.
MOVEM D,CMDGTJ+.GJEXT
RET
; Handle protocol-dependent yoyo
%UFTPM::TXNE F,F%COPN ; Connection open?
JRST @.UFTPM(V) ; Yes, run yoyo for protocol
FATAL <UFTPM UUO when no connection is open>
; Construct Server-Filename if necessary from other props, plist in A
FIXNAM::SKIPE P.SFIL(A) ; Server-Filename specified?
RET ; Yes, nothing to do
HRROI B,P.SFIL(A) ; No, start string pointer to cell
HRROI C,P.DEVI(A) ; Get Device string ptr
SKIPE P.DEVI(A) ; Device specified?
WRITE B,<%3S:> ; Yes, prefix it
HRROI C,P.DIRE(A) ; Get directory string pointer
SKIPE P.DIRE(A) ; Directory specified?
WRITE B,<<%3S>> ; Yes, expand into string
HRROI C,P.NAMB(A) ; Append Name-Body string
WRITE B,<%3S>
SKIPE C,P.VERS(A) ; Version specified?
WRITE B,<.%3D> ; Yes, append it
RET
; Clear UPDATE or INSTALL if unhandleable
; Call with A/reason why not available
; Returns +1 or jumps out to COMLP
NOUPDA::TXZN F,F%UPDA ;UPDATE or INSTALL?
RET ;No, nothing to do
TYPE <%% UPDATE or INSTALL not available - %1S%/>
PROMPT [ASCIZ/Always assuming source is more recent [Confirm] /]
CALL DOCONF ;Make sure user really wants to do it
JRST COMLP ;Didn't want to, throw to top level
RET ;Wanted to, return normally
SUBTTL Storage assignments
LS LCLHST,20 ; Local host name
LS LCLUSR,20 ; Local user name
LS STRPTR
LS EDTPTR
LS SAVPDL ; Saved stack pointer for subcommand parses
LS STACK,STKLEN ; Local stack
LS IPDL,IPDLEN ; TAKE file JFN stack
LSP TEMP,1 ; One page for general scratch use
LS TMPHST,20 ; Work space for RHOSTS code
LS NETJFN ; Network input and output JFNs
LS FILJFN ; File send/receive JFN
LS TMPJFN ; Temporary JFN for file parsing
; (should not be used by other modules)
LS FRNJFN ; Same for use by FRNFIL
LS PUPPAR ; PUPPAR tabel definition for PUPXFR
LSP NETBUF,1 ; Network I/O buffer
LSP FILBUF,1 ; Local file buffer
LS HSTNUM ; Host number
LS HSTSTR,10 ; Host name
LS HSTOPS ; Host operating system
LS FRECOR ; Pointer to user-login-default free area
LS ULGDEF ; Pointer to last-defined login default
LS USRNAM,USRSTL/5+1 ; User-Name string
LS USRPSW,USRSTL/5+1 ; User-Password string
LS USRACT,USRSTL/5+1 ; User-Account string
LS CONNAM,USRSTL/5+1 ; Connect-Name string
LS CONPSW,USRSTL/5+1 ; Connect-Password string
END