&&&&&&&&&&&& FTP.SUB FTP.SUB READ.ME FTP.IMP FTXSPL.IMP PARAM.IMP FSTORE.IMP FNODES.IMP TRANSP.IMP FTP0.IMP FTP12.IMP FTPREQ.IMP FTPMAC.MAC CONFIG.MAC QUEUE.IMP SETSRC.IMP GALAXY.MAC FTP.CMD FTXSPL.CMD FTP.RNO FTP.RNH 3A55B.RNO FTPOPR.RNO NETWRK.ADD $$$$$$$$$$$$ &&&&&&&&&&&& READ.ME This save set contains: FTP.EXE - queueing utility FTXSPL.EXE - spooling utility NETWRK.ADD - a sample network configuration file FTP.MEM - definition of what is implemented FTP.HLP - help file 3A55B.MEM - user manual FTPOPR.MEM - operator manual FTP.COM - source files in compressed form CMPRES.EXE - file compressor program FTP comprises a queueing program called FTP and a spooler called FTXSPL both are independent of GALAXY except where line-printer spooling is queued. Both FTP and FTXSPL should be mounted on the system area and be given as JACCT privileges. FTP should be implemented as a command in the Monitor, so that FTP is run at it's CCL entry point and can be run without being logged in, in order to examine the queues. NETWRK.ADD should also be mounted on SYS:. The area used for queueing requests is STD:[3,3]. It will be necessary to build a local version of SYS:NETWRK.ADD before running the system but the example file given should be a guide. The form of the file is sets of three lines as follows: M/C TITLE TRANSPORT SERVICE ADDRESS M/C TYPE The m/c types determine what the FTP program prompts the user for and what mode of transfer is used. The currently supported m/c types are:- DEC10 ;a DEC10 running either an FTP77 or FTP80 implementation GEC ;an ICF GEC MUM PRIME ;an ICF PRIME MUM IBM ;the Rutherford IBMs DLGP ;the Daresbury Laboratory protocol converter ARPA ;the UCL ARPA gateway EMAS ;the Edinburgh Multi-Access System The .EXE files should run as they are but to get the sources from their compressed form do: RU CMPRES *FTP.COM They are built by: .LOAD @FTP .SSAVE .LOAD @FTXSPL .SSAVE If you have any problems please phone me on 031-667-1081 ext 2661. Keith Farvis. $$$$$$$$$$$$ &&&&&&&&&&&& FTP.IMP !FTP.IMP ! COPYRIGHT K.FARVIS ERCC. %BEGIN %EXTERNALINTEGERSPEC CCL %EXTERNALROUTINESPEC MACINIT %EXTERNALINTEGER CNTRLC,FTPTST %EXTERNALINTEGERFNSPEC GETTIME %EXTERNALINTEGERFNSPEC JOBNUM %EXTERNALINTEGERFNSPEC PPN %EXTERNALROUTINESPEC ECHO %EXTERNALROUTINESPEC NOECHO %EXTERNALPREDICATESPEC CALLI2(%INTEGER N,%INTEGERNAME AC) %EXTERNALROUTINESPEC PROMPT(%STRING(255) STR) %EXTERNALROUTINESPEC READPPN(%INTEGERNAME N) %EXTERNALROUTINESPEC WRITEFS(%RECORD(FILESPEC)%NAME FS) %EXTERNALROUTINESPEC WRITEPPN(%INTEGER N) %EXTERNALPREDICATESPEC XISFILE(%RECORD(FILESPEC)%NAME FS) %EXTERNALROUTINESPEC DELETE(%STRING(255) FILE) %EXTERNALROUTINESPEC XDELETE(%RECORD(FILESPEC)%NAME FS) %EXTERNALRECORD(FILESPEC)%FNSPEC STRTOFS(%STRING(255) STR) %EXTERNALSTRING(255)%FNSPEC FSTOSTR(%RECORD(FILESPEC)%NAME FS) %EXTERNALINTEGERFNSPEC STRTOSIX(%STRING(6) STR) %EXTERNALSTRING(6)%FNSPEC SIXTOSTR(%INTEGER N) %EXTERNALSTRING(12)%FNSPEC OCTTOSTR(%INTEGER N) %EXTERNALROUTINESPEC READLINE(%STRING(1)%NAME STR) %EXTERNALINTEGERFNSPEC MATCH(%STRING(1)%NAME S,%STRING(255) T) %EXTERNALPREDICATESPEC SWITCH ARG(%STRING(1)%NAME SWITCHES,%STRING(11) SWITCH, %NAME X) %EXTERNALROUTINESPEC INIT NODES %EXTERNALROUTINESPEC LIST FTP NODES %EXTERNALPREDICATESPEC ADDRESS(%STRING(1)%NAME TITLE,GPASS,TS ADDRESS,%INTEGERNAME NODE) %EXTERNALPREDICATESPEC ISNODE(%STRING(1)%NAME NODE,TYPE %INTEGERNAME STATUS) %EXTERNALSTRING(12)%SPEC OUR SRC NODE %EXTERNALSTRING(12)%FNSPEC OURNODE %EXTERNALINTEGER LOGIT; !DUMMY NAME TO SATISFY THE LOADER %EXTERNALSTRING(255)%SPEC ERRMSG %STRING(255) LINE %STRING(96) SOURCE,DEST,SFILE,DFILE %RECORD(FILESPEC) QUEFILE,DFS,SFS %STRING(96) SSWITCHES,DSWITCHES %STRING(20) DNODE,DTYPE,DFILEPASS,DUSER,DUSERPASS,DACC,DACCPASS,DMODE,DCODE,DDEV %STRING(20) SNODE,STYPE,SFILEPASS,SUSER,SUSERPASS,SACC,SACCPASS,SMODE,SCODE,SDEV %STRING(20) THIS NODE,OTHER NODE,FILE !G %STRING(150) GATESW %STRING(255) TS ADDRESS %INTEGER N,S,OURPPN %CONSTINTEGER LF=8_12 %CONSTINTEGER TRUE=-1, FALSE=0 %CONSTINTEGER TTY=0, TEMP=8, QFILE=13, QDIR=14 %CONSTINTEGER DEBUG=FALSE %OWNINTEGER OPRPRV; !TRUE ALLOWS OPR [1,2] TO HAVE PRIVILIGES - DO NOT CHECK PASSWORDS !IF DEBUG IS SET THEN THE QUEPPN AND DEVICE ARE SET !TO ONES OWN AREA, OR ELSE IT IS DSKC:[3,3] %EXTERNALSTRING(6)%SPEC QDEV %OWNINTEGER QUFD=8_3 000003 %CONSTINTEGER MFD=8_1 000001 %CONSTINTEGER OPRPPN=8_1 000002, HLP PPN=8_2 000005 %CONSTINTEGER FTP=8_466460, FTD=8_466444; !FILE EXTENSIONS %CONSTSTRING(7)%ARRAY DEST MODE(1:7) = "CREATE", "WRITE", "CWRITE", "APPEND", "CAPPEND", "SUBMIT", "PRINT" %CONSTSTRING(6)%ARRAY SOURCE MODE(1:3)= "NEVER","DURING","AFTER" %CONSTSTRING(5) PRIME="PRIME", IBM="IBM", GEC="GEC", DEC10="DEC10", ARPA="ARPA", %c DLGP="DLGP", EMAS="EMAS", VAX="VAX" %conststring(8) PASSWORD="PASSWORD", ACCESS="USERS",OUTPUT SW="ACCESS", INPUT SW="DELETE" !G %CONSTSTRING(13) GATE PASS="GATEPASSWORDS" %PREDICATE ALPHA(%INTEGER S) !============================= ! Returns %TRUE if S is alphabetic %TRUE %IF 'a'<=S<='z' %OR 'A'<=S<='Z' %FALSE %END %STRING(255)%FN UPPER CASE OF(%STRING(1)%NAME STR) !=================================================== !Converts a string to upper case %STRING(255) STR1 %INTEGER N,L,S L=LENGTH(STR) STR1="" %IF L#0 %START %FOR N=1,1,L %CYCLE S=CHARNO(STR,N); S=S-32 %IF 'a'<=S<='z' STR1=STR1.TOSTRING(S) %REPEAT %FINISH %RESULT=STR1 %END %ROUTINE PARSE DEVICE(%STRING(1)%NAME DEVICE,DEV %INTEGERNAME NODE,NUM) !======================================================================= !takes a device of type DEVnnm: and parses it into three separate fields %INTEGER N,L,S DEV=""; NODE=0; NUM=0; !DEFAULTS L=LENGTH(DEVICE) %RETURN %IF L=0 %FOR N=1,1,L %CYCLE S=CHARNO(DEVICE,N) ->NODE FOUND %UNLESS 'A'<=S<='Z' DEV=DEV.TOSTRING(S) %REPEAT %RETURN NODE FOUND: %IF L-N>0 %START N=N+1 NODE=(S-'0')*8+CHARNO(DEVICE,N)-'0' %RETURN %IF N=L S=CHARNO(DEVICE,N+1) %FINISH NUM=S-'0' %END %INTEGERFN DEVTYPE(%STRING(6) DEV) !================================= !Returns the result of the DEVTYP UUO or -1 if unknown %CONSTINTEGER DEVTYP=8_53, DEV AVAL=8_40 000000 %INTEGER N N=STRTOSIX(DEV) %RESULT=-1 %UNLESS CALLI2(DEVTYP,N) %AND N&DEV AVAL#0 %RESULT=N&8_77 %END %ROUTINE NO TRAIL STR(%STRING(6)%NAME STR) %INTEGER N %FOR N=6,-1,1 %CYCLE %EXIT %IF CHARNO(STR,N)#SP %REPEAT STR=SUBSTRING(STR,1,N) %END %STRING(15)%FN PPNTOSTR(%INTEGER PN) !=========================================== !converts a ppn to a string %RESULT="[".OCTTOSTR(PN>>18).",".OCTTOSTR(PN&8_777777)."]" %END %PREDICATE READ SWITCH INI(%STRING(1)%NAME DMODE,SMODE) !====================================================== !READS THE SWITCH.INI FILE TO PICK UP DEFAULT /ACCESS AND /DELETE VALUES %RECORD(FILESPEC) FS %STRING(20) STR,SWITCH %INTEGER DMODE OK,SMODE OK,IN,CHAR,N %ON %EVENT 9,10 %START CLOSE INPUT; SELECT INPUT(IN) %TRUE %FINISH %ROUTINE READ CHAR READSYMBOL(CHAR) %UNTIL SP#CHAR#TAB; CHAR=CHAR-32 %IF 'a'<=CHAR<='z' %END %PREDICATE ALPHANUM READ CHAR %TRUE %IF 'A'<=CHAR<='Z' %OR '0'<=CHAR<='9' %FALSE %END FS=0; FS_PPN=PPN FS_FILE="SWITCH"; FS_EXT="INI" IN=INSTREAM SELECT INPUT(TEMP) XDEFINE INPUT(TEMP,FS) SELECT INPUT(TEMP) %CYCLE STR="" %WHILE ALPHANUM %CYCLE STR=STR.TOSTRING(CHAR) %REPEAT %IF STR="FTP" %START %CYCLE READ CHAR %WHILE '/'#CHAR#NL %EXIT %IF CHAR=NL SWITCH="" %WHILE ALPHANUM %CYCLE SWITCH=SWITCH.TOSTRING(CHAR) %REPEAT %EXIT %IF CHAR=NL %IF MATCH(OUTPUT SW,SWITCH)=1 %START STR="" %FOR N=1,1,12 %CYCLE %EXIT %IF %NOT ALPHANUM STR=STR.TOSTRING(CHAR) %REPEAT DMODE=STR %IF DMODE="" DMODE OK=TRUE %CONTINUE %FINISH %IF MATCH(INPUT SW,SWITCH)=1 %START STR="" %FOR N=1,1,12 %CYCLE %EXIT %IF %NOT ALPHANUM STR=STR.TOSTRING(CHAR) %REPEAT SMODE=STR %IF SMODE="" SMODE OK=TRUE %CONTINUE %FINISH %IF MATCH(PASSWORD,SWITCH)#1#MATCH(ACCESS,SWITCH) %START ERRMSG="SWITCH.INI unrecognised FTP switch - ".SWITCH %FALSE %FINISH %REPEAT %IF DMODE OK %AND SMODE OK %START CLOSE INPUT; SELECT INPUT(IN) %TRUE %FINISH %ELSE %IF CHAR#NL %START SKIPSYMBOL %WHILE NEXTSYMBOL#NL; !SKIP TO END OF LINE %FINISH %FINISH SKIPSYMBOL %WHILE NEXTSYMBOL<=SP; !AND UNTIL BEGINNING OF NEXT SPEC %REPEAT %END %PREDICATE FILEANAL(%STRING(1)%NAME TEXT,FILE,NODE,TYPE,SWITCHES,MODE,DEST DEV,FPASS,USER,UPASS,ACC,APASS,CODE, %RECORD(FILESPEC)%NAME FS,%INTEGER DEST) !========================================================================================================================= !Takes the full filespec given and parses it into node,password etc., other !switches and file spec. %STRING(80) STR %STRING(6) DEV %INTEGER STATUS,NNODE,NUM,UPASSGOT %ROUTINE GET RESPONSE(%STRING(1)%NAME OPT,%STRING(30) OPTSTR) !------------------------------------------------------------ !if the value of OPT is null then the string OPTSTR is used for prompting the user %IF OPT="" %START PRINTSTRING(OPTSTR); PRINTSTRING(" for ") PRINTSTRING(TEXT); PRINTSTRING(" : "); READLINE(OPT) %FINISH %END %ROUTINE FILL PATH(%RECORD(FILESPEC)%NAME FS) !GET THE DEFAULT PATH %CONSTINTEGER MAX SFDS=5 %RECORDFORMAT PATHBLOCK(%INTEGER FUNCT,SWITCHES,PPN, %INTEGERARRAY SFDS(1:MAXSFDS)) %RECORD(PATHBLOCK)PATH %INTEGER N PATH=0 PATH_FUNCT=-1 AC(1)=(3+MAX SFDS)<<18!ADDR(PATH) *8_047040000110; !PATH AC1,0 *8_255000000000; !JFCL %IF PATH_PPN=0 %THEN FS_PPN=OURPPN %AND %RETURN FS_PPN=PATH_PPN %FOR N=1,1,MAX SFDS %CYCLE %RETURN %IF PATH_SFDS(N)=0 FS_SFDS(N)=SIXTOSTR(PATH_SFDS(N)) NO TRAIL STR(FS_SFDS(N)) %REPEAT %END %IF SWITCH ARG(SWITCHES,"PASSWORD",UPASS) %THEN UPASSGOT=TRUE %ELSE UPASSGOT=FALSE FS=0; FPASS=""; USER=""; ACC=""; APASS=""; DEST DEV="" %UNLESS TEXT->NODE.("_").FILE %START NODE=THIS NODE; FILE=TEXT; TEXT=NODE."_".FILE %FINISH NODE=UPPER CASE OF(NODE) %IF NODE=THIS NODE %START TYPE=DEC10 %ELSE %UNLESS ISNODE(NODE,TYPE,STATUS) %START %IF LENGTH(NODE)=5 %THEN STR=SUBSTRING(NODE,1,4) %ELSE STR=""; !IF AN SRCNET NODE SPEC TRY STRIPPING OFF THE 'F' %IF STR#"" %AND ISNODE(STR,TYPE,STATUS) %START NODE=STR %ELSE ERRMSG="Not a recognised node:- ".NODE %FALSE %FINISH %FINISH %FINISH %IF NODE=THIS NODE %THEN TYPE=DEC10 %IF TYPE=DEC10 %START 1: FS=STRTOFS(FILE) STR=FSTOSTR(FS) %IF FS_PPN=0 %AND LENGTH(FS_DEV)#3 %START %IF NODE=THIS NODE %THEN FILL PATH(FS) %ELSE FS_PPN=OURPPN %FINISH USER=PPNTOSTR(FS_PPN) ACC=USER PARSE DEVICE(FS_DEV,DEV,NNODE,NUM) %IF DEV#"LPT" %AND DEV#"PLT" %START !* %IF FS_FILE="" %THEN GET RESPONSE(FILE,"Filename") %AND ->1 %UNLESS (FS_PPN=OURPPN %AND NODE=THIS NODE) %OR (OPRPRV=TRUE %AND OURPPN=OPRPPN) %START %UNLESS UPASSGOT=TRUE %START; !DO NOT CHECK FOR NULL PASSWORD NOECHO; GET RESPONSE(UPASS,"User password"); PRINTSYMBOL(LF); ECHO %FINISH %FINISH %FINISH ! CODE="BINARY" CODE="36BIT" %ELSE %IF TYPE=IBM %START %IF MODE#"SUBMIT" %START GET RESPONSE(FILE,"Dataset name") %WHILE FILE="" %FINISH GET RESPONSE(USER,"IBM ID. (2 chars)") %WHILE USER="" NOECHO GET RESPONSE(ACC,"IBM account (4 chars)") %WHILE ACC="" PRINTSYMBOL(LF); ECHO CODE="TEXT" %ELSE %IF TYPE=GEC%START %IF DEST=FALSE %AND MODE#"NEVER" %THEN ERRMSG="/DELETE:NEVER is only value accepted for GECs" %AND %FALSE GET RESPONSE(FILE,"GEC filename or for device") %IF FILE="" %START GET RESPONSE(DEST DEV,"GEC device name") %WHILE DEST DEV="" GET RESPONSE(FILE,"GEC filename for output") %FINISH GET RESPONSE(USER,"GEC login name") %WHILE USER="" NOECHO; GET RESPONSE(UPASS,"GEC login password"); PRINTSYMBOL(LF); ECHO GET RESPONSE(ACC,"GEC account name") %IF ACC="" %THEN ACC=USER CODE="TEXT" %ELSE %IF TYPE=PRIME %START GET RESPONSE(FILE,"PRIME filename") %WHILE FILE="" GET RESPONSE(USER,"PRIME login name") %WHILE USER="" NOECHO; GET RESPONSE(UPASS,"PRIME login password"); PRINTSYMBOL(LF); ECHO CODE="TEXT" %ELSEIF TYPE=VAX %START GET RESPONSE(FILE,"VAX filename") %WHILE FILE="" GET RESPONSE(USER,"VAX user name") %WHILE USER="" NOECHO; GET RESPONSE(UPASS,"VAX user password"); PRINTSYMBOL(LF); ECHO CODE="TEXT" %ELSEIF TYPE=ARPA %START GET RESPONSE(FILE,"Filename") %WHILE FILE="" GET RESPONSE(USER,"User name") %WHILE USER="" NOECHO; GET RESPONSE(UPASS,"User password"); PRINTSYMBOL(LF); ECHO CODE="TEXT" %ELSEIF TYPE=EMAS %START GET RESPONSE(FILE,"EMAS filename") %WHILE FILE="" GET RESPONSE(USER,"EMAS user name") %WHILE USER="" NOECHO; GET RESPONSE(UPASS,"EMAS background password"); PRINTSYMBOL(LF); ECHO CODE="TEXT" %ELSE%IF TYPE=DLGP %START; !PROTOCOL CONVERTER AT DARESBURY DEST DEV=OUR SRC NODE MODE="PRINT" CODE="TEXT" %ELSE ERRMSG="Not a recognised node type ".TYPE %FALSE %FINISH %TRUE %END %PREDICATE QUEUE IT !=================== !Queues a file for FTP %STRING(255) STR %STRING(6) DEVICE %INTEGER NODE,NUM,DTYP %PREDICATE OPEN QUEUE FILE %INTEGER N,KEY,TIMES %ON %EVENT 10 %START SELECT OUTPUT(QFILE); CLOSE OUTPUT %IF %NOT (SUBEVENT=5 %AND EVENTINFO=4) %THEN %SIGNAL 10,SUBEVENT,EVENTINFO %FALSE %IF TIMES>10; !WELL WE TRIED ->1 %FINISH QUEFILE=0 QUEFILE_DEV=QDEV; QUEFILE_SWITCHES="/FUN:2"; !REPLACE ONLY QUEFILE_EXT="FTP"; QUEFILE_PPN=QUFD QUEFILE_PROT=8_177 TIMES=0 1: TIMES=TIMES+1 KEY=GETTIME//100+JOBNUM; !A UNIQUE NAME %FOR N=1,1,6 %CYCLE QUEFILE_FILE=QUEFILE_FILE.TOSTRING(REM(KEY,10)+'0') KEY=KEY//10 %REPEAT XDEFINE OUTPUT(QFILE,QUEFILE) SELECT OUTPUT(QFILE) %TRUE %END %ROUTINE COMMA !OUTPUT A COMMA PRINTSYMBOL(',') %END STR=LINE %UNLESS STR->DEST.("=").SOURCE %START ERRMSG="Line syntax" ->ERROR %FINISH %UNLESS DEST->DEST.("/").DSWITCHES %START; %FINISH %UNLESS SOURCE->SOURCE.("/").SSWITCHES %START; %FINISH DSWITCHES=UPPER CASE OF(DSWITCHES) SSWITCHES=UPPER CASE OF(SSWITCHES) %UNLESS SWITCH ARG(DSWITCHES,OUTPUT SW,DMODE) %THEN DMODE="" %UNLESS SWITCH ARG(SSWITCHES,INPUT SW,SMODE) %THEN SMODE="" !NOW ADD DEFAULTS FROM SWITCH.INI IF NECESSARY %IF SMODE="" %OR DMODE="" %START ->ERROR %UNLESS READ SWITCH INI(DMODE,SMODE) %FINISH !AND CHECK VALID SWITCH VALUES %IF DMODE#"" %START %FOR N=1,1,7 %CYCLE ->DMOK %IF MATCH(DESTMODE(N),DMODE)=1 %REPEAT ERRMSG="Unknown /ACCESS value - ".DMODE ->ERROR DMOK: DMODE=DEST MODE(N) %ELSE DMODE=DESTMODE(1); !DEFAULT VALUE %IF SMODE#"" %START %FOR N=1,1,3 %CYCLE ->SMOK %IF MATCH(SOURCE MODE(N),SMODE)=1 %REPEAT ERRMSG="Unknown /DELETE value - ".SMODE ->ERROR SMOK: SMODE=SOURCE MODE(N) %ELSE SMODE=SOURCE MODE(1); !USE DEFAULT VALUE -> ERROR %UNLESS FILEANAL(DEST,DFILE,DNODE,DTYPE,DSWITCHES,DMODE,DDEV,DFILEPASS,DUSER,DUSERPASS,DACC,DACCPASS,DCODE,DFS,TRUE) !G %IF SWITCH ARG(DSWITCHES,GATE PASS,GATESW) %START; !GOT A STRING OF GATEWAY SWITCHES !G -> ERROR %UNLESS ADDRESS(DNODE,GATESW,TSADDRESS,N) !G %ELSE GATESW="" %UNLESS DSWITCHES="" %START ERRMSG="Unknown destination switch ".DSWITCHES; ->ERROR %FINISH ->ERROR %UNLESS FILEANAL(SOURCE,SFILE,SNODE,STYPE,SSWITCHES,SMODE,SDEV,SFILEPASS,SUSER,SUSERPASS,SACC,SACCPASS,SCODE,SFS,FALSE) %IF SFILE="" %START ERRMSG="No source file name specified"; ->ERROR %FINISH %UNLESS SSWITCHES="" %START ERRMSG="Unknown source switch ".SSWITCHES; ->ERROR %FINISH !NOW DO SOME MORE CHECKS %IF DNODE=THIS NODE %START %IF %NOT DEBUG %AND SNODE=THIS NODE %START ERRMSG="Cannot transfer files within the same node"; ->ERROR %FINISH DTYP=DEVTYPE(DFS_DEV) %IF DFS_DEV#"" %AND 7#DTYP#0 %AND DTYP#8_13 %START ERRMSG="Unknown or illegal destination device ".DFS_DEV; ->ERROR %FINISH OTHER NODE=SNODE %ELSE %IF SNODE=THIS NODE %START OTHER NODE=DNODE %UNLESS XISFILE(SFS) %START ERRMSG=FSTOSTR(SFS)." - File not found"; ->ERROR %FINISH %ELSE ERRMSG="This node must be specified for either source or destination file"; ->ERROR %FINISH %FINISH %IF DTYPE=DEC10 %AND DFS_FILE="" %START DFS_FILE=SFS_FILE %IF DFS_FILE="" %START; !NOT A DEC-10 AS THE SOURCE ERRMSG="A destination file specification must be given" ->ERROR %FINISH %IF DFS_EXT="" %THEN DFS_EXT=SFS_EXT %FINISH ->ERROR %UNLESS OPEN QUEUE FILE PARSE DEVICE(DFS_DEV,DEVICE,NODE,NUM) %IF DEVICE="LPT" %START DMODE=DEST MODE(7); !PRINT %FINISH !FOR A FULL DESCRIPTION OF THE FILE LOOK AT MODULE FTPREQ.IMP PRINTSTRING(OTHER NODE); NEWLINE PRINTSTRING(DNODE); PRINTSYMBOL('_') %IF DTYPE=DEC10 %THEN WRITEFS(DFS) %ELSE PRINTSTRING(DFILE); PRINTSYMBOL('=') PRINTSTRING(SNODE); PRINTSYMBOL('_') %IF STYPE=DEC10 %THEN WRITEFS(SFS) %ELSE PRINTSTRING(SFILE); NEWLINE WRITEPPN(OURPPN); NEWLINE PRINTSTRING(DFILEPASS); COMMA; PRINTSTRING(DUSER); COMMA PRINTSTRING(DUSERPASS); COMMA; PRINTSTRING(DACC); COMMA PRINTSTRING(DACCPASS); NEWLINE PRINTSTRING(SFILEPASS); COMMA; PRINTSTRING(SUSER); COMMA PRINTSTRING(SUSERPASS); COMMA; PRINTSTRING(SACC); COMMA PRINTSTRING(SACCPASS); NEWLINE PRINTSTRING(DMODE); COMMA; PRINTSTRING(SMODE); COMMA %IF DNODE=THIS NODE %THEN PRINTSTRING(SCODE) %ELSE PRINTSTRING(DCODE) NEWLINE PRINTSTRING(DDEV);COMMA; COMMA; COMMA; NEWLINE !G PRINTSTRING(GATESW); NEWLINE CLOSE OUTPUT; SELECT OUTPUT(TTY) %TRUE ERROR: SELECT OUTPUT(TTY) PRINTSYMBOL('?') PRINTSTRING(ERRMSG); NEWLINE %FALSE %END %ROUTINE HELP !============ !types out the help information %INTEGER S %ON %EVENT 9,10 %START %IF EVENT=10 %START PRINTSTRING("?No info on FTP"); NEWLINE %ELSE CLOSE INPUT; SELECT INPUT(TTY) %FINISH %RETURN %FINISH DEFINE INPUT(TEMP,"HLP:FTP.HLP") SELECT INPUT(TEMP) %CYCLE READSYMBOL(S); PRINTSYMBOL(S) %REPEAT %END %ROUTINE LIST !============ !lists the queues %RECORD(FILESPEC) FS,QDIRFS %STRING(255) TEXT %STRING(50) USER,DEST %INTEGER FILE,EXT,TRANS %ON %EVENT 9,10 %START %IF EVENT=10 %START %IF INSTREAM=QDIR %START PRINTSTRING("Problem looking up Queue area on disk") %ELSE ->1 %ELSE %IF TRANS=-1 %START; !IF ANY FILES HAVE BEEN FOUND PRINTSTRING("Where * indicates the job being transferred"); NEWLINE %FINISH %FINISH NEWLINE CLOSE INPUT SELECT INPUT(QDIR); CLOSE INPUT SELECT INPUT(TTY); %RETURN %FINISH %ROUTINE PRINT HEADER PRINTSTRING(" Seq# User Destination Source"); NEWLINE %END NEWLINE TRANS=0 QDIRFS=0; QDIRFS_DEV=QDEV QDIRFS_FILE=SIXTOSTR(QUFD) QDIRFS_EXT="UFD" QDIRFS_PPN=MFD QDIRFS_SWITCHES="/MODE:#10" SELECT INPUT(QDIR) XDEFINE INPUT(QDIR,QDIRFS) %CYCLE SELECT INPUT(QDIR) FS=0 %CYCLE READSYMBOL(FILE); READSYMBOL(EXT); EXT=EXT>>18 %IF EXT=FTD %START FS_EXT="FTD" PRINT HEADER %IF TRANS=0 TRANS=-1; !FLAG THAT ONE IS FOUND PRINTSTRING("* ") %EXIT; !SUCCESS %FINISH %IF EXT=FTP %START FS_EXT="FTP" %IF TRANS=0 %START PRINT HEADER TRANS=1 %FINISH SPACES(2) %EXIT %FINISH %REPEAT FS_DEV=QDEV FS_FILE=SIXTOSTR(FILE) FS_PPN=QUFD SELECT INPUT(QFILE) XDEFINE INPUT(QFILE,FS) READLINE(DEST) READLINE(TEXT) READLINE(USER) PRINTSTRING(FS_FILE); SPACE; PRINTSTRING(USER); PRINTSYMBOL(TAB) PRINTSTRING(TEXT); NEWLINE 1: CLOSE INPUT %REPEAT %END %ROUTINE KILL(%STRING(1)%NAME FILENAME) !======================================= !kills a queue entry %RECORD(FILESPEC) FS %STRING(255) STR,FIL %INTEGER USER FS=0; FS_DEV=QDEV FS_FILE=FILENAME; FS_EXT="FTP"; FS_PPN=QUFD 1: %IF XISFILE(FS) %START XDEFINE INPUT(QFILE,FS) SELECT INPUT(QFILE) READ LINE(LINE); !DESTINATION READLINE(STR); !CONTAINS FILESPECS READPPN(USER); READLINE(LINE); !SKIP REST OF LINE READLINE(LINE) READLINE(LINE); !HAS EITHER "MAIL" OR "POST" IF A MAIL FILE CLOSE INPUT SELECT INPUT(TTY) %UNLESS USER=OURPPN %OR PPN=OPR PPN %START PRINTSTRING("?Not the owner of the request"); NEWLINE %RETURN %FINISH XDELETE(FS) PRINTSTRING("Killed") !NOW CHECK IF MAIL FILE AND KILL FILE TO BE SENT %IF LINE->FIL.(",MAIL,").FIL %OR LINE->FIL.(",POST,").FIL %START; !A MAIL FILE %IF STR->FIL.("=").STR %AND STR->STR.("_").FIL %START DELETE(FIL) PRINTSTRING(" and post file deleted") %FINISH %FINISH NEWLINE %RETURN %FINISH %IF FS_EXT="FTP" %START; !TRY ONE WHICH HAS ALREADY STARTED FS_EXT="FTD"; ->1 %FINISH PRINTSTRING("?No such request sequence number"); NEWLINE %END !=================================================================== !MAIN PROGRAM MACINIT CNTRLC=FALSE OURPPN=PPN %IF DEBUG %START QUFD=OURPPN; !IF DEBUGGING, USE OWN AREA FOR QUEUE %ELSE N=-JOBNUM %IF OURPPN#OPRPPN %AND CALLI2(8_61,N) %START; !GET JOB STATUS AND SEE IF JACCT BIT SET %IF N&8_010000 000000=0 %THEN PRINTSTRING(" ?No privileges to modify the queue - must be RUN from SYS: ") %FINISH %FINISH THIS NODE=OUR NODE INIT NODES OPRPRV=FALSE %CYCLE !GET A COMMAND LINE %IF CCL %START AC(1)=0 *8_051400 000001; !GET COMMAND LINE (RESCAN) *8_255000 000000; !JFCL %WHILE %NOT SP#NEXTSYMBOL#TAB %THEN SKIPSYMBOL %CYCLE; !SKIP COMMAND AND SPACES S=NEXTSYMBOL; %EXIT %UNLESS ALPHA(S) SKIPSYMBOL %REPEAT %WHILE %NOT SP#NEXTSYMBOL#TAB %THEN SKIPSYMBOL READLINE(LINE); %IF LINE="" %THEN LINE="/LIST"; !DEFAULT %ELSE %CYCLE PROMPT("*") %WHILE NL#NEXTSYMBOL<=SP %THEN SKIPSYMBOL READLINE(LINE) %EXIT %IF LINE#"" %REPEAT %FINISH !PROCESS THE COMMAND LINE %IF CHARNO(LINE,1)='/' %START; !A SWITCH %IF SWITCH ARG(LINE,"EXIT",N) %THEN %EXIT %IF SWITCH ARG(LINE,"HELP",N) %THEN HELP %AND ->END %IF SWITCH ARG(LINE,"LIST",N) %THEN LIST %AND ->END %IF SWITCH ARG(LINE,"NODES",N) %THEN LIST FTP NODES %AND ->END %IF SWITCH ARG(LINE,"KILL",FILE) %START %IF OURPPN=HLP PPN %THEN PRINTSTRING("? LOGIN to modify the queue") %ELSE KILL(FILE) ->END %FINISH PRINTSTRING("? Unknown switch to FTP") %ELSE %IF OUR PPN=HLP PPN %THEN PRINTSTRING("? LOGIN to enter a file in the queue") %AND ->END %EXIT %UNLESS QUEUE IT; ! A TRANSFER COMMAND %FINISH END: %EXIT %IF CCL %REPEAT %IF OURPPN=HLP PPN %THEN PRINTSTRING(" .KJOB .") *8_047000 000012; !EXIT 0, %ENDOFPROGRAM $$$$$$$$$$$$ &&&&&&&&&&&& FTXSPL.IMP !FTXSPL.IMP ! COPYRIGHT K.FARVIS ERCC. !This is the main module of the spooler it contains the main program !loop comprising the console command processor, the processing of P and !Q type requests and 'read file' and 'send file' routines !it handles the protocol at levels 0, 1 and 2 using routines in separate modules. %BEGIN !THE FOLLOWING ROUTINES ARE CONCERNED WITH THE TRANSPORT MECHANISM %EXTERNALSTRING(12)%SPEC TASK NAME %EXTERNALROUTINESPEC INIT TRANSPORT %EXTERNALPREDICATESPEC P OPEN TRANSPORT(%STRING(1)%NAME OTHER NODE) %EXTERNALPREDICATESPEC Q OPEN TRANSPORT %EXTERNALROUTINESPEC CLOSE TRANSPORT %EXTERNALROUTINESPEC RESET TRANSPORT %EXTERNALPREDICATESPEC FTP STATE(%INTEGERNAME VALUE, %STRING(1)%NAME MESS) !QUEUE SEARCHING ROUTINE %EXTERNALPREDICATESPEC ANY REQUESTS(%STRING(1)%NAME NEXT) %EXTERNALROUTINESPEC END REQUEST !FILE STORE ROUTINES %EXTERNALSTRING(6)%FNSPEC JOBFILE(%STRING(3) NAM) %EXTERNALROUTINESPEC OPEN LOG %EXTERNALROUTINESPEC CLOSE LOG %EXTERNALROUTINESPEC LOGIT(%STRING(255) STR) %EXTERNALROUTINESPEC PSSLOG(%STRING(1)%NAME WHAT STRING,%INTEGER STIME,GSEGS,PSEGS) %EXTERNALROUTINESPEC OPEN INPUT(%INTEGER STREAM %STRING(1)%NAME FILENAME) %EXTERNALROUTINESPEC OPEN OUTPUT(%INTEGER STREAM, %STRING(1)%NAME FILENAME) %EXTERNALROUTINESPEC ABORT OUTPUT %EXTERNALROUTINESPEC READFILES(%STRING(1)%NAME FILENAME) %EXTERNALROUTINESPEC DISPOSE(%STRING(1)%NAME FILE,DISPOSE MESSAGE) !NODE ROUTINES %EXTERNALROUTINESPEC INIT NODES %EXTERNALROUTINESPEC UPD NODES %EXTERNALROUTINESPEC LIST SPOOL NODES %EXTERNALPREDICATESPEC NODEOFFLINE(%STRING(1)%NAME NODE) %EXTERNALPREDICATESPEC NODEONLINE(%STRING(1)%NAME NODE) %EXTERNALSTRING(12)%FNSPEC OURNODE; !RETURNS OUR NODE NUMBER %EXTERNALROUTINESPEC SET NODE DOWN(%STRING(12)%NAME NODE,%INTEGER SECS) %EXTERNALPREDICATESPEC GET REQUEST(%STRING(1)%NAME FILE) %EXTERNALROUTINESPEC TELL USER(%STRING(1)%NAME USER,FIL %STRING(255) MESS) %EXTERNALROUTINESPEC GET12(%INTEGERNAME N) %EXTERNALROUTINESPEC MACINIT; !SET UP CONTROL C INTERRUPTS %EXTERNALROUTINESPEC INIT0 %EXTERNALROUTINESPEC GET0(%INTEGERNAME N) %EXTERNALROUTINESPEC PUT0(%INTEGER N) %EXTERNALROUTINESPEC READ0 %EXTERNALROUTINESPEC SEND0 !LEVEL 0 PARAMETER ROUTINES %EXTERNALROUTINESPEC INIT PARAMS %EXTERNALROUTINESPEC DEF PARAMS %EXTERNALROUTINESPEC SET P PARAMS %EXTERNALROUTINESPEC SKIP PARAMS %EXTERNALPREDICATESPEC P PARAMS OK %EXTERNALROUTINESPEC PUT0 PARAMS %EXTERNALPREDICATESPEC GET Q PARAMS %EXTERNALROUTINESPEC PRIVATE CODES !LEVEL 1 AND 2 %EXTERNALROUTINESPEC READ1(%INTEGERNAME RECEIVED,RECEIVED ARG) %EXTERNALROUTINESPEC SEND1(%INTEGER COMMAND,ARG) %EXTERNALROUTINESPEC INIT2 %EXTERNALROUTINESPEC READ2(%INTEGER HEADER) %EXTERNALROUTINESPEC DATA2(%INTEGERNAME LENGTH,LAST RECORD) %EXTERNALPREDICATESPEC SEND2 %EXTERNALROUTINESPEC SKIP RECORD(%INTEGER HEADER) %EXTERNALROUTINESPEC PRINT2(%INTEGER HEADER) %EXTERNALROUTINESPEC IDLE(%INTEGER SECS) %EXTERNALPREDICATESPEC FTP RECEIVE %EXTERNALPREDICATESPEC ANY GOT %EXTERNALROUTINESPEC CHECKPOINT %EXTERNALSTRING(12)%FNSPEC OCTTOSTR(%INTEGER N) %EXTERNALSTRING(12)%FNSPEC INTTOSTR(%INTEGER N) %EXTERNALROUTINESPEC UPPERCASE(%STRING(1)%NAME STR) %EXTERNALSTRING(9)%FNSPEC HEXTOSTR(%INTEGER N) %EXTERNALPREDICATESPEC CALLI2(%INTEGER N,%INTEGERNAME M) %EXTERNALROUTINESPEC REPRT(%STRING(255) STR) %EXTERNALROUTINESPEC READLINE(%STRING(1)%NAME LINE) %EXTERNALROUTINESPEC PROMPT(%STRING(255) STR) %EXTERNALINTEGERFNSPEC GETTIME %EXTERNALINTEGERFNSPEC PPN %EXTERNALPREDICATESPEC SETSRC(%INTEGER PPN) %EXTERNALPREDICATESPEC INPUT PENDING %INTEGER RECEIVED, RECEIVED ARG; !GLOBAL LEVEL 1 RECEIVED CHARS %EXTERNALINTEGER SENT, SENT ARG; !GLOBAL LEVEL 1 SENT CHARS %CONSTINTEGER MAX DATA RECORD=1024; !ALSO DEFINED IN FTP12 AND PARAM %EXTERNALINTEGERARRAYSPEC DATA(0:MAX DATA RECORD); !THE LEVEL 2 DATA ARRAY %EXTERNALINTEGER PSS OUTPUT; !FOR LOGGING TRANSFERS OVER PSS %EXTERNALINTEGER XOURPPN %EXTERNALSTRING(20) XOURACCOUNT; !THE ACCOUNT NUMBER FOR THIS USER %EXTERNALSTRING(20) XOUR NODE; !GLOBAL CURRENT NODE NUMBER %EXTERNALSTRING(255) XOTHER NODE; !THE OTHER NODE WE ARE TALKING TO %OWNSTRING(1) NUL="" %STRING(12) COMMAND,PORQ,NODE,NEXT FILE !THESE ARE THE GLOBAL SETTINGS FROM THE PARAMETER MODULE %EXTERNALSTRING(96)%SPEC XFILENAME %EXTERNALSTRING(96)%SPEC XOPMESS %EXTERNALSTRING(96)%SPEC XMONMESS %EXTERNALSTRING(20)%SPEC XACCOUNT %EXTERNALSTRING(20)%SPEC XUSERNAME %EXTERNALSTRING(20)%SPEC XOUTDEV %EXTERNALINTEGERNAMESPEC XCODE %EXTERNALINTEGERNAMESPEC XMODE %EXTERNALINTEGERNAMESPEC XRSIZE %EXTERNALINTEGERNAMESPEC XFSIZE %EXTERNALINTEGERNAMESPEC XFACILITIES %EXTERNALSTRING(25)%SPEC XPRIV TCODE %EXTERNALINTEGERSPEC FTP81; !NEW OR OLD STYLE FTP INDICATOR %EXTERNALINTEGER I AM P; !'P' OR 'Q' FLAG WORD %INTEGER VALUE %EXTERNALINTEGER LOGLEVEL !LOGLEVEL PROVIDES THE DEGREE OF LOGGING OF MESSAGES (SEE HELP FILE BELOW) %EXTERNALSTRING(96) LOGFILE; !THE NAME OF THE CURRENT LOGFILE %EXTERNALSTRING(6)%SPEC QDEV %STRING(1) PROMPT STRING %EXTERNALINTEGER QUFD=8_3 000003 %INTEGER BYTES; !FOR THE NUMBER OF DATA BYTES WHICH HAVE BEEN TRANSFERRED %INTEGER STIME; !THE TIME AT THE START OF A TRANSFER %EXTERNALINTEGER GSEGS,PSEGS; !NUMBER OF SEGMENTS SENT AND RECIEVED ALTOGETHER %INTEGER KILL; !FLAG FOR JOB TO BE KILLED %INTEGER PAUSING; !FLAG FOR JOB TO PAUSE %INTEGER STOPPING; !FLAG FOR JOB TO STOP AFTER THIS FILE %INTEGER TRANSFERRING; !FLAG FOR A TRANSFER IN PROGRESS %INTEGER STARTED; !FLAG FOR 'START' HAVING BEEN TYPED %INTEGER PSTARTED,QSTARTED; !FLAGS FOR BEING EITHER P OR Q %INTEGER SUCCESS; !FLAG FOR SUCCESSFUL FILE TRANSFER %INTEGER SETUP TIME; !TIME SINCE LAST TRANSPORT RESET %INTEGER START TIME; !THE TIME IN MILLISECS SINCE FILE TRANSFER STARTED %INTEGER NUM TIMEOUTS; !THE NUMBER OF CONSECUTIVE TIMEOUTS %STRING(96) FILE1 %STRING(72) FILEMSG; !SET BY READ FILE AND SEND FILE ON AN ERROR %STRING(120) DISP MSG; !SET BY 'DISPOSE' ROUTINE TO SAY WHAT IT DID %STRING(255) WHAT STRING %EXTERNALSTRING(255)%SPEC ERRMSG %ROUTINESPEC SETUP %ROUTINESPEC PROCESS COMMAND !LEVEL 0 COMMANDS %CONSTINTEGER STOP=0, GO=1, RPOS=2, RNEG=3, SFT=4, STOPACK=5 !LEVEL 1 COMMANDS %CONSTINTEGER SS=16_40, MS=16_41, CS=16_42, ES=16_43, RR=16_44, MR=16_45, QR=16_46, ER=16_47 !HEADER BIT DEFNITIONS %CONSTINTEGER COMPRESSION BIT=16_40, BYTE COUNT=16_3F %CONSTINTEGER TRUE=-1, FALSE=0; !LOGIC SETTINGS %CONSTINTEGER TTY=1, FILE=2, LOG=3 %EXTERNALINTEGER DEBUG=FALSE %EXTERNALINTEGER OPRPRV; !TRUE ALLOWS OPR[1,2] PRIVILIGES - DO NOT CHECK ACCESS %CONSTINTEGER OPR PPN=8_1 000002 %CONSTINTEGER QUARTER HOUR=15*60000; !MILLISECS ! !****************************************************************************** !FOR TESTING PURPOSES, SET 'DEBUG' AND RUN BOTH FTP AND FTXSPL ON A DISK OTHER !THAN THE SYSTEM DISK. THIS WILL GIVE THE QUEUES ON [3,3] BUT INVISIBLE TO !THE PRODUCTION FTP. !ALSO THE LOG FILE WILL BE DSK:nnnFTP.LOG WHERE nnn IS THE JOB NUMBER ! !FOR BACK TO BACK TESTING, ! START ONE VERSION AS Q ONLY AND THEN START ANOTHER VERSION AS P ONLY !******************************************************************************** !THE FOLLOWING PROCEDURES ARE FOR COMMAND DECODING %PREDICATE ALPHANUM(%INTEGERNAME S) !================================== %IF 'A'<=S<='Z' %THEN %TRUE %IF 'a'<=S<='z' %THEN S=S-SP %AND %TRUE %IF '0'<=S<='9' %THEN %TRUE %FALSE %END %ROUTINE IGNORE SPACES !====================== %INTEGER S S=NEXTSYMBOL %WHILE S=SP %OR S=TAB %THEN SKIPSYMBOL %AND S=NEXTSYMBOL %END %ROUTINE IGNORE REST OF LINE !=========================== %INTEGER I %CYCLE READSYMBOL(I) %IF I=ESC %THEN NEWLINE %AND %EXIT %EXIT %IF I=NL %REPEAT %END %PREDICATE COMMAND TEST(%STRING(1)%NAME COMMAND,%STRING(12) TEXT) !================================================================= !Check if a given string is a substring of a valis command %INTEGER I %FALSE %IF LENGTH(COMMAND) > LENGTH(TEXT) %FOR I=1,1,LENGTH(COMMAND) %CYCLE %FALSE %IF CHARNO(COMMAND,I) # CHARNO(TEXT,I) %REPEAT %TRUE %END %ROUTINE READ WORD(%STRING(12)%NAME STR) !======================================== !Read a word up to the next terminator %INTEGER I IGNORE SPACES STR="" I=NEXTSYMBOL %IF I=NL %OR I=ESC %THEN %RETURN %CYCLE %UNLESS ALPHANUM(I) %START %IF STR="" %THEN STR=TOSTRING(I) %EXIT %FINISH STR=STR.TOSTRING(I) SKIPSYMBOL I=NEXTSYMBOL %REPEAT %END %ROUTINE READ NEXT(%STRING(1)%NAME STR) !======================================== !Read a number up to the next terminator %INTEGER I IGNORE SPACES STR="" I=NEXTSYMBOL %IF I=NL %OR I=ESC %THEN %RETURN %CYCLE %UNLESS '0'<=I<='9' %START %EXIT %FINISH STR=STR.TOSTRING(I) SKIPSYMBOL I=NEXTSYMBOL %REPEAT %END !REPORTING ROUTINES %ROUTINE REPORT FINISH(%STRING(1)%NAME USER,FIL) !================================================ !When a read or send has completed this informs those who wish to know %STRING(150) SUCC STR %IF SUCCESS %THEN SUCCSTR="Success ".DISP MSG %ELSE SUCCSTR="Unsuccessful - ".FILEMSG REPRT(SUCCSTR) %IF REM(LOGLEVEL,10)>0 LOGIT(SUCCSTR) TELL USER(USER,FIL,WHAT STRING." ".SUCCSTR) %END %ROUTINE ERR REPORT(%STRING(255) STRING) !======================================= REPRT(" ?".STRING) PROMPT(PROMPT STRING) %END %ROUTINE WARN REPORT(%STRING(255) STRING) !======================================== REPRT("%".STRING) PROMPT(PROMPT STRING) %END %ROUTINE INITIALISE VARIABLES !============================ !Sets up the variables in the various modules to their initial state DEF PARAMS INIT0; INIT2 PSS OUTPUT=FALSE; !FOR LOGGING A TRANSFER OVER PSS GSEGS=0; PSEGS=0; STIME=GET TIME %END %ROUTINE INIT WHAT STRING(%STRING(1)%NAME FILE) !============================================================ %IF (I AM P %AND XMODE&16_8000=0) %OR (XMODE&16_8000#0 %AND I AM P=FALSE) %START WHAT STRING=">>SENDING>> ".FILE." to ".XOTHER NODE %ELSE WHAT STRING="<RETURN %FINISH SUCCESS=FALSE; FILEMSG="" SENT=0; SENT ARG=0 OPEN OUTPUT(FILE,FILE1) SELECT OUTPUT(FILE) ! HERE TO AWAIT A 'SS' GET12(HEADER) %IF HEADER#0 %START SEND1(QR,16_22) SKIP RECORD(HEADER) %ELSE READ1(RECEIVED,RECEIVED ARG) %UNLESS RECEIVED=SS %AND RECEIVED ARG=0 %START SEND1(QR,16_22) %FINISH %FINISH ! GOT AN 'SS' OR AN ERROR BY NOW, SO INTO MAIN LOOP START TIME=GETTIME %CYCLE %IF INPUT PENDING %START; !CHECK THE CONSOLE FOR INPUT SELECT OUTPUT(TTY) PROCESS COMMAND SELECT OUTPUT(FILE) %IF KILL %START SEND1(QR,16_36) FILEMSG=" File transfer KILLed by operator"; ->RETURN %FINISH %FINISH GET12(HEADER) %IF HEADER=0 %START; !A LEVEL 1 COMMAND READ1(RECEIVED,RECEIVED ARG) %CONTINUE %IF RECEIVED=MS; !DO NOTHING ON A MARK %IF RECEIVED=ES %START %IF RECEIVED ARG=0 %START; !ES(OK) %IF SENT=0 %START; !WE HAVE NOT COMPLAINED SUCCESS=TRUE; FILEMSG=""; !ON SUCCESSFUL COMLETION PRINT2(16_80) %IF DATA(0)>0; !FLUSH LAST BUFFER SEND1(ER,0) ->RETURN %ELSE SEND1(ER,16_22) %FINISH %ELSE %IF SENT=0 %START SEND1(ER,RECEIVED ARG) %UNLESS RECEIVED ARG>16_30; !AN ES ABORT FILEMSG=" File transfer aborted by sender" %ELSE FILEMSG=" File transfer aborted by reciever:- error code ".HEXTOSTR(SENT ARG) %FINISH ->RETURN %FINISH %ELSE%IF RECEIVED=CS %START %IF RECEIVED ARG=0 %START XCODE=1 %ELSEIF RECEIVED ARG=1 %START XCODE=2 %ELSEIF RECEIVED ARG=3 %START private codes; !SET UP PRIVATE CODES %ELSE SEND1(QR,16_22) %CONTINUE %ELSE; !AN ILLEGAL COMMAND SEND1(QR,16_22) %CONTINUE %FINISH %ELSE; !LEVEL 2 DATA %IF (XFACILITIES&1=0 %AND HEADER&COMPRESSION BIT # 0) %OR HEADER&BYTE COUNT>XRSIZE %OR SENT=QR %START SEND1(QR,16_22) SKIP RECORD(HEADER) %CONTINUE %FINISH BYTES=BYTES+HEADER&BYTE COUNT READ2(HEADER) PRINT2(HEADER) %FINISH %REPEAT RETURN: SELECT OUTPUT(FILE) %IF SUCCESS=TRUE %THEN CLOSE OUTPUT %ELSE ABORT OUTPUT SELECT OUTPUT(TTY) %END %ROUTINE SEND FILE(%STRING(1)%NAME FILE1) !======================================== !Handles the writing of the file using the levels 1 and 2 of the protocol !It returns when the transfer has been completed with 'SUCCESS' set to !true or false and with a message in 'FILEMSG' %INTEGER LAST RECORD,LENGTH %ON %EVENT 9,10 %START ->SEND END %IF EVENT=9; !ER RECEIVED TRAP SUCCESS=FALSE; FILEMSG=ERRMSG." (".OCTTOSTR(EVENTINFO).")" SELECT INPUT(FILE); CLOSE INPUT SELECT INPUT(TTY); SELECT OUTPUT(TTY); NEWLINE %RETURN %FINISH %ROUTINE CHECK RECEIVER !--------------------- !Look at the messages coming back %INTEGER HEADER %CYCLE GET12(HEADER) %IF HEADER#0 %START; !NOT A LEVEL 1 COMMAND SEND1(ES,16_2A) SKIP RECORD(HEADER) %CONTINUE %ELSE READ1(RECEIVED,RECEIVED ARG); !LEVEL 1 COMMAND %IF RECEIVED=QR %START SEND1(ES,RECEIVED ARG); %CONTINUE %FINISH %IF RECEIVED=ER %START %SIGNAL 9,99; !TRAP IN SEND FILE ROUTINE %ELSE; !NOT A MESSAGE WE ARE EXPECTING OR WANTING SEND1(ES,16_2A) %FINISH %REPEAT %END SUCCESS=FALSE; FILEMSG="" OPEN INPUT(FILE,FILE1) SELECT INPUT(FILE) RECEIVED=0; RECEIVED ARG=0 START TIME=GETTIME SEND1(SS,0); !SAY WE ARE STARTING %IF XPRIV TCODE#"" %START; !PRIVATE CODE SEND1(CS,3) %ELSEIF XCODE&16_F=2 %START; !BINARY SEND1(CS,1) %FINISH; !ELSE ASCII - DON'T SEND CS DATA2(BYTES,LAST RECORD); !GET FIRST RECORD OF FILE %CYCLE SELECT INPUT(TTY) %IF INPUT PENDING %START; !CHECK CONSOLE FOR INPUT PROCESS COMMAND %IF KILL %THEN SEND1(ES,16_36) %AND ->SEND END %FINISH SELECT INPUT(FILE) CHECK RECEIVER %IF ANY GOT !SEND DATA %CONTINUE %UNLESS SEND2; !IF ONLY SUB-RECORD OUTPUT, CONTINUE %EXIT %IF LAST RECORD; !DONE IT ALL DATA2(LENGTH,LAST RECORD) BYTES=BYTES+LENGTH %REPEAT !HERE AFTER LAST RECORD SEND1(ES,0); !FINISH OFF CHECK RECEIVER SEND END: SELECT INPUT(FILE); CLOSE INPUT SELECT INPUT(TTY); SELECT OUTPUT(TTY) %IF SENT=ES %START %IF SENT ARG=16_36 %START FILEMSG=" File transfer KILLed by operator" %ELSE %IF RECEIVED ARG#0 %START FILEMSG=" File transfer terminated by receiver" %ELSE SUCCESS=TRUE; FILEMSG=""; !SUCCESSFUL COMPLETION %FINISH %FINISH %ELSE FILEMSG=" File transfer aborted by receiver" %FINISH NEWLINE %END %ROUTINE P PROCESS(%STRING(1)%NAME FIL) !======================================= !Handles the level 0 of the protocol for the P process after the transport !mechanism has been set up, it returns only when complete or with !signal 14 (transport error) %SWITCH S(0:SFT) %INTEGER COMMAND,TAKE,STOP SENT %ON %EVENT 4,14 %START ->TOUT %IF STOP SENT=TRUE; !TIMEOUT WAITING FOR AN STOPACK %SIGNAL 14,SUBEVENT,EVENTINFO %IF EVENT=14 %SIGNAL 4,SUBEVENT,EVENTINFO %FINISH %IF XMODE&16_8000=0 %THEN TAKE=TRUE %ELSE TAKE=FALSE STOP SENT=FALSE; !FLAG FOR STOP SENT SET P PARAMS; !ADD FILE PARAMETER INIT WHAT STRING(FIL) WHAT STRING=WHAT STRING."_".XFILENAME." for user ".XOUR NODE."_".XOURACCOUNT START TIME=0 REPRT(WHAT STRING) %IF REM(LOGLEVEL,10)>0 LOGIT(WHAT STRING) PUT0(SFT) PUT0 PARAMS; !ADD PARAMETERS SEND0; !SEND IT READ0; !GET REPLY GET0(COMMAND) ->S(COMMAND) %IF COMMAND<=SFT !AN ILLEGAL MESSAGE S(STOP): S(GO): S(SFT): %IF P PARAMS OK %START; %FINISH; !JUST GET PARAMS PUT0(STOP); PUT0(0); !STOP ABORT SHOULD SAY WHY***** SEND0 %IF COMMAND=SFT %THEN ERRMSG="Contention for sending files - waiting" %ELSE %C ERRMSG="Illegal message from Q - aborting" %SIGNAL 14,1 S(RNEG): %IF P PARAMS OK %START; %FINISH; !JUST GET PARAMS %IF XOPMESS#"" %THEN FILEMSG=XOPMESS %ELSE FILEMSG=XMONMESS PUT0(STOP); PUT0(0); !SHOULD SAY WHY**** SEND0 ->PEXIT S(RPOS): %UNLESS P PARAMS OK %START; !CHECK THAT THE ACKNOWLEDGEMENT IS OK PUT0(STOP); PUT0 PARAMS; !ADD PARAMS SEND0 FILEMSG=XMONMESS ->P EXIT %FINISH PUT0(GO); PUT0(0) SEND0 PRIVATE CODES; !ENABLE PRIVATE CODES %IF TAKE %START SEND FILE(FIL) %ELSE READ FILE(FIL) %FINISH PUT0(STOP); PUT0(0) SEND0 STOP SENT=TRUE READ0; !WAIT FOR LINE DOWN OR A STOPACK GET0(COMMAND) %IF COMMAND=STOPACK %START; !FTP80 %IF P PARAMS OK %START; %FINISH; !AND SKIP PARAMS %FINISH TOUT: DISPOSE(FIL,DISP MSG) %IF SUCCESS=TRUE; !IF TRANSFER OK PEXIT: REPORT FINISH(XOURACCOUNT,FIL) %END %ROUTINE Q PROCESS !======================================= !Handles the level 0 of the protocol for the Q process after the transport !mechanism has been set up, it returns only when complete or with !signal 14 (transport error) %INTEGER COMMAND,TAKE,RESP %ON %EVENT 4,14 %START %RETURN %IF RESP=STOPACK; !TIMEOUT WAITING FOR AN SFT %SIGNAL 14,SUBEVENT,EVENTINFO %IF EVENT=14 %SIGNAL 4,SUBEVENT,EVENTINFO %FINISH RESTART: SUCCESS=FALSE; !DEFAULT STATE OF FILE TRANSFER READ0 GET0(COMMAND) %UNLESS COMMAND=SFT %START ERRMSG=" did not get SFT" %SIGNAL 14,1 %FINISH %UNLESS GET Q PARAMS %START PUT0(RNEG); RESP=RNEG %ELSE PUT0(RPOS); RESP=RPOS %FINISH %IF XMODE&16_8000=0 %THEN TAKE=TRUE %ELSE TAKE=FALSE INIT WHAT STRING(XFILENAME) START TIME=0 REPRT(WHAT STRING) %IF REM(LOGLEVEL,10)>0 LOGIT(WHAT STRING) PUT0 PARAMS; !ASSEMBLE REPLY SEND0 %IF RESP=RNEG %THEN FILEMSG=XMONMESS READ0 GET0(COMMAND) %IF GET Q PARAMS %START; %FINISH; !JUST GET PARAMS %IF COMMAND=STOP %START FILEMSG=XMONMESS %IF RESP=RPOS; !ONLY CHANGE MESSAGE IF WE THOUGHT IT WAS OK ->QEXIT %FINISH %UNLESS COMMAND=GO %START ERRMSG="Did not get GO" %SIGNAL 14,1 %FINISH PRIVATE CODES; !ENABLE PRIVATE CODES %IF TAKE %START READ FILE(XFILENAME) %ELSE SEND FILE(XFILENAME) %FINISH READ0 GET0(COMMAND) SKIP PARAMS; !JUST GET PARAMS %UNLESS COMMAND=STOP %START LOGIT("Did not get STOP but continuing") %FINISH DISPOSE(XFILENAME,DISPMSG) %IF SUCCESS=TRUE; !IF TRANSFER OK QEXIT: %UNLESS DEBUG=TRUE %THEN REPORT FINISH(NUL,XFILENAME) %IF FTP81=TRUE %START PUT0(STOPACK); PUT0(0); RESP=STOPACK SEND0 INITIALISE VARIABLES ->RESTART; !WAIT FOR ANOTHER SFT OR TIMEOUT %FINISH %END !NOW ALL THE COMMANDS %ROUTINE HELP !============= PRINTSTRING("The commands are:- CURRENT types out current settings DEBUG run a test version of the spooler DETACH run the spooler detached EXIT exit to monitor leve "); PRINTSTRING("GO continue spooling after a PAUSE HELP type this text KILL abort current file transfer LOG file open a log file "); PRINTSTRING("MSGLEVEL n n=0 - log files being transferred and do not type anything n=1 - type files being transferred(default)"); PRINTSTRING(" n=10 - log level 0 message headers n=20 - log parameters being passed n=30 - log level 1 messages n=40 - log level 2 message headers"); PRINTSTRING(" n=50 - log level 2 data n=100- type transport level start-up n=200- type each byte received n=400- type each byte transmitted "); PRINTSTRING(" NEXT nnnnnn process the given request out of sequence NODES list the known nodes and their status PAUSE stop spooling jobs after this current transfer is finished"); PRINTSTRING(" RESET reset spooler to initial state SET NODE OFFLINE disable transfers to the named node SET NODE ONLINE enable transfers to the named node (default) START (P or Q) start transferring jobs in the queue"); PRINTSTRING(" STOP stop transferring files after this current one and exit to monitor level. TASK change name of listening task (default is FTX*) WHAT type the state of the spooler and of any current transfer") PRINTSTRING(" All these commands may be abbreviated to their shortest unique form. ") %END %ROUTINE DETACH !============== %INTEGER N REPRT("DETACHING") N=8_177777 000000; !DETACH JOB AND LEAVE IN USER MODE %UNLESS CALLI2(8_104,N) %START ERR REPORT("Could not DETACH job") %FINISH %END %ROUTINE EXIT !============ !RETURN TO MONITOR SELECT OUTPUT(LOG); CLOSE OUTPUT CLOSE TRANSPORT SELECT OUTPUT(TTY) %IF TRANSFERRING %START WARN REPORT("Aborting current transfer") REPRT(WHAT STRING) %FINISH *8_047000 000012; !EXIT 0, %END %ROUTINE STOP IT !=============== REPRT("[FTP is stopping]") EXIT %END %ROUTINE PAUSE IT !================ REPRT("[FTP is pausing]") PROMPT STRING="/" CLOSE TRANSPORT %END %ROUTINE RESET IT !================ !RESET VARIABLES BYTES=0; WHAT STRING=""; PROMPT STRING="/" KILL=FALSE; PAUSING=FALSE; STOPPING=FALSE; STARTED=FALSE; TRANSFERRING=FALSE UPD NODES %END %ROUTINE WHAT !============== !TO TYPE OUT THE CURRENT STATE OF A TRANSFER %IF WHAT STRING="" %START %IF PAUSING %THEN PAUSE IT %ELSE PRINTSTRING("[FTP is idle]") %ELSE PRINTSTRING(WHAT STRING); NEWLINE WRITE(BYTES//1024,1) %IF XFSIZE>0 %START PRINTSTRING(" of"); WRITE(XFSIZE,1) %IF BYTES#0 %START PRINTSTRING(" ("); WRITE((BYTES*100)//(XFSIZE*1024),0) PRINTSTRING("%)") %FINISH %FINISH PRINTSTRING(" Kbytes transferred") %IF START TIME#0#BYTES %START PRINTSTRING(" = ") PRINT((BYTES*8)/(GETTIME-STARTTIME),0,3) PRINTSTRING(" Kbaud") %FINISH %FINISH NEWLINE %END %ROUTINE CURRENT !=============== !Prints out the current settings PRINTSTRING("Logfile = "); PRINTSTRING(LOGFILE); PRINTSTRING(" Message level ="); WRITE(LOGLEVEL,1); NEWLINE PRINTSTRING("Listening task name is "); PRINTSTRING(TASK NAME); NEWLINE %IF STARTED=TRUE %START PRINTSTRING("Operating as "); %IF PSTARTED=TRUE %THEN PRINTSYMBOL('P') %IF PSTARTED=TRUE=QSTARTED %THEN PRINTSTRING(" and ") %IF QSTARTED=TRUE %THEN PRINTSYMBOL('Q') NEWLINE %FINISH %IF NEXTFILE#"" %START PRINTSTRING("NEXT request to process is "); PRINTSTRING(NEXTFILE) NEWLINE %FINISH %IF STOPPING=TRUE %START %IF TRANSFERRING=TRUE %START PRINTSTRING("[FTP will STOP]") %else PRINTSTRING("[FTP is STOPped]") NEWLINE %ELSEIF PAUSING=TRUE %START %IF TRANSFERRING=TRUE %START PRINTSTRING("[FTP will PAUSE]") %else PRINTSTRING("[FTP is PAUSEing]") NEWLINE %ELSE%IF TRANSFERRING=FALSE %START PRINTSTRING("[FTP is idle]") NEWLINE %FINISH %END %ROUTINE PROCESS P REQUEST !========================= %ON %EVENT 10 %START WARN REPORT(ERRMSG) %IF PSS OUTPUT=TRUE %START; !CALL WAS SET UP WHAT STRING=WHAT STRING." ".ERRMSG PSSLOG(WHAT STRING,STIME,GSEGS,PSEGS) %FINISH ->1 %FINISH INITIALISE VARIABLES OPEN LOG I AM P=TRUE; SUCCESS=FALSE %IF GET REQUEST(FILE1) %START %UNLESS P OPEN TRANSPORT(XOTHER NODE) %START WARN REPORT(ERRMSG) ->1 %ELSE TRANSFERRING=TRUE P PROCESS(FILE1) %IF PSS OUTPUT=TRUE %START; !CALL WAS SET UP PSSLOG(WHAT STRING,STIME,GSEGS,PSEGS) %FINISH NUM TIMEOUTS=0; !RESET TIMOUT COUNT FOR SUCCESSFUL TRANSFER %FINISH %ELSE INIT WHAT STRING(FILE1) WHAT STRING=WHAT STRING."_".XFILENAME." for user".XOUR NODE."_".XOURACCOUNT FILEMSG=XMONMESS REPORT FINISH(XACCOUNT,FILE1) %FINISH 2: END REQUEST NEXTFILE="" 1: SETUP CLOSE LOG %END %ROUTINE PROCESS Q REQUEST !========================= INITIALISE VARIABLES OPEN LOG I AM P=FALSE %UNLESS Q OPEN TRANSPORT %START WARN REPORT(ERRMSG) %ELSE TRANSFERRING=TRUE Q PROCESS NUM TIMEOUTS=0; !RESET TIMOUT COUNT FOR SUCCESSFUL TRANSFER %FINISH SETUP CLOSE LOG %END %ROUTINE PROCESS COMMAND !======================= !HERE WHEN A COMMAND HAS BEEN TYPED ON THE CONSOLE READ WORD(COMMAND) ->CONTINUE %IF COMMAND=""; !A BLANK LINE IGNORE SPACES %IF COMMAND TEST(COMMAND,"KILL") %START KILL=TRUE %IF TRANSFERRING; IGNORE REST OF LINE %RETURN %FINISH %IF COMMAND TEST(COMMAND,"WHAT") %THEN WHAT %AND ->CONTINUE %IF COMMAND TEST(COMMAND,"CURRENT") %THEN CURRENT %AND ->CONTINUE %IF COMMAND TEST(COMMAND,"PAUSE") %START PAUSING=TRUE; STARTED=FALSE %IF TRANSFERRING=FALSE %THEN PAUSE IT ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"START") %OR COMMAND TEST(COMMAND,"GO") %START %IF STARTED=TRUE %START WARN REPORT("FTP already started") ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"START") %START; !SEE IF MODIFIER PRESENT READ WORD(PORQ) %IF PORQ="" %START PSTARTED=TRUE; QSTARTED=TRUE %ELSEIF PORQ="P" %START PSTARTED=TRUE; QSTARTED=FALSE %ELSEIF PORQ="Q" %START PSTARTED=FALSE; QSTARTED=TRUE %ELSE WARN REPORT("Unknown modifier for START command ".PORQ) ->CONTINUE %FINISH %FINISH %IF TRANSFERRING=FALSE %START RESET IT; STARTED=TRUE; PROMPT STRING="!" %IF STARTED=TRUE=QSTARTED %THEN RESET TRANSPORT %FINISH ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"STOP") %START STOPPING=TRUE; STARTED=FALSE %IF TRANSFERRING=FALSE %THEN STOP IT ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"RESET") %START RESET IT; INIT NODES; LOGLEVEL=1 ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"EXIT") %THEN EXIT %IF COMMAND TEST(COMMAND,"HELP") %THEN HELP %AND ->CONTINUE %IF COMMAND TEST(COMMAND,"LOG") %START READFILES(LOGFILE) ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"NEXT") %START READNEXT(NEXTFILE) ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"MSGLEVEL") %START SKIP SYMBOL %IF NEXTSYMBOL=':' IGNORE SPACES; %IF ESC#NEXT SYMBOL#NL %THEN READ(LOGLEVEL) ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"DETACH") %THEN DETACH %AND ->CONTINUE %IF COMMAND TEST(COMMAND,"NODES") %THEN LIST SPOOL NODES %AND ->CONTINUE %IF COMMAND TEST(COMMAND,"SET") %START READ WORD(NODE); %IF COMMAND TEST(NODE,"NODE") %THEN READ WORD(NODE); !A NOISE WORD ! %IF NODE="*" %THEN READ WORD(NODE) %AND NODE="*".NODE; !A LOCAL NODE READ WORD(COMMAND) %IF COMMAND TEST(COMMAND,"ONLINE") %START %UNLESS NODE ONLINE(NODE) %START WARN REPORT("Unknown node - ".NODE) %FINISH %ELSEIF COMMAND TEST(COMMAND,"OFFLINE") %START %UNLESS NODE OFFLINE(NODE) %START WARN REPORT("Unknown node - ".NODE) %FINISH %ELSE WARN REPORT("Unknown command in SET NODE command - ".COMMAND) %FINISH ->CONTINUE %FINISH %IF COMMAND TEST(COMMAND,"DEBUG") %THEN DEBUG=TRUE %AND %SIGNAL 15,0,0 %IF COMMAND TEST(COMMAND,"TASK") %START IGNORE SPACES; %IF ESC#NEXT SYMBOL#NL %THEN READLINE(TASK NAME) %AND UPPER CASE(TASK NAME) ->CONT1 %FINISH PRINTSTRING("?Unrecognised command """) PRINTSTRING(COMMAND); PRINTSTRING(""" type HELP") NEWLINE CONTINUE: IGNORE REST OF LINE CONT1: PROMPT(PROMPT STRING) %END %ROUTINE SETUP !============= %IF XOURPPN =OPR PPN %START %UNLESS SETSRC(XOURPPN) %START; %FINISH %FINISH SELECT INPUT(TTY); SELECT OUTPUT(TTY) WHAT STRING=""; FILEMSG="" BYTES=0; KILL=FALSE; TRANSFERRING=FALSE %IF PAUSING=TRUE %THEN PAUSE IT %IF STOPPING=TRUE %THEN STOP IT FTP81=FALSE I AM P=FALSE %IF STARTED=TRUE %START %IF QSTARTED=TRUE %THEN RESET TRANSPORT %ELSE CLOSE TRANSPORT %FINISH SETUP TIME=GETTIME %END !MAIN PROGRAM !============= %ON %EVENT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 %START; !HERE WHEN OTHER SIDE BOMBS OUT AND AS A CHATCH ALL ->RESTART %IF EVENT=15; !FROM THE DEBUG COMMAND SELECT INPUT(FILE); SELECT OUTPUT(FILE) CLOSE INPUT; ABORT OUTPUT; !SO THAT FILE DOES NOT GET WRITTEN SELECT OUTPUT(TTY) %IF EVENT=10 %AND SUBEVENT=5 %START ERR REPORT(ERRMSG) %IF EVENTINFO=3 %THEN REPRT("Probably another FTXSPL running") %stop %FINISH %IF EVENT=4 %AND EVENTINFO=5 %START %IF GSEGS=0 %START; !Host has not replied ERRMSG="No response from host" %ELSE ERRMSG="Transport ".ERRMSG %FINISH %IF EVENT=4 %OR EVENT=14 %START ERRMSG=ERRMSG." on call to ".XOTHERNODE %FINISH REPRT(ERRMSG) LOGIT(ERRMSG) SETUP SELECT OUTPUT(LOG) WHAT CURRENT %IF PSS OUTPUT=TRUE %START; !THE CALL GOT SET UP WHAT STRING=WHAT STRING." ".ERRMSG PSSLOG(WHAT STRING,STIME,GSEGS,PSEGS) %FINISH %IF NUM TIMEOUTS>=1 %START SET NODE DOWN(XOTHER NODE,15*60) NEXTFILE=""; !CLEAR NEXT INDICATOR NUM TIMEOUTS=0 %ELSE %IF XOTHER NODE="UCL" %OR XOTHER NODE="ZUXA" %START SET NODE DOWN(XOTHERNODE,3*60) %FINISH NUM TIMEOUTS=NUM TIMEOUTS+1 %FINISH CLOSE OUTPUT ->MAIN %FINISH DEFINE OUTPUT(TTY,"TTY:/TRMOP"); DEFINE INPUT(TTY,"TTY:/TRMOP") SELECT INPUT(TTY); SELECT OUTPUT(TTY) XOURPPN=PPN %IF XOURPPN#8_1000002 %START PRINTSTRING(" ?MUST BE LOGGED IN AS [1,2]"); %STOP %FINISH XOUR NODE=OUR NODE TASK NAME="FTX*"; !DEFAULT TASK NAME FOR INCOMING TASKS RESTART: MACINIT INIT NODES INIT TRANSPORT INIT PARAMS %IF DEBUG=TRUE %START LOGFILE=JOBFILE("FTP").".LOG"; LOGLEVEL=31 %ELSE LOGFILE=QDEV.":FTPOPR.LOG[3,3]"; LOGLEVEL=1 %FINISH RESET IT SETUP PROMPT(PROMPTSTRING) !MAIN PROGRAM LOOP MAIN: SELECT INPUT(TTY); SELECT OUTPUT(TTY) %CYCLE %IF INPUT PENDING %THEN PROCESS COMMAND %AND %CONTINUE; !CONSOLE INPUT %IF STARTED=TRUE=QSTARTED %START %IF FTP RECEIVE %THEN PROCESS Q REQUEST %AND %CONTINUE; !ANYONE TRYING TO TALK TO US %FINISH %IF STARTED=TRUE=PSTARTED %START %IF ANY REQUESTS(NEXTFILE) %THEN PROCESS P REQUEST %AND %CONTINUE; !ANYTHING SPOOLED %FINISH IDLE(60) ! %IF TRANSFERRING=FALSE %AND GETTIME-SETUP TIME>=QUARTER HOUR %THEN SETUP %REPEAT %ENDOFPROGRAM $$$$$$$$$$$$ &&&&&&&&&&&& PARAM.IMP !PARAM.IMP ! COPYRIGHT K.FARVIS ERCC. !Contains the code to read, write and validate the parameters for the level 0 !protocol. %EXTERNALSTRING(20)%SPEC XOURNODE %EXTERNALSTRING(255)%SPEC XOTHER NODE; !THE OTHER NODE FROM US %EXTERNALINTEGERSPEC LOGLEVEL %EXTERNALINTEGERSPEC SENT, SENT ARG; !GLOBAL LEVEL 1 SENT CHARS %CONSTINTEGER MAX DATA RECORD=1024; !ALSO DEFINED IN FTP12 AND FTPSPL %CONSTINTEGER TRUE=-1, FALSE=0; !LOGIC SETTINGS %CONSTINTEGER LOG=3 %EXTERNALRECORD(FILESPEC)%FNSPEC STRTOFS(%STRING(255) SPEC) %EXTERNALPREDICATESPEC ISFILE(%STRING(255) FIL) %EXTERNALSTRING(255)%FNSPEC FSTOSTR(%RECORD(FILESPEC)%NAME FS) %EXTERNALROUTINESPEC LOGIT(%STRING(255) STR) %EXTERNALSTRING(12)%FNSPEC INTTOSTR(%INTEGER N) %EXTERNALSTRING(9)%FNSPEC HEXTOSTR(%INTEGER N) %EXTERNALROUTINESPEC WRITEHEX(%INTEGER N,M) %EXTERNALROUTINESPEC REPRT(%STRING(255) STR) %EXTERNALROUTINESPEC GET0(%INTEGERNAME N) %EXTERNALROUTINESPEC PUT0(%INTEGER N) %EXTERNALPREDICATESPEC ISNODE(%STRING(1)%NAME NAME,TYPE %INTEGERNAME STATUS) %EXTERNALPREDICATESPEC LEGAL ACCESS(%STRING(1)%NAME FILENAME, %INTEGER MODE, %STRING(20) ACCOUNT,USER,UPASS) %EXTERNALROUTINESPEC SETTIM(%INTEGER SECS) %EXTERNALROUTINESPEC UPPER CASE(%STRING(1)%NAME STR) %EXTERNALINTEGERFNSPEC UNIQUE(%INTEGER N) %RECORDFORMAT PARAMETER RECORD(%BYTEINTEGER IN,OUT,OK,MONITOR,VTYPE,TYPE,OPERATOR, %INTEGER VALUE) %OWNRECORD(PARAMETER RECORD) PARAMETER; !CONTAINS THE CURRENT PARAMETER %OWNINTEGER THIS PARAMETER; !THE NUMBER OF THE CURRENT PARAMETER %EXTERNALINTEGER ARPA MAIL %EXTERNALINTEGER BINARY FILE %CONSTINTEGER MAX PARAM=16_80; !HIGHEST PARAMETER NUMBER %CONSTINTEGER MAX PARAMS=37; !MAXIMUM NUMBER OF PARAMETERS IMPLEMENTED %CONSTINTEGER MAX STRINGS=15; !MAXIMUM NUMBER OF STRING VALUES FOR PARAMETERS %OWNRECORD(PARAMETER RECORD)%ARRAY PARAMETERS(1:MAX PARAMS); !LIST OF THE AVAILABLE PARAMETERS %OWNSTRING(96) THIS STRING %OWNRECORD (FILESPEC) FS %EXTERNALSTRING(6)%SPEC QDEV %OWNINTEGERARRAY STRING VALUES(1:MAX STRINGS); !CONTAINS STRING ADDRESSES !THIS ARRAY WILL MAP THE FOLLOWING STRING PARAMETERS %EXTERNALINTEGERNAME XCODE %EXTERNALINTEGERNAME XMODE %EXTERNALINTEGER YMODE %EXTERNALINTEGERNAME XFORMAT %EXTERNALINTEGERNAME XRSIZE %EXTERNALINTEGERNAME XTSIZE %EXTERNALINTEGERNAME XMAPPING %EXTERNALINTEGERNAME XTID %EXTERNALINTEGERNAME XTIMEOUT %EXTERNALINTEGERNAME XFACILITIES %EXTERNALINTEGERNAME XSTATE %EXTERNALINTEGERNAME XFSIZE %EXTERNALSTRING(96) XFILENAME %EXTERNALSTRING(20) XUSERNAME %EXTERNALSTRING(20) XUSERPASS %EXTERNALSTRING(20) XFILEPASS %EXTERNALSTRING(20) XKINSHIP %EXTERNALSTRING(20) XACCOUNT %EXTERNALSTRING(20) XACCPASS %EXTERNALSTRING(20) XOUTDEV %EXTERNALSTRING(80) XOPMESS %EXTERNALSTRING(80) XMONMESS %EXTERNALSTRING(80) XSPECIAL %EXTERNALSTRING(25) XPRIV TCODE %EXTERNALINTEGER FTP81 !THE ABOVE TWO ARRAYS HOLD THE PARAMETER RECORDS AND THE STRING VALUES !OF THESE RECORDS. THEY ARE ACCESSED INDIRECTLY THROUGH !THE FOLLOWING TWO ARRAYS WHICH CONTAIN INDEXES INTO THEM. !FOR EXAMPLE THE FILE-PASSWORD RECORD IS NUMBER 16_45 WHICH GIVES INDEX !NUMBER 17 THEREFOR THE RECORD IS PARAMETER(17) AND ITS VALUE, BECAUSE !IT IS A STRING IS INDEXED ALSO AND IS 4, THAT IS IS FOUND IN !STRING VALUES(4). ! 0 1 2 3 4 5 6 7 8 9 A B C D E F %CONSTBYTEINTEGERARRAY PARNUM(0:MAX PARAM)= %C 1, 2, 3, 4, 5, 6, 7, 26, 8, 27, 9, 10, 0, 11, 12, 13, 0(16), 28, 29, 30, 31, 32, 33, 34, 35, 0, 36, 0(6), 0(16), 14, 0, 15, 0, 16, 17, 18, 0, 0, 0, 19, 20, 0, 0, 0, 0, 21, 37, 0(14), 22, 0(15), 23, 24, 0(14), 25 %CONSTBYTEINTEGERARRAY STRNUM(0:MAX PARAM)= %C 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0(6), 0(16), 0, 0, 0, 13, 0, 0, 0, 0, 0, 14, 0(6), 0(16), 1, 0, 2, 0, 3, 4, 5, 0, 0, 0, 6, 7, 0, 0, 0, 0, 8, 15, 0(14), 0(16), 9, 10, 0(14), 11 !PARAMETER VALUES %CONSTINTEGER NONE=0, NONE AVAIL=1, NUMBER=2, ASTRING=3; !VALUE TYPE %CONSTINTEGER MODIFY=1, SELECT=0; !PARAMETER TYPE %CONSTINTEGER EQ=2, LE=3, NE=5, GE=6, ANY=7; !OPERATORS %CONSTSTRING(3)%ARRAY OP STR(0:7)= "=0 ", "=1 ", "EQ ", "LE ", "=4 ", "NE ", "GE ", "ANY" !PARAMETER NUMBERS %CONSTINTEGER P ID=0, MODE=1, CODE=2, FORMAT=3, MAPPING=4, RSIZE=5, TSIZE=6, DATA EST=7, T ID=8, PRIV TCODE=9, ACK WINDOW=16_0A, I REST=16_0B, MIN TOUT=16_0D, FACILITIES=16_0E, STATE=16_0F, DATA TYPE=16_20, DELIMITER=16_21, TEXT STOR=16_22, HORIZ TABS=16_23, BIN SIZE=16_24, MAX SREC=16_25, PAGE WID=16_26, PAGE LEN=16_27, PRIV SCODE=16_29, FILENAME=16_40, USERNAME=16_42, USER PASS=16_44, FILE PASS=16_45, KINSHIP=16_46, ACCOUNT=16_4A, ACC PASS=16_4B, OUTDEV=16_50 %CONSTINTEGER DEV TYPE=16_51, F SIZE=16_60, OPMESS=16_70, MON MESS=16_71, SPECIAL=16_80 %CONSTSTRING(10)%ARRAY PARAM STR(1:MAX PARAMS)= "PROTCL ID ", "MODE ", "TEXT CODE ", "FORMATTING", "BIN FORMAT", "MAX TRSIZE", "TRNS LIMIT", "TRANSFR ID", "ACK WINDOW", "INIT RSTRT", "MIN TIMOUT", "FACILITIES", "STATE OF T", "FILENAME ", "USERNAME ", "USER PASS ", "FILE PASS ", "KINSHIP ", "ACCOUNT ", "ACC PASS ", "OUTDEV TYP", "F SIZE ", "ACTN MESS ", "INFOR MESS", "SPECIAL OP", "DATA EST ", "PRIV TCODE", "DATA TYPE ", "DELIMITER ", "TEXT STORE", "HORIZ TABS", "BIN WDSIZE", "MAX SRECRD", "PAGE WIDTH", "PAGE LEN ", "PRIV SCODE", "DEV TYPE Q" !THESE ROUTINES ARE USED BY BOTH PROCESS P AND Q %EXTERNALROUTINE INIT PARAMS !=========================== !SET UP POINTER VARIABLES XCODE==PARAMETERS(PARNUM(CODE))_VALUE XMODE==PARAMETERS(PARNUM(MODE))_VALUE XFORMAT==PARAMETERS(PARNUM(FORMAT))_VALUE XMAPPING==PARAMETERS(PARNUM(MAPPING))_VALUE XRSIZE==PARAMETERS(PARNUM(RSIZE))_VALUE XTSIZE==PARAMETERS(PARNUM(TSIZE))_VALUE XTID==PARAMETERS(PARNUM(TID))_VALUE XTIMEOUT==PARAMETERS(PARNUM(MIN TOUT))_VALUE XFACILITIES==PARAMETERS(PARNUM(FACILITIES))_VALUE XSTATE==PARAMETERS(PARNUM(STATE))_VALUE XFSIZE==PARAMETERS(PARNUM(FSIZE))_VALUE !SET UP STRING VALUE ARRAY TO POINT TO GLOBAL SYMBOLS STRING VALUES(1)=ADDR(XFILENAME) STRING VALUES(2)=ADDR(XUSERNAME) STRING VALUES(3)=ADDR(XUSERPASS) STRING VALUES(4)=ADDR(XFILEPASS) STRING VALUES(5)=ADDR(XKINSHIP) STRING VALUES(6)=ADDR(XACCOUNT) STRING VALUES(7)=ADDR(XACCPASS) STRING VALUES(8)=ADDR(XOUTDEV) STRING VALUES(9)=ADDR(XOPMESS) STRING VALUES(10)=ADDR(XMONMESS) STRING VALUES(11)=ADDR(XSPECIAL) STRING VALUES(12)=ADDR(XPRIVTCODE) %END %EXTERNALROUTINE DEF PARAMS !=========================== !SET PARAMETER DEFAULTS,THOSE MARKED WITH A STAR ARE VALUES FOR 'TAKE' !BEING TRUE AND WILL BE RESET LATER IF NEED BE %INTEGER N STRING(STRING VALUES(N))="" %FOR N=1,1,MAX STRINGS %FOR N=0,1,MAX PARAM %CYCLE %CONTINUE %IF PARNUM(N)=0; !NO PARAMETER ASSIGNED TO THIS VALUE PARAMETERS(PARNUM(N))=0 PARAMETERS(PARNUM(N))_VALUE=STRNUM(N); !SAY WHICH STRING IS EQUIVALENT OR NONE %REPEAT PARAMETER=0 !FIRST [1F] QUALIFIERS PARAMETER_VTYPE=NONE AVAIL PARAMETER_TYPE=MODIFY PARAMETER_OPERATOR=ANY PARAMETERS(PARNUM(T SIZE))=PARAMETER !NEXT [2A] QUALIFIERS PARAMETER_VTYPE=NUMBER PARAMETER_OPERATOR=EQ ![2A] <0000> PARAMETERS(PARNUM(P ID))=PARAMETER PARAMETERS(PARNUM(P ID))_VALUE=0; !ERCC FTP ID NUMBER PARAMETERS(PARNUM(MODE))=PARAMETER PARAMETERS(PARNUM(T ID))=PARAMETER PARAMETERS(PARNUM(I REST))=PARAMETER PARAMETERS(PARNUM(STATE))=PARAMETER PARAMETERS(PARNUM(FSIZE))=PARAMETER ! [2A] VALUE <0008> PARAMETER_VALUE=8 PARAMETERS(PARNUM(MAPPING))=PARAMETER ! [2A] <0002> PARAMETER_VALUE=2 PARAMETERS(PARNUM(ACK WINDOW))=PARAMETER ![2A] <00FC> ![2A] <8002> PARAMETER_VALUE=16_8002 PARAMETERS(PARNUM(MODE))=PARAMETER ![AB] QUALIFIERS ![AB] <0000> PARAMETER_MONITOR=TRUE PARAMETER_OPERATOR=LE PARAMETER_VALUE=0 PARAMETERS(PARNUM(FACILITIES))=PARAMETER ![AB] <1001> PARAMETER_VALUE=16_1001 PARAMETERS(PARNUM(CODE))=PARAMETER ![AF] <0001> PARAMETER_VALUE=16_0001 PARAMETERS(PARNUM(FORMAT))=PARAMETER PARAMETERS(PARNUM(FORMAT))_OPERATOR=ANY ![AB] <0258> PARAMETER_VALUE=16_0258; !TEN MINUTES PARAMETERS(PARNUM(MIN TOUT))=PARAMETER ![AB] <0400> ![AB] <00FC> PARAMETER_VALUE=MAX DATA RECORD PARAMETERS(PARNUM(R SIZE))=PARAMETER ![32] QUALIFIERS ![32] <0000> PARAMETER_MONITOR=FALSE PARAMETER_VTYPE=ASTRING PARAMETER_TYPE=SELECT PARAMETER_OPERATOR=EQ PARAMETER_VALUE=0 PARAMETERS(PARNUM(FILENAME))=PARAMETER PARAMETERS(PARNUM(FILENAME))_VALUE=FILENAME PARAMETERS(PARNUM(USERNAME))=PARAMETER PARAMETERS(PARNUM(USERNAME))_VALUE=USERNAME PARAMETERS(PARNUM(USER PASS))=PARAMETER PARAMETERS(PARNUM(USER PASS))_VALUE=USER PASS PARAMETERS(PARNUM(FILE PASS))=PARAMETER PARAMETERS(PARNUM(FILE PASS))_VALUE=FILE PASS PARAMETERS(PARNUM(KINSHIP))=PARAMETER PARAMETERS(PARNUM(KINSHIP))_VALUE=KINSHIP PARAMETERS(PARNUM(ACCOUNT))=PARAMETER PARAMETERS(PARNUM(ACCOUNT))_VALUE=ACCOUNT PARAMETERS(PARNUM(ACC PASS))=PARAMETER PARAMETERS(PARNUM(ACC PASS))_VALUE=ACC PASS PARAMETERS(PARNUM(OUTDEV))=PARAMETER PARAMETERS(PARNUM(OUTDEV))_VALUE=OUTDEV XOUTDEV="LP" ![3A] QUALIFIERS PARAMETER_TYPE=MODIFY PARAMETERS(PARNUM(OPMESS))=PARAMETER PARAMETERS(PARNUM(OPMESS))_VALUE=OPMESS PARAMETERS(PARNUM(MON MESS))=PARAMETER PARAMETERS(PARNUM(MON MESS))_VALUE=MON MESS PARAMETERS(PARNUM(SPECIAL))=PARAMETER PARAMETERS(PARNUM(SPECIAL))_VALUE=SPECIAL !NOW FTP81 PARAMS PARAMETER_VTYPE=NONE PARAMETER_TYPE=SELECT PARAMETER_OPERATOR=ANY PARAMETER_MONITOR=FALSE PARAMETERS(PARNUM(DATA EST))=PARAMETER PARAMETERS(PARNUM(PRIV TCODE))=PARAMETER PARAMETERS(PARNUM(DATA TYPE))=PARAMETER PARAMETERS(PARNUM(DELIMITER))=PARAMETER PARAMETERS(PARNUM(TEXT STOR))=PARAMETER PARAMETERS(PARNUM(HORIZ TABS))=PARAMETER PARAMETERS(PARNUM(BIN SIZE))=PARAMETER PARAMETERS(PARNUM(MAX SREC))=PARAMETER PARAMETERS(PARNUM(PAGE WID))=PARAMETER PARAMETERS(PARNUM(PAGE LEN))=PARAMETER PARAMETERS(PARNUM(PRIV SCODE))=PARAMETER PARAMETERS(PARNUM(DEV TYPE))=PARAMETER %END %ROUTINE MONITOR PARAM(%INTEGER PARAM,QUALIFIER,VALUE) !====================================================== !OUTPUTS THE GIVEN PARAMETER TO THE LOG FILE %INTEGER OUT,TYPE,OP OUT=OUTSTREAM SELECT OUTPUT(LOG) SPACES(10) %IF PARNUM(PARAM)=0 %THEN WRITEHEX(PARAM,3) %ELSE PRINTSTRING(PARAM STR(PARNUM(PARAM))) SPACE %IF QUALIFIER>>7#0 %THEN PRINTSTRING("MON-") %ELSE SPACES(4) TYPE=QUALIFIER>>4&3; OP=QUALIFIER&7 PRINTSTRING(OP STR(OP)); PRINTSYMBOL('('); WRITEHEX(QUALIFIER,0); PRINTSYMBOL(')'); SPACE %IF TYPE=ASTRING %START PRINTSYMBOL('"') !A SPECIAL CASE FOR A STRING IN THE CURRENT PARAMETER BEING READ %IF VALUE=0 %THEN PRINTSTRING(THIS STRING) %ELSE PRINTSTRING(STRING(STRING VALUES(VALUE))) PRINTSYMBOL('"') %ELSE %IF TYPE=NUMBER %START WRITEHEX(VALUE,2); PRINTSYMBOL('='); WRITE(VALUE,0) %ELSEIF TYPE=NONE %START PRINTSTRING("ATR. UNKN.") %ELSE PRINTSTRING("NONE AVL.") NEWLINE SELECT OUTPUT(OUT) %END %EXTERNALROUTINE PUT0 PARAMS !=========================== !PUTS ALL PARAMETERS WITH THE 'OUT' ITEM SET TO TRUE, INTO THE OUTPUT BUFFER %RECORD(PARAMETER RECORD)%NAME P %STRING(255) STR %INTEGER N,M,NUM,QUALIFIER NUM=0 %FOR N=1,1,MAX PARAMS %CYCLE %IF PARAMETERS(N)_OUT=TRUE %START NUM=NUM+1; !COUNT PARAMETERS TO BE OUTPUT %FINISH %REPEAT PUT0(NUM) %RETURN %IF NUM=0 %IF LOGLEVEL>=20 %THEN LOGIT("Outgoing parameters") %FOR N=0,1,MAX PARAM %CYCLE %CONTINUE %IF PARNUM(N)=0; !PARAMETER NOT PRESENT %IF PARAMETERS(PARNUM(N))_OUT=TRUE %START P==PARAMETERS(PARNUM(N)) PUT0(N); !PARAMETER NUMBER QUALIFIER=(P_MONITOR<<7!P_VTYPE<<4!P_TYPE<<3!P_OPERATOR)&16_FF PUT0(QUALIFIER) %IF P_VTYPE=ASTRING %START STR=STRING(STRING VALUES(STR NUM(N))) P_VALUE=STR NUM(N) %IF LENGTH(STR)>0 %START PUT0(LENGTH(STR)) PUT0(CHARNO(STR,M)) %FOR M=1,1,LENGTH(STR) %ELSE PUT0(0) %ELSE %IF P_VTYPE=NUMBER %THEN PUT0(P_VALUE>>8) %AND PUT0(P_VALUE) %IF LOGLEVEL>=20 %THEN MONITOR PARAM(N,QUALIFIER,P_VALUE) %FINISH %REPEAT %IF LOGLEVEL>=20 %THEN LOGIT("") %END %ROUTINE READ PARAMETER !====================== !READS A SINGLE PARAMETER FROM THE INPUT BUFFER INTO THE GLOBAL RECORD !'PARAMETER' AND USES GLOBALS 'THIS PARAMETER' AND 'THIS STRING' ALSO %INTEGER QUALIFIER,N,M,S 1: PARAMETER=0 GET0(THIS PARAMETER) GET0(QUALIFIER) %IF QUALIFIER>>7 # 0 %THEN PARAMETER_MONITOR=TRUE %ELSE PARAMETER_MONITOR=FALSE PARAMETER_VTYPE=QUALIFIER>>4&3 PARAMETER_TYPE=QUALIFIER>>3&1 PARAMETER_OPERATOR=QUALIFIER&7 THIS STRING="" %IF PARAMETER_VTYPE=ASTRING %START GET0(N); !STRING LENGTH %IF N>0 %START %FOR M=1,1,N %CYCLE GET0(S); THIS STRING=THIS STRING.TOSTRING(S&8_177) %REPEAT %FINISH %ELSE %IF PARAMETER_VTYPE=NUMBER %START GET0(PARAMETER_VALUE); GET0(N) PARAMETER_VALUE=PARAMETER_VALUE<<8!N %ELSE PARAMETER_VALUE=0 %FINISH %IF PARNUM(THIS PARAMETER)=0 %START LOGIT("Unknown parameter read and ignored - see next line") MONITOR PARAM(THIS PARAMETER,QUALIFIER,PARAMETER_VALUE) ->1 %FINISH %IF LOGLEVEL>=20 %THEN MONITOR PARAM(THIS PARAMETER,QUALIFIER,PARAMETER_VALUE) %END %EXTERNALROUTINE SKIP PARAMS !=========================== !THIS ROUTINE THROWS AWAY THE PARAMETERS FOR A LEVEL 0 MESSAGE %INTEGER N,NUM GET0(NUM) %RETURN %IF NUM=0 %IF LOGLEVEL>=20 %THEN LOGIT("with ignored parameters") READ PARAMETER %FOR N=1,1,NUM %IF LOGLEVEL>=20 %THEN LOGIT("") %END !ROUTINES FOR 'P' PROCESS ONLY %ROUTINE CHECK PARAM !=================== !CHECKS THE SETTINGS OF THE 'VALUE' ITEM OF THE CURRENT PARAMETER READ !AND SETS THE 'OK' ITEM TO EITHER TRUE OR FALSE. %SWITCH P(0:MAX PARAM) %RECORD(PARAMETER RECORD)%NAME PAR PAR==PARAMETERS(PARNUM(THIS PARAMETER)) PAR_IN=TRUE %IF PARAMETER_MONITOR=TRUE %START PAR_OK=FALSE PAR==PARAMETERS(PARNUM(STATE)) PAR_VALUE=16_1002; PAR_OUT=TRUE %RETURN %FINISH %IF PAR_MONITOR=TRUE %AND PARAMETER_VALUE=PAR_VALUE %START PAR_OK=TRUE %RETURN %FINISH ->P(THIS PARAMETER) P(P ID): PAR_OK=TRUE; !ACCEPT ANY VALUE %RETURN P(MODE): %IF PAR_VALUE#XMODE %THEN PAR_OK=FALSE %ELSE PAR_OK=TRUE %RETURN P(CODE): %IF PARAMETER_VALUE=16_1001 %OR PARAMETER_VALUE=2 %OR PARAMETER_VALUE=1 %OR PARAMETER_VALUE=8 %START %IF XMODE&16_8000=0 %AND PAR_VALUE#XCODE %START PAR_OPERATOR=EQ PAR_OK=FALSE %ELSE PAR_VALUE=PARAMETER_VALUE PAR_OK=TRUE %FINISH %ELSE PAR_OK=FALSE %FINISH %RETURN P(FORMAT): %IF PARAMETER_VALUE&16_CFFC#0 %START %IF (PARAMETER_VALUE&16_1000#0 %AND PARAMETER_VALUE&16_10=0) %OR %C (PARAMETER_VALUE&16_2000#0 %AND PARAMETER_VALUE&16_20=0) %THEN PAR_OK=FALSE %ELSE %C PAR_VALUE=PARAMETER_VALUE %AND PAR_OK=TRUE %ELSE%IF PARAMETER_VALUE<=3 %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %ELSE PAR_OK=FALSE %RETURN P(MAPPING): %IF PARAMETER_VALUE=16_0024 %START PAR_VALUE=PARAMETER_VALUE PAR_OK=TRUE %ELSE PAR_OK=FALSE %RETURN P(RSIZE): %IF PARAMETER_VALUE<=MAX DATA RECORD %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %ELSE PAR_VALUE=MAX DATA RECORD %IF PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY %THEN PAR_OK=TRUE %ELSE PAR_OK=FALSE %FINISH %RETURN P(TSIZE): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %RETURN P(T ID): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %RETURN P(ACK WINDOW): P(I REST): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %RETURN P(MIN TOUT): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE SETTIM(XTIMEOUT) %RETURN P(FACILITIES): %IF PARAMETER_VALUE<=1 %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %ELSEIF PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY %START PAR_VALUE=1; PAR_OK=TRUE %ELSE PAR_VALUE=1 %AND PAR_OK=FALSE %RETURN P(STATE): %IF PARAMETER_VALUE#0 %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=FALSE %ELSE PAR_OK=TRUE %RETURN P(FILENAME): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE; !MAIL RETURNS FILENAME %RETURN P(USERNAME): P(USERPASS): P(FILEPASS): P(KINSHIP): P(ACCOUNT): P(ACCPASS): PAR_OK=FALSE %RETURN P(OUTDEV): XOUTDEV=THIS STRING; PAR_OK=TRUE %RETURN P(FSIZE): PAR_VALUE=PARAMETER_VALUE PAR_OK=TRUE %RETURN P(OPMESS): XOPMESS=THIS STRING PAR_OK=TRUE REPRT(XOPMESS) %IF LOGLEVEL>=20 %THEN LOGIT("") LOGIT(XOPMESS) %RETURN P(MONMESS): XMONMESS=THIS STRING; PAR_OK=TRUE REPRT(XMONMESS) %IF LOGLEVEL>=20 %THEN LOGIT("") LOGIT(XMONMESS) %RETURN P(SPECIAL): XSPECIAL=THIS STRING PAR_OK=FALSE %RETURN P(PRIV TCODE): XPRIVTCODE=THIS STRING %IF THIS STRING="36BIT" %THEN PAR_OK=TRUE %ELSE PAR_OK=FALSE %RETURN P(*):PAR_MONITOR=FALSE; PAR_VTYPE=NONE; PAR_OPERATOR=ANY; PAR_OK=TRUE %END %EXTERNALROUTINE SET P PARAMS !============================ !SET REST OF PARAMETERS DEPENDANT ON WHETHER 'TAKE' OR 'GIVE' %STRING(12) TYPE %INTEGER N PARAMETER=0 %IF BINARY FILE=TRUE %AND XPRIV TCODE="" %START; !BINARY MODE - BUT NOT SPECIAL XCODE=2 PARAMETERS(PARNUM(MAPPING))_VALUE=16_0024 PARAMETERS(PARNUM(MAPPING))_OUT=TRUE %FINISH %IF XMODE&16_8000=0 %START; !ON A TAKE PARAMETERS(PARNUM(TSIZE))_OUT=TRUE %IF XTSIZE#0 PARAMETERS(PARNUM(FSIZE))_OUT=TRUE %IF XFSIZE#0 %AND (ISNODE(XOTHERNODE,TYPE,N) %AND TYPE#"IBM") %FINISH !* PARAMETERS(PARNUM(P ID))_OUT=TRUE PARAMETERS(PARNUM(MODE))_OUT=TRUE PARAMETERS(PARNUM(CODE))_OUT=TRUE PARAMETERS(PARNUM(FORMAT))_OUT=TRUE %IF XPRIV TCODE="" %AND BINARY FILE=FALSE; !IF NOT SPECIAL PARAMETERS(PARNUM(RSIZE))_OUT=TRUE XTIMEOUT=60; !ONE MINUTE PARAMETERS(PARNUM(MIN TOUT))_OUT=TRUE PARAMETERS(PARNUM(FACILITIES))_VALUE=1; !COMPRESSION PARAMETERS(PARNUM(FACILITIES))_OUT=TRUE PARAMETERS(PARNUM(FILENAME))_OUT=TRUE %IF XFILENAME#"" PARAMETERS(PARNUM(FILEPASS))_OUT=TRUE %IF XFILEPASS#"" PARAMETERS(PARNUM(ACCOUNT))_OUT=TRUE %IF XACCOUNT#"" PARAMETERS(PARNUM(ACCPASS))_OUT=TRUE %IF XACCPASS#"" PARAMETERS(PARNUM(USERNAME))_OUT=TRUE %IF XUSERNAME#"" PARAMETERS(PARNUM(USERPASS))_OUT=TRUE %IF XUSERPASS#"" %IF XPRIV TCODE#"" %START PARAMETERS(PARNUM(PRIV TCODE))_VTYPE=ASTRING PARAMETERS(PARNUM(PRIV TCODE))_TYPE=SELECT PARAMETERS(PARNUM(PRIV TCODE))_OPERATOR=EQ PARAMETERS(PARNUM(PRIV TCODE))_OUT=TRUE %FINISH PARAMETERS(PARNUM(OUTDEV))_OUT=TRUE %IF XMODE&16_4000#0; !SPOOLED OUTPUT %END %EXTERNALPREDICATE P PARAM OK !============================ !TRUE IF ALL RECEIVED PARAMETERS ARE OK ON AN 'RPOS' FROM Q %RECORD(PARAMETER RECORD)%NAME P %INTEGER N,RESULT,PARAM COUNT GET0(PARAM COUNT) %TRUE %IF PARAM COUNT=0 %IF LOGLEVEL>=20 %THEN LOGIT("with incoming parameters") %FOR N=1,1,PARAM COUNT %CYCLE READ PARAMETER CHECK PARAM %REPEAT !NOW CHECK THEY ARE ALL OK RESULT=TRUE %FOR N=1,1,MAX PARAMS %CYCLE P==PARAMETERS(N) %IF (P_IN %AND %NOT P_OK) %OR ( (P_OUT %AND P_MONITOR) %AND %NOT P_IN) %START RESULT=FALSE P_OUT=TRUE %ELSE P_OUT=FALSE %AND P_MONITOR=FALSE %REPEAT %IF XCODE=2 %AND XMAPPING#16_0024 %START PARAMETERS(PARNUM(STATE))_VALUE=16_1002 %IF PARAMETERS(PARNUM(STATE))_VALUE=0 PARAMETERS(PARNUM(STATE))_OUT=TRUE PARAMETERS(PARNUM(CODE))_OUT=TRUE PARAMETERS(PARNUM(MAPPING))_OUT=TRUE RESULT=FALSE %FINISH %IF XCODE#8 %THEN XPRIV TCODE=""; !CLEAR PRIVATETE CODE IF NOT RELEVANT %IF LOGLEVEL>=20 %THEN LOGIT("") %TRUE %IF RESULT=TRUE %FALSE %END !NOW ROUTINES FOR 'Q' PROCESS ONLY %EXTERNALPREDICATE GET Q PARAMS !=============================== !GETS THE PARAMETERS FOR Q ON AN 'SFT' FROM P AND SETS 'OK' ITEM !ACCORDING TO THE 'VALUE' ITEM RECEIVED. SUBSEQUENTLY IT SETS THE !'OUT' ITEM IF MONITORING WAS REQUESTED OR A PARAMETER WAS NOT 'OK' %SWITCH P(0:MAX PARAM) %RECORD(PARAMETER RECORD)%NAME PAR %INTEGER N,PARAMETER COUNT,TAKE,OK,SAVCODE %STRING(20) S,T %STRING(4) EXT GET0(PARAMETER COUNT) %IF PARAMETER COUNT=0 %THEN %FALSE %IF LOGLEVEL>=20 %THEN LOGIT("Incoming parameters") %FOR N=1,1,PARAMETER COUNT %CYCLE READ PARAMETER PAR==PARAMETERS(PARNUM(THIS PARAMETER)) PAR_IN=TRUE; PAR_MONITOR=PARAMETER_MONITOR; PAR_VTYPE=PARAMETER_VTYPE PAR_TYPE=PARAMETER_TYPE; PAR_OPERATOR=PARAMETER_OPERATOR %IF PAR_VTYPE=NONE AVAIL %START PAR_OK=TRUE %CONTINUE %FINISH ->P(THIS PARAMETER) P(P ID): %IF PARAMETER_VALUE>16_FF %THEN FTP81=TRUE %ELSE FTP81=FALSE PAR_OK=TRUE %CONTINUE P(MODE): %IF PARAMETER_VALUE&16_8000=0 %THEN TAKE=TRUE %ELSE TAKE=FALSE PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE; !LET 'LEGAL ACCESS' ROUTINE CHECK VALIDITY LATER !HERE TO ADD REST OF DEFAULT PARAMETERS ON A TAKE=FALSE %IF PAR_OK=TRUE %AND TAKE=FALSE %START PARAMETER=0 ! [2B] <0400> PARAMETER_VTYPE=NUMBER !* PARAMETER_TYPE=MODIFY PARAMETER_MONITOR=FALSE PARAMETER_OPERATOR=LE PARAMETER_VALUE=16_0400 PARAMETERS(PARNUM(T SIZE))=PARAMETER %IF PARAMETERS(PARNUM(T SIZE))_IN=FALSE ![2B] <00FC> PARAMETER_VALUE=MAX DATA RECORD PARAMETERS(PARNUM(R SIZE))=PARAMETER %IF PARAMETERS(PARNUM(R SIZE))_IN=FALSE %FINISH %CONTINUE P(CODE): %IF PARAMETER_VALUE=16_1001 %OR PARAMETER_VALUE=2 %OR PARAMETER_VALUE=1 %OR PARAMETER_VALUE=8 %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %ELSEIF (PARAMETER_OPERATOR=LE %AND PARAMETER_VALUE>=1) %START PAR_VALUE=(PARAMETER_VALUE&16_1000)!1; PAR_OK=TRUE %ELSE PAR_OK=FALSE PAR_OUT=TRUE %CONTINUE P(FORMAT): %IF PARAMETER_VALUE&16_CFFC=0 %START %IF (PARAMETER_VALUE&16_1000#0 %AND PARAMETER_VALUE&16_10=0) %OR %C (PARAMETER_VALUE&16_2000#0 %AND PARAMETER_VALUE&16_20=0) %START PAR_OK=FALSE %ELSE !* %IF PARAMETER_TYPE=MODIFY %AND (PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY) %START %IF PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY %START %IF PARAMETER_VALUE&2#0 %THEN PAR_VALUE=2 %ELSE PAR_VALUE=1; !USE FORTRAN FORMATTING IF POSSIBLE %IF PAR_VALUE=2 %AND FTP81=FALSE %THEN PAR_VALUE=3; !BACK COMPATIBILITY %ELSE PAR_VALUE=PARAMETER_VALUE %FINISH PAR_OK=TRUE %FINISH !* %ELSEIF PARAMETER_TYPE=MODIFY %AND (PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY) %START %ELSEIF PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY %START %IF PARAMETER_VALUE&2#0 %THEN PAR_VALUE=2 %ELSE PAR_VALUE=1; !USE FORTRAN FORMATTING IF POSSIBLE %IF PAR_VALUE=2 %AND FTP81=FALSE %THEN PAR_VALUE=3; !BACK COMPATIBILITY PAR_OK=TRUE %ELSE%IF PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY %START %IF PARAMETER_VALUE>2 %THEN PAR_VALUE=2 %ELSE PAR_VALUE=PARAMETER_VALUE %IF PAR_VALUE=2 %AND FTP81=FALSE %THEN PAR_VALUE=3; !BACK COMPATIBILITY PAR_OK=TRUE %ELSEIF PARAMETER_OPERATOR=EQ %AND PARAMETER_VALUE=16_80 %AND FTP81=TRUE %START PAR_VALUE=PARAMETER_VALUE PAR_OK=TRUE %ELSE PAR_OK=FALSE PAR_OUT=TRUE %CONTINUE P(MAPPING): %IF PARAMETER_VALUE=16_0024 %OR PARAMETER_VALUE=16_4001 %START PAR_VALUE=PARAMETER_VALUE PAR_OK=TRUE %ELSE PAR_OK=FALSE %FINISH %CONTINUE P(RSIZE): %IF PARAMETER_VALUE<=MAX DATA RECORD %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %ELSE PAR_VALUE=MAX DATA RECORD %IF PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY %THEN PAR_OK=TRUE %ELSE PAR_OK=FALSE %FINISH PAR_OUT=TRUE %CONTINUE P(TSIZE): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %CONTINUE P(T ID): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %CONTINUE P(ACK WINDOW): P(I REST): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE; !JUST IGNORE PARAMETER %CONTINUE P(MIN TOUT): PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE SETTIM(XTIMEOUT) %CONTINUE P(FACILITIES): %IF PARAMETER_VALUE<=1 %AND (PARAMETER_OPERATOR=EQ) %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=TRUE %ELSEIF PARAMETER_OPERATOR=LE %OR PARAMETER_OPERATOR=ANY %START %IF PARAMETER_VALUE&1=1 %THEN PAR_VALUE=1 %ELSE PAR_VALUE=0 PAR_OK=TRUE %ELSE PAR_VALUE=1 %AND PAR_OK=FALSE PAR_OUT=TRUE %CONTINUE P(STATE): %IF PARAMETER_VALUE#0 %START PAR_VALUE=PARAMETER_VALUE; PAR_OK=FALSE %ELSE PAR_OK=TRUE %CONTINUE P(FILENAME): XFILENAME=THIS STRING PAR_OK=TRUE %CONTINUE P(ACCOUNT): XACCOUNT=THIS STRING PAR_OK=TRUE %CONTINUE P(USERNAME): XUSERNAME=THIS STRING PAR_OK=TRUE %CONTINUE P(USERPASS): XUSERPASS=THIS STRING PAR_OK=TRUE %CONTINUE P(ACCPASS): XACCPASS=THIS STRING PAR_OK=TRUE %CONTINUE P(FILEPASS): XFILEPASS=THIS STRING PAR_OK=TRUE %CONTINUE P(KINSHIP): XKINSHIP=THIS STRING PAR_OK=TRUE %CONTINUE P(OUTDEV): XOUTDEV=THIS STRING PAR_OK=TRUE %CONTINUE P(FSIZE): PAR_VALUE=PARAMETER_VALUE PAR_OK=TRUE %CONTINUE P(OPMESS): XOPMESS=THIS STRING PAR_OK=TRUE XOPMESS=XOTHER NODE." sent operator message ".XOPMESS REPRT(XOPMESS) %IF LOGLEVEL>=20 %THEN LOGIT("") LOGIT(XOPMESS) %CONTINUE P(MONMESS): XMONMESS=THIS STRING PAR_OK=TRUE XMONMESS=XOTHER NODE." sent monitor message ".XMONMESS REPRT(XMONMESS) %IF LOGLEVEL>=20 %THEN LOGIT("") LOGIT(XMONMESS) %CONTINUE P(SPECIAL): XSPECIAL=THIS STRING PAR_OK=FALSE %CONTINUE P(PRIV TCODE): UPPER CASE(THIS STRING) XPRIV TCODE=THIS STRING PAR_OK=TRUE %CONTINUE P(*): PAR_MONITOR=TRUE; PAR_OPERATOR=ANY; PAR_VTYPE=NONE PAR_OK=TRUE %CONTINUE !* PAR==PARAMETERS(PARNUM(STATE)) !* XMONMESS="Invalid parameter" !* PAR_VALUE=16_1001; PAR_OK=FALSE %REPEAT %IF XCODE&9#0 %THEN PARAMETERS(PARNUM(MAPPING))_OK=TRUE; !DO NOT FAULT BIN PARAM !NOW MARK FOR OUTPUT, THOSE WHICH ARE WRONG OR NEED MONITORED OK=TRUE %FOR N=1,1,MAX PARAMS %CYCLE PAR==PARAMETERS(N) %IF (PAR_IN %AND (PAR_MONITOR %OR %NOT PAR_OK)) %OR PAR_OUT=TRUE %START PAR_OUT=TRUE; PAR_MONITOR=FALSE; PAR_OPERATOR=EQ %UNLESS PAR_VTYPEFAIL %FINISH %IF XMODE=16_4001 %START; !OUTPUT TO A DEVICE XOUTDEV="LP" %IF XOUTDEV="" XUSERNAME="JOB OUTPUT" %IF XUSERNAME="" XACCOUNT=XUSERNAME %IF XACCOUNT="" ! EXT=".IBM" ! %IF XOUTDEV="LP" %AND XUSERNAME="DSPL" %START; !**MAKE DL OUTPUT SAME AS RAL OUTPUT ! XOUTDEV="D60"; EXT=".TSO" ! %FINISH ! %IF XOUTDEV="D60" %START; !**SPECIAL FOR IBM OUTPUT ! XACCOUNT="RJE OUTPUT" ! %CYCLE ! XFILENAME="D60:".INTTOSTR(UNIQUE(6)).EXT ! %REPEAT %UNTIL %NOT ISFILE(XFILENAME) ! %FINISH %IF XFILENAME#"" %START; !GUARD AGAINST SILLY FILENAMES FS=STRTOFS(XFILENAME); XFILENAME=FSTOSTR(FS) %FINISH %IF XFILENAME="" %OR FS_FILE="" %START %CYCLE XFILENAME=QDEV.":".INTTOSTR(UNIQUE(6)) %IF LENGTH(XOUTDEV)>0 %START XFILENAME=XFILENAME."." %IF LENGTH(XOUTDEV)>3 %START XFILENAME=XFILENAME.SUBSTRING(XOUTDEV,1,3) %ELSE XFILENAME=XFILENAME.XOUTDEV %FINISH %FINISH XFILENAME=XFILENAME."[3,3]" %REPEAT %UNTIL %NOT ISFILE(XFILENAME) %FINISH %FINISH %IF ARPA MAIL=TRUE %OR %C (XMODE&1=1 %AND XFILENAME="" %AND PARAMETERS(PARNUM(FILENAME))_VTYPE=NONE AVAIL) %OR %C XFILENAME="...MAIL" %START ARPA MAIL=TRUE; !ARPA TYPE MAIL ENTRY %ELSE ARPA MAIL=FALSE %IF ARPA MAIL=TRUE %OR XOUTDEV="POST" %START; !**SPECIAL FOR NETWORK MAIL** !* %IF XOURNODE="UMIST" %START !* XMONMESS="NETWORK MAIL NOT SUPPORTED ON ".XOURNODE !* XSTATE=16_1001 !* ->FAIL !* %FINISH %IF XUSERNAME->S.(":").T %AND T="" %START XFILENAME=XUSERNAME %ELSE XFILENAME=QDEV.":".INTTOSTR(UNIQUE(6)).".MAI[3,5]" %UNTIL %NOT ISFILE(XFILENAME) PARAMETERS(PARNUM(FILENAME))_OUT=TRUE; !TELL P WHAT I AM USING %FINISH XACCOUNT="MAIL" XUSERNAME=XACCOUNT %IF XUSERNAME="" %%ELSE%IF XUSERNAME="" %OR XFILENAME="" %START XMONMESS="must supply FILENAME and USERNAME parameters" XSTATE=16_1001; ->FAIL %FINISH XACCOUNT=XUSERNAME %IF XACCOUNT="" !ENSURE ALL CHANGED STRING PARAMS HAVE THE TYPE SET PROPERLY %IF XFILENAME#"" %THEN PARAMETERS(PARNUM(FILENAME))_VTYPE=ASTRING %IF XUSERNAME#"" %THEN PARAMETERS(PARNUM(USERNAME))_VTYPE=ASTRING %IF XACCOUNT#"" %THEN PARAMETERS(PARNUM(ACCOUNT))_VTYPE=ASTRING %IF XOUTDEV#"" %THEN PARAMETERS(PARNUM(OUTDEV))_VTYPE=ASTRING SAVCODE=XCODE; !SAVE CURRENT ACCESS MODE FOR LATER %UNLESS LEGAL ACCESS(XFILENAME,XMODE,XACCOUNT,XUSERNAME,XUSERPASS) %START PAR==PARAMETERS(PARNUM(STATE)); PAR_OUT=TRUE; PAR_OK=FALSE %IF PAR_VALUE=0 %THEN PAR_VALUE=16_1012 OK=FALSE %FINISH %IF XCODE#SAVCODE %START PAR==PARAMETERS(PARNUM(CODE)) !* PAR_TYPE=MODIFY PAR_OUT=TRUE; PAR_OK=FALSE OK=FALSE %FINISH %IF XFSIZE#0 %AND TAKE=FALSE %START PAR==PARAMETERS(PARNUM(FSIZE)) PAR_OPERATOR=EQ PAR_OK=TRUE; PAR_OUT=TRUE %FINISH %IF XCODE=8 %START %UNLESS XPRIV TCODE="36BIT" %START PARAMETERS(PARNUM(PRIV TCODE))_OK=FALSE XMONMESS="The supplied private code is not supported on DEC-10" OK=FALSE %FINISH %ELSE XPRIV TCODE="" %IF XCODE&3=2 %START BINARY FILE=TRUE %IF 16_4001#XMAPPING#16_0024 %START; !GET MAPPING RIGHT PARAMETERS(PARNUM(CODE))_OK=FALSE XMONMESS="Only 36 bit binary code supported on DEC-10" PAR==PARAMETERS(PARNUM(MAPPING)) PAR_VALUE=16_0024 !* PAR_TYPE=MODIFY PAR_OUT=TRUE; PAR_OK=FALSE OK=FALSE %FINISH %ELSE BINARY FILE=FALSE PAR==PARAMETERS(PARNUM(RSIZE)) %IF PAR_IN=FALSE %START; !TELL P WHAT WE ARE USING PAR_OK=TRUE; PAR_OUT=TRUE; PAR_OPERATOR=EQ; PAR_MONITOR=FALSE %FINISH %TRUE %IF OK=TRUE FAIL: %FOR N=1,1,MAX PARAMS %CYCLE PAR==PARAMETERS(N) %IF PAR_OUT %START %IF PAR_OK %START; !DO NOT OUTPUT AN OK PARAMETER -I.E. NO MONITORING ON AN 'RNEG' PAR_OUT=FALSE %ELSE %IF XMONMESS="" %START XMONMESS="Unacceptable parameter value: parameter ".PARAM STR(N) XMONMESS=XMONMESS." operator ".OP STR(PAR_OPERATOR)." value " %IF PAR_VTYPE=ASTRING %START XMONMESS=XMONMESS.STRING(STRING VALUES(PAR_VALUE)) %ELSEIF PAR_VTYPE=NUMBER %START XMONMESS=XMONMESS.HEXTOSTR(PAR_VALUE) %FINISH %FINISH %FINISH PAR_MONITOR=FALSE PAR_OPERATOR=EQ %FINISH %REPEAT PAR==PARAMETERS(PARNUM(STATE)) PAR_VALUE=16_1002 %IF PAR_VALUE=0 PAR_OUT=TRUE XMONMESS="Unacceptable parameter value" %IF XMONMESS="" PARAMETERS(PARNUM(MONMESS))_OUT=TRUE %FALSE %END %EXTERNALROUTINE PRIVATE CODE !============================ !THIS SETS UP THE CODES WE KNOW ABOUT %RETURN %IF XCODE#8 %IF XPRIV TCODE="36BIT" %START XCODE=2 XMAPPING=16_4001 BINARY FILE=TRUE %FINISH %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& FSTORE.IMP !FSTORE.IMP ! COPYRIGHT K.FARVIS ERCC. !This file includes the DEC-10 filestore interface for FTPSPL %INCLUDE "IMP:IOLIB.INC" %CONSTINTEGER TRUE=-1, FALSE=0 !THE FOLLOWING ROUTINE IS FOR PUTTING STUFF IN THE GALAXY %EXTERNALROUTINESPEC QUEUE(%STRING(70) FSPEC, %STRING(12) JOB,USER,DEVICE,%INTEGER PPN,SIZE,LIMIT,DISPOSE,LOG,%STRING(1)%NAME MESS) !ROUTINE TO SET UP SEARCH LIST %EXTERNALPREDICATESPEC SETSRC(%INTEGER PPN) %EXTERNALINTEGERFNSPEC GET TIME %EXTERNALINTEGERFNSPEC GETNOW %EXTERNALINTEGERSPEC OPRPRV %EXTERNALINTEGER CNTRLC ; !TO DISABLE CNTRL C INTERRUPTS %EXTERNALROUTINESPEC DELETE(%STRING(255) FILE) %EXTERNALROUTINESPEC READFS(%RECORD(FILESPEC)%NAME FS) %EXTERNALINTEGERFNSPEC MATCH(%STRING(1)%NAME S,%STRING(255) T) %EXTERNALPREDICATESPEC SWITCH ARG(%STRING(1)%NAME S,%STRING(11) T,%NAME X) %EXTERNALINTEGERFNSPEC STRTOSIX(%STRING(6) STR) %EXTERNALRECORD(FILESPEC)%FNSPEC STRTOFS(%STRING(255) STR) %EXTERNALSTRING(255)%FNSPEC FSTOSTR(%RECORD(FILESPEC)%NAME FS) %EXTERNALSTRING(12)%FNSPEC OCTTOSTR(%INTEGER N) %EXTERNALINTEGERFNSPEC STRTOOCT(%STRING(1)%NAME S) %EXTERNALROUTINESPEC UPPER CASE(%STRING(1)%NAME S) %EXTERNALROUTINESPEC RESET OUTPUT %EXTERNALSTRING(6)%FNSPEC SIXTOSTR(%INTEGER N) %EXTERNALPREDICATESPEC CALLI2(%INTEGER N,%INTEGERNAME AC) %EXTERNALSTRING(9)%FNSPEC HEXTOSTR(%INTEGER N) %EXTERNALSTRING(12)%FNSPEC INTTOSTR(%INTEGER N) %EXTERNALSTRING(18)%FNSPEC DATETIME %EXTERNALSTRING(9)%FNSPEC DATE %EXTERNALSTRING(8)%FNSPEC TIME %EXTERNALINTEGERFNSPEC GET DATE %EXTERNALPREDICATESPEC ISNODE(%STRING(1)%NAME NAME,TYPE %INTEGERNAME STATUS) %INTEGERFNSPEC ERSATZ(%STRING(1)%NAME S) %EXTERNALSTRING(255)%SPEC ERRMSG %EXTERNALINTEGERSPEC I AM P %EXTERNALINTEGERSPEC ARPA MAIL %EXTERNALSTRING(96)%SPEC LOGFILE %EXTERNALINTEGERSPEC LOGLEVEL %EXTERNALSTRING(96)%SPEC XMONMESS %EXTERNALSTRING(96)%SPEC XFILENAME %EXTERNALSTRING(20)%SPEC XOURACCOUNT %EXTERNALSTRING(20)%SPEC XACCOUNT %EXTERNALSTRING(20)%SPEC XUSERNAME %EXTERNALSTRING(20)%SPEC XOUTDEV %EXTERNALINTEGERNAMESPEC XFSIZE %EXTERNALINTEGERNAMESPEC XCODE %EXTERNALINTEGERNAMESPEC XMODE %EXTERNALINTEGERSPEC YMODE %EXTERNALINTEGERNAMESPEC XSTATE %EXTERNALINTEGERSPEC XOURPPN %EXTERNALSTRING(20)%SPEC XOUR NODE %EXTERNALSTRING(255)%SPEC XOTHER NODE %EXTERNALSTRING(255)%SPEC XREMOTE NAME %EXTERNALSTRING(6)%SPEC QDEV %EXTERNALINTEGERSPEC QUFD !STREAM NUMBERS %CONSTINTEGER TTY=1, LOG=3,TEMP=8 %CONSTINTEGER MFD=8_1 000001, OPR PPN=8_1 000002 %CONSTSTRING(8) DEC10="DEC10", IBM="IBM"; !NODE TYPE %ROUTINESPEC LOGIT(%STRING(255) STR) %OWNINTEGER LAST DATE=0 %ROUTINE NEWLINE !=============== !TO AVOID DOUBLE IN FILES PRINTSYMBOL(NL) %END %EXTERNALROUTINE REPRT(%STRING(255) STRING) !==================================== !A fancy printstring routine *8_047040 000034; !GETLIN 1, %IF AC(1)>>18=0 %THEN PRINTSTRING("FTP - "); !IF DETACHED PRINTSTRING(STRING); NEWLINE %END %EXTERNALSTRING(15)%FN PPNTOSTR(%INTEGER PN) !=========================================== !converts a ppn to a string %RESULT="[".OCTTOSTR(PN>>18).",".OCTTOSTR(PN&8_777777)."]" %END %EXTERNALINTEGERFN PPNTOOCT(%STRING(20) PPN STR) !============================================== !converts a string with the form [p,pn] to an octal number %STRING(20) DUMMY,PROJ,PROG %INTEGER IN %ON %EVENT 3 %START SELECT INPUT(IN) %RESULT=0 %FINISH IN=INSTREAM %IF PPN STR->DUMMY.("[").PPN STR %START; %FINISH; !BE TOLERANT OF NO BRACKETS %IF PPN STR->PPNSTR.("]").DUMMY %START; %FINISH %IF PPN STR->PROJ.(",").PROG %START; !A PROPER PAIR %RESULT=STRTOOCT(PROJ)<<18!STRTOOCT(PROG) %ELSE %RESULT=STRTOOCT(PPNSTR); !ELSE ASSUME AN OCTAL NUMBER %END %EXTERNALROUTINE PARSE DEVICE(%STRING(1)%NAME DEVICE,DEV %INTEGERNAME NODE,NUM) !=============================================================================== !TAKE A DEVICE SPEC 'DEVNNM' AND PARSE IT INTO PARAMETERS %INTEGER N,L,S DEV=""; NODE=0; NUM=0; !DEFAULTS L=LENGTH(DEVICE) %RETURN %IF L=0 %FOR N=1,1,L %CYCLE S=CHARNO(DEVICE,N) ->NODE FOUND %UNLESS 'A'<=S<='Z' DEV=DEV.TOSTRING(S) %REPEAT %RETURN NODE FOUND: %IF L-N>0 %START N=N+1 NODE=(S-'0')*8+CHARNO(DEVICE,N)-'0' %RETURN %IF N=L S=CHARNO(DEVICE,N+1) %FINISH NUM=S-'0' %END %EXTERNALINTEGERFN DEVTYPE(%STRING(6) DEV) !================================= !Returns the result of the DEVTYP UUO or -1 if unknown %CONSTINTEGER DEVTYP=8_53 %INTEGER N N=STRTOSIX(DEV) %RESULT=-1 %UNLESS CALLI2(DEVTYP,N);!* %AND N&DEV AVAL#0 %RESULT=N&8_77 %END %EXTERNALROUTINE READFILES(%STRING(1)%NAME FIL) !============================================== ! Reads a DEC-10 filespec into a string - doing syntactic checking as it does so %RECORD(FILESPEC) FS READFS(FS) FIL=FSTOSTR(FS) %END %EXTERNALROUTINE DOSETSRC(%RECORD(FILESPEC)%NAME FS) !=================================================== %IF XOURPPN=OPR PPN %AND (FS_PPN#0 %AND (FS_DEV="" %AND DEVTYPE(FS_DEV)=0)) %START %UNLESS SETSRC(FS_PPN) %THEN LOGIT("SETSRC failure for ".PPNTOSTR(FS_PPN)) %FINISH %END %EXTERNALINTEGERFN UNIQUE(%INTEGER N) !============================ ! !returns a sort of random integer with at least N octal !digits guaranteed. Useful for creating random filenames. ! %INTEGER I1,I3 I1=GET NOW N=3*N ;!Number of places to shift in each convolution I3=I1>>N %CYCLE I1=I3+I1-I3<>N %REPEAT %UNTIL I3=0 %IF I1<(1<<(N-3)) %THEN I1=(-I1-1)&((1<>18&15 AC(2)=CHAN<<23 AC(1)=8_070000 000140; !CLOSE N,140 - THROW AWAY FILE *8_434040 000002; !IOR 1,2 *8_256000 000001; !XCT 1 RELEASE(CHAN) FREEVEC(OUTSCB_BUFVEC&8_777777) FREEVEC(ADDR(OUTSCB)) OUTVEC(OUTST)_NAME==OUNSCB OUTSCB==OUTVEC(OUTST)_NAME %END %EXTERNALROUTINE DISPOSE(%STRING(1)%NAME FILE,MESSAGE) !======================================================= ! Called after a file has been transferred to delete, print or submit it !THIS ROUTINE ACTS AS IF IT IS 'Q' I.E. THE FILESTORE %STRING(8) TYPE %STRING(6) DEVICE %RECORD(FILESPEC) FS %INTEGER MODE,SIZE,STATUS,PPN,DISP %ON %EVENT 10,15 %START %IF EVENT=15 %THEN MESSAGE=ERRMSG %ELSE MESSAGE=MESSAGE. "failed" %RETURN %FINISH %ROUTINE EDIT MAIL FILE !DOCTOR MAIL FILE FOR TELL SYSTEM TO LOOK LIKE AN ARPA MAIL FILE %INTEGER S,in,out %ON %EVENT 9,10 %START CLOSE INPUT; CLOSE OUTPUT; !UPDATE FILE SELECT INPUT(IN); SELECT OUTPUT(OUT) %RETURN %if event=9 %signal 10,0,0 %FINISH IN=INSTREAM; OUT=OUTSTREAM SELECT INPUT(TEMP); SELECT OUTPUT(TEMP) DEFINE INPUT(TEMP,FILE) DEFINE OUTPUT(TEMP,FILE) PRINTSTRING(XREMOTE NAME); NEWLINE %UNLESS CHARNO(XREMOTE NAME,LENGTH(XREMOTE NAME))>18; PROG=N&8_777777 ACC->PROJECT.(",").PROGRAMMER PROJECT->DUMMY.("[").PROJECT; PROGRAMMER->PROGRAMMER.("]").DUMMY %TRUE %IF (PROJECT="*" %OR PROJ=STRTOOCT(PROJECT)) %AND %C (PROGRAMMER="*" %OR PROG=STRTOOCT(PROGRAMMER)) %FALSE %END;!OF PPN MATCH READ CHAR ACCESS ELEMENT="" ;!Initialize List Element to null string %WHILE CHAR#',' %AND CHAR#')' %AND CHAR#'/' %CYCLE ACCESS ELEMENT=ACCESS ELEMENT.TOSTRING(CHAR) ;!Build up element char by char READ CHAR !Get everything in between Square Brackets in one go %IF CHAR='[' %THEN %START %CYCLE ACCESS ELEMENT=ACCESS ELEMENT.TOSTRING(CHAR) READ CHAR %REPEATUNTIL CHAR=']' %FINISH %REPEAT ACCESS OK=TRUE; !ALWAYS ALLOW ACCESS %RETURN !Process Access Element ACCESS ELEMENT->NODE ACC.("=").ACCESS CODES NODE ACC->NODE.("_").ACC !Check node N OK=FALSE; ACC OK=FALSE %IF NODE="*" %OR NODE="ALL" %OR NODE="GATEWAY" %START; !MAKE GATEWAY COVER ALL REMOTES FLAG GATEWAY=TRUE; NODE=XOTHER NODE %ELSE FLAG GATEWAY=FALSE %UNLESS ISNODE(NODE,TYPE,STATUS) %START NOD=SUBSTRING(NODE,1,LENGTH(NODE)-1) %IF LENGTH(NODE)>1; !STRIP OFF FINAL 'F' IF PRESENT %UNLESS ISNODE(NOD,TYPE,STATUS) %START XMONMESS="not a recognised node - ".NODE %AND %SIGNAL 9 %ELSE NODE=NOD %FINISH %FINISH %IF XOTHER NODE=NODE %START; !NODES MATCHES N OK=TRUE %IF TYPE=DEC10 %AND FLAG GATEWAY=FALSE %START; !I.E. DEC-10S CANNOT BE COVERED BY GLOBAL NAME 'GATEWAY' ACC OK=TRUE %IF ACC="*" %OR PPN MATCH(ACCOUNT,ACC) %ELSE ACC OK=TRUE %IF ACCOUNT=ACC %OR ACC="*" %FINISH %FINISH !Check Access Codes FLAG R=FALSE; FLAG D=FALSE; FLAG C=FALSE; FLAG P=FALSE; FLAG S=FALSE; FLAG W=FALSE; FLAG A=FALSE; A OK=FALSE; !Initially no access permitted %FOR I=1,1,LENGTH(ACCESS CODES) %CYCLE N=CHARNO(ACCESS CODES,I) %IF N='*' %START; A OK=TRUE %ELSE %IF N='R' %START; FLAG R=TRUE %ELSE %IF N='D' %START; FLAG D=TRUE %ELSE %IF N='C' %START; FLAG C=TRUE %ELSE %IF N='W' %START; FLAG W=TRUE %ELSE %IF N='A' %START; FLAG A=TRUE %ELSE %IF N='P' %START; FLAG P=TRUE %ELSE %IF N='S' %START; FLAG S=TRUE %ELSE XMONMESS="not a recognised access code - ".TOSTRING(N) %AND %SIGNAL 9 %REPEAT !Now look at flags !If A OK is true then all access is permitted %IF %NOT A OK %THEN %START !Only check out sensible possibilities N=MODE&16_8FFF; !IGNORE BATCH AND PRINT BITS ->CODE(N) %IF N<=5 ->CODE 8000(N-16_8000) %IF 16_8001<=N<=16_8004 CODE 8000(3): XMONMESS="Unrecognised mode of file access ".HEXTOSTR(MODE); %SIGNAL 9 CODE(1): %IF FLAG C %THEN A OK=TRUE; ->FINAL CHECK CODE(2): %IF FLAG W %THEN A OK=TRUE; ->FINAL CHECK CODE(3): %IF FLAG C %AND FLAG W %THEN A OK=TRUE; ->FINAL CHECK CODE(4): %IF FLAG A %THEN A OK=TRUE; ->FINAL CHECK CODE(5): %IF FLAG C %AND FLAG A %THEN A OK=TRUE; ->FINAL CHECK CODE 8000(4): CODE 8000(1): %IF FLAG R %AND FLAG D %THEN A OK=TRUE; ->FINAL CHECK CODE 8000(2): %IF FLAG R %THEN A OK=TRUE;!* ->FINAL CHECK %FINISH !Set ACCESS OK to TRUE if node, ppn, and access all match FINAL CHECK: ENTRY FOUND=TRUE %IF N OK=TRUE=ACC OK %IF (MODE&16_4000#0 %AND FLAG P=FALSE) %OR (MODE&16_2000#0 %AND FLAG S=FALSE) %THEN A OK=FALSE %IF ENTRY FOUND=TRUE %START %IF A OK=TRUE %START ACCESS OK=TRUE %ELSE; !FOUND A USER UNIQUE ENTRY %IF XMONMESS="" %THEN XMONMESS="specified mode of access not permitted for this user" %FINISH %ELSE %IF XMONMESS="" %THEN XMONMESS="access not permitted by /USERS switch" %FINISH %END; !OF PROCESS ACCESS XMONMESS="" PASSFS=0; PASSFS_PPN=PPN FTP FOUND=FALSE; PASS OK=FALSE; ENTRY FOUND=FALSE ACCESS OK=TRUE; !ALWAYS ALLOW ACCESS IF PASSWORD IS OK PASSFS_FILE="SWITCH"; PASSFS_EXT="INI" IN=INSTREAM SELECT INPUT(TEMP) XDEFINE INPUT(TEMP,PASSFS) SELECT INPUT(TEMP) %CYCLE STR="" %WHILE ALPHANUM %CYCLE STR=STR.TOSTRING(CHAR) %REPEAT %IF STR="FTP" %START; !PROGRAM NAME FOUND FTP FOUND=TRUE %CYCLE READ CHAR %WHILE '/'#CHAR#NL %EXIT %IF CHAR=NL SWITCH="" %WHILE ALPHANUM %CYCLE SWITCH=SWITCH.TOSTRING(CHAR) %REPEAT %EXIT %IF CHAR=NL %IF MATCH(PASSWORD,SWITCH)=1 %START STR="" %FOR N=1,1,12 %CYCLE %EXIT %IF %NOT ALPHANUM STR=STR.TOSTRING(CHAR) %REPEAT PASS STR=PASS; UPPER CASE(PASS STR) %IF STR=PASS STR %START CLOSE INPUT; SELECT INPUT(IN) %TRUE %ELSE XMONMESS="password does not match" %AND %SIGNAL 9 %CONTINUE %FINISH %IF MATCH(ACCESS,SWITCH)=1 %START READ CHAR %IF CHAR=':' %EXIT %IF CHAR=NL %IF CHAR='(' %START %CYCLE PROCESS ACCESS %REPEATUNTIL CHAR#',' %OR ACCESS OK %ELSE PROCESS ACCESS %CONTINUE %FINISH %IF MATCH(OUTPUT SW,SWITCH)#1#MATCH(INPUT SW,SWITCH) %START XMONMESS="unrecognised switch - ".SWITCH; %SIGNAL 9 %FINISH %REPEAT %IF ENTRY FOUND=TRUE %START %IF PASS OK=TRUE=ACCESS OK %START CLOSE INPUT; SELECT INPUT(IN) %TRUE %ELSE ENTRY FOUND=FALSE; !GO ROUND AGAIN %FINISH %FINISH %IF CHAR#NL %START SKIPSYMBOL %WHILE NEXTSYMBOL#NL; !SKIP TO END OF LINE %FINISH SKIPSYMBOL %WHILE NEXTSYMBOL<=SP; !AND UNTIL BEGINNING OF NEXT SPEC %REPEAT %END %EXTERNALPREDICATE LEGAL ACCESS(%STRING(1)%NAME FILENAME, %INTEGER MODE, %STRING(20) ACCOUNT,USERNAME,PASSWORD) !===================================================================================================== ! Taking the role of being the filestore i.e. 'Q', this predicate returns ! %TRUE if the given file can be read or written in the filestore in ! the given mode for the given account and with the given password ! If it is not permitted then %FALSE is returned and XSTATE is set ! for the given failure code and a message is put in XMONMESS. ! If it succeeds then the file size is obtained for a file to be read %INTEGER IN,PN,UFD PROT,FILE PROT,FIRST,FILE EXISTS,CODE,TAKE,DTYPE,NODE,NUM %STRING(6) DEV %RECORD(FILESPEC) FS,UFD FS %EXTERNALRECORD(SCB)%NAMESPEC INSCB %ON %EVENT 10 %START CLOSE INPUT; !TEMP STREAM %IF EVENTINFO#1 %AND FIRST %AND (TAKE %AND MODE&1) %START; !ON FIRST DEFINE TO SEE IF FILE EXISTS FILE EXISTS=FALSE; FIRST=FALSE; FILE PROT=0 ->ONE %FINISH SELECT INPUT(IN) %IF SUBEVENT=4 %START %IF FS_PPN=0 %START XMONMESS=" no directory specified for file" %ELSE XMONMESS=" does not exist" %IF EVENTINFO=1 %START XMONMESS=" UFD".XMONMESS %ELSE%IF EVENTINFO=2 %START XMONMESS="File protection error for ".FILENAME %FINISH %ELSE XMONMESS=ERRMSG XSTATE=16_1001 ->FAIL %FINISH %PREDICATE SPECIAL CASES !------------------------ !PREDICATE TO CHECK IF ACCESS FOR SPECIAL DEVICES %STRING(20) PNSTR PNSTR=PPNTOSTR(FS_PPN) %TRUE %IF XOUTDEV="POST"%OR ARPA MAIL=TRUE %OR XOUTDEV="D60" %OR DTYPE=7 %C %OR DTYPE=8_13 %OR XMODE=16_4001 %OR %C (I AM P %AND (PNSTR=XOURACCOUNT %OR (OPRPRV=TRUE %AND XOURACCOUNT="[1,2]"))) %C %OR (I AM P=FALSE %AND OPRPRV=TRUE %AND XACCOUNT="[1,2]" %AND (XOTHERNODE="ERCC" %OR XOTHERNODE="UMIST")) %OR FS_PPN=QUFD %FALSE %END UFD FS=STRTOFS("DSK:.UFD[1,1]/EXT:6"); !FOR LOOKING UP USERS UFD %IF MODE&16_8000=0 %THEN TAKE=TRUE %ELSE TAKE=FALSE IN=INSTREAM; SELECT INPUT(TEMP) FS=STRTOFS(FILENAME) %IF I AM P=FALSE %AND MODE=16_4001 %START %IF XOUTDEV="LP" %START FS_DEV="LPT" %ELSEIF XOUTDEV#"POST" %START FS_DEV=XOUTDEV %FINISH %FINISH PN=ERSATZ(FS_DEV) FS_PPN=PN %IF FS_PPN=0; !MAKE PPN INTO ERSATZ PPN %IF FS_PPN=0 %THEN FS_PPN=PPNTOOCT(XUSERNAME); !TRY GETTING PPN FROM THE USERNAME PARSE DEVICE(FS_DEV,DEV,NODE,NUM) %IF DEV="LPT" %OR DEV="PLT" %START %IF TAKE=FALSE %START XMONMESS=" cannot read from ".FS_DEV; ->FAIL %FINISH XOUTDEV=FS_DEV; FS_DEV=QDEV; FS_PPN=QUFD %FINISH DOSETSRC(FS) %IF FS_DEV#"" %AND PN=0 %START DTYPE=DEVTYPE(FS_DEV); !GET THE TYPE OF DEVICE %IF DTYPE=-1 %START XMONMESS=" unknown device"; ->FAIL %ELSEIF DTYPE#0 %AND DTYPE#7 %AND DTYPE#8_13 %AND DTYPE#3 %START XMONMESS=" non-disk devices other than LPTs and PLTs not supported"; ->FAIL %FINISH %FINISH %IF FS_DEV="" %AND FS_PPN=0 %START XMONMESS=" filename must include a device or [ppn] specification" XSTATE=16_1001 ->FAIL %FINISH FILENAME=FSTOSTR(FS); !CHANGE FILENAME APPROPRIATELY FS_SWITCHES=FS_SWITCHES."/EXT:#16" FIRST=TRUE; !TO SEE IF IT BOMBS ON THIS DEFINE INPUT %IF DEV#"NUL" %START XDEFINE INPUT(TEMP,FS) FILE EXISTS=TRUE %ELSE FILE EXISTS=FALSE FIRST=FALSE FILE PROT=(INSCB_LKENT_PRV>>27)&7 %IF %NOT TAKE %START XFSIZE=INSCB_LKENT_SIZ %IF XCODE=2 %THEN XFSIZE=(XFSIZE*9)//2 %ELSE XFSIZE=XFSIZE*5 XFSIZE=(XFSIZE+1023)//1024; !NEXT HIGHEST KBYTE %FINISH UFD FS_DEV=SIXTOSTR(INSCB_LKENT_DEV) CLOSE INPUT %IF MODE=1 %START XMONMESS=" already exists" XSTATE=16_1001 ->FAIL %FINISH ONE: XMONMESS="" SELECT INPUT(IN) %TRUE %IF SPECIAL CASES %OR CHECK ACCESS(FS_PPN,MODE,PASSWORD,ACCOUNT,CODE) ;!IF SPECIAL OR PERMITTED TO !Otherwise check the 'all other users' field of the UFD and FILE protection codes %IF CODE<=2 %START; !IF NO FTP ENTRY IN SWITCH.INI FILE XMONMESS="" SELECT INPUT(TEMP) UFD FS_FILE=SIXTOSTR(FS_PPN) XDEFINE INPUT(TEMP,UFD FS) UFD PROT=(INSCB_LKENT_PRV>>27)&7 CLOSE INPUT; SELECT INPUT(IN) %IF TAKE=FALSE %START %IF MODE=16_8002 %START %TRUE %IF UFD PROT&4=4 %AND FILE PROT<=5 %ELSE; !FOR READ AND REMOVES %TRUE %IF UFD PROT&2=2 %AND FILE PROT<=1 %FINISH %ELSE %IF UFD PROT&2=2 %START %IF FILE EXISTS=TRUE %START %TRUE %IF MODE&2=2 %AND FILE PROT<=2; !REPLACE %TRUE %IF MODE&4=4 %AND FILE PROT<=4; !APPEND %ELSE %TRUE %IF MODE&1=1; !A CREATE REQUIRED %FINISH %FINISH %FINISH XMONMESS="illegal access mode for directory " %ELSE XSTATE=16_1016 %FALSE %FINISH XSTATE=16_1016 FAIL: XMONMESS=XOUR NODE."_".FILENAME.XMONMESS %FALSE %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& FNODES.IMP !FNODES.IMP !COPYRIGHT K.FARVIS 1978,79 !Contains the information and control of the currently acceptable nodes for FTP !to talk to, what kind of nodes they are and their state (whether up or down) etc. %include "imp:iolib.inc" %EXTERNALPREDICATESPEC CALLI2(%INTEGER N,%INTEGERNAME AC) %EXTERNALINTEGERFNSPEC GETNOW %EXTERNALSTRING(255)%FNSPEC FSTOSTR(%RECORD(FILESPEC)%NAME FS) %EXTERNALSTRING(6)%FNSPEC SIXTOSTR(%INTEGER N) %EXTERNALSTRING(12)%FNSPEC OCTTOSTR(%INTEGER N) %EXTERNALINTEGERFNSPEC STRTOOCT(%STRING(1)%NAME STR) %EXTERNALSTRING(12)%FNSPEC INTTOSTR(%INTEGER N) %EXTERNALSTRING(255)%SPEC ERRMSG %STRING(12)%FNSPEC OUR NODE %STRING(6)%FNSPEC ANF NODE NAME(%INTEGER N) %CONSTINTEGER TTY=0,TEMP=8; !STREAMS %CONSTINTEGER OFFLINE=-1, DOWN=0, UP=1; !NODE STATUS %CONSTINTEGER MAX MAX NODES=100; !CURRENT MAX NODE LIMIT %EXTERNALINTEGER MAXNODES %EXTERNALSTRING(10)%ARRAY NODES(0:MAX MAX NODES) %EXTERNALSTRING(7)%ARRAY NODETYPE(0:MAX MAXNODES) %EXTERNALSTRING(150)%ARRAY NODE ADDRESS(0:MAX MAX NODES) %OWNSTRING(20)%ARRAY NODE NO(0:MAX MAX NODES) %OWNINTEGERARRAY LOCAL NODE(0:MAX MAX NODES) %OWNINTEGERARRAY NODE STATUS(0:MAX MAX NODES) %OWNINTEGERARRAY NODE TIME(0:MAX MAX NODES) %EXTERNALSTRING(12) OUR SRC NODE %CONSTINTEGER MAX SRC TABLE=9 %CONSTSTRING(6)%ARRAY ANF TITLE(0:MAX SRC TABLE)= "ERCC", "DUNDEE", "YORK", "YORKS", "KELVIN", "OXFORD", "SXKL10", "BLUE", "ORANGE", "UCNWCS" %CONSTSTRING(12)%ARRAY SRC TITLE(0:MAX SRC TABLE)= "EDXA", "DDXA", "YKXA", "YORKS", "GWXA", "XXXA", "", "", "", "BGXA" %EXTERNALSTRING(6) QDEV; !THE QUEUEING DEVICE %CONSTINTEGER WHERE CALLI=8_63 %routinespec check netwrk file %routinespec read net file(%record(filespec)%NAME fs) %owninteger netwrk file time=0 !THE NEXT ROUTINE IS FOR FTP %EXTERNALROUTINE LIST FTP NODES !============= !LISTS THE KNOWN NODES %INTEGER N,M PRINTSTRING(" List of nodes to which file transfer is possible from this PPN Node type node type node type"); NEWLINE M=0 %FOR N=0,1,MAX NODES %CYCLE %CONTINUE %IF NODES(N)="GATEWAY" PRINTSTRING(NODES(N)); PRINTSYMBOL(TAB); PRINTSTRING(NODE TYPE(N)) M=M+1 %IF REM(M,3)=0 %THEN NEWLINE %ELSE PRINTSYMBOL(TAB) %REPEAT NEWLINE %END !THE NEXT THREE ROUTINES ARE USED BY THE SPOOLERS COMMANDS %EXTERNALROUTINE LIST SPOOL NODES !========================== !LISTS THE NODES FOR FTPSPL %INTEGER OUT,N OUT=OUTSTREAM SELECT OUTPUT(TTY) PRINTSTRING(" Node type status address"); NEWLINE %FOR N=0,1,MAX NODES %CYCLE PRINTSTRING(NODES(N)); PRINTSYMBOL(TAB) PRINTSTRING(NODE TYPE(N)); PRINTSYMBOL(TAB) %IF NODE STATUS(N)=UP %START PRINTSTRING("UP") %ELSEIF NODE STATUS(N)=DOWN %START PRINTSTRING("DOWN") %ELSE PRINTSTRING("OFF-LINE") PRINTSYMBOL(TAB); PRINTSTRING(ANF NODE NAME(LOCAL NODE(N))) PRINTSYMBOL('.'); PRINTSTRING(NODE ADDRESS(N)) NEWLINE %REPEAT SELECT OUTPUT(OUT) %END %EXTERNALPREDICATE NODE OFFLINE(%STRING(1)%NAME NODE) !=============================== !SETS NODE OFF-LINE %INTEGER N %FOR N=0,1,MAX NODES %CYCLE %FALSE %IF NODES(N)="" %IF NODES(N)=NODE %THEN NODE STATUS(N)=OFFLINE %AND %TRUE %REPEAT %FALSE %END %EXTERNALPREDICATE NODE ONLINE(%STRING(1)%NAME NODE) !============================================== %INTEGER N %FOR N=0,1,MAX NODES %CYCLE %FALSE %IF NODES(N)="" %IF NODES(N)=NODE %THEN NODE STATUS(N)=UP %AND %TRUE %REPEAT %FALSE %END %ROUTINE REMOVE SPACES(%STRING(1)%NAME STR) !=========================================================== !just that %string(12) str1 %integer n %return %if length(str)=0 STR1="" %FOR N=1,1,LENGTH(STR) %CYCLE %CONTINUE %IF CHARNO(STR,N)=SP; !DELETE SPACES STR1=STR1.TOSTRING(CHARNO(STR,N)) %REPEAT STR=STR1 %END %ROUTINE NO LEADING ZEROES(%STRING(1)%NAME NUMBER) !================================================= !Removes the leading zeoes of a string format number %INTEGER N,M N=LENGTH(NUMBER) %RETURN %IF N<=1 %FOR M=1,1,N %CYCLE %EXIT %IF '0'#CHARNO(NUMBER,M)#SP %REPEAT %RETURN %IF M=1; !NO LEADING ZEROES NUMBER=SUBSTRING(NUMBER,M,N) %END %EXTERNALSTRING(6)%FN QDEVICE !============================ !returns the name of the device for queueing FTP requests i.e. SYS: device %string(6) str *8_561040 000135; !hrroi 1,135 - move arg1,[xwd -1,.gtrdv] *8_047040 000041; !gettab 1, *8_402000 000001; !setzm 1 str=sixtostr(ac(1)) remove spaces(str) %result=str %end %EXTERNALSTRING(6)%FN ANF NODE NAME(%INTEGER NODE) !====================================== !Returns the node name for a given octal node number %STRING(12) STR %INTEGER N %INTEGERARRAY ARGS(0:1) %RESULT=OUR NODE %IF NODE=-1 ARGS(0)=2; !NUMBER OF ARGS ARGS(1)=NODE; !NODE NUMBER N=2<<18!ADDR(ARGS(0)); !RETURN NODE NAME %IF CALLI2(8_157,N) %START STR=SIXTOSTR(N) REMOVE SPACES(STR) %RESULT=STR %FINISH %RESULT=OCTTOSTR(NODE) %END %EXTERNALSTRING(10)%FN NODE NAME(%STRING(1)%NAME NUMBER) !=========================================================== !returns the node title for a given address %integer n,IN %ON %EVENT 3 %START CLOSE INPUT; SELECT INPUT(IN) %RESULT="" %FINISH IN=INSTREAM NO LEADING ZEROES(NUMBER) CHECK NETWRK FILE %FOR N=0,1,MAX NODES %CYCLE %IF NODENO(N)=NUMBER %THEN %RESULT=NODES(N) %REPEAT %RESULT="" %END %EXTERNALSTRING(12)%FN OUR NODE !============================== !returns the node name for the node we are running on. %INTEGER N N=8_436471 000000; !SIXBIT/CTY/ TO GET OUR NODE NUMBER %UNLESS CALLI2(WHERE CALLI,N) %THEN %RESULT="" %RESULT=ANF NODE NAME(N) %END %STRING(12)%FN OUR SRC NAME !================================================= %INTEGER N %STRING(6) ANF NAME ANF NAME=OUR NODE %FOR N=0,1,MAX SRC TABLE %CYCLE %RESULT=SRC TITLE(N) %IF ANF NAME=ANF TITLE(N) %REPEAT %RESULT="" %END %ROUTINE UPDATE STATUS(%INTEGER N) !============================= !UPDATE THE STATUS OF A NODE WHEN THE TIME LIMIT HAS ELAPSED %RETURN %IF NODE STATUS(N)=OFFLINE %IF NODE TIME(N)7 %THEN NODE TYPE(N)=SUBSTRING(STR,1,7) %ELSE NODE TYPE(N)=STR NODE STATUS(N)=UP %UNLESS NODE ADDRESS(N)->LOCAL.(".").STR %THEN ERRMSG="?Incorrect format of address line" %AND %FALSE; !MUST HAVE ANF-10 NODE LOCAL NODE(N)=STRTOOCT(LOCAL) %IF STR->DUMMY.("TSK.").STR1 %AND DUMMY="" %THEN STR=STR1; !"TSK" IS NOISE NODE ADDRESS(N)=STR; !GET MAIN PART OF ADDRESS 1: %IF STR->STR1.(".").DUMMY %THEN STR=STR1 %ELSE DUMMY=""; !GET NEXT ELEMENT UP TO '.' %IF STR="" %THEN NODENO(N)="0" %AND %TRUE !* %IF STR="" %THEN ERRMSG="?No numeric address field" %AND %FALSE 2: S=CHARNO(STR,1) %IF '0'<=S<='9' %START NODENO(N)=STR NO LEADING ZEROES(NODENO(N)) %ELSEIF S='(' %START ->2 %IF STR->STR1.(")").STR %AND STR#""; !IF (USER,PASS,5W,8P)ADDR STR=DUMMY; !GET REST OF ADDRESS AND TRY NEXT FIELD ->1 %ELSE NODENO(N)="0"; !NAME OR NUMBER %TRUE %END %ROUTINE READ NET FILE(%RECORD(FILESPEC)%NAME FS) !======================== !put all nodes on line %INTEGER N %ON %EVENT 9 %START MAX NODES=N-1 %RETURN %FINISH %FOR N=0,1,MAX MAX NODES %CYCLE ->ER1 %UNLESS READ NET ITEM(N) %REPEAT ERRMSG="?Too many entries in ".FSTOSTR(FS)." for internal tables =".inttostr(n) ->ER ER1: ERRMSG=ERRMSG." in ".FSTOSTR(FS)." - ".NODE ADDRESS(N) ER: SELECT OUTPUT(TTY) PRINTSTRING(ERRMSG); NEWLINE %STOP %END %EXTERNALROUTINE UPD NODES !========================= !update the tables to the current state %INTEGER N %FOR N=0,1,MAX NODES %CYCLE %CONTINUE %IF NODE STATUS(N)=OFFLINE NODE STATUS(N)=UP %REPEAT %END %EXTERNALPREDICATE ADDRESS(%STRING(1)%NAME TITLE,TS ADDRESS,%INTEGERNAME NODE NUM) !================================================================================== !gets the transport service address of the the given title and also the !node number for the task connect %STRING(255) DUMMY %INTEGER N ;!G ,N1,N2 %FOR N=0,1,MAX NODES %CYCLE %IF NODES(N)=TITLE %START TS ADDRESS=NODE ADDRESS(N) NODE NUM=LOCAL NODE(N) %TRUE %FINISH %REPEAT ERRMSG="Unknown node ".TITLE %FALSE %END %STRING(255)%FN UPPER CASE(%STRING(1)%NAME STR) !============================================= !Convert the given string to to upper case %STRING(255) STR1 %INTEGER N,L,S L=LENGTH(STR) %RESULT="" %IF L=0 STR1="" %FOR N=1,1,L %CYCLE S=CHARNO(STR,N) S=S-32 %IF 'a'<=S<='z' STR1=STR1.TOSTRING(S) %REPEAT %RESULT=STR1 %END %EXTERNALPREDICATE ISNODE(%STRING(1)%NAME NODE,TYPE %INTEGERNAME STATUS) !======================================================================= !determines whether a given node name is a supported one, and if so, !returns the type of node and it's status %INTEGER N %STRING(100) NOD NOD=UPPER CASE(NODE) %FOR N=0,1,MAX NODES %CYCLE %IF NODES(N)=NOD %START TYPE=NODE TYPE(N) %IF NODE STATUS(N)=DOWN %THEN UPDATE STATUS(N) STATUS=NODE STATUS(N) %TRUE %FINISH %REPEAT STATUS=DOWN; TYPE="" %FALSE %END %EXTERNALROUTINE SET NODE DOWN(%STRING(1)%NAME NODE,%INTEGER SECS) !=================================================== !Makes a note that the node is down and sets a time stamp on it %INTEGER N %FOR N=0,1,MAX NODES %CYCLE %IF NODES(N)=NODE %START NODE TIME(N)=GETNOW+(SECS*3) NODE STATUS(N)=DOWN %RETURN %FINISH %REPEAT %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& TRANSP.IMP !TRANSP.IMP ! COPYRIGHT K.FARVIS ERCC. ! IS THE TRANSPORT MECHANISM FOR FTP !USES SPECIAL MACRO READ AND WRITE ROUTINES WHICH WILL !TIMEOUT ON A READ OR WRITE AFTER THE TIME SET BY SETTIM !ROUTINE. THEREFORE THE TWO SIGNALLED EVENTS POSSIBLE ARE !EVENT 14 (TRANSPORT TIMEOUT) AND EVENT 4 (I/O TRANSMISSION ERROR) %INCLUDE "IMP:IOLIB.INC" %EXTERNALRECORD(SCB)%NAMESPEC INSCB %EXTERNALRECORD(SCB)%NAMESPEC OUTSCB %EXTERNALRECORD(SCBNAME)%ARRAYSPEC INVEC(-1:MAXCHANS) %EXTERNALRECORD(SCBNAME)%ARRAYSPEC OUTVEC(-1:MAXCHANS) %EXTERNALRECORD(SCB)%SPEC IUNSCB,OUNSCB; !NUL STREAMS %SYSTEMPREDICATESPEC IOUUO(%INTEGER FN,CHAN,%INTEGERNAME AC) %SYSTEMROUTINESPEC SCBDEFINE(%INTEGER N,%RECORD(FILESPEC)%NAME FS,%RECORD(SCBNAME)%NAME IOSCB, %INTEGER CHNTYP) %SYSTEMROUTINESPEC GETSCB(%RECORD(SCBNAME)%NAME R,%INTEGER LENGTH) %SYSTEMINTEGERFNSPEC GETVEC(%INTEGER SIZE) %SYSTEMROUTINESPEC FREEVEC(%INTEGER THIS) %SYSTEMROUTINESPEC RELEASE(%INTEGER CHAN) %EXTERNALPREDICATESPEC CALLI2(%INTEGER N,%INTEGERNAME ARG) %EXTERNALROUTINESPEC NODE OFFLINE(%STRING(1)%NAME NODE) %EXTERNALROUTINESPEC SET NODE DOWN(%STRING(1)%NAME NODE,%INTEGER SECS) %EXTERNALSTRING(10)%FNSPEC NODE NAME(%STRING(1)%NAME NUMBER) %EXTERNALSTRING(6)%FNSPEC ANF NODE NAME(%INTEGER N) %EXTERNALROUTINESPEC UPD NODES; !UPDATE NODE TABLES %EXTERNALPREDICATESPEC ADDRESS(%STRING(1)%NAME TITLE,TR ADDRESS,%INTEGERNAME GATEWAY) %EXTERNALROUTINESPEC OPEN LOG %EXTERNALROUTINESPEC CLOSE LOG %EXTERNALROUTINESPEC LOGIT(%STRING(255) STR) %EXTERNALROUTINESPEC SLEEP(%INTEGER N) %EXTERNALROUTINESPEC WRITEHEX(%INTEGER N,M) %EXTERNALSTRING(6)%FNSPEC SIXTOSTR(%INTEGER N) %EXTERNALSTRING(255)%FNSPEC FSTOSTR(%RECORD(FILESPEC)%NAME FS) %EXTERNALSTRING(12)%FNSPEC OCTTOSTR(%INTEGER N) %EXTERNALSTRING(15)%FNSPEC PPNTOSTR(%INTEGER N) %EXTERNALSTRING(12)%FNSPEC INTTOSTR(%INTEGER N) %EXTERNALSTRING(9)%FNSPEC HEXTOSTR(%INTEGER N) %EXTERNALSTRING(255)%FNSPEC ASCTOSTR(%NAME ADR) %EXTERNALROUTINESPEC STRTOASC(%STRING(1)%NAME STR,%NAME ADR) %EXTERNALINTEGERFNSPEC STRTOINT(%STRING(1)%NAME S) %EXTERNALSTRING(20)%SPEC XOUR NODE %EXTERNALINTEGERSPEC XOUR PPN %EXTERNALSTRING(255)%SPEC XOTHER NODE %EXTERNALSTRING(255) XREMOTE NAME %EXTERNALINTEGERSPEC ARPA MAIL %EXTERNALINTEGERSPEC DEBUG %EXTERNALINTEGERSPEC OPRPRV %EXTERNALINTEGER MAX SUBRECORD %EXTERNALINTEGERSPEC I AM P %EXTERNALINTEGERSPEC PSS OUTPUT %EXTERNALINTEGERSPEC LOGLEVEL %EXTERNALSTRING(12)%SPEC OUR SRC NODE %OWNSTRING(30) BYTE MODE="/MODE:#140000000003/BYTE:8" ;! ASYNCHRONOUS I/O AND DO NOT REASSEMBLE PACKETS AND BYTE MODE %CONSTINTEGER TTY=1, FTP=5, LOG=3 %CONSTINTEGER TRUE=-1, FALSE=0, RH=8_777777, LH=8_777777 000000, UP=1, DOWN=0, OFFLINE=-1 %CONSTINTEGER OPEN=8_50 !NOW THE TRANSPORT SUBEVENTS %CONSTINTEGER NO SUCH HANDLER=2 %CONSTINTEGER TSK UUO=8_177, GET STATE=1, TASK WAIT=5,LOOKUP=2,ENTER=3 %EXTERNALSTRING(12) TASK NAME="FTX*" %OWNINTEGER TASK ASCIZ=0 %OWNSTRING(25) LOCAL TASK="" %EXTERNALSTRING(25) XLOCAL TASK %ROUTINESPEC CLOSE TRANSPORT %ROUTINESPEC GOT %EXTERNALROUTINESPEC FTPOUT; !OUTPUT FOR FTP %EXTERNALINTEGER FTPTST; !INPUT TESTING FLAG %EXTERNALINTEGERSPEC FTPRD; !SPECIAL READING ROUTINE %EXTERNALINTEGERSPEC FTPWT; !SPECIAL WRITING ROUTINE %EXTERNALROUTINESPEC SETTIM(%INTEGER SECS); !SET TIMEOUT INTERVAL %ROUTINESPEC GET(%INTEGERNAME N) %PREDICATESPEC ANY GOT %EXTERNALSTRING(255)%SPEC ERRMSG %ROUTINE FTP NOT RUNNING !======================== SET NODE DOWN(XOTHER NODE,15*60) ERRMSG=ERRMSG." - will try again later to ".XOTHER NODE LOGIT(ERRMSG) %END %ROUTINE TMONITOR(%STRING(150) STRING,%INTEGER HEX) !======================================================== !Monitors the transport level %INTEGER OUT OUT=OUTSTREAM SELECT OUTPUT(TTY) PRINTSTRING(STRING) WRITEHEX(HEX,3) %IF HEX#-1 NEWLINE %IF STRING#"" SELECT OUTPUT(OUT) %END %ROUTINE CLOSE INOUT !=================== !ROUTINE TO CLOSE THE SPECIAL FTP INPUT/OUTPUT COMBO %INTEGER INSTR,OUTST %RETURN %IF INSCB_DEVTYP=UNDEV=OUTSCB_DEVTYP INSTR=INSTREAM; OUTST=OUTSTREAM RELEASE(INSCB_FILOPFN>>18&15) FREEVEC(INSCB_BUFVEC&8_777777) FREEVEC(ADDR(INSCB)) FREEVEC(OUTSCB_BUFVEC&8_777777) FREEVEC(ADDR(OUTSCB)) !DEFAULT BACK TO UNDEFINED INVEC(INSTR)_NAME==IUNSCB INSCB==INVEC(INSTR)_NAME OUTVEC(OUTST)_NAME==OUNSCB OUTSCB==OUTVEC(OUTST)_NAME %END %ROUTINE TASK FUNCTION(%INTEGER CHAN,FUNCT,NODE NUM,%STRING(1)%NAME LOCAL,REMOTE) !================================================================================== !PERFORMS A TASK FUNCTION - EITHER LOOKUP OR ENTER %INTEGERARRAY TSKADR(0:4), ADR1(0:19), ADR2(0:19),ADR3(0:19) %INTEGER N TSKADR(0)=FUNCT ;!FUNCTION TSKADR(1)=CHAN TSKADR(2)=20<<18!ADDR(ADR1(0)); !FIRST NPD TSKADR(3)=20<<18!ADDR(ADR2(0)); !SECOND NPD TSKADR(4)=20<<18!ADDR(ADR3(0)); !THIRD NPD %FOR N=2,1,19 %CYCLE ADR1(N)=0; ADR2(N)=0; ADR3(N)=0; !CLEAR NPDS %REPEAT ADR1(0)=-1; !LOCAL ADR1(1)=LENGTH(LOCAL); !LENGTH OF ASCII STRING STRTOASC(LOCAL,ADR1(2)) ADR2(0)=NODE NUM ADR2(1)=LENGTH(REMOTE) STRTOASC(REMOTE,ADR2(2)) ADR3(0)=-1 ADR3(1)=0 N=5<<18!ADDR(TSKADR(0)) %UNLESS CALLI2(TSK UUO,N) %START ERRMSG="Task function error for ".REMOTE %signal 10,5,n %FINISH %END %PREDICATE TASK INFO(%INTEGER CHAN,FUNCT,%INTEGERNAME VALUE,REASON,REM NODE,%STRING(1)%NAME LOCAL,REMOTE) !================================================================================== !PERFORMS A TASK FUNCTION - EITHER 'GET STATE' OR 'TASK WAIT' CURRENTLY !THAT IS IT EITHER DOES A TASK WAIT OR !CHECKS THE STATE OF THE FTP TASK AND RETURNS A VALUE FOR THE STATE !THE REASON FOR A DISCONNECT AND THE NAME OF THE LOCAL AND REMOTE TASK %INTEGERARRAY TSKADR(0:4), ADR1(0:19), ADR2(0:19),ADR3(0:19) %INTEGER N TSKADR(0)=FUNCT ;!FUNCTION TSKADR(1)=CHAN TSKADR(2)=20<<18!ADDR(ADR1(0)); !FIRST NPD TSKADR(3)=20<<18!ADDR(ADR2(0)); !SECOND NPD TSKADR(4)=20<<18!ADDR(ADR3(0)); !THIRD NPD %FOR N=2,1,19 %CYCLE ADR1(N)=0; ADR2(N)=0; ADR3(N)=0; !CLEAR NPDS %REPEAT ADR1(0)=-1; !LOCAL ADR1(1)=LENGTH(LOCAL); !LENGTH OF ASCII STRING STRTOASC(LOCAL,ADR1(2)) N=5<<18!ADDR(TSKADR(0)) %UNLESS CALLI2(TSK UUO,N) %START VALUE=N %FALSE %FINISH %TRUE %UNLESS FUNCT=GET STATE VALUE=TSKADR(2) %IF VALUE=0 %START REASON=TSKADR(3) %ELSE REASON=0 LOCAL=ASCTOSTR(ADR2(2)) REM NODE=ADR3(0) REMOTE=ASCTOSTR(ADR3(2)) %FINISH %TRUE %END %ROUTINE FTP OPEN(%INTEGER N,%RECORD(FILESPEC) FS) !================================================== !Opens a special FTP stream for both input and output %RECORD(SCB)%NAME ISCB,OSCB %STRING(255) STR %INTEGER OLD JBFF,IN %CONSTINTEGER JBFF=8_121 SCBDEFINE(N,FS,INVEC(N),STREAM) ISCB==INVEC(N)_NAME GETSCB(OUTVEC(N),SCBSIZE) OSCB==OUTVEC(N)_NAME !NOW COPY INPUT TO OUTPUT SCB BUT MAKE SOME CHANGES OSCB=ISCB OSCB_BUFHEDS=ADDR(OSCB_RINGHEAD_BUFADR)<<18 OSCB_BUFNUM=OSCB_BUFNUM<<18 OSCB_RINGHEAD_BUFADR=GETVEC(OSCB_BUFVEC>>18) OSCB_BUFVEC=(OSCB_BUFVEC&LH)!OSCB_RINGHEAD_BUFADR ISCB_BUFHEDS=ISCB_BUFHEDS!OSCB_BUFHEDS ISCB_BUFNUM=ISCB_BUFNUM!OSCB_BUFNUM %UNLESS IOUUO(OPEN,ISCB_FILOPFN>>18&15,ISCB_STATUS) %START ERRMSG="Open error for device".SIXTOSTR(ISCB_DEVNAM) %SIGNAL 10,6,0 %FINISH ISCB_RINGHEAD_BUFADR=ISCB_BUFVEC&RH; !RESTORE BUFADR AFTER OPEN UUO OSCB_RINGHEAD_BUFADR=OSCB_BUFVEC&RH; !RESTORE BUFADR AFTER OPEN UUO OLD JBFF=AC(JBFF) AC(JBFF)=ISCB_RINGHEAD_BUFADR; !IN ORDER TO BUILD INPUT BUFFERS AC(1)=ISCB_IBUFOP+8_6000<<18!(ISCB_BUFNUM&8_777777) *8_256000000001; !DO INBUF N,M AC(JBFF)=OSCB_RINGHEAD_BUFADR; !IN ORDER TO BUILD OUTPUT BUFFERS AC(1)=OSCB_OBUFOP+8_6000<<18!OSCB_BUFNUM>>18 *8_256000000001; !DO OUTBUF N,M AC(JBFF)=OLD JBFF; !RESTORE JBFF ISCB_OPER==FTPRD; !SPECIAL READING FUNCTION OSCB_OPER==FTPWT; !SPECIAL WRITING FUNCTION ISCB_RINGHEAD_BYTPTR=(ISCB_RINGHEAD_BYTPTR&RH)!8<<24 OSCB_RINGHEAD_BYTPTR=(OSCB_RINGHEAD_BYTPTR&RH)!8<<24 %IF N=INSTREAM %THEN INSCB==INVEC(N)_NAME; !SET CURRENT SCB POINTER %IF N=OUTSTREAM %THEN OUTSCB==OUTVEC(N)_NAME; !SET CURRENT SCB POINER IN=INSTREAM SELECT INPUT(N) FTPTST=TRUE N=NEXTSYMBOL; !GET BUFFER RING ESTABLISHED SELECT INPUT(IN) SETTIM(300); !SET TIMEOUT INTERVAL %IF LOGLEVEL>=100 %START STR="Opened task device ".FSTOSTR(FS) TMONITOR(STR,-1) %FINISH %END %EXTERNALROUTINE FTP ENTER(%INTEGER N,%INTEGERNAME GATE,%STRING(1)%NAME LOCAL,REMOTE) !================================================================================ !OPENS THE FTP STREAM FOR OUTPUT %RECORD(SCB)%NAME SCB %STRING(150) STR %INTEGER VALUE,REASON,REM NODE SCB==OUTVEC(N)_NAME TASK FUNCTION(SCB_FILOPFN>>18&15,ENTER,GATE,LOCAL,REMOTE) %IF I AM P=TRUE %IF TASK INFO(SCB_FILOPFN>>18&15,TASK WAIT,VALUE,REASON,REM NODE,LOCAL,REMOTE) %START; %FINISH %IF TASK INFO(SCB_FILOPFN>>18&15,GET STATE,VALUE,REASON,REM NODE,LOCAL,REMOTE) %START; !GET STATE %IF VALUE=3 %START; !LINK IS OPERATIONAL %IF GATE=0 %OR GATE=-1 %THEN GATE=REM NODE %IF I AM P=TRUE %START STR="Outgoing call on node ".ANF NODE NAME(GATE)." to ".REMOTE %ELSE STR="Incoming call on node ".ANF NODE NAME(GATE)." from ".REMOTE %FINISH STR=STR." on ".LOCAL %IF LOGLEVEL>=100 %THEN TMONITOR(STR,-1) LOGIT(STR) %ELSE CLOSE TRANSPORT ERRMSG="Call to ".XOTHERNODE." on ".ANF NODE NAME(GATE)." failed. Reason = ".HEXTOSTR(REASON) %SIGNAL 10,5,REASON %FINISH %FINISH !IF WE GET HERE WE WILL SEND OUT AN SFT AND THEN TIMEOUT ON INPUT %END %EXTERNALROUTINE INIT TRANSPORT !============================= !Routine to set up global values that are relevant to this transport station %STRING(255) STR,DUMMY %INTEGER N OPRPRV=FALSE MAXSUBRECORD=63 STRTOASC(TASK NAME,TASK ASCIZ) %IF LOCAL TASK="" %START %IF ADDRESS(OUR SRC NODE,STR,N) %START %IF CHARNO(STR,1)='(' %START %IF STR->DUMMY.(")").STR %START; %FINISH; !REMOVE PARAMETER FIELD %FINISH %IF CHARNO(STR,1)='.' %THEN STR=SUBSTRING(STR,2,LENGTH(STR)); !REMOVE ANY DOT %IF STR->STR.(".").DUMMY %START; %FINISH %IF STR="FTP" %OR STR="ftp" %THEN LOCAL TASK=XOURNODE %ELSE LOCAL TASK=STR %ELSE LOCAL TASK=XOURNODE LOCAL TASK=LOCAL TASK.".FTX" %FINISH %END %ROUTINE OPEN RECEIVER !====================== !THIS ROUTINE OPENS AN INPUT TASK IN NON-BLOCKING MODE JUST TO LISTEN TO THE LINE %RECORD(FILESPEC) FS FS=0; FTPTST=FALSE FS_DEV="TSK" FS_SWITCHES=BYTE MODE FTP OPEN(FTP,FS) XLOCAL TASK=LOCAL TASK TASK FUNCTION(OUTVEC(FTP)_NAME_FILOPFN>>18&15,LOOKUP,-1,XLOCAL TASK,TASK NAME) %END %EXTERNALPREDICATE P OPEN TRANSPORT(%STRING(1)%NAME NODE) !========================================================= !Opens an output task to the specified node, doing a handshake by !exchanging node numbers if it is a DEC-10 %RECORD(FILESPEC) FS %OWNSTRING(25) LAST DEST="" %STRING (200) LOCAL,S1,S2 %INTEGER OTHER NODE %ON %EVENT 10 %START CLOSE TRANSPORT FTP NOT RUNNING %FALSE %FINISH FS=0; FS_SWITCHES=BYTE MODE %SIGNAL 10,10 %UNLESS ADDRESS(NODE,XREMOTE NAME,OTHER NODE) XLOCAL TASK=LOCAL TASK %IF ARPA MAIL=TRUE %START XREMOTE NAME=XREMOTE NAME.".MAIL" XLOCAL TASK=XLOCAL TASK.".MAIL" %FINISH LOCAL=XLOCAL TASK !NOW MARK WHETHER IT IS VIA PSS %IF XREMOTE NAME->S1.(".PSS(").S2 %THEN PSS OUTPUT=TRUE %ELSE PSS OUTPUT=FALSE FS_DEV="TSK".OCTTOSTR(OTHER NODE) CLOSE TRANSPORT %IF LAST DEST=NODE %THEN SLEEP(10000); !ALLOW TIME FOR OTHER FTP HANDLER TO RECOVER IF SENT TO LAST TIME ! %IF LAST DEST="UCL" %OR LAST DEST="ZUXA" %THEN SLEEP (60000); !LONG WAIT FOR UCL LAST DEST=NODE FTP OPEN(FTP,FS) FTP ENTER(FTP,OTHER NODE,LOCAL,XREMOTE NAME) %TRUE %END %EXTERNALPREDICATE Q OPEN TRANSPORT !================================ !THIS INITIALISES THE OUTPUT SIDE OF THE TRANSPORT FOR THE 'Q' PROCESS %STRING(100) NUMBER,DUMMY,LOCAL %INTEGER N %ON %EVENT 10 %START CLOSE TRANSPORT FTP NOT RUNNING %FALSE %FINISH N=-1 XLOCAL TASK=LOCAL TASK FTP ENTER(FTP,N,XLOCAL TASK,XREMOTE NAME) %IF XLOCAL TASK->XLOCAL TASK.(".MAIL").DUMMY %OR %C XLOCAL TASK->XLOCAL TASK.("MAIL").DUMMY %C %THEN ARPA MAIL=TRUE %ELSE ARPA MAIL=FALSE %IF XREMOTE NAME->NUMBER.(".").DUMMY %START; !GET THE NODE NUMBER XOTHER NODE=NODE NAME(NUMBER); !HENCE THE NAME XOTHER NODE=XREMOTE NAME %IF XOTHER NODE="" %ELSE XOTHER NODE=ANF NODE NAME(N); !AN ANF-10 NODE %TRUE %END %EXTERNALROUTINE CLOSE TRANSPORT !=============================== !CLOSES THE TRANSPORT MECHANISM %INTEGER IN,OUT IN=INSTREAM; OUT=OUTSTREAM SELECT INPUT(FTP); SELECT OUTPUT(FTP) CLOSE INOUT SELECT INPUT(IN); SELECT OUTPUT(OUT) %END %EXTERNALROUTINE RESET TRANSPORT !=============================== !RESETS THE TRANSPORT TO JUST LISTEN CLOSE TRANSPORT; OPEN RECEIVER %END %EXTERNALROUTINE IDLE(%INTEGER SECS) !==================== !CAUSES A SLEEP FOR 'SECS' SECONDS OR UNTIL TTY INPUT AC(1)=8_320<<18!(SECS*1000); !SLEEP FOR N SECS OR UNTIL TTY INPUT OR RB.IPC OR RB.RIO *8_047040 000072; !HIBER UUO *8_320000 000000 %END %EXTERNALPREDICATE FTP STATE(%INTEGERNAME VALUE,%STRING(1)%NAME MESS) !================================================================ !RETURNS TRUE FOR TRANSPORT OK, FALSE FOR BROKEN !IF FALSE THE REASON IS RETURNED IN THE STRING %INTEGER IN,REASON,REM NODE %STRING(100) REMOTE,LOCAL LOCAL=XLOCAL TASK REMOTE=XREMOTE NAME IN=INSTREAM; SELECT INPUT(FTP) %IF TASK INFO(INSCB_FILOPFN>>18&15,GET STATE,VALUE,REASON,REM NODE,LOCAL,REMOTE) %START %IF VALUE=0 %start; !LINK IS NOT OPERATIONAL MESS="Call to ".XOTHERNODE." closed with reason ".HEXTOSTR(REASON) SELECT INPUT(IN) %FALSE %FINISH %FINISH !IF LINK EITHER OPERATIONAL OR ELSE I DON'T KNOW SAY IT IS OK SELECT INPUT(IN) %TRUE %END %EXTERNALPREDICATE FTP UP !======================== !RETURNS TRUE FOR TRANSPORT OK, FALSE FOR BROKEN- assumes INSTREAM=FTP %INTEGERARRAY TSKADR(0:4), ADR1(0:19), ADR2(0:19),ADR3(0:19) %INTEGER N TSKADR(0)=GET STATE ;!FUNCTION TSKADR(1)=INSCB_FILOPFN>>18&15 TSKADR(2)=3<<18!ADDR(ADR1(0)); !FIRST NPD TSKADR(3)=20<<18!ADDR(ADR2(0)); !SECOND NPD TSKADR(4)=20<<18!ADDR(ADR3(0)); !THIRD NPD %FOR N=0,1,19 %CYCLE ADR1(N)=0; ADR2(N)=0; ADR3(N)=0; !CLEAR OTHER NPDS %REPEAT ADR1(0)=-1; !LOCAL ADR1(1)=LENGTH(XLOCAL TASK) STRTOASC(XLOCAL TASK,ADR1(2)) N=5<<18!ADDR(TSKADR(0)) %UNLESS CALLI2(TSK UUO,N) %START %TRUE; !JUST IN CASE ITS OK %FINISH %IF TSKADR(2)=0 %start; !LINK IS NOT OPERATIONAL %FALSE %FINISH !IF LINK EITHER OPERATIONAL OR ELSE I DON'T KNOW SAY IT IS OK %TRUE %END %EXTERNALPREDICATE FTP RECEIVE !=============================== !TEST WHETHER THERE IS INPUT ON EITHER FTP RECEIVERS !AND IF THERE IS SET JUST ONE TO BE ON THE FTP CHANNEL %string(100) MESS %INTEGER IN,N %UNLESS FTP STATE(N,MESS) %START; !IF LINK CLOSED OPEN LOG LOGIT(MESS) RESET TRANSPORT CLOSE LOG %FALSE %FINISH IN=INSTREAM SELECT INPUT(FTP) FTPTST=TRUE N=NEXT SYMBOL %IF FTPTST=TRUE %START; !GOT SOMETHING %IF N&8_300=8_300 %THEN SKIPSYMBOL; !AN OLD DEC-10 FTP TELLING ME ITS NODE NUMBER SELECT INPUT(IN) %TRUE %FINISH SELECT INPUT(IN) %FALSE %END !NOW THE DATA HANDLING ROUTINES %EXTERNALPREDICATE ANY GOT !========================= !TEST WHETHER THERE IS ANY INPUT PENDING ON THE FTP LINK !RETURN TRUE IF THERE IS AND FALSE IF THERE IS NOT %INTEGER N,IN IN=INSTREAM SELECT INPUT(FTP) FTPTST=TRUE N=NEXT SYMBOL SELECT INPUT(IN) %FALSE %IF FTPTST=FALSE FTPTST=FALSE %TRUE %END !THE REST OF THE ROUTINES RELY ON THE FTP STREAM BEING SELECTEDPRIOR TO ENTRY %EXTERNALROUTINE GET(%INTEGERNAME N) !=================================== !GET A SYMBOL FROM THE FTP TRANSPORT SYSTEM READSYMBOL(N) %IF 400>LOGLEVEL>=200 %THEN TMONITOR("",N) %END %EXTERNALROUTINE GOT !==================== !THIS TELLS THE TRANSPORT SYSTEM THAT WE HAVE GOT A FULL RECORD %IF 400>LOGLEVEL>=200 %THEN TMONITOR("GOT WHOLE BUFFER",-1) %END %EXTERNALROUTINE PUT(%INTEGER N) !=============================== !GIVE A SYMBOL TO THE TRANSPORT SYSTEM PRINTSYMBOL(N) %IF LOGLEVEL>=400 %THEN TMONITOR("",N) %END %EXTERNALROUTINE PUT OUT !======================= !THIS INDICATES THAT WE HAVE 'PUT' A FULL RECORD OUT TO THE TRANSPORT !SYSTEM AND THAT WE WISH IT TO BE SENT FTPOUT %IF LOGLEVEL>=400 %THEN TMONITOR("BUFFER OUTPUT",-1) %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& FTP0.IMP !FTP0.IMP ! COPYRIGHT K.FARVIS ERCC. !THIS FILE CONTAINS THE ROUTINES WHICH WILL READ AND WRITE RECORDS AT !LEVEL ONE OF THE FTP PROTOCOL. !THEY USE THE BUFFERS 'SCOM' AND 'RCOM' AND REQUIRE THE ROUTINES !'GET' 'PUT' AND 'PUT OUT' WHICH WORK WITH THE TRANSPORT MECHANISM !DIRECTLY !THE CURRENT INPUT AND OUTPUT STEAMS ARE PRESERVED ACROSS ROUTINE CALLS %EXTERNALINTEGERSPEC XOTHER NODE %EXTERNALINTEGERSPEC MAX SUB RECORD; !FOR OUTPUTTING - SPECIAL FOR UMIST %EXTERNALINTEGERSPEC LOGLEVEL %EXTERNALSTRING(255)%SPEC ERRMSG %EXTERNALINTEGERSPEC SENT,SENT ARG %CONSTINTEGER TRUE=-1, FALSE=0 %CONSTINTEGER TTY=1, LOG=3, FTP=5 %EXTERNALSTRING(8)%FNSPEC TIME %EXTERNALROUTINESPEC WRITEHEX(%INTEGER N,M) %EXTERNALROUTINESPEC GOT %EXTERNALROUTINESPEC GET(%INTEGERNAME N) %EXTERNALROUTINESPEC PUT(%INTEGER N) %EXTERNALROUTINESPEC PUT OUT %OWNINTEGER GET0LEN; !POINTER TO CURRENT BYTE IN RCOM USED BY GET0 ROUTINE %OWNINTEGER FIRST IN SUB RECORD; !FLAG WORD FOR FIRST SUB RECORD BEING INPUT %OWNINTEGER FIRST OUT SUB RECORD; !FLAG WORD FOR FIRST SUB RECORD BEING OUTPUT %OWNINTEGER READ EOR; !FLAG FOR LAST SUB-RECORD HAVING BEEN READ %OWNINTEGER SEND EOR; !FLAG TO SEND LAST SUB-RECORD !THE COMMAND BUFFERS %OWNINTEGERARRAY RCOM(0:63); !INPUT COMMAND BUFFER %OWNINTEGERARRAY SCOM(0:63); !OUTPUT COMMAND BUFFER !LEVEL 0 COMMANDS %CONSTINTEGER STOP=0, GO=1, RPOS=2, RNEG=3, SFT=4, STOPACK=5 %CONSTSTRING(7)%ARRAY COMMANDS0(0:5)="STOP", "GO", "RPOS", "RNEG", "SFT", "STOPACK" !HEADER BIT DEFNITIONS %CONSTINTEGER EOR BIT=16_80, COMPRESSION BIT=16_40, BYTE COUNT=16_3F %ROUTINE NEWLINE !=============== PRINTSYMBOL(NL) %END %EXTERNALROUTINE INIT0 !====================== !initialise the variables for this level FIRST IN SUB RECORD=TRUE FIRST OUT SUB RECORD=TRUE RCOM(0)=0 SCOM(0)=0 %END %ROUTINE R0 !========== !called from the two subsequent routines to get a level 0 subrecord !into the internal buffer RCOM() %INTEGER N,IN,OUT,HEADER IN=INSTREAM; SELECT INPUT(FTP) GET(HEADER) RCOM(0)=HEADER&BYTE COUNT %IF HEADER&EOR BIT#0 %THEN READ EOR=TRUE %ELSE READ EOR=FALSE %IF RCOM(0)>0 %START GET(RCOM(N)) %FOR N=1,1,RCOM(0) %FINISH GOT SELECT INPUT(IN) %IF LOGLEVEL>=10 %START OUT=OUTSTREAM; SELECT OUTPUT(LOG) PRINTSTRING(TIME); PRINTSTRING(" >>-0->>") %IF READ EOR %THEN PRINTSTRING(" EOR ") %ELSE SPACES(5) printstring("Count="); WRITE(RCOM(0),0); PRINTSYMBOL(TAB) %IF FIRST IN SUBRECORD %and RCOM(0)>0 %START; !ONLY FOR FIRST PART OF RECORD PRINTSTRING("Command=") %IF RCOM(1)<=STOPACK %THEN PRINTSTRING(COMMANDS0(RCOM(1))) %ELSE WRITEHEX(RCOM(1),0) %IF RCOM(0)>1 %START; !SOME PARAMETER ARG PRINTSYMBOL(TAB); PRINTSTRING("Parameters="); WRITE(RCOM(2),0) %FINISH %FINISH NEWLINE SELECT OUTPUT(OUT) %FINISH FIRST IN SUB RECORD=FALSE %UNLESS RCOM(0)=0 GET0LEN=1; !RESET BUFFER POINTER %END %EXTERNALROUTINE READ0 !===================== !ISSUED BY THE USER TO GET A NEW LEVEL 0 RECORD FIRST IN SUB RECORD=TRUE R0 %END %EXTERNALROUTINE GET0(%INTEGERNAME N) !==================================== !Issued after an initial READ0 in order to get the items from the level 0 !record and it also reads subsequent subrecords behind the scenes. %WHILE GET0LEN>RCOM(0) %CYCLE %IF READ EOR=TRUE %START ERRMSG="Trying to read beyond a Level 0 record boundary" %SIGNAL 14,1 %FINISH R0; !READ NEXT SUB RECORD %REPEAT N=RCOM(GET0LEN) GET0LEN=GET0LEN+1 R0 %WHILE GET0LEN>RCOM(0) %AND READ EOR=FALSE; !READ AHEAD IF NECESSARY %END %ROUTINE S0 !========== !USED BY THE FOLLOWING TO ROUTINES TO SEND OUT THE DATA IN THE ARRAY 'SCOM' %INTEGER N,EOR,OUT OUT=OUTSTREAM; SELECT OUTPUT(FTP) %IF SEND EOR %THEN EOR=1 %ELSE EOR=0 PUT(EOR<<7!SCOM(0)); !HEADER WORD %IF LOGLEVEL>=10 %START SELECT OUTPUT(LOG) NEWLINE %IF EOR=0 PRINTSTRING(TIME); PRINTSTRING(" <<-0-<<") %IF EOR=1 %THEN PRINTSTRING(" EOR ") %ELSE SPACES(5) PRINTSTRING("Count="); WRITE(SCOM(0),0); SPACE %IF FIRST OUT SUB RECORD %START PRINTSTRING(" Command=") %IF SCOM(1)<=STOPACK %THEN PRINTSTRING(COMMANDS0(SCOM(1))) %ELSE WRITEHEX(SCOM(1),0) PRINTSYMBOL(TAB); PRINTSTRING("Parameters="); WRITE(SCOM(2),0) %FINISH NEWLINE SELECT OUTPUT(FTP) %FINISH %IF SCOM(0)>0 %START PUT(SCOM(N)) %FOR N=1,1,SCOM(0) %FINISH PUT OUT SELECT OUTPUT(OUT) FIRST OUT SUB RECORD=FALSE SCOM(0)=0; !CLEAR ARRAY %END %EXTERNALROUTINE SEND0 !===================== !ISSUED BY USER TO INIIATE OUTPUT OF A LEVEL 0 RECORD SEND EOR=TRUE; !INDICATE LAST SUBRECORD IN SEQUENCE S0 FIRST OUT SUB RECORD=TRUE; !FOR NEXT TIME %END %EXTERNALROUTINE PUT0(%INTEGER N) !=================================== !PUTS A BYTE INTO THE ZERO LEVEL BUFFER AND OUTPUTS A SUB-RECORD IF NECESSARY %IF SCOM(0)=MAX SUB RECORD %START; !OUTPUT A SUB RECORD SEND EOR=FALSE; S0; !SEND IT AS A SUB-RECORD %FINISH SCOM(0)=SCOM(0)+1 SCOM(SCOM(0))=N %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& FTP12.IMP !FTP12.IMP ! COPYRIGHT K.FARVIS ERCC. !THIS IS LEVEL 1 AND 2 OF THE FTP PROTOCOL !THE INPUT/OUTPT STREAM ASSIGNMENTS ARE KEPT ACROSS ROUTIE CALLS %EXTERNALSTRING(255)%SPEC ERRMSG %EXTERNALINTEGERSPEC XOTHER NODE; !THE OTHER NODE FROM US %EXTERNALINTEGERSPEC MAX SUB RECORD; !FOR OUTPUTTING - SPECIAL FOR UMIST %EXTERNALINTEGERSPEC LOGLEVEL %EXTERNALINTEGERSPEC SENT, SENT ARG; !GLOBAL LEVEL 1 SENT CHARS %CONSTINTEGER MAX DATA RECORD=1024; !ALSO DEFINED IN PARAM AND FTPSPL %CONSTINTEGER CR=13, LF=10; !CARRIAGE RETURN AND LINE FEED %CONSTINTEGER TRUE=-1, FALSE=0; !LOGIC SETTINGS %CONSTINTEGER LOG=3, FTP=5 %EXTERNALSTRING(8)%FNSPEC TIME %EXTERNALROUTINESPEC LOGIT(%STRING(255) STR) %EXTERNALROUTINESPEC ABORT OUTPUT %EXTERNALSTRING(12)%FNSPEC INTTOSTR(%INTEGER N) %EXTERNALROUTINESPEC WRITEHEX(%INTEGER N,M) %EXTERNALROUTINESPEC WRITEOCTAL(%INTEGER N,M) %EXTERNALROUTINESPEC GOT %EXTERNALROUTINESPEC GET(%INTEGERNAME N) %EXTERNALROUTINESPEC PUT(%INTEGER N) %EXTERNALROUTINESPEC PUT OUT %EXTERNALINTEGERNAMESPEC XCODE %EXTERNALINTEGERNAMESPEC XFORMAT %EXTERNALINTEGERNAMESPEC XFACILITIES %EXTERNALINTEGERNAMESPEC XRSIZE %EXTERNALINTEGERSPEC BINARY FILE %EXTERNALINTEGERARRAY DATA(0:MAX DATA RECORD); !DATA BUFFER FOR LEVEL 2 %OWNINTEGER DATA PTR; !POINTER TO ABOVE ARRAY %OWNINTEGER MON LINE LENGTH; !FOR MONITOR2 ROUTINE %OWNINTEGER PR2NUM,PR2SYM; !OWNS FOR PRINT2 ROUTINE %OWNINTEGER PENDING; !FOR FORTRAN CARRIAGE CONTROL CHARACTERS !LEVEL 1 COMMANDS %CONSTINTEGER SS=16_40, MS=16_41, CS=16_42, ES=16_43, RR=16_44, MR=16_45, QR=16_46, ER=16_47 %CONSTSTRING(2)%ARRAY COMMANDS1(16_40:16_47) = "SS", "MS", "CS", "ES", "RR", "MR", "QR", "ER" !HEADER BIT DEFNITIONS %CONSTINTEGER EOR BIT=16_80, COMPRESSION BIT=16_40, BYTE COUNT=16_3F !LEVEL 1 AND 2 ROUTINES %EXTERNALROUTINE GET12(%INTEGERNAME N) !===================================== !Get a byte from the transport system, it is used to get a level 1 or 2 header word %INTEGER IN IN=INSTREAM; SELECT INPUT(FTP) GET(N) SELECT INPUT(IN) %END %ROUTINE MONITOR1(%INTEGER SENDING,COM,ARG) !========================================== !output monitoring info to the log file %INTEGER N N=OUTSTREAM SELECT OUTPUT(LOG) PRINTSTRING(TIME) %IF SENDING=TRUE %THEN PRINTSTRING(" <<-1-<< ") %ELSE PRINTSTRING(" >>-1->> ") %IF SS<=COM<=ER %THEN PRINTSTRING(COMMANDS1(COM)) %ELSE WRITEHEX(COM,3) WRITEHEX(ARG,3); PRINTSYMBOL(NL) SELECT OUTPUT(N) %END %EXTERNALROUTINE READ1(%INTEGERNAME RECEIVED,RECEIVED ARG) !========================================================= !read a level 1 command %INTEGER IN IN=INSTREAM; SELECT INPUT(FTP) GET(RECEIVED) GET(RECEIVED ARG) GOT SELECT INPUT(IN) %IF LOGLEVEL>=30 %THEN MONITOR1(FALSE,RECEIVED,RECEIVED ARG) %END %EXTERNALROUTINE SEND1(%INTEGER COMMAND,ARG) !=========================================== !send a level 1 command %INTEGER OUT OUT=OUTSTREAM; SELECT OUTPUT(FTP) PUT(0); !HEADER PUT(COMMAND); SENT=COMMAND PUT(ARG); SENT ARG=ARG PUT OUT SELECT OUTPUT(OUT) %IF LOGLEVEL>=30 %THEN MONITOR1(TRUE,SENT,SENT ARG) %END %EXTERNALROUTINE INIT2 !===================== !initialise the level 2 variables PENDING=SP PR2NUM=0; PR2SYM=0 DATA(0)=0 DATA PTR=1 %END %ROUTINE MONITOR2 HEADER(%INTEGER HEADER) !======================================== !log monitoring info for level 2 header word %STRING(15) STR STR=INTTOSTR(HEADER&BYTE COUNT) %IF HEADER&COMPRESSION BIT#0 %THEN STR=STR." CMPRS " %IF HEADER&EOR BIT#0 %THEN STR=STR." EOR " LOGIT("Header=".STR) MON LINE LENGTH=0 %END %ROUTINE MONITOR2 ITEM(%INTEGER N) !================================= !log monitoring info for level 2 items in record %INTEGER M MON LINE LENGTH=MON LINE LENGTH+1 %IF XCODE=1 %START; !ASCII PRINTSYMBOL(N) M=72 %ELSE WRITEOCTAL(N&16_FF,4) M=20 %FINISH %IF MON LINE LENGTH>M %THEN PRINTSYMBOL(NL) %AND MON LINE LENGTH=0 %END !THE FOLLOWING ROUTINES ARE CALLED FROM 'READ FILE' ROUTINE %EXTERNALROUTINE READ2(%INTEGER HEADER) !====================================== !gets a level 2 data record into the internal data array, from the info given in HEADER as !read by a previous GET12 call %INTEGER N,M,SYM,OUT,IN IN=INSTREAM; SELECT INPUT(FTP) OUT=OUTSTREAM %IF LOGLEVEL>=50 %START SELECT OUTPUT(LOG) %FINISH MONITOR2 HEADER(HEADER) %IF LOGLEVEL>=40 M=HEADER&BYTE COUNT %IF M>0 %START M=DATA(0)+M %IF M>MAX DATA RECORD %START SELECT OUTPUT(OUT); SELECT INPUT(IN) ABORT OUTPUT ERRMSG="Receiving level 2 data larger than the maximum record size" %SIGNAL 10,0,0; !RETURN FATAL ERROR TO READ FILE %FINISH %IF HEADER&COMPRESSION BIT %START GET(SYM) DATA(N)=SYM %FOR N=DATA(0)+1,1,M MONITOR2 ITEM(SYM) %IF LOGLEVEL>=50 %ELSE GET(DATA(N)) %FOR N=DATA(0)+1,1,M %IF LOGLEVEL>=50 %START MONITOR2 ITEM(DATA(N)) %FOR N=DATA(0)+1,1,M %FINISH %FINISH DATA(0)=M %FINISH LOGIT("") %AND SELECT OUTPUT(OUT) %IF LOGLEVEL>=50 SELECT INPUT(IN) %END %ROUTINE PRSYM(%INTEGER DATA) !============================ !ROUTINE FOR OUTPUTING 8-BIT BYTES TO 36-BIT WORDS PR2NUM=PR2NUM+1 %IF PR2NUM=9 %START PRINTSYMBOL(PR2SYM<<8!DATA) PR2SYM=0; PR2NUM=0 %RETURN %FINISH %IF PR2NUM=5 %START PRINTSYMBOL(PR2SYM<<4!DATA>>4) PR2SYM=DATA %RETURN %FINISH PR2SYM=PR2SYM<<8!DATA %END %EXTERNALROUTINE PRINT2(%INTEGER HEADER) !======================================= !TO OUTPUT THE DATA READ BY READ2, TO A FILE %INTEGER N,M %IF BINARY FILE=TRUE %START; !BINARY %IF DATA(0)>0 %START PRSYM(DATA(N)) %FOR N=1,1,DATA(0) %FINISH DATA(0)=0 %RETURN %FINISH !HERE FOR TEXT %IF HEADER&EOR BIT # 0 %START; !EOR %IF XFORMAT&16_2#0 %START; !CARRIAGE CONTROL FEATURE %IF DATA(1)='1' %THEN NEWPAGE %ELSE%IF DATA(1)='+' %THEN PRINTSYMBOL(CR) %ELSE NEWLINE %IF DATA(1)='0' %THEN NEWLINE; !I.E. TWO NEWLINES M=2 %ELSE M=1 %IF DATA(0)>=M %START %FOR N=M,1,DATA(0) %CYCLE %IF DATA(N)=LF %AND XFORMAT&16_2000#0 %THEN PRINTSYMBOL(CR) PRINTSYMBOL(DATA(N)) %IF DATA(N)=CR %AND XFORMAT&16_1000#0 %THEN PRINTSYMBOL(LF) %REPEAT %FINISH %IF XFORMAT&3=1 %THEN NEWLINE; !END OF RECORD=END OF LINE BUT NOT IF FORMATTING DATA(0)=0 %FINISH %END !THE FOLLOWING ROUTINES ARE CALLED FROM 'SEND FILE' ROUTINE %EXTERNALPREDICATE SEND2 !======================= !SEND OUT THE DATA IN THE ARRAY 'DATA' IN SUB RECORDS IF NECESSARY !RETURNS TRUE IF THE LAST SUB-RECORD HAS BEEN OUTPUT AND FALSE OTHERWISE %INTEGER N,M,END,LEN,SYM,HEADER,START,FINISH,OUT OUT=OUTSTREAM START=DATA PTR; FINISH=DATA(0) %IF START+MAX SUBRECORD > FINISH %THEN END=FINISH %ELSE END=START+MAX SUBRECORD-1 LEN=END-START+1 %IF XFACILITIES&1#0 %AND START+2<=END %START; !COMPRESSION %FOR N=START,1,END-2 %CYCLE %IF DATA(N)=DATA(N+1)=DATA(N+2) %START; !FOUND SOMETHING WORTH COMPRESSING %IF N=START %START; !A SUBRECORD FOR COMPRESSION SYM=DATA(N) %FOR M=START+1,1,END %CYCLE %IF DATA(M)#SYM %THEN LEN=M-START %AND %EXIT %REPEAT END=START+LEN-1 HEADER=COMPRESSION BIT!LEN %IF END>=FINISH %THEN HEADER=HEADER!EOR BIT SELECT OUTPUT(FTP) PUT(HEADER); PUT(SYM) %IF LOGLEVEL>=40 %START SELECT OUTPUT(LOG) MONITOR2 HEADER(HEADER) MONITOR2 ITEM(SYM) %IF LOGLEVEL>=50 NEWLINE %FINISH ->RETURN %ELSE; !FOUND SOME COMPRESSION TO DO, SO OUTPUT FIRST BIT FIRST LEN=N-START END=N-1 %EXIT %FINISH %FINISH %REPEAT %FINISH HEADER=LEN %IF END>=FINISH %THEN HEADER=HEADER!EOR BIT SELECT OUTPUT(FTP) PUT(HEADER) %UNLESS LEN=0 %START PUT(DATA(N)) %FOR N=START,1,END %FINISH %IF LOGLEVEL>=40 %START SELECT OUTPUT(LOG) MONITOR2 HEADER(HEADER) %IF LOGLEVEL>=50 %START MONITOR2 ITEM(DATA(N)) %FOR N=START,1,END NEWLINE %FINISH %FINISH RETURN: SELECT OUTPUT(OUT) %IF END>=FINISH %START DATA(0)=0; DATA PTR=1 %TRUE %FINISH DATA PTR=END+1; !MOVE POINTER UP %FALSE; !MORE TO BE OUTPUT %END %EXTERNALROUTINE DATA2(%INTEGERNAME LENGTH,LAST) !=============================================== !ROUTINE TO FILL THE DATA ARRAY FROM A FILE, SETS LAST TO TRUE WHEN THE LAST RECORD HAS BEEN READ %INTEGER LEN,M,N,SYM %ON %EVENT 9 %START LENGTH=DATA(0) LAST=TRUE %RETURN %FINISH %IF BINARY FILE=TRUE %START; !BINARY MODE N=1 %CYCLE %EXIT %IF N+9>XRSIZE; !ON A FULL BUFFER READSYMBOL(SYM) DATA(N)=SYM>>28 DATA(N+1)=SYM>>20 DATA(N+2)=SYM>>12 DATA(N+3)=SYM>>4 DATA(N+4)=SYM<<4; !SO THAT IF NEXT READ BOMBS OUT, THE LAST ! PART OF THE LAST WORD WILL STILL BE TRANSMITTED N=N+4 DATA(0)=N READSYMBOL(SYM) DATA(N)=DATA(N)!SYM>>32 DATA(N+1)=SYM>>24 DATA(N+2)=SYM>>16 DATA(N+3)=SYM>>8 DATA(N+4)=SYM DATA(0)=N+4 N=N+5 %REPEAT N=NEXTSYMBOL; !TEST FOR EOF %ELSE; !TEXT MODE %IF XFORMAT&16_2#0 %START DATA(1)=PENDING; M=2; PENDING=SP; DATA(0)=DATA(0)+1 %ELSE M=1 %FOR LEN=M,1,XRSIZE %CYCLE READ SYMBOL(N) %UNTIL N#0; !IGNORE NULLS %IF 0#XFORMAT#16_80 %START; !FOR APPLICATION OF FORMATTING %IF XFORMAT&2#0 %START; !FORTRAN FORMATTING 1: %IF N=CR %START %IF NEXTSYMBOL=LF %START SKIPSYMBOL; PENDING=SP %ELSEIF NEXTSYMBOL=FF %START SKIPSYMBOL; PENDING='1' %ELSE PENDING='+' %EXIT %ELSE%IF N=FF %START PENDING='1'; %EXIT %ELSEIF N=LF %START PENDING=SP; %EXIT %FINISH %ELSEIF N=CR %AND NEXTSYMBOL=LF %START; !IF EOR IS SIGNIFICANT %IF XFORMAT&16_3001#0 %THEN SKIPSYMBOL %IF XFORMAT&16_2000#0 %THEN N=LF; !LF IMPLIES CR OR ELSE CR IMPLIES LF %EXIT %IF XFORMAT&16_1#0 %ELSEIF N=NL %AND XFORMAT&1#0 %START %EXIT; !IF A NEWLINE CHARACTER %FINISH %FINISH DATA(0)=DATA(0)+1 DATA(DATA(0))=N %IF LEN=XRSIZE %AND XFORMAT&2#0 %START; !FOR END OF RECORD ON FORTRAN FORMATTING N=NEXTSYMBOL %IF N=CR %OR N=LF %OR N=FF %START SKIPSYMBOL; ->1 %FINISH %FINISH %REPEAT %CYCLE N=NEXTSYMBOL; !TEST FOR EOF %EXIT %IF N#0 SKIPSYMBOL; !IGNORE NULLS ESP AT EOF %REPEAT %FINISH LENGTH=DATA(0) LAST=FALSE; !NOT THE LAST RECORD %END %EXTERNALROUTINE SKIP RECORD(%INTEGER HEADER) !============================================ !Skips a record at level 2 given the header word. LOGIT("Ignoring record") READ2(HEADER) DATA(0)=DATA(0)-HEADER&BYTE COUNT %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& FTPREQ.IMP !FTPREQ.IMP !COPYRIGHT K.FARVIS 1978,79 !Contains the fetching of requests generated by the FTP program from the !QUEUE area, checking for legality etc. ! !The format of the request file is as follows: ! ! other node name ! dest node _ dest filename = source node _ source filename ! submitter of request ! d file pass, d username, d username pass, d account, d account pass ! s file pass, s username, s username pass, s account, s account pass ! dest mode, source mode, file type ! output dev type, opmess, monmess,spec option !G ! destination node gateway passwords ! !many of these fields are left blank and unprocessed %CONSTINTEGER TTY=1, QDIR=12, QFILE=13, TRUE=-1, FALSE=0 %EXTERNALROUTINESPEC READPPN(%INTEGERNAME PPN) %EXTERNALSTRING(15)%FNSPEC PPNTOSTR(%INTEGER N) %EXTERNALINTEGERFNSPEC STRTOSIX(%STRING(6) S) %EXTERNALSTRING(6)%FNSPEC SIXTOSTR(%INTEGER N) %EXTERNALROUTINESPEC XRENAME(%RECORD(FILESPEC)%NAME FS,FS1) %EXTERNALROUTINESPEC XDELETE(%RECORD(FILESPEC)%NAME FS) %EXTERNALSTRING(255)%FNSPEC FSTOSTR(%RECORD(FILESPEC)%NAME FS) %EXTERNALRECORD(FILESPEC)%FNSPEC STRTOFS(%STRING(255) SPEC) %EXTERNALSTRING(12)%SPEC OUR SRCNODE %EXTERNALPREDICATESPEC LEGAL ACCESS(%STRING(1)%NAME FIL, %INTEGER MODE, %STRING(20) ACCOUNT,USER,UPASS) %EXTERNALROUTINESPEC REPRT(%STRING(255) MESS) %EXTERNALROUTINESPEC LOGIT(%STRING(255) MESS) %EXTERNALROUTINESPEC TELL USER(%STRING(1)%NAME USER,FIL,%STRING(255) MESSAGE) %EXTERNALROUTINESPEC PARSE DEVICE(%STRING(1)%NAME DEVICE,DEV, %INTEGERNAME NODE,NUM) %EXTERNALROUTINESPEC CHECK NETWRK FILE %EXTERNALPREDICATESPEC ISNODE(%STRING(1)%NAME NODE,TYPE %INTEGERNAME STATUS) %ROUTINESPEC UPPERCASE(%STRING(1)%NAME STR) %ROUTINESPEC END REQUEST %EXTERNALINTEGERSPEC LOGLEVEL %EXTERNALSTRING(255)%SPEC ERRMSG %EXTERNALSTRING(96)%SPEC XSPECIAL %EXTERNALSTRING(96)%SPEC XOPMESS %EXTERNALSTRING(96)%SPEC XMONMESS %EXTERNALSTRING(96)%SPEC XFILENAME %EXTERNALSTRING(20)%SPEC XFILEPASS %EXTERNALSTRING(20)%SPEC XACCOUNT %EXTERNALSTRING(20)%SPEC XACCPASS %EXTERNALSTRING(20)%SPEC XUSERNAME %EXTERNALSTRING(20)%SPEC XUSERPASS %EXTERNALSTRING(20)%SPEC XOUTDEV %EXTERNALSTRING(25)%SPEC XPRIV TCODE %EXTERNALINTEGERNAMESPEC XCODE %EXTERNALINTEGERNAMESPEC XMODE %EXTERNALINTEGERNAMESPEC XFORMAT %EXTERNALINTEGERNAMESPEC XRSIZE %EXTERNALINTEGERSPEC YMODE %EXTERNALSTRING(20)%SPEC XOUR NODE %EXTERNALSTRING(20)%SPEC XOURACCOUNT %EXTERNALSTRING(255)%SPEC XOTHER NODE !G %EXTERNALSTRING(255)%SPEC XGATE PASS %EXTERNALINTEGERSPEC ARPA MAIL %EXTERNALINTEGERSPEC BINARY FILE %EXTERNALSTRING(6)%SPEC QDEV %EXTERNALINTEGERSPEC QUFD %CONSTINTEGER FT=8_4664; !'FT' IN SIXBIT %CONSTINTEGER FTP=8_466460; !IN SIXBIT %CONSTINTEGER FTD=8_466444; !IN SIXBIT %CONSTINTEGER MFD=8_1 000001; !MFD %CONSTSTRING(8) DEC10="DEC10", IBM="IBM", GEC="GEC", PRIME="PRIME", ARPA="ARPA" %CONSTINTEGER UP=1; !NODE STATUS !NOW THE PERMITTED DESTINATION AND SOURCE MODES %CONSTSTRING(7)%ARRAY DEST MODES(0:7)= "", "CREATE", "WRITE", "CWRITE", "APPEND", "CAPPEND", "SUBMIT", "PRINT" %CONSTSHORTINTEGERARRAY DMODES(0:7)= 16_0001, 16_0001, 16_0002, 16_0003, 16_0004, 16_0005, 16_2001, 16_4001 %CONSTSTRING(6)%ARRAY SOURCE MODES(0:3)= "", "NEVER", "DURING", "AFTER" %CONSTSHORTINTEGERARRAY SMODES(0:3)= 16_8002, 16_8002, 16_8004, 16_8001 %OWNRECORD(FILESPEC) QUEFILE; !HOLDS CURRENT QUEUE FILE %ROUTINE READTEXT(%STRING(1)%NAME STR,%INTEGER SEP) !------------------------------------------------- !will read a string up to the separating character and include !bracketed expressions - with [] %INTEGER S STR="" %CYCLE READSYMBOL(S) %IF S='[' %START %CYCLE STR=STR.TOSTRING(S) READSYMBOL(S) %REPEATUNTIL S=']' %FINISH %EXIT %IF S=SEP STR=STR.TOSTRING(S) %REPEAT %END %EXTERNALPREDICATE ANY REQUESTS(%STRING(1)%NAME NEXT) !=============================== !Looks for requests on the QUEUE area and returns true if any present, and !also renames the selected request to .FTD to note that oprocessing is !beginning %RECORD(FILESPEC) FS,QDIRFS %STRING(6) SAVE FILE,SAVE EXT %INTEGER GOT,FILE,EXT,NEXTFILE,FIRST TIME %ON %EVENT 9,10 %START %FALSE %IF EVENT=10 ->END %FINISH %PREDICATE NODE UP !DETERMINE WHETHER THE NODE TO WHICH THE REQUEST REFERS IS UP %string(20) other node,TYPE %STRING(255) DUMMY %INTEGER STATUS,PPN %ON %EVENT 9,10 %START CLOSE INPUT; SELECT INPUT(QDIR) QUEFILE_FILE=SAVE FILE; QUEFILE_EXT=SAVE EXT; !RESTORE OLD FILE NAMES %FALSE %FINISH %IF FIRST TIME=TRUE %START; !IF WE HAVE FOUND A FILE TO TRY ON THIS RUN THROUGH CHECK NETWRK FILE FIRST TIME=FALSE %FINISH SELECT INPUT(QFILE) XDEFINE INPUT(QFILE,QUEFILE) READTEXT(OTHER NODE,NL); UPPER CASE(OTHER NODE) READTEXT(DUMMY,NL) READPPN(PPN) CLOSE INPUT; SELECT INPUT(QDIR) %IF IS NODE(OTHER NODE,TYPE,STATUS) %START %IF STATUS=UP %START %TRUE %ELSE QUEFILE_FILE=SAVE FILE; QUEFILE_EXT=SAVE EXT; !RESTORE OLD VALUES %FALSE %FINISH %ELSE; !NO SUCH NODE REPRT("Deleted request for non-existent host - ".OTHER NODE) END REQUEST; !DELETE REQUEST FOR NON-EXISTENT NODE %FALSE %FINISH %END FIRST TIME=TRUE QDIRFS=0 QDIRFS_DEV=QDEV QDIRFS_FILE=SIXTOSTR(QUFD) QDIRFS_EXT="UFD" QDIRFS_PPN=MFD QDIRFS_SWITCHES="/MODE:#10" XDEFINE INPUT(QDIR,QDIRFS) SELECT INPUT(QDIR) QUEFILE=0; GOT=FALSE; NEXTFILE=STRTOSIX(NEXT) QUEFILE_DEV=QDEV; QUEFILE_PPN=QUFD SAVE FILE=""; SAVE EXT="" !FIND THE FIRST 'FILE'.FTP OR ANY 'FILE'.FTD (I.E. INCOMPLETE TRANSFER) OR 'NEXT' %CYCLE READSYMBOL(FILE); READSYMBOL(EXT); EXT=EXT>>18 %CONTINUE %UNLESS EXT>>6=FT; !IS IT A FILE.FT? SAVE FILE=QUEFILE_FILE; SAVE EXT=QUEFILE_EXT; !SAVE OLD VERSION OF FILE %IF FILE=NEXTFILE %START; !GOT 'NEXT' QUEFILE_FILE=SIXTOSTR(FILE) %IF EXT=FTP %THEN QUEFILE_EXT="FTP" %ELSE QUEFILE_EXT="FTD" %IF NODE UP %START; %FINISH; !CHECK FOR EXISTENCE BUT DO IT ANYWAY GOT=TRUE %EXIT %FINISH %IF EXT=FTD %START QUEFILE_FILE=SIXTOSTR(FILE); QUEFILE_EXT="FTD" %CONTINUE %UNLESS NODE UP; !DO NOT BOTHER TO GO FURTHER GOT=TRUE %EXIT %IF NEXTFILE=0; !SUCCESS %IF NOT LOOKING FOR 'NEXT' %FINISH %IF EXT=FTP %AND GOT=FALSE %START; !NOTE FIRST ONE ONLY QUEFILE_FILE=SIXTOSTR(FILE); QUEFILE_EXT="FTP" %CONTINUE %UNLESS NODE UP; !DO NOT BOTHER TO GO FURTHER GOT=TRUE %FINISH %REPEAT END: CLOSE INPUT; SELECT INPUT(TTY) %FALSE %IF GOT=FALSE %IF QUEFILE_EXT="FTP" %START; !RENAME TO FILE.FTD FS=QUEFILE; QUEFILE_EXT="FTD" QUEFILE_PROT=8_177 XRENAME(FS,QUEFILE) %FINISH XDEFINE INPUT(QFILE,QUEFILE) SELECT INPUT(QFILE) %TRUE %END %EXTERNALROUTINE UPPER CASE(%STRING(1)%NAME STR) !================================================ !Convert the given string to to upper case %STRING(255) STR1 %INTEGER N,L,S L=LENGTH(STR) %RETURN %IF L=0 STR1=STR; STR="" %FOR N=1,1,L %CYCLE S=CHARNO(STR1,N) S=S-32 %IF 'a'<=S<='z' STR=STR.TOSTRING(S) %REPEAT %END %PREDICATE CONVERT MODE(%STRING(1)%NAME DMODE,SMODE, %INTEGERNAME DM,SM) !========================================================================== !Takes the modes given as strings to FTP transfer mode codes for !both source and destination. %INTEGER N %FOR N=0,1,7 %CYCLE %IF DMODE=DEST MODES(N) %THEN DM=DMODES(N) %AND ->SOURCE %REPEAT XMONMESS="Unknown destination mode ".DMODE." in FTP request file" %FALSE SOURCE: %FOR N=0,1,3 %CYCLE %IF SMODE=SOURCE MODES(N) %THEN SM=SMODES(N) %AND %TRUE %REPEAT XMONMESS="Unknown source mode ".SMODE." in FTP request file" %FALSE %END %EXTERNALPREDICATE GET REQUEST(%STRING(1)%NAME FIL) !=================================================== !get and validate the request in the file opened by ANY REQUESTS above !return %TRUE if the request is valid and access permission is allowed or %FALSE !if not and set the reason in ERRMSG. %RECORD(FILESPEC) FS %STRING(96) DFILE,SFILE,DUMMY %STRING(20) DNODE,DFILEPASS,DUSERNAME,DUSERPASS,DACCOUNT,DACCPASS,DMODE %STRING(20) SNODE,SFILEPASS,SUSERNAME,SUSERPASS,SACCOUNT,SACCPASS,SMODE,TYPE,CODE %STRING(6) DEVICE %INTEGER STATUS,SM,DM,NODE,NUM,USERPPN %CONSTINTEGER COMMA=',' %ON %EVENT 9 %START XMONMESS="Illegal FTP request file format" CLOSE INPUT; SELECT INPUT(TTY) %FALSE %FINISH READTEXT(XOTHERNODE,NL) READTEXT(DNODE,'_'); READTEXT(DFILE,'=') READTEXT(SNODE,'_'); READTEXT(SFILE,NL) READPPN(USERPPN); XOURACCOUNT=PPNTOSTR(USERPPN); READTEXT(DUMMY,NL) READTEXT(DFILEPASS,COMMA); READTEXT(DUSERNAME,COMMA); READTEXT(DUSERPASS,COMMA); READTEXT(DACCOUNT,COMMA); READTEXT(DACCPASS,NL) READTEXT(SFILEPASS,COMMA); READTEXT(SUSERNAME,COMMA); READTEXT(SUSERPASS,COMMA); READTEXT(SACCOUNT,COMMA); READTEXT(SACCPASS,NL) READTEXT(DMODE,COMMA); READTEXT(SMODE,COMMA); READTEXT(CODE,NL) READTEXT(XOUTDEV,COMMA); READTEXT(XOPMESS,COMMA); READTEXT(XMONMESS,COMMA); READTEXT(XSPECIAL,NL) !G READTEXT(XGATE PASS,NL) CLOSE INPUT SELECT INPUT(TTY) UPPER CASE(XOTHERNODE) UPPER CASE(DNODE); UPPER CASE(SNODE) UPPER CASE(DMODE); UPPER CASE(SMODE) UPPER CASE(CODE); UPPER CASE(XOUTDEV) %IF XSPECIAL="MAIL" %START ARPA MAIL=TRUE; XSPECIAL="" !SPECIAL FOR EMAS MAIL %IF ISNODE(DNODE,TYPE,STATUS) %AND (TYPE="RCO" %OR TYPE="EMAS") %START DFILE="...MAIL" DMODE="CREATE" %FINISH %ELSE ARPA MAIL=FALSE %IF CODE="BINARY" %START XCODE=2; BINARY FILE=TRUE %ELSE%IF CODE="FORTRAN" %START BINARY FILE=FALSE XFORMAT=3 XCODE=16_1001 %%ELSEIF CODE="TEXT" %START BINARY FILE=FALSE XFORMAT=1; !TEXT MODE FORMATTING XCODE=16_1001 %ELSE; !SET UP PRIVATE CODES XPRIV TCODE=CODE XCODE=8 %FINISH %UNLESS CONVERT MODE(DMODE,SMODE,DM,SM) %THEN %FALSE ;! %IF DM&16_6000 %THEN SM=SM&16_8000!1!(DM&16_6000); !MAKE SM INTO 16_?001 %IF DNODE=XOURNODE %START XOTHERNODE=SNODE XMODE=SM; YMODE=DM XFILENAME=SFILE XFILEPASS=SFILEPASS XUSERNAME=SUSERNAME XUSERPASS=SUSERPASS XACCOUNT=SACCOUNT XACCPASS=SACCPASS %IF ISNODE(SNODE,TYPE,STATUS) %AND TYPE=IBM %START XFORMAT=1 %ELSE %IF TYPE=GEC %START XFORMAT=1; !16_F01 %ELSE %IF TYPE=PRIME %START XFORMAT=1; !16_F01 %FINISH FS=STRTOFS(DFILE) PARSE DEVICE(FS_DEV,DEVICE,NODE,NUM) %IF DEVICE="LPT" %OR DEVICE="PLT" %START XMODE=16_C001; YMODE=16_4001; XOUTDEV=FS_DEV FS_DEV=QDEV; FS_PPN=QUFD %ELSE %UNLESS LEGAL ACCESS(DFILE,DM,XOURACCOUNT,DUSERNAME,DUSERPASS) %START FIL=DFILE XMONMESS=XMONMESS." whilst attempting to write ".DFILE %FALSE %FINISH %FINISH FIL=FSTOSTR(FS) %TRUE %ELSE%IF SNODE=XOURNODE %OR SNODE=OUR SRCNODE %START XMODE=DM; YMODE=SM XOTHER NODE=DNODE XFILENAME=DFILE XFILEPASS=DFILEPASS XUSERNAME=DUSERNAME XUSERPASS=DUSERPASS XACCOUNT=DACCOUNT XACCPASS=DACCPASS %IF ISNODE(DNODE,TYPE,STATUS) %AND TYPE=DEC10 %START; !A DEC-10 FS=STRTOFS(DFILE) PARSE DEVICE(FS_DEV,DEVICE,NODE,NUM) %IF DEVICE="LPT" %OR DEVICE="PLT" %START XMODE=16_4001; YMODE=16_C001; XOUTDEV=FS_DEV %FINISH %ELSE %IF TYPE=IBM %START XFORMAT=1 %IF XMODE=16_2001 %THEN XRSIZE=80 %ELSE XRSIZE=200 %ELSEIF TYPE=GEC %START XFORMAT=1; !16_F01 %ELSE %IF TYPE =PRIME %START XFORMAT=1; !16_F01 %FINISH FIL=SFILE %UNLESS LEGAL ACCESS(SFILE,SM,XOURACCOUNT,SUSERNAME,SUSERPASS) %START XMONMESS=XMONMESS." whilst attempting to read ".SFILE %FALSE %FINISH %TRUE %ELSE XMONMESS="This node not specified for either node" %FINISH %FALSE %END %EXTERNALROUTINE END REQUEST !=========================== !here after a request has been successfully processed. XDELETE(QUEFILE) %END %EXTERNALROUTINE REQUEUE REQUEST !==================================== !Here on some kind of abort to requeue the request %RECORD (FILESPEC) FS FS=QUEFILE FS_EXT="FTP" XRENAME(QUEFILE,FS) %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& FTPMAC.MAC TITLE FTPMAC ;COPYRIGHT K.FARVIS 1978,79 SEARCH IMPPRM,UUOSYM EXTERN CNTRLC,FTPTST ENTRY ERR,HIBARG,TOUT ENTRY MACINI,SETTIM TWOSEG 400000 INTLOC: PORTAL .+1 ;ALLOW EXECUTE ONLY ENTRY SKIPN CNTRLC ;ARE WE ALLOWING? JRST [setom 1 ;yes getlch 1 tlz 1,4 ;set echo back on setlch 1 RESET ;CLEAR ANY JACCT EXIT] ;EXIT MOVEM 1,SAV ;SAVE AC MOVE 1,INTBLK+2 ;GET RETURN ADDR EXCH 1,SAV ;EXCHANGE RETURN ADDR AND AC1 SETZM INTBLK+2 ;REENABLE INTERRUPTS JRST @SAV ;DISMISS ;MACINI SETS UP THE INTERRUPT BLOCK MACINI: MOVE 1,[4,,INTLOC] MOVEM 1,INTBLK ;STORE IN INTERRUPT BLOCK MOVEI 1,2 ;TRAP CTL C'S MOVEM 1,INTBLK+1 SETZM INTBLK+2 SETZM INTBLK+3 SETZM CNTRLC ;SET CNTRLC FLAG TO FALSE MOVEI 1,INTBLK MOVEM 1,.JBINT## ;STORE IN JOBDAT MOVE T1,[%CNTIC] ;GET NUMBER OF TICKS PER SECOND GETTAB T1, JRST ERR MOVEM T1,TICKS POPJ P, SUBTTL TIMEOUT SETTING ;SETTIM TAKES NUMBER OF SECONDS AS ARGUMENT ; %ROUTINE SETTIM(%INTEGER SECS) SETTIM: MOVE T1,TICKS ;GET CLOCK TICKS IMUL T1,ARG1 ;GET TIMEOUT AS TICKS MOVEM T1,TOUT ;SAVE HRRZI ARG1,^D2000 ;MILLISECS - USE 2 SECOND SLEEP TIMES HRLI ARG1,100 ;I/O FINISHED BIT MOVEM ARG1,HIBARG ;SAVE AS HIBERNATE ARGUMENT SETZM FTPTST ;SET TEST FLAG TO FALSE POPJ P, ERR: SETZ AC, ERROR ^D14,0,AC,IMPSTR RELOC 0 TOUT: Z TICKS: Z HIBARG: Z SAV: 0 INTBLK: BLOCK 4 PRGEND SUBTTL READING SEARCH IMPPRM,UUOSYM EXTERN $INTST,$OUTTST,OUTSCB,INSCB,INERR EXTERN ERR,FTPTST,HIBARG,TOUT EXTERN GSEGS,PSEGS ENTRY FTPRD,FTPWT,FTPOUT TWOSEG 400000 FTPRD: MOVSI T1,400000 ;SET BIT 0 FOR TESTING FOR ZERO SYMBOL SKIPGE FLAGS(IOREG) ;IS THE ZERO SYMBOL PENDING BIT SET(BIT 0) JRST (J) ;YES RETURN ZERO FTPRD0: SOSGE 0,BYTCNT(IOREG) JRST FTPR01 ILDB AC,BYTPTR(IOREG) SKIPN AC ;IS IT ZERO IORM T1,FLAGS(IOREG) ;YES, NOTE IT JRST (J) ; AND RETURN FTPR01: XCT 0,IBUFOP(IOREG) ;GET A BUFFER JRST FTPR0X ;GOT ONE XCT STATZ(IOREG) ;TEST ERROR BITS JRST $INTST ;SOME SET SKIPE FTPTST ;ARE WE ONLY TESTING JRST [SETZM FTPTST ;CLEAR INDICATOR JRST (J)] ;RETURN MOVE AC,UPTIM GETTAB AC, ;GET UPTIME JRST ERR ADD AC,TOUT ;ADD TIMOUT PERIOD MOVEM AC,FINISH ;START TIMEOUT TIMER FTPR02: MOVE IOREG,INSCB MOVE AC,HIBARG HIBER AC, ;HIBERNATE TILL I/O OR TIME SKIP XCT IBUFOP(IOREG) ;INPUT AGAIN JRST FTPR0X ;GOT SOMETHING XCT STATZ(IOREG) JRST $INTST PUSH P,J ;SAVE J,T1 AND ARG1 PUSH P,ARG1 PUSH P,T1 PUSH P,IOREG PUSHJ P,FTPUP## ;ARE WE STILL ACTIVE? POP P,IOREG POP P,T1 POP P,ARG1 POP P,J JUMPE AC,INERR ;THE CALL IS CLOSED MOVE AC,UPTIM GETTAB AC, ;GET NEW TIME JRST ERR CAMGE AC,FINISH ;HAVE WE TIMED OUT? JRST FTPR02 ;NOT YET, TRY AGAIN FTPR03: SETZ AC, ERROR ^D14,0,AC,IMPSTR ;HERE TO FIX A TSKSER BUG, WHERE THE BYTE COUNT GETS SCREWED IN THE BUFFER CONTROL ;BLOCK BUT IS CORRECT IN THE BUFFER HEADER, DUE TO TSKSER NOT GETTING CALLED ;BY UUOCON. FTPR0X: REPEAT 0,< SKIPN IBUFFS ;DO WE WANT TO TYPE THE BUFFERS OUT JRST FTPRX1 ;NO PUSH P,BUFADR(IOREG) PUSHJ P,PRRING## ;OUTPUT THE RING TO TTY: FTPRX1: >;END REPEAT AOS GSEGS ;ADD ONE TO THE NUMBER OF SEGMENTS RECIEVED HRRZ AC,BUFADR(IOREG) ;GET THE BUFFER ADDRESS HLRZ AC,1(AC) ;GET DAP TYPE CAIL AC,1 ;IS DAP TYPE LESS THAN 1 (DATA WITHOUT EOR) CAILE AC,2 ;IS IT DATA ? JRST FTPR01 ;NO THROW IT AWAY HRRZ AC,BUFADR(IOREG) ;GET BUFFER ADDRESS AGAIN HRRZ AC,1(AC) ;GET THE BYTE COUNT IN HEADER ;* SPECIAL TO FIX A BUG WHERE THE COUNTS GET OUT OF STEP MOVEM AC,BYTCNT(IOREG); TELL THE CONTROL BLOCK WHAT IT SHOULD BE. JRST FTPRD0 ;AND THEN READ THEM SUBTTL WRITING FTPWT: SOSGE 0,BYTCNT(IOREG) JRST FTPWTO IDPB ARG1,BYTPTR(IOREG) POPJ P, FTPWTO: MOVEI T1,FTPWT ;RETURN TO WRITER AFTER THE OUT UUO PUSH P,T1 FTPOUT: MOVE IOREG,OUTSCB XCT 0,OBUFOP(IOREG) PJRST WAIT XCT STATZ(IOREG) ;TEST ERROR BITS JRST OUTTST ;SOME SET MOVE T1,UPTIM GETTAB T1, ;GET UPTIME JRST ERR ADD T1,TOUT ;ADD TIMOUT PERIOD MOVEM T1,FINISH ;START TIMEOUT TIMER FTPWT2: MOVE IOREG,OUTSCB MOVE T1,HIBARG HIBER T1, ;HIBERNATE TILL I/O OR TIME JFCL XCT OBUFOP(IOREG) ;OUTPUT PJRST WAIT ;DONE XCT STATZ(IOREG) JRST OUTTST MOVE T1,UPTIM GETTAB T1, ;GET NEW TIME JRST ERR CAMGE T1,FINISH ;HAVE WE TIMED OUT? JRST FTPWT2 ;NOT YET, TRY AGAIN FTPWT3: SETZ AC, MOVE T1,(P) ;LOCATE STACK BACK TO CALLING ROUTINE CAIN T1,FTPWT ;WAS IT FTOM FTPWT POP P,T1 ;YES, POP IT ERROR ^D14,0,AC,IMPSTR OUTTST: MOVE T1,(P) ;LOCATE STACK BACK TO CALLING ROUTINE CAIN T1,FTPWT ;WAS IT FTOM FTPWT POP P,T1 ;YES, POP IT JRST $OUTTST WAIT: ;HERE WHEN OUT UUO HAS BEEN DONE BUT WE WAIT IN ORDER TO BE SURE MOVE T1,[CALLI 10] ;START CONSTRUCTING THE WAIT CALLI LDB T2,[POINT 4,OBUFOP(IOREG),12];GET THE CHANNEL NUMBER DPB T2,[POINT 4,T1,12] ;MAKE WAIT CHAN, COMMAND XCT T1 ;DO IT REPEAT 0,< SKIPN OBUFFS ;DO WE WANT TO TYPE OUT BUFFERS? POPJ P, ;NO, FINISHED PUSH P,BUFADR(IOREG) PUSHJ P,PRRING## >;END REPEAT AOS PSEGS ;ADD ONE TO THE NUMBER OF SEGMENTS OUTPUT POPJ P, RELOC 0 IBUFFS: Z ;FLAG FOR TYPEING INPUT BUFFERS OBUFFS: Z ;FLAG FOR TYPEING OUTPUT BUFFERS FINISH: Z UPTIM: %NSUPT END $$$$$$$$$$$$ &&&&&&&&&&&& CONFIG.MAC TITLE CONFIG CONTAINS VERSION NUMBER AND EDIT HISTORY ; COPYRIGHT K.FARVIS ERCC 1980,1981,1982 VWHO==0 VFTP==16 VMINOR==0 VEDIT==74 SEARCH JOBDAT LOC .JBVER BYTE (3)VWHO(9)VFTP(6)VMINOR(18)VEDIT RELOC REPEAT 0,< **REVISION HISTORY** Prior to version 10 it worked ok to DEC-10s and GECs and the IBM but not with all facilities of the latter two. ;VERSION 10 ;15 Add ability to delete entries in FTP queue when they have started transferring Add support for defaulting to XFORMAT=0 for text mode transfers. Allow the type of /ACCESS switch determine what one is prompted for in an FTP request. Add ability to send to GEC devices as well as files. ;16 REMOVE XFORMAT=0 FACILITY IT WAS WRONG. CHECK FOR /DEL:NEVER TO GECS AS THE ONLY VALID SWITCH 17 ADD ESSEX AND HATFIELD MACHINES, INCREASE TIMEOUT TO 30 MINUTES AND SET A NODE DOWN AFTER 3 SUCCESSIVE TIMEOUTS. ALSO FIX XOUTDEV PARAMETER ON A /ACC:PRINT 20 ADD PRIME SUPPORT 21 ADD SET NODE= COMMAND AND FIX TEST MODE TRANSFERS TO GECS 22 ADD OXFORD VERSION 11 23 add support for network mail (xoutdev=POST) and allow job submission on the DEC-10s both for mail and IBM output (xoutdev=D60) also change node names to 4 chars and only generate the end "f" in TRANSP module and in FSTORE when checking SWITCH.INI 24 MAKE MORE ROBUST, CATCH MORE ERRORS 25 Make set gateway=? work 26 PROGRAM ROUND PROBLEM WITH BYTE COUNT BEING WRONG IN TSKSER VERSION 12 -START VERSION 1 COMPATIBILITY 27 DO NOT OUTPUT VERSION ID PARAMETER AND ACCEPT 0 OR 1 ALLOW POST TO A DEVICE ALLOW A FILE SPEC TO DEFAULT TO CURRENT PATH RATHER THAN PPN 30 ALLOW POST TO GO TO A TTY DEVICE - E.G. CTY: FOR EASY COMMNS. 31 make changes for ARPA post format compatibility VERSION 13 FTP80 COMATIBILITY PHASE 1 32 make major FTP80 compatibility changes up to stage one as defined in Chris Coopers paper to SERCNET network devel meeting 25-aug-81 also add Private transfer code parameter to allow a value="36BIT" for DEC-10 interworking 33 Add full support for ARPA MAIL according to Chris Bennets revised paper use TSK. UUO to get name of remote process prompt for nul IBM DATASET name 34 start sending full [P,PN]s as username only use one listening task TSK:FTP do not send out node number to DEC-10s but get it from TSK. UUO but tolerate an incoming old type of task change to allow remote node names in /USERS field 35 make complete use of TSK. UUO and iuse NETWRK.ADD for the addresses 36 make qdevice and our SRC name be generated in FNODES so that we do not have to build new versions for every machine 37 A FEW BUG FIXES FOR FTP80 AND MAIL 40 bug fixes to recover from bad packet/window size, send EORs on blank lines at level 2 and move to proper TS addresses in NETWRK.ADD 41 sort problem of not always sending mapping params and not sending filename and username back on a mail request. also look upand read netwrk.add whenever it changes VERSION 14 42 ADD ABILITY FOR USER TO DEFINE HIS LOCAL NETWRK.ADD FILE add allowance for take job input with no filename 43 Sort SET NODE *XXXX OFFLINE and do a frig for Queueing under galaxy v4 REMOVE LOCAL NETWRK.ADD FACILITY AND INSTEAD ADD /GATEPASS SWITCH 44 INCREASE MAX DATA RECORD SIZE TO 1024 45 fix ABORT OUTPUT routine to work correctly and increase TS address length to 150 chars 46 search multiple FTP lines in switch.ini output a PSS log to FTPPSS.LOG[3,3] test that a set phys guide 40 or 50 pages makes it work better - it does check for newer NETWRK.ADD file when you check for requests 47 INCLUDE SUPPORT FOR DL PROTOCOL CONVERTER 50 DO NOT REJECT NEW FTP-80 PARAMS BUT JUST MONITOR THEM 51 (POST) CONVERT TO INTERFACE TO GALAXY V4 FTP80 (FTP) ON A /KILL: COMMAND, FOR POST, DELETE POST FILE AS WELL (MAISPL) SORT OUT BUGS WITH SENDING BACK BUM MESSAGES 52 (FTPSPL) send STOPACK to FTP80s and wait for another SFT or TS RESET (POST) add a To: field 53 (FTP)(FTPSPL) add EMAS private code 54 (FTP)(FTPSPL) use 36BIT private code between DEC10s 55 (FTP)(FTPSPL) for DEC10s start sending destination PPN as username and remove requirement for/USERS switch in switch.ini 57 (FTPSPL) various fixes for EAAK, including: a) sending monitoring back on RPOS of parameters which I have changed b) making code to read NETWRK.ADD file more secure c) make a "Reading level 2 data beyond record boundary" a fatal error **VERSION 15** 60 (FTXSPL) CHANGE name to FTXSPL and add TASK command. (MAISPL) make more inteligent for error reporting and fix a bug whereby "[1,2]" became [1,2]" 61 (FTXSPL) make all error messages have the SENDING etc line prefixing them (MAISPL) put in mail-list and relaying code 62 (post) make mail to oneself work properly (mailspl) make SRC mail work properly 63 (post) make POST send only JNT mail - maispl still receives old SRC 64 (post) create post file with <077> protection (maispl) change Comment: to Comments: field, and do relaying properly and change logging information format. and convert TELL messages to own 65 (post) add support for TELL.INI names and make a reply-to field (maispl) sort out various problems with MIC file and recover from bad mail files 66 (maispl) add SETUSR program use and make MIC file more robust. 67 (all) make galaxy version 4 code dependent on a sigle module - QUEUE (not quite true - a hack in PSTLIB to force old mail) and make mail even more robust. *****VERSION 16**** 70 (FTXSPL) fix enormously longstanding problem where TSK input buffers get set up in the wrong place - randomly. I have no idea how FTXSPL ever worked properly. (FTXSPL) put raw TS address at start of incoming mail file rather than interpreting it in order to be compatible with York code. (FTXSPL) change the way that the log file is opened so that it is closed between transfers. (FTXSPL) be more intelligent about putting nodes down. (FTXSPL) convert the task name in the TASK command to upper case. (POST) put in a via field when sending mail so that we know exactly which ANF-10 node it came from. (POST) put post files in users own area rather than [3,5] (MAISPL) put * at the start of each line to POST on an error, so as not to ^C out with a . at the start of a line. (MAISPL) interpret TS address at head of mail file. 71 (POST) DO NOT ALLOW WILDCARDS IN TELL.INI FILE DEFINITIONS (FTXSPL) USE KBYTES IN WHAT MESSAGE 72 (MAISPL+ FTXSPL) fix mail addressing problems from ANF-10 hosts (MAISPL) fix problem of relaying to our own host by another name (MAISPL) if mail is sent to me as as a funny host name I will now accept it. (POST) sort problem of mail being created on wrong [3,5] disk area (FTXSPL) make private codes work again (FTXSPL) remove support for EMAS-EMAS private code, fix 36BIT private code (POST) make queue. UUO work (except that /dispose:delete does not work) (POST) use the destination user name as the jobname (MAISPL) add logging to print out the headers of each file in MAIL.LOG (POST) do not use a via field to indicate the local ANF-10 node -use a comment in the From field. 73 (FTXSPL) make P process wait for other end to clear call down or send stopack (FTXSPL) fix Fortran formatting problem as a P station (FTXSPL) fix NEXT command and remove extra s from log file (FTXSPL) do not fall over if FTP request in for non-existent node (MAISPL) double up ' and ^ chars in mail to be returned, so that MIC does not munge them. (POST) sort out replies of 'yes' or 'no' to REPLY-TO prompt (POST) did not delete null post file when it bombed out (say no indirect file) (MAISPL) add logging of headers as a runtime option switch .RUN MAISPL-HEADERS ****RELEASE TAPE TO YORK,DUNDEE,BANGOR,HATFIELD,ESSEX,OXFORD**** 74 (MAISPL) change name of job back to MAIL SYSTEM when finished ****VERSION 17**** **END OF REVISION HISTORY** >;end of repeat 0 END $$$$$$$$$$$$ &&&&&&&&&&&& QUEUE.IMP !QUEUE.IMP !ENTERS A FILE INTO A GIVEN GALAXY QUEUE %INCLUDE "IMP:IOLIB.INC" %CONSTINTEGER MAX STREAMS=15 %EXTERNALRECORD(SCBNAME)%ARRAY %SPEC INVEC(-1:MAX STREAMS) %EXTERNALRECORD(SCB)%NAMESPEC INSCB %EXTERNALRECORD(FILESPEC)%FNSPEC STRTOFS(%STRING(255) STR) %EXTERNALPREDICATESPEC CALLI2(%INTEGER N,%INTEGERNAME X) %EXTERNALSTRING(6)%FNSPEC SIXTOSTR(%INTEGER N) %EXTERNALINTEGERFNSPEC PPN %SYSTEMPREDICATESPEC GETTAB(%INTEGER N,M,%INTEGERNAME RES) %externalstring(255)%fnspec asctostr(%name adr) %systemroutinespec zero(%name from,to) %externalintegerfnspec strtosix(%string(6) s) %externalintegerfnspec strtooct(%string(1)%name s) %externalroutinespec strtoasc(%string(1)%name s, %name adr) %externalstring(12)%fnspec inttostr(%integer n) %EXTERNALROUTINESPEC QUEUEIT(%NAME N,%STRING(1)%NAME MESS); !TO SEND REQUEST TO QUASAR %EXTERNALSTRING(255)%SPEC ERRMSG %owninteger edinburgh %constinteger true=-1, false=0 !now the galaxy v4 data %constinteger maxarg=25 %recordformat arg pair(%integer type,value) %recordformat queue argument(%integer function,node,response %record(arg pair)%array arg(1:max arg)) %ownrecord (queue argument) quearg !now the galaxy v4 symbols %constinteger quprt=1, quplt=4, qubat=5 %constinteger qbfil=8_10, qbfrm=8_12, qbodp=8_14, qblim=8_17, qblog=8_22 %constinteger qbnod=8_25, qbnam=8_26, qboid=8_27, qbnot=8_30, qbblt=8_31 %constinteger qbjbn=8_32, qbfrr=8_37 !now the FTP ones %constinteger quftp=8_777777 %constinteger qbfad=8_777777, qbfun=8_777776, qbfup=8_777775, qbfan=8_777774 %constinteger qbfap=8_777773, qbfma=8_777772 ,qbflo=8_777771, qbfmo=8_777770 %constinteger qbffn=8_777767, qbffp=8_777766, qbfco=8_777765, qbfde=8_777764 %constinteger qbfio=8_777763, qbfpr=8_777762, qbfso=8_777761, qbfml=8_777760 !now the values %constinteger qblnl=1, qbllg=2, qblle=3 %constinteger qbnty=1 %constinteger qbbnd=1, qbbde=2, qbbsp=3 %constinteger print device=8_5460, plot device=8_6054, batch device=8_5156; !sixbit/lp/pl/in/ %STRING(6)%FN DEVICE OF(%RECORD(FILESPEC) FS) !================================================== !returns the device on which a file exists ! %STRING(6) DEV %INTEGER N,M,TEMP,ARG,DEVNAME %RECORDFORMAT DSKCHR(%INTEGER NAM,UFT,FCT,UNT,SNM) %RECORD(DSKCHR) D %IF FS_DEV#"" %THEN %RESULT=FS_DEV %ELSE FS_DEV="ALL" %FOR N=1,1,MAX STREAMS %CYCLE %IF INVEC(N)_NAME_DEVTYP=UNDEV %START TEMP=N; ->OK %FINISH %REPEAT ERRMSG="No free streams for routine QUEUE " %SIGNAL 10 OK: FS_SWITCHES="/EXT:#16" XDEFINE INPUT(TEMP,FS) N=INSTREAM; SELECT INPUT(TEMP) DEVNAME=INSCB_LKENT_DEV CLOSE INPUT SELECT INPUT(N) D=0 D_NAM=DEVNAME ARG=5<<18!ADDR(D) %IF CALLI2(8_45,ARG) %START; %FINISH %RESULT = SIXTOSTR(D_SNM) %END %INTEGERFN ERSATZ(%STRING(6) DEV) !================================ !RETURNS THE PPN IMPLIED BY AN ERSATZ DEVICE NAME %INTEGER PN %CONSTINTEGER DEVPPN=8_55, DSK=8_446353 000000; !SIXBIT 'DSK' %RESULT=0 %IF LENGTH(DEV)#3 PN=STRTOSIX(DEV) %RESULT=0 %IF PN=DSK %OR %NOT CALLI2(DEVPPN,PN) %RESULT=PN %END %INTEGERFN GETJOB(%INTEGER N) %INTEGER M %UNLESS GETTAB(N,-1,M) %START M=0 %FINISH %RESULT=M %END %externalpredicate is version 4 !============================== !IS THIS VERSION 4 GALAXY? %integer cty,n %constinteger where=8_63, get special pid=8_126 cty=8_436471 000000; !sixbit/cty/ %if calli2(where,cty) %and cty=8_50 %then edinburgh=true %else edinburgh=false; !i.e. EDXA %true %IF GETTAB(get special pid,3,N) %AND N#0; !PID for MDA %false %END %routine set arg(%integername args,%integer type,value) !====================================================== !fill in a value for the queue argument record args=args+1 quearg_arg(args)_type=type; quearg_arg(args)_value=value %end %externalroutine FTP(%record(filespec)%name file, %string(1)%name jobnm,dest,dfile,user, %c pass %integer gateway,mode,mail,dispose,log %string(1)%name resp) !================================================================================================================ !routine for issuing ftp requests to galaxy v4 using QUEUE. UUO ! !FILE name of DEC-10 file !JOBNM name of the job !DEST name of remote machine !DFILE name of remote file !USER name of remote user !PASS password for remote user !GATEWAY node through which to send transfer !MODE 1=Make 2=Replace 3=Replace-make 4=Append 5=Append-make 6=Job input 7=Job output !MAIL non-zero for mail !DISPOSE non-zero for delete !LOG 1=Append 2=Supercede 3=Spool log file !RESP is a (255) string for response from GALAXY ! %integerarray response(1:52) %integerarray address(1:4) %integerarray filename,dfilename(1:11) %integerarray username,userpass(1:4) %string(12) str %integer n,i,error,disp,jobnam,d,node,args zero(response(1),userpass(4)); !zero arrays !file in file block filename(1)=strtosix(file_dev) filename(2)=strtosix(file_file) filename(3)=strtosix(file_ext) filename(4)=file_ppn filename(5)=strtosix(file_sfds(1)) filename(6)=strtosix(file_sfds(2)) filename(7)=strtosix(file_sfds(3)) filename(8)=strtosix(file_sfds(4)) filename(9)=strtosix(file_sfds(5)) !now the destination file strtoasc(dfile,dfilename(1)) !fill in the destination address %if length(dest)>6 %start address(1)=strtosix(substring(dest,1,6)) %if length(dest)>=12 %then n=12 %else n=length(dest) address(2)=strtosix(substring(dest,7,n)) %else address(1)=strtosix(dest) address(3)=gateway !the job name jobnam=strtosix(jobnm) !Now the username strtoasc(user,username(1)) !now the password strtoasc(pass,userpass(1)) %if dispose#0 %then disp=1 %else disp=0 !set up the request quearg=0; args=0 quearg_function=1<<35!quftp; !set response bit quearg_node=-1 ;!central site quearg_response=52<<18!(addr(response(1))&8_777777) set arg(args,9<<18!qbfil,addr(filename(1))) set arg(args,10<<18!qbffn,addr(dfilename(1))) set arg(args,3<<18!qbfad,addr(address(1))) set arg(args,4<<18!qbfun,addr(username(1))) set arg(args,4<<18!qbfup,addr(userpass(1))) set arg(args,8_400001<<18!qbjbn,jobnam) ;!/jobname:? set arg(args,8_400001<<18!qbflo,log) ;!/ftplog:? set arg(args,8_400001<<18!qblog,qbllg) ;!/output:always set arg(args,8_400001<<18!qbodp,disp) ;!/disp:? set arg(args,8_400001<<18!qbnot,qbnty) ;!/notify set arg(args,8_400001<<18!qbfmo,mode) ;!/mode:? set arg(args,8_400001<<18!qbfio,1) ;!/direc:out set arg(args,8_400001<<18!qbfml,mail) ;!/mail:? ac(1)=(3+(args*2))<<18!addr(quearg)&8_777777 *8_047040 000201; !queue. 1, *8_634100 000002; !tdza 2,2 *8_476000 000002; !setom 2 %if ac(2)=0 %start error=ac(1) resp="[File did not get queued to GALAXY - error code = ".inttostr(error)."]" %return %finish resp=asctostr(response(1)) %end %externalroutine mail(%record(filespec)%name file, %string(1)%name jobnm,dest, %c %integer gateway, %string(1)%name resp) !============================================================================================ !to do v4 mail %string(12) blank blank="" FTP(file,jobnm,dest,blank,blank,blank,gateway,1,1,1,1,resp) %end %externalroutine que v4(%record(filespec)%name file, %string(1)%name jobname,user, %c device %integer user ppn,size,limit,dispose,log %string(1)%name resp) !================================================================================================================ !routine for issuing mail requests to galaxy v4 using QUEUE. UUO %integerarray response(1:52) %integerarray filename(1:9) %integerarray username(1:2) %string(12) str %integer n,i,error,disp,jobnam,d,node,args zero(response(1),username(2)); !zero arrays !file in file block filename(1)=strtosix(file_dev) filename(2)=strtosix(file_file) filename(3)=strtosix(file_ext) filename(4)=file_ppn filename(5)=strtosix(file_sfds(1)) filename(6)=strtosix(file_sfds(2)) filename(7)=strtosix(file_sfds(3)) filename(8)=strtosix(file_sfds(4)) filename(9)=strtosix(file_sfds(5)) !Now the username N=LENGTH(USER) %IF N=0 %START USERNAME(1)=GETJOB(8_31) USERNAME(2)=GETJOB(8_32) %ELSE %IF N<6 %THEN I=N %ELSE I=6 USERNAME(1)=STRTOSIX(SUBSTRING(USER,1,I)) USERNAME(2)=STRTOSIX(SUBSTRING(USER,7,N)) %IF N>6 %FINISH %IF USER PPN=0 %THEN user ppn=PPN %IF JOBNAME="" %THEN JOBNAM=STRTOSIX(FILE_FILE) %ELSE jOBNAM=STRTOSIX(JOBNAME) %if dispose#0 %then disp=1 %else disp=0 d=strtosix(device); node=(d&8_777777)>>6; d=d>>24; !get device and node %if node#0 %start str=sixtostr(node) node=strtooct(str) %finish !set up the type of request quearg=0; args=0 %if d=print device %start quearg_function=quprt %elseif d=plot device %start quearg_function=quplt %elseif d=batch device %start quearg_function=qubat disp=0 %else resp="[Cannot queue to device ".device."]" %return %finish quearg_function=1<<35!quearg_function; !set response bit quearg_node=-1 ;!central site quearg_response=52<<18!(addr(response(1))&8_777777) set arg(args,9<<18!qbfil,addr(filename(1))) set arg(args,2<<18!qbnam,addr(username(1))) set arg(args,8_400001<<18!qblim,size<<18!limit) ;!/limit:? and /core:? ***requires patch to QSRQUE set arg(args,8_400001<<18!qbnod,node) ;!/node:? set arg(args,8_400001<<18!qboid,user ppn) ;!/ppn: set arg(args,8_400001<<18!qbjbn,jobnam) ;!/jobname:? ! set arg(args,8_400001<<18!qbfrm,0) ;!/forms: ! set arg(args,8_400001<<18!qbnot,qbnty) ;!/notify %if quearg_function=1<<35!qubat %start; !for batch output set arg(args,8_400001<<18!qblog,log) ;!/output:? set arg(args,8_400001<<18!qbblt,2) ;!/batlog:supercede %else set arg(args,8_400001<<18!qbodp,disp) ;!/disp:? %finish ac(1)=(3+(args*2))<<18!addr(quearg)&8_777777 *8_047040 000201; !queue. 1, *8_634100 000002; !tdza 2,2 *8_476000 000002; !setom 2 %if ac(2)=0 %start error=ac(1) resp="[File did not get queued to GALAXY - error code = ".inttostr(error)."]" %return %finish resp=asctostr(response(1)) %end %EXTERNALROUTINE QUEUE(%STRING(70) FILSPEC, %STRING(12) JOB NAME, USER NAME,DEVICE,%INTEGER USER PPN,SIZE,LIMIT,DISPOSE,LOG,%STRING(1)%NAME MESSAGE) !==================================================================================================== ! !This routine sends a file request to QUASAR for V2 or calls QUE V4 for version 4 ! !Arguments are: !FILSPEC a full filespec which if it does not include a structure name ! the file will be looked up for it. !JOB NAME the JOB NAME in the queue which defaults to the file name !USER NAME which defaults to the user name of this job !DEVICE any device recognised by QUASAR, may include node number !USER PPN PPN of request, defaults to this jobs PPN !SIZE OUTPUT size of file in blocks, INPUT memory size in pages !LIMIT OUTPUT page limit or INPUT time limit(seconds) !DISPOSE for OUTPUT 0 = preserve, 1=delete, 2=rename ! for INPUT /output:value !LOG what to do with the log file for batch jobs ! 1=nolog, 2=always, 3=only on error ! %RECORDFORMAT FPARAM(%INTEGER SIZE,INF,START,REP1,REP2) %RECORDFORMAT FD(%INTEGER DEV,FILE,EXT,PPN,%INTEGERARRAY SFD(1:5)) %RECORDFORMAT EQ(%INTEGER HEAD,PID,LEN,REQDEV,JOBNAME,SEQ,SPC,AFT,DED,LIM1, %C LIM2,LIM3,LIM4,LIM5,%INTEGERARRAY CHECK(1:5),ACC(1:8),USERNAME(1:2), %C %INTEGER OWNER, %INTEGERARRAY OWN PATH(1:5),%RECORD(FPARAM) FP, %RECORD(FD) F, %C %RECORD(FPARAM) FP1, %RECORD(FD) F1) %RECORD(EQ) E %RECORD(FILESPEC) FS %INTEGER N,I,EPPN,LEN,SIZ,NUM OF FILES, DELETE, OUTPUT SW,CTY %CONSTINTEGER QSRVER=8_33; !QUEUE VERSION %CONSTINTEGER EQLEN=35, FPLEN=9 ; !LENGTH OF EQ AND BASIC F %CONSTINTEGER INP DEV=8_515660; !SIXBIT/INP/ %ON %EVENT 15 %START PRINTSTRING(ERRMSG) PRINTSTRING("IN QUEUE routine") %RETURN %FINISH FS=STRTOFS(FILSPEC) %IF FS_FILE="" %START ERRMSG="filename missing in QUEUE request" %signal 15 %FINISH EPPN=ERSATZ(FS_DEV) %IF EPPN#0 %START FS_PPN=EPPN; FS_DEV=""; !USE ERSATZ PPN %FINISH FS_DEV=DEVICE OF(FS) %if is version 4 %or edinburgh=true %start; !galaxy v4 que v4(fs,job name,user name,device,user ppn,size,limit,dispose,log,message) %return %FINISH E=0; !initialise the record E_LEN=QSRVER<<18!EQLEN E_REQDEV=STRTOSIX(DEVICE) %if DISPOSE>1 %then DISPOSE=1 %IF E_REQDEV>>18=INP DEV %START; !DISTINGUISH BETWEEN INPUT AND OUTPUT QUEUES NUM OF FILES=2; DELETE=0; OUTPUT SW=DISPOSE!8_500!LOG; !UNIQUE AND NON-RESTARTABLE %ELSE NUM OF FILES=1; DELETE=DISPOSE; OUTPUT SW=0 %FINISH %IF JOBNAME="" %THEN E_JOBNAME=STRTOSIX(FS_FILE) %ELSE E_JOBNAME=STRTOSIX(JOBNAME) E_SEQ=8_600!(GETJOB(8_26)<<12); !STATION # OF LAST LOCATE COMMAND AND PRIV BIT TO ALLOW DELETES AFTER PRINTING E_SPC=NUM OF FILES ;!NUMBER OF REQUESTS E_LIM1=OUTPUT SW<<27 E_LIM2=SIZE<<18!LIMIT N=LENGTH(USERNAME) %IF N=0 %START E_USERNAME(1)=GETJOB(8_31) E_USERNAME(2)=GETJOB(8_32) %ELSE %IF N<6 %THEN I=N %ELSE I=6 E_USERNAME(1)=STRTOSIX(SUBSTRING(USERNAME,1,I)) E_USERNAME(2)=STRTOSIX(SUBSTRING(USERNAME,7,N)) %IF N>6 %FINISH %IF USER PPN=0 %THEN E_OWNER=PPN %ELSE E_OWNER=USER PPN !Now fill the file parameter block E_FP_INF=8_10001 000001!(DELETE&1)<<17; !STANDARD BIT SETTINGS E_FP_START=1 !Now fill the file definition record E_F_DEV=STRTOSIX(FS_DEV) E_F_FILE=STRTOSIX(FS_FILE) E_F_EXT=STRTOSIX(FS_EXT) %IF FS_PPN=0 %THEN E_F_PPN=PPN %ELSE E_F_PPN=FS_PPN SIZ=4; !SIZE OF PATH BLOCK LEN=EQLEN+FPLEN; !BASIC LENGTH OF ENTRY %FOR N=1,1,5 %CYCLE %EXIT %IF FS_SFDS(N)="" SIZ=SIZ+1; !INCREASE LENGTH OF PATH BLOCK COUNT LEN=LEN+1; !INCREASE LENGTH OF ENTRY COUNT E_F_SFD(N)=STRTOSIX(FS_SFDS(N)) %REPEAT E_FP_SIZE=5<<18!SIZ %IF NUM OF FILES=2 %START E_FP1=E_FP; E_F1=E_F; E_F1_EXT=STRTOSIX("LOG"); !PUT IN A LOG FILE E_FP1_INF=E_FP1_INF!8_200000; !SAY THIS IS THE LOG FILE E_FP_SIZE=5<<18!FPLEN; !USE MAX PATH SIZE FOR FIRST SPEC LEN=LEN+FPLEN+5; !ADD ONE MORE FILESPEC OVER THE BASIC LENGTH %FINISH E_HEAD=8_400000 000007!(LEN<<18); !REPLY, LENGTH AND TYPE(7=CREATE) QUEUEIT(E,MESSAGE) %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& SETSRC.IMP %INCLUDE "IMP:IOLIB.INC" %EXTERNALRECORD(SCB)%NAME%SPEC INSCB %EXTERNALSTRING(6)%FNSPEC SIXTOSTR(%INTEGER I) %EXTERNALROUTINESPEC RESET INPUT %EXTERNALROUTINESPEC USET INPUT(%INTEGER N) %OWNINTEGER N,F,C,CC,I,I1,I2,J,NENTRY %CONSTINTEGER MAX ENTRIES=5500 %OWNINTEGERARRAY PPNS(1:MAX ENTRIES) %OWNINTEGERARRAY LOCATION(1:MAX ENTRIES) %CONSTINTEGER UUPHS=8_400000000000; !Physical lookup %CONSTINTEGER IODMP=8_17; !Dump mode I/O %CONSTINTEGER OPEN=8_050; !Open UUO %CONSTINTEGER LOOKUP=8_076 %CONSTINTEGER ENTER=8_077 %CONSTINTEGER USETO=8_075 %CONSTINTEGER UFD=8_654644000000; !SIXBIT/UFD/ %CONSTINTEGER RBDIR=8_400000; !This is a directory bit %CONSTINTEGER STRUUO=8_50; !STRUUO code %OWNINTEGERARRAY STR ARG(1:50); !Where STRUUO args get built ! !Standard library ROUTINE s ! %EXTERNALSTRING(255)%SPEC ERRMSG %EXTERNALROUTINESPEC SLEEP(%INTEGER TIME) %EXTERNALPREDICATESPEC CALLI2(%INTEGER N,%INTEGERNAME AC) %SYSTEMROUTINESPEC CLOSE(%INTEGER CHAN) %SYSTEMINTEGERFNSPEC GET CHANNEL %SYSTEMPREDICATESPEC IO UUO(%INTEGER UUO,CHAN,%NAME ARG) %SYSTEMROUTINESPEC RELEASE(%INTEGER CHAN) ! ! %OWNINTEGER NSTRUCS; !No of structures %OWNINTEGER CREATION=0; !Creation date/time of AUXACC.SYS %OWNINTEGER CHAN=0; !I/O channel %CONSTINTEGER TEMP STREAM=13; !TEMP STREAM NUMBER %ROUTINE READ AUXACC(%INTEGERNAME NO) !============================================= ! !Reads AUXACC.SYS putting PPN's into array PPN, and Location of the !first word (-1) of an entry into Location ! %ON %EVENT 9 %START NO=N %RETURN %FINISH %INTEGERFN NEXT READ SYMBOL(C) F=F+1 %RESULT=C %END F=0 CC=NEXT; !Throw away first entry N=0 %CYCLE %SIGNAL %EVENT 15,1,1 %UNLESS NEXT=-1 N=N+1 %IF N>MAX ENTRIES %THEN %SIGNAL 15,1,6 NO=NEXT; !No of words to follow PPNS(N)=NEXT; !PPN LOCATION(N)=F-3 CC=NEXT %FOR I=1,1,NO-1 %REPEAT %END %INTEGERFN FIND(%INTEGER PPN) !===================================== N=0 %FOR I=1,1,NENTRY %CYCLE %IF PPN=PPNS(I) %THEN %RESULT=LOCATION(I) %IF PPNFALSE %FINISH %TRUE %IF PPN=PREVIOUS PPN CHAN=-1 IN=INSTREAM DEFINE INPUT(TEMP STREAM,"SYS:AUXACC.SYS/MODE:#400000000014/EXTEND:#35/BUFF:1") SELECT INPUT(TEMP STREAM) %IF CREATION#INSCB_LKENT_TIM %START READ AUXACC(NENTRY) CREATION=INSCB_LKENT_TIM RESET INPUT %FINISH I1=FIND(PPN) %IF I1=0 %THEN ->FALSE I2=I1>>7 I1=I1&8_177 USET INPUT(I2+1) %IF I1>0 %START SKIP SYMBOL %FOR I=1,1,I1 %FINISH READ SYMBOL(C) READ SYMBOL(N) READ SYMBOL(CC) %SIGNAL %EVENT 15,1,1 %UNLESS C=-1 %AND (CC=PPN %OR CC=PPN!8_777777) CHAN=GET CHANNEL N=N//5 NSTRUCS=0 ZERO SEARCH LIST DO UFD(PPN) %FOR I=1,1,N SET SEARCH LIST RELEASE(CHAN) CLOSE INPUT; SELECT INPUT(IN) PREVIOUS PPN=PPN %TRUE FALSE: RELEASE(CHAN) %IF CHAN>=0; !IF ONE IN USE CLOSE INPUT SELECT INPUT(IN) PREVIOUS PPN=0 %FALSE %END %ENDOFFILE $$$$$$$$$$$$ &&&&&&&&&&&& GALAXY.MAC TITLE GALAXY interface to GALAXY SEARCH QSRMAC ;GALAXY PARAMETERS SEARCH SBSMAC ;SUB-SYSTEMS GROUP MACROS SEARCH MACTEN ;USEFUL MACROS SEARCH UUOSYM ;TOPS10-UUO SYMBOLS IFN FTJSYS, ;TOPS20-JSYS SYMBOLS SEARCH QPRM ;MPB PARAMETERS SEARCH IMPPRM ;IMP PARAMETERS DEFINE FAIL(MSG)< JRST [MOVEI 1,%A MOVEI 2,ERRMSG## JSP J,.$MOVE## POP P,J ;GET ORIG RETURN ADDRESS MOVEI ARG1,^D15 ;%SIGNAL 15 SETZB ARG2,ARG3 GOTO .$SNAL## %A: MSG] > ;END OF DEFINE FAIL ; MACRO TO MOVE DATA AROUND -- WIPES TEMP DEFINE DATAM(SWRD,SFIELD,DWRD,DFIELD)< LOAD(TEMP,SWRD,SFIELD) XLIST STORE(TEMP,DWRD,DFIELD) LIST SALL > ;END OF DEFINE DATAM TWOSEG RELOC 400000 ;%EXTERNALROUTINE QUEUEIT(%NAME ARG BLOCK,%STRING(1)%NAME MESSAGE) QUEUEIT:: SETMM 110(P) ;STACK CHECK PUSHJ P,SAVEACS## ;SAVE IMP REGISTERS MOVEM ARG2,SARG2# ;SAVE THE STRING NAME ADDRESS HRRZ M,ARG1 ;SET UP M MOVEI T1,1000 ;NUMBER OF WORDS PUSHJ P,CORGET ;GET A PAGE MOVE T1,.JBFF## ;GET TOP OF CORE SOS T1 ;MAKE SURE IN LOWER PAGE ANDI T1,777000 ;GET START OF PAGE MOVEI T2,(T1) ;GET ANOTHER COPY SETZM (T1) ;CLEAR IT HRLI T3,(T1) ;SET UP BLT POINTER HRRI T3,1(T1) BLT T3,777(T1) ;ZERO PAGE HRL T1,M ;SET UP BLT POINTER BLT T1,77(T2) ;COPY ARG BLOCK INTO FREE PAGE MOVE M,T2 ;SET UP NEW M TXO M,1B0 ;MARK AS PAGE MODE PUSHJ P,MSGSND ;SEND THE MESSAGE PUSHJ P,RCVACK ;GET THE ACK PJRST RESTORE## ;RESTORE ACS AND RETURN TO CALLER CPOPJ: POPJ P, CORGET: ADDB T1,.JBFF## ;BUMP HIGHEST, GET SAME SUBI T1,1 ;BACK OFF BY ONE CAMG T1,.JBREL## ;ALREADY HAVE ENOUGH POPJ P, ;YES, CAN SAVE A CORE UUO CORE T1, ;ACQUIRE THE CORE FAIL(IMPSTR) POPJ P, ;AND RETURN ;ERROR ROUTINES ;ERR CONCATENATES THE STRING POINTED TO BY T1 ONTO THE END OF ERRMSG ERR: MOVE 1,T1 MOVEI 2,ERRMSG## JSP J,.$CONC## ;CONCATENATE ONTO ERRMSG POPJ P, IFN FTUUOS,< QUEQRY: SETZB T1,T2 ;CLEAR QUERY BLOCK SETZB T3,T4 ;FOR GOOD MEASURE MOVE S2,[4,,T1] ;LENGTH,,ARGUMENTS IPCFQ. S2, ;FIND OUT WHATS THERE SETZ T4, ;NOTHING, CLEAR T4 MOVE S2,T4 ;COPY QUEUE STATUS INTO S2 JUMPE S2,CPOPJ ;RETURN IF NOTHING THERE CAMN T2,QSRPID ;FROM QUASAR POPJ P, ;YES, RETURN NOW PUSHJ P,QUEIGN ;FLUSH THE JUNK MAIL JRST QUEQRY ;LOOK AGAIN QUEIGN: ANDX T1,IP.CFV ;CLEAR ALL BUT PAGE MODE BIT TXO T1,IP.CFT ;SET TO TRUNCATE SETZB T2,T3 ;CLEAR THEM AGAIN MOVEI T4,1 ;LENGTH = 0 , LOC = 1 MOVE S2,[4,,T1] ;SET UP LENGTH AND BLOCK ADDRESS IPCFR. S2, ;THROW AWAY THE MESSAGE FAIL(IMPSTR) POPJ P, ;RETURN QUEWAT: PUSHJ P,QUEQRY ;FIND OUT WHATS THERE JUMPN S2,CPOPJ ;SOMETHING, RETURN MOVX S2, ;FLAGS,,NAP TIME HIBER S2, ;WAIT FOR A REASONABLE TIME JFCL ;WATCH THIS LOOP JRST QUEWAT ;TRY NOW > ;END OF IFN FTUUOS ; SUBROUTINE TO RECEIVE AN EXPECTED "ACK" FROM QUASAR ; IT RETURNS TO THE CALLER AFTER RECEIVING A "GOOD" ONE ; ISSUES AN ERROR MESSAGE AND QUITS ON A "BADDY" RCVACK: MOVEI M,FBTEMP ;AREA FOR SHORT RECEIVE IFN FTUUOS,< PUSHJ P,QUEWAT ;WAIT FOR A RETURNED MESSAGE ANDX T1,IP.CFV ;CLEAR ALL BUT THE PAGE MODE BIT SETZB T2,T3 ;CLEAR THESE AGAIN HRRI T4,(M) ;WHERE TO RECEIVE INTO TXNN T1,IP.CFV ;IS IT A PAGE JRST RCVA.1 ;NO, GO GET IT MOVE M,.JBREL## ;GET A PAGE TO RECEIVE INTO MOVEI M,777(M) ;ROUND UP ADR2PG M ;CONVERT TO PAGE NUMBER HRRI T4,(M) ;SET THE ADDRESS HRLI T4,1000 ;LENGTH OF A PAGE PG2ADR M ;STILL NEED TO POINT TO IT RCVA.1: MOVE S2,[4,,T1] ;READY TO GET IT IPCFR. S2, ;GET THE ACK FROM QUASAR FAIL(IMPSTR) > ;END OF IFN FTUUOS IFN FTJSYS,< SETZB T1,T2 ;CLEAR FLAGS, SENDER MOVE T3,MYPID ;RECEIVER HRLI T4,FBAREA ;SIZE OF SHORT MESSAGE HRRI T4,FBTEMP ;TEMPORARY BLOCK PUSH P,S1 ;SAVE USER AREA BASE MOVEI S1,4 ;FOUR WORDS MOVEI S2,T1 ;IN T1-T4 MRECV ;RECEIVE THE ACK FAIL(IMPSTR) POP P,S1 ;RESTORE USER BASE > ;END OF IFN FTJSYS LOAD S2,TEX.ST(M) ;GET THE MESSAGE STATUS WORD TXNE S2,TX.NMS ;NORMAL "ACK" (NO MESSAGE ASSOCIATED) JRST RCVA.3 ;YES, SEE IF IT IS TIME TO RETURN ;FALL ONTO THE NEXT PAGE FOR THE OUTPUT OF THE MESSAGE RECEIVED ;HERE TO OUTPUT THE BODY OF THE ACK MESSAGE RCVA.4: SETZM ERRMSG## ;CLEAR ERROR MESSAGE PUSH P,S2 ;SAVE S2 MOVEI T1,[IMPSTR<[>] ;CHARACTER FOR INFORMATIONAL MESSAGES TXNN S2,TX.FAT!TX.WRN ;FATAL OR WARNING JRST RCVA.2 ;NEITHER, JUST REPORT THE TEXT MOVEI T1,[IMPSTR] ;FATAL CHARACTER TXNN S2,TX.FAT ;WAS IT FATAL MOVEI T1,[IMPSTR<%QSR>] ;NO, LOAD WARNING CHARACTER PUSHJ P,ERR ;OUTPUT THE "?" OR "%" LOAD T1,TEX.ST(M),TX.SUF ;GET THE MESSAGE SUFFIX HRLZS T1 ;INTO THE OTHER SIDE FOR TTYSIX MOVE ARG1,T1 ADDI P,4 PUSHJ P,SIXTOS## ;OUTPUT THE FULL ERROR CODE MOVEI T1,-1(P) PUSHJ P,ERR SUBI P,4 MOVEI T1,[IMPSTR< >] RCVA.2: PUSHJ P,ERR ;MAKE THE OUTPUT PRETTY MOVEI ARG1,TEX.MS(M) ;AND FINALLY, OUTPUT THE MESSAGE ADDI P,103 PUSHJ P,ASCTOS## MOVEI T1,-77(P) PUSHJ P,ERR SUBI P,103 MOVE S2,(P) TXNN S2,TX.FAT!TX.WRN ;ANOTHER CHECK JRST [MOVEI T1,[IMPSTR<]>] ;GEE..IT TAKES A LOT TO DO NICE WORK PUSHJ P,ERR JRST .+1] POP P,S2 TXNE S2,TX.FAT ;AGAIN, WAS IT FATAL JRST FAIL1 ;NO, WELL STORE IT FOR IMP PUSH P,S2 MOVEI 1,ERRMSG MOVE 2,SARG2 JSP J,.$MOVE ;MOVE IT TO SECOND ARGUMENT POP P,S2 RCVA.3: TXNE S2,TX.MOR ;MORE COMING JRST RCVACK ;YES, DO THIS ALL OVER AGAIN POPJ P, ;CONTINUE PROCESSING FAIL1: POP P,J ;GET ORIGINAL RETURN ADDRESS MOVEI ARG1,^D15 SETZB ARG2,ARG3 JRST .$SNAL## IFN FTUUOS,< MSGSND: MOVX T4,%CNST2 ;GET SECOND STATES WORD GETTAB T4, ;TO LOOK FOR GALAXY-10 ZERO T4 ;WHAT!! TXNN T4,ST%GAL ;SYSTEM HAVE SUPPORT FOR GALAXY-10 FAIL(IMPSTR) SETO T4, ;FLAG INDICATING FIRST TRY MSGS.1: MOVX T3,%SIQSR ;GETTAB FOR PID OF [SYSTEM]QUASAR GETTAB T3, ;SEE IF IT IS RUNNING FAIL(IMPSTR) MOVEM T3,QSRPID ;REMEMBER QUASAR'S PID SETOM RTYCNT ;INIT RETRY COUNTER JUMPN T3,MSGGO ;THERE HE IS, SEND THE MESSAGE MOVEI T3,3 ;NOT UP YET, TRY A SLEEP SLEEP T3, ;GIVE IT A CHANCE AOJN T4,MSGS.1 ;JUMP IF ALREADY GAVE A MESSAGE OUTSTR [ASCIZ/ %QMRWFQ Waiting For [SYSTEM]QUASAR to Start /] JRST MSGS.1 ;TRY NOW MSGGO: SETZB T1,T2 ;CLEAR FLAGS,MY PID MOVEI T4,(M) ;MESSAGE ADDRESS, T3 = QSRPID LOAD S2,.MSTYP(M),MS.CNT ;GET THE LENGTH OF THE MESSAGE TXNN M,1B0 ;IS THIS A PAGE MODE REQUEST JRST MSGGO1 ;NO, SEND IT MOVX T1,IP.CFV ;INDICATE A PAGE SEND LSH T4,-^D9 ;CONVERT 'M' TO A PAGE NUMBER MOVEI S2,1000 ;LENGTH MUST BE 1000 MSGGO1: HRL T4,S2 ;INCLUDE CORRECT SIZE IN HEADER MSGGO2: MOVE S2,[4,,T1] ;ARGUMENT FOR SEND IPCFS. S2, ;SEND THE MESSAGE SKIPA ;FAILED, SEE WHY POPJ P, ;RETURN TO CALLER CAIE S2,IPCDD% ;QUASAR DISABLED CAIN S2,IPCRS% ;OR MY QUOTA EXHAUSTED JRST RETRY ;YES, TRY IT AGAIN CAIE S2,IPCRR% ;QUASAR FULL CAIN S2,IPCRY% ;OR SYSTEM FULL JRST RETRY ;YES, TRY IT AGAIN FAIL(IMPSTR) RETRY: MOVEI S2,2 ;WAIT BEFORE TRYING AGAIN SLEEP S2, ;TAKE A QUICK NAP AOSE RTYCNT ;COUNT THE RETRIES JRST MSGGO2 ;TRY NOW OUTSTR [ASCIZ/ %QMRMBR Send has failed, Message Being Re-sent /] JRST MSGGO2 ;NOW RETRY IT > ;END OF IFN FTUUOS IFN FTJSYS,< MSGSND: SETO T4, ;FLAG INDICATING FIRST TRY PUSH P,S1 ;SAVE USER BASE MSGS.1: MOVEI S1,3 ;NUMBER OF WORDS MOVEI S2,T1 ;USE T1-T3 MOVEI T1,.MURSP ;READ SYSTEM PID TABLE MOVX T2,.SPQSR ;WANT PID OF SYSTEM QUASAR MUTIL ;READ THE TABLE SETZ T3, ;ASSUME IT CONTAINS AN INVALID PID MOVEM T3,QSRPID ;REMEMBER QUASAR'S PID SETOM RTYCNT ;INIT RETRY COUNTER JUMPN T3,MSGGO ;JUMP IF QUASAR IS RUNNING MOVEI S1,^D3000 ;WAIT FOR IT DISMS ;TAKE A NAP AOJN T4,MSGS.1 ;JUMP IF ALREADY GAVE A MESSAGE OUTSTR [ASCIZ/ %QMRWFQ Waiting For [SYSTEM]QUASAR to Start /] JRST MSGS.1 ;TRY NOW MSGGO: SETZ T1, ;ASSUME NO FLAGS SKIPN T2,MYPID ;DO I HAVE A PID TXO T1,IP%CPD ;NO, CREATE ONE ON THIS SEND MOVEI T4,(M) ;POINT TO THE MESSAGE LOAD S2,.MSTYP(M),MS.CNT ;GET THE LENGTH OF THE MESSAGE TXNN M,1B0 ;IS THIS PAGED JRST MSGGO1 ;NO, SEND IT TXO T1,IP.CFV ;SET PAGE MODE FLAG LSH T4,-^D9 ;CONVERT ADDR TO A PAGE NUMBER MOVEI S2,1000 ;LENGTH OF A PAGE MSGGO1: HRL T4,S2 ;INCLUDE THE LENGTH MOVEI S1,4 ;FOUR WORDS MOVEI S2,T1 ;IN T1-T4 MSEND ;SEND THE PACKET JRST MSGGO2 ;FAILED, SEE WHY SKIPN MYPID ;DO I ALREADY HAVE THE PID MOVEM T2,MYPID ;NO, SAVE IT POP P,S1 ;RESTORE S1 POPJ P, ;AND RETURN TO CALLER ;MORE OF THE TOPS20 VERSION ON THE NEXT PAGE MSGGO2: CAIE S1,IPCFX6 ;CHECK FOR EXHAUSTED QUOTAS CAIN S1,IPCFX7 ;AND RETRY IF POSSIBLE JRST RETRY ;IS POSSIBLE CAIE S1,IPCFX8 ;ANOTHER RECOVERABLE ERROR CAIN S1,IPCFX5 ;QUASAR DISABLED JRST RETRY ;YES, TRY AGAIN FAIL(IMPSTR) RETRY: SKIPN MYPID ;DO I HAVE A PID MOVEM T2,MYPID ;NO, MAYBE THIS IS IT MOVEI S1,^D2000 ;WAIT BEFORE TRYING AGAIN DISMS ;WAIT AOSE RTYCNT ;COUNT THE RETRIES JRST MSGGO ;TRY NOW OUTSTR [ASCIZ/ %QMRMBR Send has failed, Message Being Re-sent /] JRST MSGGO ;AND TRY THE SEND AGAIN > ;END OF IFN FTJSYS SUBTTL Data Storage XLIST ;FORCED OUT LITERAL POOL LIT LIST SALL FBSIZE==FPXSIZ+FDXSIZ ;THE LARGEST FD/FP WE CAN BUILD MAX FBAREA==MAXSIZ ;THE LARGEST FILE BLOCK/MESSAGE NEEDED RELOC 0 MYPID: BLOCK 1 ;MY PID (NECESSARY FOR SEND/RECEIVE) QSRPID: BLOCK 1 ;PID OF SYSTEM QUASAR RTYCNT: BLOCK 1 ;RETRY COUNTER WHEN SEND TO QUASAR FAILS FBTEMP: BLOCK FBAREA ;LARGEST FILE BLOCK THAT CAN BE BUILT FROM MPB DATA ;ALSO USED TO SEND/RECEIVE "SHORT" MESSAGES END ;END, NO STARTING ADDRESS $$$$$$$$$$$$ &&&&&&&&&&&& FTP.CMD FTP.IMP,FNODES.IMP,FTPMAC.MAC/LIB,CONFIG.MAC,SETSRC $$$$$$$$$$$$ &&&&&&&&&&&& FTXSPL.CMD FTXSPL.IMP,FTP0.IMP,FTP12.IMP,PARAM.IMP,FSTORE.IMP,TRANSP.IMP,FTPMAC.MAC,FNODES.IMP,FTPREQ.IMP,CONFIG.MAC,SETSRC,QUEUE,GALAXY $$$$$$$$$$$$ &&&&&&&&&&&& FTP.RNO .AP.FLAGS ALL FTP-B as implemented on the ERCC DECsystem-10 .s It has been modified for interworking with FTP-80 .p 0 The ERCC DECsystem-10 now supports an implementation of FTP-B as described in the document (1). The facilities offered in this implementation are listed below. .s TRANSPORT SERVICE Has timeout facilities. Does not have Transport Reset but does a clear down and re-initialise. Synchronisation at startup is done by exchanging node id's. .s .ts 30 ATTRIBUTES Comment .LM 30 .s .i-30 [00] Protocol id yes, =0 and accepts 0 - FF .i-30 [01] Mode of access .i-26 [0001]Make only yes,default for writing .i-26 [0002]Replace only yes .i-26 [0003]Replace or Make yes .i-26 [0004]Append yes .i-26 [0005]Append or Make yes .i-26 [2001]Take Job Input yes, default for device IBM: .i-26 [4001]Take Job Output yes, default for device LPT: .i-26 [8001]Read and Remove yes .i-26 [8002]Read only yes, default for reading .i-26 [8004]Destructive read no, meaningless on DEC-10 .i-26 [A001]Give Job Input yes, default for device IBM: .i-26 [C001]Give Job Output yes, default for device LPT: .i-30 [02]Codes .i-26 [0001]IA5 yes .i-26 [0002]Binary yes .i-26 [0004]EBCDIC no .i-26 [0008]Private no .i-26 [0FF0]reserved no .i-26 [1000]Any parity yes, parity ignored .i-26 [2000]Odd parity no .i-26 [4000]Even parity no .i-26 [8000]Parity Bit Zero no .i-30 [03]Format Effectors .i-26 [0001]End of Record yes .i-26 [0002]Fortran Contol yes .i-26 [0010] CR yes .I-26 [0020] LF yes .i-26 [0040] NL yes .i-26 [0080] FF yes .i-26 [0100] VT yes .i-26 [0200] HT yes .i-26 [0400] BS yes .i-26 [1000] CR->LF yes .i-26 [2000] LF->CR yes .i-30 [04]Binary Mapping yes, [0024] - aligned packing into 36-bit word - only .i-30 [05]Max Record Size yes, =252 .i-30 [06]Max Transfer Size yes, no effect .i-30 [08]Transfer id yes, no effect .i-30 [0A]Ack Window no, ignored .i-30 [0B]Initial Restart Mark no, ignored .i-30 [0D]Min Time-out yes .i-30 [0E]Facilities .i-26 [0001]Compression yes .i-26 [0002]Retry later no .i-26 [0004]Restart Requests no .i-26 [0008]Restart Acks no .i-26 [0010]Hold no .i-26 [0020]GO Params. no .i-26 [FFC0]Reserved .i-30 [0F]State of Transfer yes .i-30 [40]Filename yes, full DEC-10 filespec allowed dev:name.ext[ppn,sfds] .i-30 [42]Username yes, PPN as an octal string of the area on Q to be read from or written to .i-30 [44]Username pass yes, FTP password for the area on Q to be read from or written to .i-30 [45]File pass yes, ignored .i-30 [46]Kinship yes, ignored .i-30 [4A]Account yes, PPN as an octal string of the submitter of the request .i-30 [4B]Account pass yes, ignored .i-30 [50]Output Device Type yes .i-30 [60]File Size yes, .i-30 [70]Operator message yes .i-30 [71]Monitor Message yes, kept in log file .i-30 [80]Special Options no, not allowed .s 2.lm 0 DATA TRANSFER PHASE .s .lm 30 .i-30 [40] SS yes .i-30 [41] MS yes, ignored .i-30 [42] CS no, not allowed .i-30 [43] ES yes .i-30 [44] RR no, not allowed .i-30 [45] MR no, not allowed .i-30 [46] QR yes .i-30 [47] ER yes .lm 0.S 2 IMPLEMENTATION .AP It is implemented as a spooling system using network tasks, transfer requests being generated by a program like QUEUE. See documents (2) and (3) for a description of these programs. .s 2 REFERENCES .S 1.#A Network Independent File Transfer Protocol prepared by the High level Protocol Group .b 2.#Section 3A55B of the Edinburgh Installation Manual - SRC DECsytem-10 Installation ERCC .b 3.#Operators Guide to FTP - SRC DECsystem-10 Installation ERCC. $$$$$$$$$$$$ &&&&&&&&&&&& FTP.RNH .NF The commands are as follows:- DESTINATION__SPEC/SWITCHES = SOURCE__SPEC/SWITCHES generate a request to do this transfer /EXIT return to monitor mode /HELP type a list of the options available /LIST list the FTP queue of requests, submitted on this machine /KILL:SEQ_# remove the given request from the queue /NODES type a list of hosts which FTP recognises .f.S DESTINATION and SOURCE are node names and SPECs for DEC-10s are full DEC-10 file specifications. The default node is the current node, the default directory is ones own and default output file-name is the same as the input file-name. .S The output switches are /PASSWORD and /ACCESS, the input switches are /PASSWORD and /DELETE all of which may be abbreviated. The /PASSWORD values are the FTP passwords given in the users SWITCH.INI file and if omitted but required, you are prompted later. .nf The /ACCESS values are: CREATE(default), WRITE, CWRITE, APPEND, CAPPEND, SUBMIT and PRINT SUBMIT is the default for device IBM: and PRINT for LPT: The /DELETE values are: NEVER(default), DURING and AFTER These defaults may be redefined in SWITCH.INI $$$$$$$$$$$$ &&&&&&&&&&&& 3A55B.RNO .ps 60,64 .t3A55B FTP-Transferring Files Across the Network 3A55B#####################################################Page#1 ##########################################################Sep 80 .st Sep 80 .nap .s10 .c64 FTP - TRANSFERRING FILES ACROSS THE ICF NETWORK .s3 .nf .s2 CONTENTS page .s2 1##BACKGROUND .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 2 .s 2##IMPLEMENTATION . .. .. .. .. .. .. .. .. .. .. .. .. .. 2 .s 3##REQUESTING A TRANSFER .. .. .. .. .. .. .. .. .. .. .. 2 .s 4##THE FTP PROGRAM .. .. .. .. .. .. .. .. .. .. .. .. .. 3 .s 5##EXAMPLES . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 5 .s 6##REQUIREMENTS FOR OTHER HOSTS ON SERCNET .. .. .. .. .. 5 .s 7##FILE ACCESS PERMISSION .. .. .. .. .. .. .. .. .. .. .. 7 .s 8##INTERROGATING THE QUEUES .. .. .. .. .. .. .. .. .. .. 9 .s 9##KILLING A REQUEST . .. .. .. .. .. .. .. .. .. .. .. .. 9 .s 10#LISTING AVAILABLE HOSTS . .. .. .. .. .. .. .. .. .. .. 10 .s 11#LOG OF TRANSFERS .. .. .. .. .. .. .. .. .. .. .. .. .. 10 .s 12#REFERENCES AND FURTHER READING . .. .. .. .. .. .. .. .. 10 .pg .f .lm4 .i-4 1. BACKGROUND .s2 FTP stands for File Transfer Protocol, a protocol designed to be network independent. It is implemented on the DEC-10 and allows the transfer of files between two DEC-10's networked together via DECNET. .s With the advent of the DECNET/SERCNET gateway (2) it becomes possible to transfer files across both networks to similar FTP processes on SERCNET hosts. .s The version of FTP described here will be replaced later by a more comprehensive system which will allow multiple transfers and will be integrated into the Galaxy spooling system. It will appear on the DEC-10 in 1981. .s2 .tp10 .i-4 2. IMPLEMENTATION .s2 This protocol has been implemented on the Edinburgh DEC-10 as a spooling system with requests for transfers being generated by a monitor command called FTP. These requests are subsequently processed by a spooler called FTPSPL which is run as an operator job. It communicates with a similar job on the destination machine. These spoolers handle the actual transfer and check the validity of access to the specified files. A note that the transfer has occurred is sent to each user involved through a log file, FTP.LOG, in their directory (see 9 below). There is no possibility of file security being breached, as each user is able to control who has permission to read or write files in their directory and to limit the type of access allowed (see 7 below). .s In general files may be transferred between any DEC-10 on SERCNET and any other SERCNET host which supports FTP. .s2 .tp10 .i-4 3. REQUESTING A TRANSFER .s2 Note: It is necessary to read this section carefully because the default conditions are designed to ensure maximum file security across the network. Thus it may be necessary to specify various switch settings, in order not to be caught by file protection errors. .s The preliminary conditions necessary for a successful transfer are as follows: .s .lm11 .i-2 - That the user has sufficient knowledge of the nature of the remote computer's filestore, namely, the format of file names, and whether a user identity (eg: user name, number or PPN and password etc). .s .i-2 - That appropriate access permission has been granted to the submitter by the sender and recipient of the file(s) to be transferred (see section 7). If the submitter of the request is either the sender or recipient of the file, full access permission is assumed. .s .i-2 - That the user is aware of the meaning and default settings of the ACCESS and DELETE switches (see below in this section). .lm4 .s2 .tp10 .i-4 4. THE FTP PROGRAM .s This is run by issuing the monitor command FTP with arguments as follows: .s #####_.FTP#DESTINATION__SPEC/SWITCH1/SWITCH2/... .br #########################= SOURCE__SPEC/SWITCH1/SWITCH2/... .s .tp10 DESTINATION__SPEC and SOURCE__SPEC are specified as NODE__FILESPEC; .s NODE is the unabbreviated node name of the source or destination computer, if no node name is given the current host is assumed. .b FILESPEC for a DEC-10 may be the full DEC-10 file specification, eg: .s #####ERCC__DSKA:FOO.TXT[100,101] .s If no directory specification is given, one's own area is used and if no destination file name is given then the source file name is used. .s FILESPEC for any other computer is a full file specification which will be recognised by that computer's filestore and takes no default values. .s To read a file from another machine the source (input file) side of the FTP commands should refer to that file. To write a file to another machine the destination (output file) side of the FTP command should refer to that file. .s SWITCHES have the general form: /SWITCH:ARGUMENT, these arguments are described in detail in Section 4 but a brief description of the switch functions follows: .s .nf #####HELP type a list of the options available #####LIST list the FTP queue of requests, submitted on this machine #####KILL:xxxx remove the given request from the queue (xxxx is the sequence no of the request) #####NODES type a list of the hosts which FTP recognises .f .s .lm4 Switches associated with the DESTINATION__SPEC are PASSWORD and ACCESS: .s .f .lm18 .i-9 PASSWORD has as its argument the FTP password for the output file. The passwords on the DEC-10 are not those used by LOGIN but special ones for FTP which are kept in a SWITCH.INI file in the same directory as the destination file (see section 7). The meaning of the password on other hosts varies from system to system (see section 6). The password switch may be omitted; in which case the program will prompt the user later for the password if it is required. .s .i-9 ACCESS###has the following permitted arguments which control access to the files: .s .nf CREATE - create a new file only ( default) WRITE - replace an existing file only CWRITE - create or replace an existing file APPEND - append to an already existing file CAPPEND - create or append to an existing file SUBMIT - enter file into the machine's batch ##########queue PRINT - spool file to the specified output ##########device (default for device "LPT" and ##########"PLT") .f .s .lm4 Switches associated with the SOURCE__SPEC are PASSWORD and DELETE; .s .lm18 .i-9 PASSWORD#has as its argument the FTP password in the SWITCH.INI file in the same directory as the source file (see section 6). .s .i-9 DELETE###relates to the deletion of the source file; it has three possible arguments: .tp10 .s .nf NEVER - do not delete ( default). AFTER - if deletion is to take place after #########the transfer. DURING - if deletion is to take place at the . #########same time. .f .s Deletion after the transfer will only result if the transfer is successful. .lm4 .f .s The defaults for ACCESS and DELETE may be overridden by the submitter of a request. The submitter's SWITCH.INI file may contain a line for FTP giving the required switches. eg: .s #####FTP/ACCESS:CWRITE/DELETE:AFTER .s in a user's SWITCH.INI file would mean that every time a request was submitted without giving an ACCESS or DELETE switch the defaults taken would be CWRITE and AFTER respectively. .s2 .tp10 .i-4 5. Examples .s 5.1 A user [72,15] on the ERCC DEC-10 typing: .nf .s #####_.FTP =UMIST__FRED.TXT[66,21] .s would generate a request with the defaults set as follows: .s #####ERCC__FRED.TXT[72,15]/ACCESS:CREATE = ##### UMIST__FRED.TXT[66,21]/DELETE:NEVER .f .s Also the user would be prompted for the password for UMIST_[66,21], but not for the file on his/her own area. .s 5.2 The same user typing: .s .nf #####_.FTP UMIST__JOHN.EXE[66,21]/ACC:WRITE= JANE.EXE[27,14]/PASS:xyz .s would generate the request: .s #####UMIST__JOHN.EXE[66,21]/ACCESS:WRITE = ##### ERCC__JANE.EXE[27,14]/PASSWORD:xyz/DELETE:NEVER .s .f and would be asked for the password for UMIST__[66,21]. .s 5.3 To print a file on the UMIST line printer the user would type: .nf .s #####._FTP UMIST__LPT02:=FRED.LST/DEL:AFTER .s this would generate the request: .s #####UMIST__LPT02:FRED.LST/ACCESS:PRINT = ##### ERCC__FRED.LST[72,15]/DELETE:AFTER .f .s and no passwords would be required, being inappropriate for a line printer. .s2 .tp10 .i-4 6. REQUIREMENTS FOR OTHER HOSTS ON SERCNET .s2 6.1 Introduction .s For each type of host on SERCNET, the DEC-10 FTP prompts for the necessary information required for that machine. The user has only to provide the right values for each argument. .s The arguments required from both the DEC-10 and the other machine in question are given below. .s Note that in the examples the computer prompts are in lower case and the users replies are in upper case. Text including and to the right of the ';' is comment only. .s 6.2 GEC 4000 series .s Transfers to and from these machines require a filename, a username and sometimes a password, eg: .s2 .nf _.FTP RLGAF__=JONAH.DAT ;send a file to the ;RL GEC machine 'A' GEC filename or for device for RLGAF__ : .XYZ ;give file GEC login name for RLGAF__ :SMITH ;and username GEC login password for RLGAF__ : ;user has no password GEC account name for RLGAF__ : ;default to username .f .s For transferring files from a GEC to the DEC-10, a filename, a GEC user name and the appropriate DEC-10 FTP password must be given: .s .nf ready ;GEC prompt TRANSFER ;FTP transfer command TRANSFER process for MAFS, version 4 ;title from GEC remote computer? NET.EDXAF ;the ERCC DEC-10 local filename? (null implies a device) _.XYZ ;the file name remote filename? (null implies a device) JONAH.DAT[72,15] ;the ERCC filename remote username? ;defaults to the GEC username remote password? (this is not echoed) MYPASS ;the DEC-10 FTP password on [72,15] local username? STOP ;do not prompt for any more arguments options? (default is SEND, MAKE or APPEND) FETCH ;read the file from the DEC-10 to the GEC .F .s For a full description of the TRANSFER facility on the ICF GEC MUMS see the OS4000 Reference Manual.(3) .s .tp10 6.3 The IBM 360/195 at Rutherford (called RLIAF) .s Transfers to and from this machine require the user identifier (ID) and user account name. In addition, it should be noted that file transfers to and from RLIAF only work for OS datasets. Attempts to transfer ELECTRIC datasets will fail. .s When transferring to RLIAF, it should be noted that access can either be for normal file transfer or for submission of batch jobs. See reference (1) for a description of the format of file to send to the HASP system. An example might be: .s .nf _.FTP RLIAF__=IBMFOR.TXT ;send a job to the IBM ;batch system at RL Dataset name for RLIAF__ : OCT.10*RGD ;not needed for batch job IBM ID. (2 chars) for RLIAF__ : ID ;give the ID IBM account (4 chars) for RLIAF__ : 1234 ;give a/c name .f .s .s When transferring from the IBM to the DECsystem-10, it should be remembered that although the ID and account name are both prompted for, the account name is not echoed. An example might be: .s .nf _.FTP ERCC__IBMFOR.TXT=RLIAF__OCT.10*RGD IBM ID. (2 chars) for RLIAF__OCT.10*RGD : ID IBM account (4 chars) for RLIAF__OCT.10*RGD : .s EXIT .s .f At present it is only possible to initiate transfers to and from the IBM from another host and not from the IBM itself. .s 6.4 PRIME machines .s Transfers to and from these machines require a filename, a username and sometimes a password, eg: .s2 .nf _.FTP RLPBF__=JONES.DAT ;send a file to the ;RL PRIME machine B PRIME filename for RLPBF__ : __ABCD ;give suitable name PRIME login name for RLPBF__ :SMITH ;and username PRIME login password for RLPBF__ :XYZ ;user password .f .s For transferring files from a PRIME to the DEC-10, a filename, a PRIME account name and the appropriate DEC-10 FTP password must be given. .s .nf ok, ;PRIME prompt FTP ;FTP command ftp v.6.4: default parameters(without passwords): remote site = rlpa local treepath = ......> ;FTP header > SITE EDXA ;specify ERCC DEC-10 > REMOTE username password ;DEC-10 username and ;FTP password > ACCOUNT accountname ;PRIME account name .s then either: .s > SEND __ABCD JONES.DAT[72,15] ;send file __ABCD to DEC-10 .s or: .s > FETCH JONES.DAT[72,15] __ABCD ;get file __ABCD from DEC-10 >QUIT ;return to command level .f .s For a full description of the PRIME FTP facility on the ICF PRIME MUMS see the PRIME Reference Manual.(4) .s2 .tp10 .i-4 7. FILE ACCESS PERMISSION .s2 Access to files in a DEC-10's directory is determined either by an FTP entry in a SWITCH.INI file in that directory or by the standard DEC-10 file and UFD protection system if no FTP entry is given in SWITCH.INI. .s The access in SWITCH.INI is governed by the setting of two switches : PASSWORD and USERS: .s .lm18 .i-9 PASSWORD#takes as a value, up to 12 alphanumeric characters A password is needed by anyone other than the user who wishes to read or write in the users area. .s .i-9 USERS####specifies those who may access your directory and what type of access they may have. Its value is a list of other users, and access key letters, separated by commas and enclosed in round brackets. .b DEC-10 users are specified by node name and project-programmer number, which may include wild project or programmer numbers. .s SERCNET users are specified either by their SERCNET title or the global name 'GATEWAY' and the user name or user identifier, or '*' for all users. .s The access key letters may be a subset of the following: .s .nf #####R - read #####D - delete after read #####C - create new files #####W - write - replace old versions #####A - append #####* - all of the above .i-18 .s .lm4 eg: .s #####/USERS:(ERCC__[100,*]=*,GATEWAY__SMITH=RWC,GATEWAY__*=CW) .s .f Two or more USERS switches maybe used but in the absence of any, no access privileges are assumed. .s .lm4 When attempting to read or write a file, if no SWITCH.INI file is found, or PASSWORD and USERS switches are not present then the 'all-other-users' field of the directory and file protection codes are used to determine access permission. .s A typical SWITCH.INI file might look as follows: .nf .s #####LOGIN/DSKFUL:PAUSE/PAGE #####FTP/PASS:friends/USERS:(UMIST__[100,*]= RC,UMIST__[*,*]=R,GATEWAY__*=RCW) #####FTP/ACCESS:CWRITE/DELETE:AFTER .f .s This would allow anybody logged on to UMIST with project number 100 to read files from this directory and create new files, anybody else from UMIST to read them only and all users on a host on SERCNET (excluding the UMIST DEC-10) to read, create and write files. For security reasons, it is important that the user should protect his/her SWITCH.INI file against being read by unauthorised persons. .s Where the /USERS switch is used, the scan stops once a match is found for a node and user. Therefore, in the above example, access for user UMIST__[100,100] would be RC and not R. It is therefore neccesary to specify individual users before wild specifications in the list. .s The other two FTP switch settings in the example above are redefining the default settings for /ACCESS and /DELETE. .s2 .tp10 .i-4 8. INTERROGATING THE QUEUES .s2 The FTP command, if given on its own or with the /LIST switch, will list the queue of files waiting transfer to or from the Edinburgh DEC-10 but not those queued on any other machine. For example if the queues are interrogated after the previous example transfers have been requested the output would look as follows: .nf .s .tp10 _.FTP/L .s Seq# User Destination Source .s *UMI168#[72,15]##ERCC__FRED.TXT[72,15]=UMIST__FRED.TXT[66,21] UMI653#[72,15]##UMIST__JOHN.EXE[66,21]=ERCC__JANE.EXE[27,14] UMI358#[72,15]##UMIST__LPT02:FRED.LST=ERCC__FRED.LST[72,15] RLG446#[72,15]##RLGAF__.XYZ=ERCC__JONAH.DAT[72,15] RLI465#[72,15]##RLIAF__OCT.IDFRED=ERCC__IBMFOR.TXT[72,15] RLP284#[72,15]##RLPBF____ABCD=ERCC__JONES.DAT[72,15] .s Where * indicates the job being transferred .f .s2 .tp10 .i-4 9. KILLING A REQUEST .s2 A file transfer request may be removed from the queue by appending the switch KILL to the FTP command. This switch takes as its value the sequence number given when the queue is listed. A request can only be killed by the submitter of the request or by the operator. Thus to kill the second request shown in Section 4 above, one would type: .nf .s #####_.FTP/KILL:UMI653 .s the system would respond: .s #####Killed .f .s2 .tp10 .i-4 10. LISTING AVAILABLE HOSTS .s The switch NODES appended to an FTP command will cause the current set of hosts which offer an FTP service to be displayed at the terminal eg: .s #####_.FTP/NODES .s #####List of nodes to which file transfer is possible .nf #####Node type node type node type #####UMIST DEC10 ERCC DEC10 YORKF DEC10 #####KELVIN DEC10 IBMTST IBM IBM IBM #####NEGAF GEC BRGAF GEC RLGCF GEC #######. #######. #######. #######. .f .s2 .tp10 .i-4 11. LOG OF TRANSFERS .s2 A note of each transfer which has taken place is left in a log file FTP.LOG in the directory of the submitter of the request, and in the source and destination directories. The log includes an indication of whether or not the transfer was successful and if not, why it failed. Thus it is possible to keep track of who has been reading files from your directory and why a transfer to your directory failed. .s A log file for ERCC__[72,15] after the requests shown in section 8 had been proccessed would looks as follows: .s .nf 12:45:56 10-Apr-79 <>SENDING>> JANE.EXE[27,14] to UMIST__JOHN.EXE[66,21] for user ERCC__[72,15] Success 15:14:23 10-Apr-79 >>SENDING>> FRED.LST[72,15] to UMIST__LPT02:FRED.LST for user ERCC__[72,15] Success queueing file succeeded 10:24:54 14-Jul-80 >>SENDING>> JONAH.DAT[72,15] to RLGAF__.XYZ for user ERCC__[72,15] Success 11:04:05 15-Jul-80 >>SENDING>> IBMFOR.TXT[72,15] to RLIAF__ for user ERCC__[72,15] Success 11:05:16 14-Jul-80 >>SENDING>> JONES.DAT[72,15] to RLPBF____ABCD for user ERCC__[72,15] Success .f .s2 .s2 .tp10 .i-4 12. REFERENCES AND FURTHER READING .s2 References. .s .f .lm9 .i-5 (1)##3A55A - Submitting IBM Jobs From the DECsystem-10 .s .i-5 (2)##3A55C - The DECsystem-10 Network Gateway .s .i-5 (3)##OS4000 Reference Manual - Interactive Computing Facility. Rutherford Laboratory, Chilton, Didcot, Oxon. OX11 0QX. .s .i-5 (4)##PRIME Reference Manual - Interactive Computing Facility. Rutherford Laboratory, Chilton, Didcot, Oxon. OX11 0QX. .s .i-5 Further Reading. .s .i-5 (5)##A Network Independent File Transfer Protocol, High Level Protocol Group - EPSS Liaison Group. Dec 77 $$$$$$$$$$$$ &&&&&&&&&&&& FTPOPR.RNO .centre OPERATORS GUIDE TO FTP (FILE TRANSFER PROTOCOL) .S 2.C CONTENTS .S 1.#Overview .s 2.#Running the spooler .s 3.#Commands to the spooler .s 4.#Examining the queues .s 5.#Testing .s 6.#References .pg .hl Overview .f FTP (File Transfer Protocol) is as a system which allows a user to queue requests for file transfers to other machines. This is achieved by having a monitor command called FTP which puts a file transfer request into the FTP queue, and a spooler called FTXSPL running on the DECsystem-10 to handle the transfer itself. .p 0 The spooler handles the setting up of the necessary tasks between the machines and handles the transfer and possible subsequent respooling of the file (say to the IBM 360/195 or to the line-printer or plotter). .hl Running the spooler The spooler is normally run as an OPSER sub-job with the following sequence of commands: .s;.nf :SLOG ;log in a sub-job :DEF FTP= ;define the sub-job as FTP FTP-R FTXSPL ;run the spooler FTP-START ;start spooling .hl Commands to the spooler .f Below are a list of all the commands available in FTXSPL. They may all be abbreviated to their shortest unique form, except that "S" or "ST" is interpreted as START rather than STOP .s;.lm 12;.ts 12 .i-12 CURRENT type the current settings of parameters .i-12 DEBUG run a test version of the spooler .i-12 DETACH detach the job and continue running detached. All subsequent output to the terminal is prefixed by "FTP- " .i-12 EXIT exit to monitor level immediately, aborting any current transfer .i-12 GO continue with the next request after a PAUSE .i-12 HELP type a list of the available commands on the console .i-12 KILL abort the current file transfer but continue with any subsequent requests .i-12 LOG file open the named file as a log file. A log file called FTPOPR.LOG[3,3] is automatically opened when the spooler is run .i-12 MSGLEVEL n determines the level of logging in the log file, the values are cumulative i.e. 30 includes 20, 10 and 0, and are as follows: .i-5 n=0##log the files being transferred and whether or not they succeed but do not type anything .i-5 n=1##type the files being transferred and whether or not they succeed (default) .i-5 n=10#log protocol level 0 message headers .i-5 n=20#log parameters passed at protocol level 0 .i-5 n=30#log messages passed at protocol level 1 .i-5 n=40#log protocol level 2 header words .i-5 n=50#log protocol level 2 data i.e. the data bytes of the file being transferred. Please note that this produces a lot of output. .i-5 n=100#type the transport level start-up procedure and each byte being received .i-12 NEXT seq# do the request whose sequence number is given, next .i-12 NODES type out a list of the nodes known to the spooler and their status .i-12 PAUSE stop processing requests after the current transfer and await operator action. When the current transfer is finished "[FTP is pausing]" is typed on the console .i-12 RESET reset all the variables to their original values except for the name of the log file and the node status .i-12 SET (NODE) OFFLINE disables transfers either to or from the named node .i-12 SET (NODE) ONLINE enables file transfers both to and from the named node (depending on the mode of operation - see START command) .I-12 START (P or Q) start transferring files in the queue for processing (P), or start accepting files from other machines (Q), or both (when no P or Q modifier is used) .i-12 STOP stop processing requests after the current transfer and return to monitor level. This will type "[FTP is stopping]" on the console when the transfer is complete. .i-12 TASK change name of listening task (default is FTX*) .i-12 WHAT types the file transfer in progress with an indication of how far the transfer has progressed and at what baud rate. .lm 0 .hl Examining the queue The queue of requests for transfers is examined by running the FTP command with no parameters or with the switch /LIST. This will print out the files involved and who submitted the request See the document 3A55B in the Edinburgh Installation Manual(1) for a full description of running FTP. .hl Testing To test the spooler back to back you should run two versions of the spooler one started as Q only, the other started as P only. Note that it is necessary to open a different log file on the first spooler before the second spooler is started otherwise the second spooler will give an enter error. You can use the DEBUG command in the spoolers, this will create job-specific log files and set the MSG level to 31. .s If you run both the spoolers and FTP from a disk other than the system disk, the queues will go onto the disk from which they are run, in the area [3,3] so that you can run a parallel FTP system for testing purposes. .s You can send a file to yourself, either using local ANF-10 tasks or using a call over the SRCNET gateway. .s For the first, make sure that both P and Q spoolers have your own node name set online (use the NODE and SET NODE ONLINE commands). Then do an FTP command: e.g. .s.nf FTP TEST__file2=file1 .s.f The second method using the gateway is as follows. Make sure that the gateway is set online in both spoolers and then use the SRCNET type of nodename e.g. .s.nf FTP EDXA__file2=file1 .hl References 1.##The Edinburgh DECsystem-10 Installation Manual. section 3A55B $$$$$$$$$$$$ &&&&&&&&&&&& NETWRK.ADD APGA 53.TSK.(2W,8P,F,TTS).20.FTP GEC BANGOR 53.TSK.(2W,8P,F,TTS).1050000.UCNWCS.FTP DEC10 BDGA 53.TSK.(2W,8P,F,TTS).11.FTP GEC BHGA 53.TSK.(2W,8P,F,TTS).13.FTP GEC BRGA 53.TSK.(2W,8P,F,TTS).10.FTP GEC CADA 53.TSK.(2W,8P,F,T)8000020.FTP OTHER CAGA 53.TSK.(2W,8P,F,TTS).8.FTP GEC CAVA 53.TSK.(2W,8P,F,T)8003001.FTP VAX CAVS 53.TSK.(2W,8P,F,T)8002001.FTP VAX CAXA 53.TSK.(2W,8P,F,TTS)8002020.FTP IBM CAXU 53.TSK.(2W,8P,F,TTS)8000010.FTP GEC CDGA 53.TSK.(2W,8P,F,TTS).7.FTP GEC CFGA 53.TSK.(2W,8P,F,TTS).12.FTP GEC CYPA 53.TSK.(2W,8P,F,TTS).30.FTP PRIME DDXA 60.FTP DEC10 DLGA 53.TSK.(2W,8P,F,TTS).1011700.FTP GEC DUNDEE 60.FTP DEC10 EAPA 53.TSK.(2W,8P,F,TTS).24.FTP PRIME EDGA 53.TSK.(2W,8P,F,TTS).7001100.FTP GEC EDXA 53.TSK.(2W,8P,F,TTS)7001001.ERCC.FTX DEC10 ERCC 50.FTX DEC10 ESSEX 53.TSK.(2W,8P,F)40.PSS(blah,blah).ESSX.SXKL10.FTX DEC10 GBXU 53.TSK.(2W,8P,F,TTS)8004001.FTP GEC GWGA 53.TSK.(2W,8P,F,TTS).5.FTP GEC GWXA 53.TSK.(2W,8P,F,TTS).1101.KELVIN.FTP DEC10 HWGA 53.TSK.(2W,8P,F,TTS).7003001.FTP GEC IBM 53.TSK.(2W,8P,F,TTS).1.FTP IBM KELVIN 53.TSK.(2W,8P,F,TTS).1101.KELVIN.FTP DEC10 KWGA 53.TSK.(2W,8P,F,TTS).21.FTP GEC LLGA 53.TSK.(2W,8P,F,TTS).1030100.FTP GEC MAGA 53.TSK.(2W,8P,F,TTS).1020300.FTP GEC MAGB 53.TSK.(2W,8P,F,TTS).1020100.FTP GEC MHXU 53.TSK.(2W,8P,F,TTS).8005001.FTP GEC NEGA 53.TSK.(2W,8P,F,TTS).9.FTP GEC NMPA 53.TSK.(2W,8P,F,TTS).14.FTP PRIME ED2972 53.TSK.(2W,7P,F,TTS)7001002.(blah,blah).2972-3.FTP EMAS REGA 53.TSK.(2W,8P,F,TTS).16.FTP GEC REVA 53.TSK.(2W,8P,F,T).7002002.FTP VAX RLGB 53.TSK.(2W,8P,F,TTS).4.FTP GEC RLGC 53.TSK.(2W,8P,F,TTS).15.FTP GEC RLGK 53.TSK.(2W,8P,F,TTS).37.FTP GEC RLIA 53.TSK.(2W,8P,F,TTS).1.FTP IBM RLPA 53.TSK.(2W,8P,F,TTS).6.FTP PRIME RLPB 53.TSK.(2W,8P,F,TTS).22.FTP PRIME RLPC 53.TSK.(2W,8P,F,TTS).23.FTP PRIME RLVA 53.TSK.(2W,8P,F,TTS).17.FTP VAX SHGA 53.TSK.(2W,8P,F,TTS).34.FTP GEC SVPA 53.TSK.(2W,8P,F,TTS).27.FTP PRIME SYPE 53.TSK.(2W,8P,F,TTS).26.FTP PRIME TSO 53.TSK.(2W,8P,F,TTS).1000200.FTP DLGP UCL 53.TSK.(1W,8P,F,TTS).32.UCL-CS.FTP ARPA UMPA 53.TSK.(2W,8P,F,TTS).28.FTP PRIME WKPA 53.TSK.(2W,8P,F,TTS).25.FTP PRIME YKXA 53.TSK.(2W,8P,F,TTS).6000000.YORK.FTP DEC10 YORK 53.TSK.(2W,8P,F,TTS).6000000.YORK.FTP DEC10 YORKS 53.TSK.(2W,8P,F,TTS).6000000.YORKS.FTP DEC10 YORKVAX 53.TSK.(2W,8P,F,TTS).6000003.FTP VAX YORK77 53.TSK.(2W,8P,F,TTS).6000000.YORK.FTX DEC10 ZUGA 53.TSK.(2W,8P,F,TTS).18.FTP GEC ZUPA 53.TSK.(2W,8P,F,TTS).29.FTP PRIME ZUXA 53.TSK.(1W,8P,F,TTS).32.UCL-CS.FTP ARPA ZMGA 53.TSK.(2W,8P,F,TTS).46.FTP GEC SELFPSS 53.TSK.(2W,8P,F)40.PSS(blah,blah).SERC.S.EDXA.ERCC.FTX DEC10 HATFIELD 53.TSK.(2W,8P,F)40.PSS(blah,blah).HATF.ORANGE.FTP DEC10 TEST 53.TSK.(2W,7P,F,TTS).7000001.ERCC.FTP DEC10 $$$$$$$$$$$$