!* !* !******************************************************************** !* * !* * !* F T R A N S E X E C U T I V E * !* * * * * * * * * * * * * * * * * !* * !* * !******************************************************************** !* ! C O N S T A N T S ! - - - - - - - - - !* conststring (15) version = "12 : 20/03/85" conststring (1) snl = " "; !A STRING NEWLINE constinteger amdahl = 369, xa = 371 INCLUDE "TARGET" if TARGET = 2900 start { machine specific constants } constinteger MAX LINE = 132 constinteger line len = 41 {for oper screen driving} conststringname DATE = X'80C0003F' conststringname TIME = X'80C0004B' constinteger SEG SHIFT = 18 constinteger uinf seg = 9 finish { 2900 } ! if TARGET = 370 start constinteger SEG SHIFT = 16 finish ! if TARGET = XA or TARGET = AMDAHL start constinteger SEG SHIFT = 20 finish ! unless TARGET = 2900 start constinteger line len = 40 {for oper screen driving} constinteger com seg = 31 conststringname DATE = COM SEG << SEG SHIFT + X'3B' conststringname TIME = COM SEG << SEG SHIFT + X'47' constinteger MAX LINE = 80 { for convenience on terminals } constinteger uinf seg = 239 finish constinteger max fsys = 99 constinteger max stations = 512 ownstring (1) null string = "" if TARGET = 2900 start conststring (15) private code = "INTER EMAS" finish else start conststring (15) private code = "INTER EMAS-A" finish conststring (17) array stream status type(0 : 24) = c "Idle", "Allocated", "Active", "Connecting", "Disconnecting", "Aborting", "Suspending", "Deallocating", "Aborted", "Selected", "Awaiting SFT", "SFT sent", "Awaiting STOP", "STOP sent", "RPOS sent", "RNEG sent", "STOPACK sent", "GO sent", "Receiving data", "Transmitting data", "Last block sent", "End data sent", "Quit sent", "End data ack sent", "Spooler called" constinteger n modes = 2 conststring (3) array modes(0 : n modes) = c "ISO", "EBC", "BIN" conststring (15) array doc state(0 : 6) = c "Deleted", "Queued", "Sending", "Running", "Receiving", "Processing", "Transferring" conststring (25) array start mess(1 : 10) = c "System Full", "Invalid Username", "Invalid Password", "Already Running", "Cannot Start Process", "Work File Failure", "No User Service", "FTRANS File Not Available", "Usergroup Full", "No Resource Left" conststring (24) array FTP errors(32:52) = c "R error resume", "R error no resume", "protocol R detected", "","","","","", "S error resume", "S error no resume", "protocol S detected", "","","","","", "Awaiting MR", "Awaiting RR after reset", "Await ER[OK] aft ES[OK]", "Await ER[E] aft ES[E]", "Await ER[H] aft ES[H]" conststring (24) array FTP aborts(48:54) = c "Awaiting data", "", "Awaits ES[OK] aft QR[OK]", "Awaits ES[H] aft QR[H]", "Awaits ES[E] aft QR[E]", "After GO", "" conststring (15) array comms stream status(0:11) = c "Unused", "Disconnecting", "Connecting", "Connected", "Suspending", "Aborting", "Claiming", "Enabling", "Enabled", "Queued", "Paging in", "Active" constinteger n priorities = 5 conststring (5) array priorities(1 : n priorities) = c "VLOW", "LOW", "STD", "HIGH", "VHIGH" conststring (7)array FTP type desc(1:3) = "MAIL","JOB","OUTPUT" conststring (2) array ocp type(0 : 15) = c "??", "50", "60", "70", "80", "72", "72", "??", "??", "??", "??", "??", "??", "??", "??", "??" conststring (3)array comms type (0:2) = "???","NSI","TS" constinteger on = 1 constinteger off = 0 constinteger no = 0 constinteger yes = 1 constinteger special = 3 constinteger no address = 0 conststring (35) array my errs(201 : 241) = c "Bad Parameters", "No Such Queue", "Queue Full", "All Queues Full", "Not In Queue", "User Not Known", "No Files In Queue", "File Not Valid", "No Free Document Descriptors", "Not Enough Privilege", "Invalid Password", "Invalid Filename", "Invalid Descriptor", "Command Not Known", "Invalid Username", "Username Not Specified", "Not Available From A Process", "Invalid Length", "Document Destination Not Specified", "Invalid Destination", "Invalid Source", "Invalid Name", "Invalid Delivery", "Invalid Time", "Invalid Priority", "Invalid Copies", "Invalid Forms", "Invalid Mode", "Invalid Order", "Invalid Start", "Invalid Rerun", "Invalid Tapes", "Invalid Discs", "Invalid Start After", "Invalid Fsys", "FTRANS File Create Fails", "Invalid Out", "Invalid Outlim", "Invalid Outname", "Descriptor Full", "Invalid DAP mins" conststring (20) array FTP act(87:103) = c "Connect", "Input Connected", "Output Connected", "Input Control Mess.", "Output Control Mess.", "Input Disconnected", "Output Disconnected", "P Command Reply", "P Command Sent", "Q Command Reply", "Q Command Sent", "Data Input", "Command Overflow", "Input Aborted", "Output Aborted", "Timeout", "SPOOLR reply" constintegerarray prtys(1 : n priorities) = c 1, 1000001, 2000001, 3000001, 4000001 constbyteintegerarray fail type(1 : 10) = c 1, 2, 2, 0, 2, 2, 1, 2, 0, 2 !* 0 NO ERROR MESSAGE REQUIRED CAN TRY AGAIN !* 1 ERROR MESSAGE REQUIRED BUT CAN TRY AGAIN !* 2 ERROR MESSAGE REQUIRED BUT DO NOT TRY AGAIN constinteger already exists = 16; !DIRECTOR FLAG constinteger already connected = 34 constinteger does not exist = 32; !DIRECTOR FLAG constinteger user not acreditted = 37; !DIRECTOR FLAG constinteger max documents = 1000; !MAX DOCUMENT DESCRIPTORS ON EACH FILE SYSTEM constinteger document entry size = 256;!SIZE IN BYTES OF A DOCUMENT DESCRIPTOR constinteger password document entry size = 144 ; !Size of the PASSWORD descriptors. constinteger info size = 256; !SIZE IN BYTES OF INFO RETURNED TO USERS constinteger max priority = 10000; !PRIORITY ADDED TO BASE PRIORITY IF RESOURCE = 0 constinteger small weight = 4; !THIS SHOULD BE INCREASED TO FAVOUR SMALL JOBS constinteger requested = 255 constinteger comm connected = 3; !comms conn stream status. constinteger comm claiming = 6 constinteger comm enabling = 7 constinteger no route = 0 constinteger user call = 1 constinteger job call = 2 constinteger ok = 0; !GENERAL SUCCESSFUL REPLY FLAG constinteger rejected = 3 constinteger unused = 0; !DESCRIPTOR STATUS constinteger queued = 1; !DITTO constinteger transferring = 6; !FTP file transfer activity constinteger set = 1 constinteger lp = 1 constinteger jrnl = 0 constinteger closed = 0; !REMOTE STATUS constinteger open = 1; !DITTO constinteger logging on = 2; !DITTO constinteger logged on = 3; !DITTO constinteger switching = 4; !DITTO constinteger logging off = 5; !DITTO constinteger unallocated = 0; !STREAM STATUS constinteger allocated = 1; !DITTO constinteger active = 2; !DITTO constinteger connecting = 3; !DITTO constinteger disconnecting = 4; !DITTO constinteger aborting = 5; !DITTO constinteger suspending = 6; !DITTO constinteger deallocating = 7; !DITTO constinteger aborted = 8; !used by FTP line only constinteger selected = 9; !USED ONLY FOR FTP STREAMS constinteger awaiting sft = 10 constinteger sft sent = 11 constinteger awaiting stop = 12 constinteger stop sent = 13 constinteger rpos sent = 14 constinteger rneg sent = 15 constinteger stopack sent = 16 constinteger go sent = 17 constinteger receiving data = 18 constinteger transmitting data = 19 constinteger last block sent = 20 constinteger end of data sent = 21 constinteger quit sent = 22 constinteger end of data acknowledge sent = 23 constinteger spooler called = 24 constinteger all queues = 1; !WHICH DISPLAY TYPE constinteger all streams = 2; !DITTO constinteger individual queue = 3; !DITTO constinteger individual stream = 4; !DITTO constinteger non empty queues = 5; !DITTO constinteger active streams = 6; !DITTO constinteger individual document = 7; !DITTO constinteger full individual queue = 8;!DITTO constinteger all remotes = 9; !DITTO constinteger logged on remotes = 10; !DITTO constinteger individual remote = 11; !DITTO constinteger FTP status = 12 constinteger bad params = 201; !GENERAL BAD PARAMETER REPLY FLAG constinteger no such queue = 202; !QUEUE REQUESTED DOES NOT EXIST constinteger queue full = 203; !OUTPUT REQUESTS LISTS FULL REPLY FLAG constinteger all queues full = 204; !NO FREE LIST CELLS OR INDEX FULL constinteger not in queue = 205; !FIND DOCUMENT IN QUEUE FAILURE FLAG constinteger user not known = 206; !PROCESS NOT KNOWN IN CONFIGURATION constinteger no files in queue = 207 constinteger file not valid = 208 constinteger no free document descriptors = 209 constinteger not enough privilege = 210 constinteger invalid password = 211 constinteger invalid filename = 212 constinteger invalid descriptor = 213 constinteger command not known = 214 constinteger invalid username = 215 constinteger username not specified = 216 constinteger not available from a process = 217 constinteger invalid length = 218 constinteger document destination not specifed = 219 constinteger invalid destination = 220 constinteger invalid srce = 221 constinteger invalid name = 222 constinteger invalid delivery = 223 constinteger invalid time = 224 constinteger invalid priority = 225 constinteger invalid copies = 226 constinteger invalid forms = 227 constinteger invalid mode = 228 constinteger invalid order = 229 constinteger invalid start = 230 constinteger invalid rerun = 231 constinteger invalid decks = 232 constinteger invalid tapes or discs = 233 constinteger invalid start after = 234 constinteger invalid fsys = 235 constinteger FTRANS file create fails = 236 constinteger invalid out = 237 constinteger invalid outlim = 238 constinteger invalid outname = 239 constinteger descriptor full = 240 constinteger invalid dap mins = 241 constinteger not assigned = x'80808080'; !INTERNAL UNASSIGNED VARIABLE PATTERN constinteger file header size = 32; !SS STANDARD FILE HEADER SIZE constinteger r = b'00000001'; !READ PERMITION constinteger w = b'00000010'; !WRITE PERMITION constinteger sh = b'00001000' constinteger zerod = b'00000100'; !ZERO FILE ON CREATION constinteger tempfi = b'00000001'; !TEMP FILE ON CREATION constinteger list size = 1000; !SIZE OF QUEUE CELLS LIST constinteger header size = 2048; !NUMBER OF BYTES ALLOCATED For AN OUTPUT FILE HEADER constinteger default oper update rate = 0;!REFRESH OPER EVERY 0 SECS(IE DONT) constinteger fep io buff size = 4096; !NUMBER OF BYTES IN THE RJE CONTROL BUFFERS FOR EACH FEP constinteger max fep = 7; !MAXIMUM FEPS SUPPORTED constinteger max oper = 7; !MAXIMUM OPERS SUPPORTED constinteger oper display size = 21; !NUMBER OF LINES IN AN OPER DISPLAY constinteger last q per stream = 15; !NUMBER OF QUEUES BEING SERVED BY ONE STREAM constinteger connect stream = x'370001' constinteger disconnect stream = x'370005'; !DISCONNECT COMMUNICATIONS STREAM constinteger stream control message = x'370007'; !STREAM HIGH LEVEL CONTROL MESSAGE constinteger enable stream = x'370002';!START TRANSFER ON COMMUNICAIONS STREAM constinteger disable stream = x'370004'; !DISABLE A TRANSFER ON COMMUNICATIONS STREAM constinteger suspend = 4; !MODE OF DISABLING A COMMS STREAM constinteger abort = 5; !DITTO !----------------------------------------! ! OPER Picture driving declarations constinteger max pic types = 4 constinteger max pic files = 16 constinteger max pic lines = 798 { because of the 32k limit on file size } constinteger max screen = 31 constinteger picture act = 24 constinteger oper dest = x'00320000' constinteger screens per oper = 4 constinteger FTP status summary display = 1 constinteger FTP line status display = 2 constinteger individual queue display = 3 constinteger individual document display = 4 ! ! ! recordformat picturef(integer base, { connect address } p2, p3, { DA and pages-1 for comms controllers enable } screens, { bit map showing where this pic is being displayed } count, { the number of interactive processes looking at it } picture type, { which type of picture it is } tick, { for picture ageing } id1, string (15) id2 ) { to identify precisely what picture is of } recordformat screenf(integer picture, { number of picture on display or } stream, top) recordformat pe ( integer dest,srce,p1,p2,p3,p4,p5,p6) recordformat uinff(string (6)user, string (31) batchfile, integer mark, fsys, procno, isuff, reason, batchid, sessiclim, scidensad, scidens, oper, msgfad, sct date, sync1 dest, sync2 dest, async dest) constrecord (uinff)name uinf = uinf seg << seg shift ! ! ! externalroutinespec dpon ( record (pe) name p) externalroutinespec dout(record (pe)name p) !----------------------------------------! constinteger FTP in control stream = 6 constinteger FTP out control stream = 7 constinteger clock tick = 11; !ACTIVITY NUMBER TO UPDATE OPER ON CLOCK TICK constinteger default clock tick = 60; !IE THE TIME INTERVAL. constinteger descriptor update = 12; !UPDATE THE DOC DESCRIPTORS ON THE FILE SYSTEMS. constinteger solicited oper message = 19; !OPER MESSAGE ACTIVITY IN REPLY TO PROMPT constinteger unsolicited oper message = 20; !OPER MESSAGE OUT OF THE BLUE constinteger open fsys = 21; !ACTIVITY NUMBER OF OPEN FILE SYSTEM constinteger user mess = 22; !ACTIVITY NUMBER OF USER MESSAGE ROUTINE constinteger spooler reply act = 23; !Reply when spooler gets kick for DEXECMESS. constinteger picture maintainance = 24 constinteger fep input control connect = 25 constinteger FTP input mess = 80; !CONTROL MESSAGE FROM FEP FTP ACTIVITY constinteger FTP output reply mess = 81 !FTP OUTPUT CONTROL MESSAGE REPLY ACTIVITY. constinteger FTP input control connect = 82 !CONNECT FTP INPUT CONTROL STREAM. constinteger FTP input control connect reply = 83 !CONNECT FTP INPUT CONTROL STREAM FREPLY. constinteger FTP output control connect reply = 84 !CONNECT FTP OUTPUT CONTROL STREAM REPLY. constinteger FTP input control enable reply = 85 !ENABLE FTP INPUT CONTROL STREAM ENABLE REPLY. constinteger FTP output control enable reply = 86 constinteger close control = 58 constinteger FTP connect = 87 constinteger FTP input connected = 88 constinteger FTP output connected = 89 constinteger FTP input control message = 90 constinteger FTP output control message = 91 constinteger FTP input disconnected = 92 constinteger FTP output disconnected = 93 constinteger FTP p command reply = 94 constinteger FTP p command sent = 95 constinteger FTP q command reply = 96 constinteger FTP q command sent = 97 constinteger FTP data input = 98 constinteger FTP command overflow = 99 constinteger FTP input aborted = 100 constinteger FTP output aborted = 101 constinteger FTP timed out = 102 constinteger FTP confirmation from spooler = 103 constinteger elapsed int = x'000A0002';!ELASPED INTERVAL TIME SERVICE constinteger display dest = x'00320006'; !OPER DISPLAY SERVICE constinteger display no flash dest = x'0032000B' constinteger FTP block division = 16; !none emas to emas FTP transfers transfer limiter.. constinteger FTP emastoemas block division = 8 !NOTE these values MUST be 2/4/8/16/32 . !The FTP local control flags (user facility) follow. !--------------------------- !First set constbyteinteger FTP no mail = x'01' constbyteinteger FTP fail mail = x'02' constbyteinteger FTP overwrite = x'04' constbyteinteger FTP non text or data = x'08' constbyteinteger FTP binary data = x'20' constbyteinteger FTP ANSI = x'10' constbyteinteger FTP local output = x'40' constbyteinteger FTP binary read only = x'80' !Second set constbyteinteger FTP text read only = x'01' constbyteinteger FTP fixed term delay = x'80' constbyteinteger FTP no fixed term delay = x'7F' constinteger viable = 0; !these are FTP transfer states conststring (15) spoolFTP = "FTP" conststring (15) spoolmail = "MAIL" conststring (15) thisukac = "UK.AC" constinteger FTP mail = 1 constinteger FTP job = 2 constinteger FTP output = 3 !-------------------------------------------- !Consts for FTP eval conststring (16) array qual descr(0:3) = C "Att. unknown", "No val available", "Bitfield", "String" conststring (3) array op descr(2:7) = c "EQ", "LE", "", "NE", "GE", "ANY" conststring (11) array mon descr(0:1) = c "", " / monitor" conststring (4) array type descr(0:4) = c "STOP", "", "RPOS", "RNEG", "SFT" constbyteinteger attribute unknown = x'00' constbyteinteger no val available = x'10' constbyteinteger op mask = x'07' constbyteinteger form mask = x'70' constinteger iso text = 3 constinteger data = 4 constbyteinteger unknown type = 0 constbyteinteger NSI type = 1 constbyteinteger TS type = 2 constbyteinteger BASE type = 3 constbyteintegerarray connect retry times(0 : 10) = c 0,5,10,10,15,20,20,30,30,30,60 ! 0,1,2,2,5,5,5,8,8,10,10 constinteger rejected info = x'1001' constinteger rejected attribute = x'1002' constinteger rejected deferred = x'1003' constinteger rejected no resume = x'1004' constinteger satisfactory termination = x'2000' constinteger problem termination = x'2001' constinteger aborted no retry = x'3010' constinteger aborted retry possible = x'3011' constinteger p station = 0 constinteger q station = 1 if TARGET = 2900 start constinteger FTP std mess len = 7; !THE LENGTH OF THE BASIC FTP CONTROL MESSAGE. finish else start constinteger FTP std mess len = 127 finish constbyteinteger hold = x'10' constinteger FTP data = x'40'; !OTHER DATA control FOR ENABLE. constinteger translate = x'40' constinteger no translation = x'50'; !EMAS TO EMAS MODE or free text constinteger FTP command = x'60'; !COMMAND(NEGOTIATION). constbyteinteger FTP stop = x'00'; !THESE ARE FTP CONTROL BYTES constbyteinteger FTP go = x'01' constbyteinteger FTP rpos = x'02' constbyteinteger FTP rneg = x'03' constbyteinteger FTP sft = x'04' constbyteinteger FTP stopack = x'05' constbyteinteger FTP ss = x'40' constbyteinteger FTP ms = x'41' constbyteinteger FTP cs = x'42' constbyteinteger FTP es = x'43' constbyteinteger FTP qr = x'46' constbyteinteger FTP er = x'47' constbyteinteger bits = x'20' constbyteinteger strings = x'30' constbyteinteger eq = x'02' constbyteinteger le = x'03' constbyteinteger ne = x'05' constbyteinteger ge = x'06' constbyteinteger any = x'07' constbyteinteger monitor = x'80' constinteger sender = 0; !FTP OUTGOING. constinteger receiver = 1; !FTP INCOMING. constinteger ready = 0 constinteger already enabled = 1 constinteger read and remove = x'8001' constinteger take job output = x'4001' constinteger take job input = x'2001' constinteger give job output = x'C001' constbyteinteger FTP data error = x'20' constbyteinteger R error resume = x'20' constbyteinteger R error no resume = x'21' constbyteinteger S error resume = x'28' constbyteinteger S error no resume = x'29' constbyteinteger protocol R detected = x'22' constbyteinteger protocol S detected = x'2A' constbyteinteger FTP data abort = x'30' constbyteinteger awaiting data = x'30' constbyteinteger ER ok expected = x'32' constbyteinteger ER e expected = x'33' constbyteinteger ES e expected = x'34' constbyteinteger FTP default timeout = 7 constinteger FTP selected timeout = 5 !FTP timeout values follow. constbyteinteger station capacity retry time = 1; !max lines active for station. constbyteinteger connect delay = 1; !the station already being tried. constbyteinteger connect fail delay = 5; !the connection failed. constbyteinteger auto poll delay = 5 {for auto output return from remote jobmills} constbyteinteger transfer fail delay = 10; !the last transfer there failed. constbyteinteger deferred delay = 15; !the transfer was deferred by the other end. constbyteinteger allocate fail delay = 10; !the last allocate failed constinteger successful = 1 constinteger display start line = 72; !START LINE OF DISPLAY ownstring (255) ns1 conststring (11) FTP work dest = "FTPWORKDOC" !* !********************************************************************** !* * !* F T A M A N A C T I V I T I E S * !* -*-*-*-*-*- -*-*-*-*-*-*-*-*-*- * !* * !* 11 - CLOCK TICK * !* 12 - PERIODIC DESCRIPTOR UPDATING (BY FSYS) * !* 19 - OPERATOR MESSAGE IN REPLY TO A PROMPT * !* 20 - UNSOLICITED OPERATOR MESSAGE * !* 21 - OPEN FILE SYSTEM * !* 22 - USER MESSAGE * !* 58 - WILL USE FOR FEP/FSYS GOING DOWN(FSYS = P_P3) * !********************************************************************** !* !* !* ! R E C O R D F O R M A T S ! - - - - - - - - - - - - - !* COMMUNICATIONS RECORD FORMAT - EXTANT FROM CHOPSUPE 20A ONWARDS * if TARGET = 2900 start recordformat c COMF(integer OCPTYPE, IPLDEV, SBLKS, SEPGS, NDISCS, DLVNADDR, GPCTABSIZE, GPCA, SFCTABSIZE, SFCA, SFCK, DIRSITE, DCODEDA, SUPLVN, TOJDAY, DATE0, DATE1, DATE2, TIME0, TIME1, TIME2, EPAGESIZE, USERS, CATTAD, SERVAAD, byteinteger NSACS, RESV1, SACPORT1, SACPORT0, NOCPS, RESV2, OCPPORT1, OCPPORT0, integer ITINT, CONTYPEA, GPCCONFA, FPCCONFA, SFCCONFA, BLKADDR, RATION, SMACS, TRANS, longinteger KMON, integer DITADDR, SMACPOS, SUPVSN, PSTVA, SECSFRMN, SECSTOCD, SYNC1DEST, SYNC2DEST, ASYNCDEST, MAXPROCS, KINSTRS, ELAPHEAD, COMMSRECA, STOREAAD, PROCAAD, SFCCTAD, DRUMTAD, TSLICE, FEPS, MAXCBT, PERFORMAD, INTEGER SP0,SP1,SP2,SP3,SP4,SP5, integer LSTL, LSTB, PSTL, PSTB, HKEYS, HOOT, SIM, CLKX, CLKY, CLKZ, HBIT, SLAVEOFF, INHSSR, SDR1, SDR2, SDR3, SDR4, SESR, HOFFBIT, BLOCKZBIT, BLKSHIFT, BLKSIZE, END) finish else start recordformat C COMF(integer OCPTYPE, SLIPL, TOPS, SEPGS, NDISCS, NSLDEVS, DLVNADDR, DITADDR, SLDEVTABAD, STEER INT, DIRSITE, DCODEDA, exSUPLVN, TOJDAY, DATE0, DATE1, DATE2, TIME0, TIME1, TIME2, PAGESIZE, USERS, CATTAD, SERVAAD, NOCPS, ITINT, RATION, TRANS, longinteger KMON, integer SUPVSN, SECSFRMN, SECSTOCD, SYNC1DEST, SYNC2DEST, ASYNCDEST, MAXPROCS, KINSTRS, ELAPHEAD, COMMSRECA, STOREAAD, PROCAAD, TSLICE, FEPS, MAXCBT, PERFORMAD, END) finish !* if TARGET = 2900 start recordformat tran document descriptorf(STRING (7) HEADER, byteinteger state, string (6) user, (string (15) dest or integer spare1,spare2,spare3,spare4), {these spare integers are for FTP use only and will be lost in SPOOLR calls} (integer date and time received, date and time started or c byteinteger FTRANS action, confirm, type, tfsys, integer transfer ident), {the FTRANS units are set by us when requesting SPOOLR to do something} integer specific fep, date and time deleted, start after date and time, priority, data start, data length, integer time, (integer output limit or integer FTP data record), halfinteger mode of access, byteinteger priority requested, forms, mode, copies, order, rerun, decks, drives, fails, outdev, srce, output, delivery, name, byteintegerarray vol label(1:8), byteinteger external user, external password, external name, FTP alias, storage codename, device type, device qualifier, data type, text storage, FTP user flags, FTP file password,special options, auto requeue, guest address,sp4,sp5, byteinteger properties, byteinteger try emas to emas, FTP retry level, (byteinteger string ptr or string (148) string space)) !* recordformat document descriptorf(byteinteger state, string (6) user, (string (15) dest or integer spare1,spare2,spare3,spare4), {these spare integers are for FTP use only and will be lost in SPOOLR calls} (integer date and time received, date and time started or c byteinteger FTRANS action, confirm, type, tfsys, integer transfer ident), {the FTRANS units are set by us when requesting SPOOLR to do something} integer specific fep, date and time deleted, start after date and time, priority, data start, data length, integer time, (integer output limit or integer FTP data record), halfinteger mode of access, byteinteger priority requested, forms, mode, copies, order, byteinteger rerun, decks, drives, fails, outdev, srce, output, delivery, name, byteintegerarray vol label(1:8), byteinteger external user, external password, external name, FTP alias, storage codename, device type, device qualifier, data type, text storage, FTP user flags, FTP file password,special options, auto requeue, guest address, FTP user flags2, sp5, byteinteger properties, byteinteger try emas to emas, FTP retry level, (byteinteger string ptr or string (148) string space)) finish else start recordformat tran document descriptorf(STRING (7) HEADER, byteinteger state, string (6) user, (string (15) dest or integer spare1,spare2,spare3,spare4), {these spare integers are for FTP use only and will be lost in SPOOLR calls} (integer date and time received, date and time started or c byteinteger FTRANS action, confirm, type, tfsys, integer transfer ident), {the FTRANS units are set by us when requesting SPOOLR to do something} integer specific fep, date and time deleted, start after date and time, priority, data start, data length, integer time, (integer output limit or integer FTP data record), shortinteger mode of access, byteinteger priority requested, forms, mode, copies, order, rerun, decks, drives, fails, outdev, srce, output, delivery, name, byteintegerarray vol label(1:8), byteinteger external user, external password, external name, FTP alias, storage codename, device type, device qualifier, data type, text storage, FTP user flags, FTP file password,special options, auto requeue, guest address, FTP user flags2,sp5, byteinteger properties, byteinteger try emas to emas, FTP retry level, (byteinteger string ptr or string (148) string space)) !* recordformat document descriptorf(byteinteger state, string (6) user, (string (15) dest or integer spare1,spare2,spare3,spare4), {these spare integers are for FTP use only and will be lost in SPOOLR calls} (integer date and time received, date and time started or c byteinteger FTRANS action, confirm, type, tfsys, integer transfer ident), {the FTRANS units are set by us when requesting SPOOLR to do something} integer specific fep, date and time deleted, start after date and time, priority, data start, data length, integer time, (integer output limit or integer FTP data record), shortinteger mode of access, byteinteger priority requested, forms, mode, copies, order, byteinteger rerun, decks, drives, fails, outdev, srce, output, delivery, name, byteintegerarray vol label(1:8), byteinteger external user, external password, external name, FTP alias, storage codename, device type, device qualifier, data type, text storage, FTP user flags, FTP file password,special options, auto requeue, guest address, FTP user flags2,sp5, byteinteger properties, byteinteger try emas to emas, FTP retry level, (byteinteger string ptr or string (148) string space)) finish !* recordformat password document descriptor f(byteinteger external password, FTP file password, special options, spareb, integer spareI1, spareI2, spareI3, (byteinteger string ptr or string (127) string space)) !* if TARGET = 2900 start recordformat infof(integer vsn, state, string (7) ident, user, string (15) dest, srce, output, string (31) name, delivery, string (7) array vol label(1:8), integer date and time received, date and time started, halfinteger dap mins, dap c exec time, integer date and time deleted, data start, data length, time, output limit, physical size, priority, start after date and time, ahead, byteinteger forms, mode, copies, order, rerun, decks, drives, fails) finish else start !* recordformat infof(integer vsn, state, string (7) ident, user, string (15) dest, srce, output, string (31) name, delivery, string (7) array vol label(1:8), integer date and time received, date and time started, shortinteger dap mins, dap c exec time, integer date and time deleted, data start, data length, time, output limit, physical size, priority, start after date and time, ahead, byteinteger forms, mode, copies, order, rerun, decks, drives, fails) finish !* if TARGET = 2900 start recordformat queuef(string (15) name, (halfintegerarray streams(0 : 15) or halfintegerarray lines(0 : 15)), string (7) default user, string (31) default delivery, integer default start, default priority, default time, default output limit, default forms, default mode, default copies, default rerun, length, head, max length, maxacr, halfinteger q by, general access, integer resource limit, amount) finish else start recordformat queuef(string (15) name, (shortintegerarray streams(0 : 15) or shortintegerarray lines(0 : 15)), string (7) default user, string (31) default delivery, integer default start, default priority, default time, default output limit, default forms, default mode, default copies, default rerun, length, head, max length, maxacr, shortinteger q by, general access, integer resource limit, amount) finish !* !* !Note that the FTP line tables are in two sections. !The first gives basic information used on stream 'scans', ie in !response to a QUEUE user command for active documents. The first section !will fit in a single page. The second sections contains the meaty bits. ! ! recordformat line f(string (15) name, string (7) unit name, string (6) user, byteinteger parity, integer status, (integer bytes sent or integer records received), integer bytes to go, block, part blocks, document, bin offset, byteinteger service, user abort, unit size, fep, integer abort retry count, offset, station ptr, (integer vrecord length, vbytes to go, split vrecord length or c integer current vrecord length, current vrecord length addr,known to have records), integer data transfer start {for timing the transfer},account, integer in comms stream, out comms stream, integer in stream ident, out stream ident, integer transfer status, tcc subtype, in block addr, out block addr, byteinteger activity, station type, spb2, suspend, in stream status, out stream status, timer, output buffer status, output transfer pending, new FTP data record, byteintegerarray bspare(0:9), integer aux document, pre abort status, bytes transferred, record (pe) output transfer record) !* !* recordformat fepf(byteinteger incomming calls accepted, outgoing calls permitted, FTP available, closing, comms type, integer FTP input stream, FTP output stream, FTP in buff disc addr, FTP out buff disc addr, FTP in buff disc blk lim, FTP out buff disc blk lim, FTP in buff con addr, FTP out buff con addr, FTP in buff offset, FTP out buff offset, FTP in buff length, FTP out buff length, FTP input cursor, FTP output cursor, FTP suspend on output) !* if TARGET = 2900 start recordformat FTP bits(byteinteger qual, set, halfinteger value) finish else start recordformat FTP bits(byteinteger qual, set, shortinteger value) finish recordformat FTP strings(byteinteger qual, set, string (39) value) recordformat FTP tablef(integer user fsys, binary data record, spare1, spare2, byteinteger emastoemas, data control,mail,mail to send, mail displ, sp1,sp2,sp3, string (73) stopack message, calling address, byteintegerarray emastoemas header (0:31), record (FTP bits) protocol id,mode,data type,text tran code, text format,del pres,max tran rec size,tran limit, file size,facilities,timeout,restart mark, binary word size, binary format, Ispare, record (FTP strings) username,username password,filename,file password, private code name,device type,device type qualifier, special options) !* record format FTP pointers f(integer link list displ, ftp table displ, queues, queue entry size, queue displ, queue name displ, streams, stream entry size, stream displ, hash length, sp1, sp2,sp3, stations, station entry size, station displ, control entry, station addresses displ, guest entry, byte integer array discs(0:max fsys), string (63) dead letters, this full host, integer expanded address displ, integer array hash t(0:1023)) record format FTP station f(byte integer max lines , byteinteger status, byteinteger service , byteinteger connect retry ptr, fep, address type, SERVICES, byteinteger q lines , integer limit , integer last call, last response, system loaded, connect attempts, connect retry time, integer array ispare(0:4), integer seconds, bytes, integer last q response by us, p transfers, q transfers, p kb, q kb, p mail, q mail, integer name, shortest name, integerarray address(1:4), integer pss entry, integer mail, integer ftp, integer description, (integer queue or integer route), integer flags, byteintegerarray string space(0 : 375){decrement this if more fields added, keep to 512 total}) recordformat name f(integer link, host entry, string (255) name) recordformat exp addr f( integer address type, integerarray ptr (1:4)) !that is an index into the string store in the database that contains !all the expaned TS addresses for the stations. !* recordformat lcf(integer document, priority, size, station ptr, (byteinteger SPB1,FTP timer,FTP flags,gen flags or integer flags), integer link,string (6) user, byteinteger order) ! if TARGET = 2900 start recordformat file inff(string (11)NAME, integer SD,halfinteger PGS, H0, byteinteger CODES, CODES2, DAYNO, USE, OWNP, EEP, PHEAD, ARCH, byteinteger CCT, SSBYTE, halfinteger PREFIX) finish else start recordformat file inff(string (11)NAME, integer SD, shortinteger PGS, H0, byteinteger CODES, CODES2, DAYNO, USE, OWNP, EEP, PHEAD, ARCH, CCT, SSBYTE, shortinteger PREFIX) finish if TARGET # 2900 start RECORDFORMAT FINFF((INTEGER NKB, RUP, EEP, APF, USE, ARCH, FSYS, CONSEG, CCT, CODES, DAYNO, CODES2, SSBYTE or INTEGERARRAY i(0:12)),STRING (6)OFFER) finish else start RECORDFORMAT FINFF(INTEGER NKB, RUP, EEP, APF, USE, ARCH, FSYS, CONSEG, CCT, CODES, BYTEINTEGER SP1, DAYNO, SP2, CODES2, INTEGER SSBYTE ,STRING (6)OFFER) finish !* recordformat daf((integer blksi, nblks, last blk, spare, integerarray da(1 : 512) or integer sparex, integerarray i(0:514))) !* !* recordformat fhf(integer end, start, size, type, free hole, datetime, binary record, records) !* if TARGET = 2900 start recordformat FTP f(byteinteger length, type, halfinteger pair ref, in ident, out ident, string (127) address) finish else start recordformat FTP f( shortinteger control, type, pair ref, in ident, out ident, fail or status, spare, string (113) address) finish recordformat opf(integer update rate, prompt on, display type, which display, which page, string (10) specific user, string (41) command) !* recordformat f systems f(integer addr, password addr, closing) !* ! S Y S T E M R O U T I N E S P E C S ! - - - - - - - - - - - - - - - - - - if TARGET = 2900 start system string (255) fn spec substring(string name s,integer i,j) systemroutinespec move(integer length, from, to) systemroutinespec fill(integer length, from, filler) finish else start externalstring (255)fnspec substring(Stringname s, integer i,j) externalroutinespec move(integer length, from, to) externalroutinespec fill(integer length, from, filler) finish external integerfnspec pack date and time(string (8) date, time) external integerfnspec current packed dt external string (8) fnspec unpack date(integer p) external string (8) fnspec unpack time(integer p) !* ! E X T E R N A L R O U T I N E S P E C S ! - - - - - - - - - - - - - - - - - - - - ! if TARGET = 2900 start externalstringfnspec derrs(integer flag) externalintegerfnspec dexecmess(string (6) user,integer sact,len,addr) externalintegerfnspec ddap(integerfn a(integer a,b,c), integer act, addr) externalintegerfnspec dsfi(string (6) user, integer fsys, integer type, set, address) !%externalintegerfnspec change context externalintegerfnspec d check bpass(string (6) user, string (63) bpass, integer fsys) externalintegerfnspec dpon3(string (6) user, record (pe)name p, integer invoc, msgtype, outno) externalroutinespec dpoff(record (pe)name p) externalroutinespec dtoff(record (pe)name p) externalintegerfnspec dgetda(string (6) user, string (11) file, integer fsys, address) externalintegerfnspec dchsize(string (6) user, string (11) file, integer fsys, newsize) externalroutinespec get av fsys(integername n, integerarrayname a) externalintegerfnspec dfsys(string (6) user, integername fsys) externalintegerfnspec dpermission( c string (6) owner, user, string (8) date, string (11) file, integer fsys, type, adrprm) externalintegerfnspec ddestroy(string (6) user, string (11) file, string (8) date, integer fsys, type) externalintegerfnspec ddisconnect(string (6) user, string (11) file c integer fsys, destroy) externalintegerfnspec drename(string (6) user, string (11) oldname, newname, integer fsys) externalintegerfnspec dfstatus(string (6) user, string (11) file, integer fsys, act, value) externalintegerfnspec dfilenames(string (6) user, record (file inff)arrayname inf, integername filenum, maxrec, nfiles, integer fsys, type) externalintegerfnspec dfinfo(string (6) user, string (11) file, integer fsys, address) externalintegerfnspec dcreate(string (6) user, string (11) file, integer fsys, nkb, type) externalintegerfnspec dconnect(string (6) user, string (11) file, integer fsys, mode, apf, integername seg, gap) externalintegerfnspec dmessage(string (6) user, integername l, integer act, fsys, adr) externalintegerfnspec dtransfer( c string (6) user1, user2, string (11) file, newname, integer fsys1, fsys2, type) externalintegerfnspec dnewgen(string (6) user, string (11) file, c newgen of file, integer fsys) finish else start EXTERNALINTEGERFNSPEC D AV FSYS(INTEGERNAME N, INTEGERARRAYNAME A) EXTERNALINTEGERFNSPEC DCHECKBPASS(STRINGNAME USER, BPASS, INTEGERNAME FSYS) EXTERNALINTEGERFNSPEC DCHSIZE(STRINGNAME FILE INDEX, FILE, INTEGERNAME FSYS, NKB) ! The physical size of file FILE belonging to file index FILE INDEX on ! disc-pack FSYS (or -1) is altered (if necessary) so that its new size ! is NEWKB Kbytes. The size may not be reduced to zero. The file may ! be connected in the caller's virtual memory (only). If the caller is ! not the file owner, he must either have W access to the file index or ! be privileged. !%EXTERNALINTEGERFNSPEC CHANGE CONTEXT EXTERNALINTEGERFNSPEC DCONNECT(STRINGNAME FILE INDEX, FILE, INTEGERNAME FSYS, MODE, SEG, GAP) EXTERNALINTEGERFNSPEC DCREATE(STRINGNAME FILE INDEX, FILE, INTEGERNAME FSYS, NKB, TYPE, DA) ! A file of name FILE is created, in file index FILE INDEX on disc-pack ! FSYS, of E Epages, where E is the smallest number of Epages containing ! NKB Kbytes. The maximum size of file allowed is 16 Mbytes. Subsystems ! requiring larger files should arrange that they be made up of subfiles ! comprising files created by this procedure. ! ! Bits in TYPE may be set: ! ! 2**0 For a temporary file (destroyed when the creating process ! stops if the file was connected, or at System start-up). ! ! 2**1 For a very temporary file (destroyed when the file is ! disconnected). ! ! 2**2 For a file which is to be zeroed when created. ! ! 2**3 To set "CHERISHed" status for the file. ! ! ! Temporary files are made into ordinary files (that is, the "temporary" ! attribute is removed) on being RENAMEd, OFFERed, TRANSFERred or ! PERMITted, and also explicitly by an appropriate call on procedure ! DFSTATUS. ! ! The disc address of the first section of the file is returned in DA. EXTERNALINTEGERFNSPEC DDESTROY(STRINGNAME FILE INDEX, FILE, DATE, INTEGERNAME FSYS, TYPE) ! File FILE belonging to file index FILE INDEX on disc-pack FSYS, is ! destroyed. TYPE should be set to 1 to destroy a file from archive ! storage, otherwise it should be set to zero. When TYPE=1, DATE should ! be set to the archive date. DATE is ignored if TYPE=0. ! ! The procedure fails if 'OWNP' for the file is either zero (no access) ! or 8 (do not destroy). EXTERNALINTEGERFNSPEC DDISCONNECT(STRINGNAME FILE INDEX, FILE, INTEGERNAME FSYS, DSTRY) ! The file of name FILE belonging to file index FILE INDEX on disc-pack ! FSYS is disconnected from the caller's virtual memory. Parameter ! DESTROY should be set either to 0 or 1. If set to 1 the file will be ! destroyed, provided that it belongs to the process owner (not necessary ! if the process is privileged) and the "use-count" for the file is zero ! after disconnection. Otherwise the parameter is ignored. EXTERNALINTEGERFNSPEC DFILENAMES(STRINGNAME GROUP, INTEGERNAME FILENO, MAXREC, C NFILES, FSYS, TYPE, RECORD (file inff)ARRAYNAME INF) ! This procedure delivers, in the record array INFS (which should be ! declared (0:n)), a sequence of records describing the on-line files ! (for TYPE=0), archived files (for TYPE=1) or backed-up files (for ! TYPE=2) belonging to group GROUP on fsys FSYS (or -1 if not known). ! ! The procedure works differently for on-line files (TYPE=0) and ! off-line files (TYPE>0). ! ! For on-line files, the records returned give the names of files and ! groups belonging to GROUP but not the contents of any of these groups. ! DFILENAMES must be called again with GROUP set to the name of the ! subgroup to determine these. Thus ! ! FLAG = DFILENAMES(ERCC99,... ! ! returns the names of files and groups in ERCC99's main file index. If ! there is a group called PROJ:, the contents of it can be found with ! ! FLAG = DFILENAMES(ERCC99.PROJ:,... ! ! The group separator, :, may be omitted if desired. ! ! Note that the usage of . and : (USEP and GSEP) is reversed in EMAS3. ! The UINF fields USEP, USEPCH etc allow utilities to be written which ! will work for both EMAS2 and EMAS3. ! ! MAXREC is set by the caller to specify the maximum number of records he ! is prepared to accept in the array INFS, and is set by Director to be ! the number of records returned. ! ! NFILES is set by Director to be the number of files actually held on ! on-line storage or on archive storage, depending on the value of TYPE. ! ! FILENO is not normally used. [ If the top bit of MAXREC is set, FILENO ! is used in the same way as for off-line files, described below ] ! ! The format of the records returned in INFS is ! ! %string(11)NAME, %integer SPARE1, KBYTES, ! %byteinteger ARCH, CODES, CCT, OWNP, ! EEP, USE, CODES2, SSBYTE, SPARE2, PHEAD, DAYNO, GROUP ! ! ( 32 bytes ) ! PHEAD is non-zero if the file or group has been permitted itself to a ! user or user group. ! GROUP is non-zero if NAME is the name of a group. ! ! For off-line files, TYPE = 1 or 2, GROUP will normally be be the name ! of a file index eg ERCC99 or ERCC99{UTILS} when all the names in the ! index will be returned. If an actual group name is given eg ! ! ERCC99.PROJ: ! ! then only names of the form ! ! ERCC99.PROJ:name ! ! are returned. MAXREC and NFILES are used in the same way as above. ! ! Filenames are stored in chronological order of archive (or backup) date, ! youngest first. FILENO is set by the caller to specify the "file-number" ! from which names are to be returned, zero representing the most recently ! archived file. Thus the caller can conveniently receive subsets of names ! of a very large number of files. ! ! The format of the records returned in INFS is ! ! %string(11)NAME, %integer KBYTES, ! %string(8)DATE, %string(6)TAPE, ! %halfinteger PREFIX, CHAPTER, ! %byteinteger EEP, PHEAD, SPARE, COUNT ! ! ( 40 bytes ) ! To allow the full filenames to be reconstructed, the array INFS, in ! general, contains some records which hold group names. Records refering ! to filenames can be distinguished by the fact that KBYTES > 0. If PREFIX ! is > 0, the name is a member of a group whose name is given in the ! record INFS(PREFIX). The chain can be followed back until a record ! with a zero PREFIX field is found. ! ! Note. MAXREC does not give the number of filenames returned but the ! number of records in INFS. ! ! TAPE and CHAPTER are returned null to unprivileged callers. EXTERNALINTEGERFNSPEC DFINFO(STRINGNAME FILE INDEX, FILE, INTEGERNAME FSYS, C STRINGNAME S, INTEGERARRAYNAME I) ! This procedure returns detailed information about the attributes of ! file or group FILE belonging to file index FILE INDEX on disc-pack ! FSYS, in a record written to address ADR. ! ! A caller of the procedure having no permitted access to the file ! receives an error result of 32, as though the file did not exist. ! ! The format of the record returned is: ! recordformat DFINFOF((integer NKB, RUP, EEP, APF, USE, ARCH, FSYS, CONSEG, CCT, CODES, byteinteger SP1, DAYNO, SP2, CODES2, integer SSBYTE or INTEGERARRAY i(1:12)), string (6)OFFER) ! ! where ! NKB the number of Kbytes (physical file size) ! zero indicates a group name ! RUP the caller's permitted access modes ! EEP the general access permission ! APF 1-4-4 bits, right-justified, giving respectively the Execute, ! Write and Read fields of APF, if the file is connected in ! this VM ! USE the current number of users of the file ! ARCH the value of the archive byte for the file (see procedure ! DFSTATUS) ! FSYS disc-pack number on which the file resides ! CONSEG the segment number at which the file is connected in the ! caller's VM, zero if not connected ! CCT the number of times the file has been connected since this ! field was last zeroed (see procedure DFSTATUS) ! CODES information for privileged processes ! SP1 spare ! DAYNO Day number when file last connected ! SP2 spare ! CODES2 information for internal use ! SSBYTE information for the subsystem's exclusive use ! OFFER the username to which the file has been offered, otherwise ! null EXTERNALINTEGERFNSPEC DFLAG(INTEGERNAME FLAG, STRINGNAME TXT) EXTERNALINTEGERFNSPEC DEXECMESS(STRINGNAME USER, INTEGERNAME SACT,LEN,ADDR) EXTERNALINTEGERFNSPEC DFSTATUS(STRINGNAME FILE INDEX, FILE, INTEGERNAME FSYS, ACT, VALUE) ! This procedure is supplied to enable the attributes of file FILE ! belonging to file index FILE INDEX on disc-pack FSYS to be modified, ! as follows. ! ! Parameter VALUE is for use by the archive/backup program (ACT=13), ! and by the subsystem (ACT=18), otherwise it should be set to zero. ! ! ACT ACTION ! ! 0 HAZARD Remove CHERISHed attribute ! ! 1 CHERISH Make subject to automatic System back-up procedures ! Note: If the file is one of ! SS#DIR, SS#OPT or SS#PROFILE ! then the 'archive-inhibit' bit is also set. ! Similarly, the 'archive-inhibit' bit is ! cleared by HAZARD for these files. ! ! 2 UNARCHIVE Remove the "to-be-archived" attribute ! ! 3 ARCHIVE Mark the file for removal from on-line to archive ! storage. ! ! 4 NOT TEMP Remove the "temporary" attribute. ! ! 5 TEMPFI Mark the file as "temporary", that is, to be ! destroyed when the process belonging to the file ! owner stops (if the file is connected at that ! time), or at system start-up. ! ! 6 VTEMPFI Mark the file as "very temporary", that is, to be ! destroyed when it is disconnected from the owner's ! VM. ! ! 7 NOT PRIVATE May now be written to magnetic tape either for ! back-up or archive. May be called only by ! privileged programs. ! ! 8 PRIVATE Not to be written to magnetic tape either for ! back-up or archive. May be called only by ! privileged programs. ! ! 9 SET CCT Set the connect count for the file to VALUE. ! ! 11 ARCH Operation 1 (PRIVILEGED). ! Set currently-being-backed-up bit (bit 2**1 in ! ARCH byte), unless the file is currently connected ! in write mode, when error result 52 is given. ! ! 12 ARCH Operation 2 (PRIVILEGED). ! Clear currently-being-backed-up bit (2**1) and ! has-been-connected-in-write-mode bit (2**0). ! ! 14 ARCH Operation 4 (PRIVILEGED). ! Clear the UNAVAilable and privacy VIOLATed bits in ! CODES. Used by the back-up and archive programs ! when the file has been read in from magnetic tape. ! ! 15 CLR USE Clear file use-count and WRITE-CONNECTED status ! (PRIVILEGED). ! ! 16 CLR NOARCH Clear archive-inhibit bit in CODES. PRIVILEGED - ! for System ! ! 17 SET NOARCH Set archive-inhibit bit in CODES. Library use ! ! 18 SSBYTE Set SSBYTE to be the bottom 8 bits of VALUE (byte ! for a subsystem's exclusive use). ! ! 19 ARCH Operation 5 (PRIVILEGED). ! Set the WRCONN bit in CODES2. Used to prevent any ! user connecting the file in write mode during ! back-up or archive. ! ! 20 ARCH Operation 6 (PRIVILEGED). ! Clear the WRCONN bit in CODES2. Used when back-up ! is complete. ! ! 21 DAYNO Set DAYNO to bottom 8 bits of VALUE EXTERNALINTEGERFNSPEC DFSYS(STRINGNAME FILE INDEX, INTEGERNAME FSYS) EXTERNALINTEGERFNSPEC DFSYSDATA(INTEGERNAME FSYS, INTEGERARRAYNAME DATA) EXTERNALINTEGERFNSPEC DGETDA(STRINGNAME FILE INDEX, FILE, INTEGERNAME FSYS, INTEGERARRAYNAME I) ! This procedure provides the disc addresses of the sections of file FILE ! belonging to file index FILE INDEX on disc-pack FSYS. Data is written ! from address ADR in the format ! ! (%integer SECTSI, NSECTS, LASTSECT, %integerarray DA(0:255)) ! ! where SECTSI is the size (in epages) of the sections (except ! possibly the final section) ! ! NSECTS is the number of sections, and hence the number ! of entries returned in array DA ! ! LASTSECT is the size (in epages) of the final section ! ! In each entry in the DA array, the top byte contains the FSYS number. EXTERNALINTEGERFNSPEC DMESSAGE(STRINGNAME USER, INTEGERNAME LEN, ACT, INVOC, FSYS, ADR) EXTERNALINTEGERFNSPEC DNEWGEN(STRINGNAME FILE INDEX, FILE, NEWGEN, INTEGERNAME FSYS) ! This procedure provides a means of introducing an updated version ! (i.e. a new generation) of file FILE belonging to file index FILE INDEX ! even though it may be connected in other users' virtual memories. ! ! If FILE is not connected in any virtual memory, a call on DNEWGEN is ! equivalent to destroying FILE and then renaming NEWGEN to FILE, ! except that the new version of FILE retains the former FILE's access ! permissions. ! ! If FILE is connected in some virtual memory, then the filename ! NEWGEN "disappears", and any subsequent connection of FILE into ! a virtual memory yields the contents of the new generation formerly ! held in NEWGEN. ! ! When the number of users of a former copy of FILE becomes zero ! (i.e. when it is not connected in any virtual memory), that copy is ! destroyed. EXTERNALINTEGERFNSPEC DPERMISSION(STRINGNAME FILE INDEX, C USER, DATE, FILE, INTEGERNAME FSYS, TYPE, ADR) ! This procedure allows the caller to set access permissions, or specific ! preventions, for file connection to individual users, groups of users ! or to all users to file FILE belonging to file index FILE INDEX. It ! also allows a caller to determine the modes (if any) in which he may ! access the file. ! ! TYPE determines the service required of the procedure: ! ! TYPE Action ! ! 0 set OWNP (not for files on archive storage) ! 1 set EEP ! 2 put USER into the file list (see "Use of file ! access permissions", below) ! 3 remove USER from file list ! 4 return the file list ! 5 destroy the file list ! 6 put USER into the index list (see "Use of file ! access permissions", below) ! 7 remove USER from the index list ! 8 return the index list ! 9 destroy the index list ! 10 give modes of access available to USER for FILE ! 11 set EEP for the file index as a whole ! ! TYPEs 0 to 9 and 11 are available only to the file owner and to ! privileged processes. For TYPE 10, ADRPRM (see below) should be the ! address of an integer into which the access permission of USER to the ! file is returned. If USER has no access to the file, error result 32 ! will be returned from the function, as though the file did not exist. ! If the file is on archive storage, TYPE should be set to 16 plus the ! above values to obtain the equivalent effects. ! ! ADRPRM is either the permission being attached to the file, bit ! values interpreted as follows: ! ! all bits zero prevent access ! 2**0 allow READ access ! 2**1 allow WRITE access not allowed for files ! 2**2 allow EXECUTE access on archive storage ! 2**3 If TYPE = 0, prevent the file from being ! destroyed by e.g. DDESTROY, DDISCONNECT (and ! destroy). ! or, except for type 10, it is the address of an area into which access ! permission information is to be written ! ! %recordformat(%integer BYTES RETURNED, OWNP, EEP, SPARE, ! %record(EF)%array INDIV PRMS(0:15)) ! ! and EF is ! %recordformat EF(%string(6)USER, %byteinteger PERMISSION) ! ! where: ! ! BYTES indicates the amount of data returned. ! RETURNED ! ! OWNP is the file owner's own permission to the file, or the ! requesting user's "net" permission if the caller of the ! procedure is not the file owner (see "Use of file access ! permissions", below). ! ! EEP is the general (all users) access permission to the file ! ("everyone else's permission"). ! ! UPRM The PERMISSION values in the sub-records are those ! for the corresponding users or groups of users denoted by ! USER. Up to 16 such permissions may be attached to a ! file. ! ! Use of file access permissions ! ! The general scheme for permissions is as follows. With each file ! there are associated: ! ! OWNP the permission of the owner of the file to access it ! ! EEP everyone else's permission to access it (other than users ! whose names are explicitly or implicitly attached to the ! file) ! ! INDIV PRMS a list of up to 16 items describing permissions for ! individual users, e.g. ERCC00, or groups of users, e.g. ! ERCC?? (specifying all usernames of which the first four ! characters are "ERCC") ! ! In addition, a user may attach a similar list of up to 16 items to ! his file index as a whole and an EEP for the file index. These ! permissions apply to any file described in the index along with those ! attached to that particular file. ! In determining the mode or modes in which a particular user may access ! a file, the following rules apply: ! ! 1. If the user is the file owner then OWNP applies. ! ! 2. Otherwise, if the user's name appears explicitly in the list for ! the file, the corresponding permission applies. ! ! 3. Otherwise, if the user's name is a member of a group of users ! represented by a list item for the file, the corresponding ! permission applies. ! ! 4. Otherwise EEP applies if greater than zero. ! ! 5. Otherwise, if the user's name appears explicitly in the list for ! the index, the corresponding permission applies. ! ! 6. Otherwise, if the user's name is a member of a group of users ! represented by a list item for the index, the corresponding ! permission applies. ! ! 7. Otherwise, everybody else's permission to the file index applies. ! ! In the event of a user's name appearing more than once (implicitly) ! within groups specified in a single list, the actual list item to be ! selected to give the permission should be regarded as indeterminate. EXTERNALINTEGERFNSPEC DPOFF(RECORD (pe)NAME P) EXTERNALINTEGERFNSPEC DPON3(STRINGNAME USER, RECORD (pe)NAME P, C INTEGERNAME INVOC, MSGTYPE, OUTNO) EXTERNALINTEGERFNSPEC DRENAME(STRINGNAME FILE INDEX, OLDNAME, NEWNAME, INTEGERNAME FSYS) ! File OLDNAME belonging to file index FILE INDEX on disc-pack FSYS is ! renamed NEWNAME. ! ! A file may not be renamed while it is connected in any virtual memory. EXTERNALINTEGERFNSPEC DSFI(STRINGNAME FILE INDEX, INTEGERNAME FSYS, TYPE, C SET, STRINGNAME S, INTEGERARRAYNAME I) ! This procedure is used to set or read information in file index FILE ! INDEX (or user record in some cases) on disc-pack FSYS. TYPE specifies ! which data item is to be referenced (see list below). SET must be 1 ! to write the data item into the index, or 0 to read the item from the ! index. ADR is the address of an area, which must be available in write ! or read mode, to or from which the data item is to be transferred. ! ! TYPE Data item Data type & size ! ! 0 BASEFILE name (the file to be connected ! and entered at process start-up) string(18) ! ! 1 DELIVERY information (to identify string(31) ! slow-device output requested by the ! index owner) ! ! 2 CONTROLFILE name (a file for use by the ! subsystem for retaining control information) string(18) ! ! 3 ADDRTELE address and telephone number of user string(63) ! ! 4 INDEX USE (may not be reset) ! Gives (in successive integers from ADR): ! a) number of files ! b) number of file descriptors currently in use ! c) number of free file descriptors ! d) index size (Kbytes) ! e) Number of section descriptors (SDs) ! f) Number of free section descriptors ! g) Number of permission descriptors (PDs) ! h) Number of free permission descriptors integer(x8) ! ! 5 Foreground and background passwords ! (reading is a privileged operation), a zero ! value means "do not change" integer(x2) ! ! 6 Date last logged-in: (Y-70)<<9 ! (M<<5) ! D and ! date last started (non-interactive) (same) ! (may not be reset) integer(x2) ! ! 7 ACR level at which the process owning this ! index is to run (may be set only by privileged ! processes) integer ! ! 8 Director Version (may be set only by privileged ! processes) integer(x2) ! ! 9 ARCHIVE INDEX USE (may not be reset) ! Gives (in successive integers from ADR): ! a) number of archived files ! b) number of archived Kbytes ! c) number of backed-up files ! d) number of backed-up Kbytes ! e) index size (Kbytes) ! f) number of file descriptors ! g) number of free file descriptors ! h) number of permission descriptors ! i) number of free permission descriptors integer(x9) ! ! 10 Stack size (Kbytes) integer ! ! 11 Limit for total size of all files in disc ! storage (Kbytes) (may be set only by privileged ! processes integer ! ! 12 Maximum file size (Kbytes) (may be set only by ! privileged processes) integer ! ! 13 Current numbers of interactive and batch ! processes, respectively, for the user (may ! not be reset) integer(x2) ! ! 14 Process concurrency limits (may be set only ! by privileged processes). The three words ! denote respectively the maximum number of ! interactive, batch and total processes which ! may be concurrently running for the user. ! (Setting the fields to -1 implies using ! the default values, currently 1, 1 and 1.) integer(x3) ! ! 15 When bit 2**0 is set, TELL messages to the ! index owner are rejected with flag 48. integer ! ! 16 Set Director monitor level (may be set only ! by privileged processes) integer(x2) ! ! 17 Set SIGNAL monitor level (may be set only ! by privileged processes) integer ! ! 18 Initials and surnames of user (may ! be set only by privileged processes) string(31) ! ! 19 Director monitor file string(11) ! ! 20 Thousands of instructions executed, interactive ! and batch modes (may be reset only by ! privileged processes) integer(x2) ! ! 21 Thousands of instructions executed (current ! session only) integer ! ! 22 Thousands of instructions executed in Director ! procedures (current process session only) ! (may not be reset) integer ! ! 23 Page-turns, interactive and batch modes ! (may be reset only by privileged processes) integer(x2) ! ! 24 Page-turns (current process session only) integer ! ! 25 Thousands of bytes output to slow-devices ! (local or remote) (may be reset only by ! privileged processes) integer ! ! 26 Thousands of bytes input from slow-devices ! (local or remote) (may be reset only by ! privileged processes) integer ! ! 27 Milliseconds of OCP time used, interactive ! and batch modes (may be reset only by ! privileged processes) integer(x2) ! ! 28 Milliseconds of OCP time used (current ! session only) integer ! ! 29 Seconds of interactive terminal connect time ! (may be reset only by privileged processes) integer ! ! 30 No. of disc files, total disc Kbytes, no. of ! cherished files, total cherished Kbytes, no. ! of temporary files, total temporary Kbytes ! (cannot be reset) integer(x6) ! ! 31 No. of archive files, total archive Kbytes integer(x2) ! ! 32 Interactive session length in minutes integer ! 0 or 5 <= x <= 240 ! ! 33 Funds integer ! ! 34 The FSYS of the Group Holder of the index integer ! owners funds, if he has a GH ! ! 35 Test BASEFILE name string(18) ! ! 36 Batch BASEFILE name string(18) ! ! 37 Group Holder of funds for scarce resources string(6) ! ! 38 Privileges integer ! ! 39 Default LP string(15) ! ! 40 Dates passwords last changed integer(x2) ! (may not be reset) ! ! 41 Password data integer(x8) ! ! 42 Get accounting data integer(x17) ! ! 43 Mail count integer ! (may be reset only by privileged processes) ! ! 44 Supervisor string(6) ! ! 45 Secure record about 512 bytes ! ! 46 Gateway access id string(15) ! ! 47 File index attributes byte ! ! 48 User type byte EXTERNALINTEGERFNSPEC DTOFF(RECORD (pe)NAME P) EXTERNALINTEGERFNSPEC DTRANSFER(STRINGNAME FILE INDEX1, FILE INDEX2, FILE1, C FILE2, INTEGERNAME FSYS1, FSYS2, TYPE) ! This procedure transfers FILE1 belonging to file index FILE INDEX1 on ! FSYS1 to the ownership of file index FILE INDEX2 on FSYS2 under name ! FILE2. ! ! TYPE = 0 'accepts' a file which has been 'offered'. This call ! is non-privileged. ! 1 a privileged call to transfer a file. ! 2 like 1, but, in addition, forces a re-allocation of the ! disc space. ! 3 a privileged call to copy the file. ! 4 as 3 but works even when file connected W (for test purposes) finish !* !* !* externalroutinespec dump(integer start, finish, conad) externalroutinespec i to e(integer ad, l) externalstringfnspec i to s(integer value) externalstringfnspec h to s(integer value, places) externalintegerfnspec s to i(stringname s) externalroutinespec pt rec(record (pe)name p) externalroutinespec print log(integer stream,q) externalroutinespec prompt(string (23) s) !* !* ! E X T E R N A L V A R I A B L E S ! - - - - - - - - - - - - - - - - - extrinsicinteger com36; !ADDRESS OF RESTART REGISTERS extrinsicinteger oper no; !CURRENT OPER OUTPUT CONSOLE extrinsicinteger my fsys; !FTRANS FILE SYSTEM extrinsicinteger my service number; !FTRANS SERVICE NUMBER extrinsicstring (6) my name; !FTRANS USERNAME !* !* !* !* ! !************************************************************************* !THE MAIN ENTRY POINT TO THE FTRANS EXECUTIVE PROCESS. ! ! externalroutine control(integer lines,database conad,pointers addr) ! ! MAX Fsys Maximum number of FSYS ! QCONAD Address of basic queue description area. ! LINES Number of file transfer lines available ! LCONAD Address of the LINE descriptor area. ! LNCONAD Address of the 'short' LINE descriptor area. ! FTP STNS Number of external FTP hosts. ! STCONAD Address of the external host table area. ! LINK LIST CONAD Address of the LINK LIST area. ! N O T E here that the control values MAX FTP LINES, FTP Q LINES, ! FTP SERVICE and FTP LIMIT are contained in the first FTP STATION record. ! I N T E G E R S ! - - - - - - - - integer temp, free list, erase, kicked, stopping, c mon level, e page size, block size, closing, FTP check, FTP queue , pt, ptl, ms, msl, picture tick, status header change, ada, refresh line integer lconad, qconad, stconad, link list conad, FTP stns, control entry, guest entry, address cache addr, hash length if TARGET # 2900 start string (63) dsfis integerarray dsfiia(1:32) finish STRING (63) MAIL MC INTEGER MAIL DIS ! msl = 0; ptl = 0 !* !* ! S T R I N G N A M E S ! - - - - - - - - - - - !* !* ! I N T E G E R N A M E S ! - - - - - - - - - - - - !* !* ! S T R I N G S ! - - - - - - - string (31) PSS, IPSS string (63) send message string (11) system ! !* !* ! R E C O R D N A M E S ! - - - - - - - - - - - ! - - - - - - - - - - - if TARGET = 2900 start constrecord (comf)name com = x'80000000'+48<<seg shift finish else start constrecord (comf)name com = 31 << seg shift finish record (name f)name name entry record (queuef)name queue record (ftp pointers f)name pointers !* !* ! R E C O R D A R R A Y F O R M A T S ! - - - - - - - - - - - - - - - - - - record (lcf)arrayformat list cells af(1 : list size) record (linef)arrayformat larf(1 : lines) record (FTP stationf) arrayformat FTPsf(1: max stations) record (exp addr f)arrayformat exp addr af(1: max stations) !* !* ! R E C O R D A R R A Y N A M E S ! - - - - - - - - - - - - - - - - record (lcf)arrayname list cells record (linef)arrayname FTP lines record (FTP stationf) arrayname FTP stations record (exp addr f)arrayname expanded addresses !* !* ! R E C O R D S ! - - - - - - - !* !* ! B Y T E I N T E G E R A R R A Y S ! - - - - - - - - - - - - - - - - - byteintegerarray kick(1 : lines); !SIGNIFICANCE: 2**0 KICK line INTO ACTION SOMETHING TO DO !* 2**1 STOP line I.E. SUPPRESS KICKED BIT !* !* ! I N T E G E R A R R A Y S ! - - - - - - - - - - - - - integerarray line addresses ( 1 : lines ) ! only used for FTP summary picture so only one such array necessary ( since only one summary held at once ) !* ! R E C O R D A R R A Y S ! - - - - - - - - - - - - record (opf)array oper(-1 : max oper) record (fepf)array feps(0 : max fep) record (f systems f)array f systems(0 : max fsys) record (FTP tablef)array FTP tables(0:lines) record (picturef)array pictures ( 1:max pic files) record (screenf) array screens ( 0:max screen ) !* !* ! R O U T I N E S A N D F U N C T I O N S S P E C S ! - - - - - - - - - - - - - - - - - - - - - - - - - routinespec move with overlap(integer length, from, to) integerfnspec generate pic(integer pic,picture type,id1, refresh, string (15) id2) routinespec picture manager(record (pe)name p,integer picture type,id1,string (15) id2) routinespec initialise pictures routinespec refresh pic(integer pic type, id1, string (15) id2 ) stringfnspec ident to s(integer ident) routinespec user message(record (pe)name p) routinespec update descriptors(integer fsys) routinespec display text(integer oper no, line, col, string (255) s) routinespec update oper(integer oper no, display type, which display, which page, switch screen, string (10) specific user) stringfnspec dt stringfnspec users delivery(string (6) u, integer fsys) routinespec opmessage(record (pe)name p) routinespec switch gear integerfnspec check filename(string (6) u,string (15) f, integer fsys, allow temp) routinespec interpret descriptor(integer type ,a,integername l, string (6) user, integername ident, f) routinespec interpret command(string (255) s,string (6) user, integer console ) routinespec initialise routinespec user command(string (255) s, string (6) u, integername f) routinespec add to queue(integer ident,delay, all, fixed delay, integername flag) routinespec remove from queue(integer ident, integername flag) routinespec delete document(integer ident, integername flag) integerfnspec document addr(integer ident) integerfnspec password document addr(integer ident) routinespec connect or create(string (6) u, string (11) f, integer fs, size, mode, flgs, integername cad) routinespec output message reply from fep(record (pe)name p) routinespec FTP input message from fep(record (pe)name p) routinespec FTP output message to fep(integer fep, record (FTP f)name FTP) routinespec FTP control(record (pe)name p, integername refresh line) routinespec requeue FTP document(integer document,delay,all,fixed) routinespec fire clock tick routinespec clock ticks routinespec set document timers(integer addr ptr, time, specific document) routinespec check FTP(integer line) routinespec handle close(record (pe)name p) routinespec close fsys(integer fsys) routinespec time out(integer remote number) routinespec fep down(integer fep) routinespec open fep(record (pe)name p) routinespec open file system(integer fsys) routinespec any extra files(integer fsys,special) stringfnspec errs(integer flag) {used to decide on D call} !* !* !* !* !INITIAL ENTRY HERE if TARGET = 2900 start *stln_temp; !TO ALLOW NDIAGS TO EXIT FROM CONTROL finish else start *st_10,temp finish com36 = temp ! temp = change context print string("FTRANS ".version.snl) !TELL OPERATOR CONSOLE WE HAVE STARTED if lines = 0 then c printstring("CONFIGURATION FAILURE".snl."F/STOP , F/CONFIG only".snl) c else start POINTERS == record(pointers addr) FTP stns = POINTERS_STATIONS QCONAD = DATABASE CONAD + POINTERS_QUEUE DISPL LCONAD = DATABASE CONAD + POINTERS_STREAM DISPL ST CONAD = DATABASE CONAD + POINTERS_STATION DISPL LINK LIST CONAD = DATABASE CONAD + POINTERS_LINK LIST DISPL hash length = pointers_hash length address cache addr = databaseconad + pointers_station addresses displ expanded addresses == array(database conad + pointers_expanded address displ, exp addr af) list cells == array(link list conad, list cells af) FTP lines == array(lconad, larf) FTP stations == array(stconad,FTPsf) queue == record(qconad) guest entry = pointers_guest entry control entry = pointers_control entry finish INITIALISE !SET UP TABLES AND LISTS !* ! MAIN LOOP OF THE FTRANS EXECUTIVE !* cycle switch gear; !IF WE EXIT GO ROUND AGAIN print log(1,jrnl) !HERE DO THE SAME AS VOLUMS repeat !* !* routine switch gear !********************************************************************** !* * !* ACCEPTS IN COMMING MESSAGES TO FTRANS AND SWITCHES TO THE * !* APPROPRIATE ROUTINE. IF ANY ERRORS OCCUR IN A SUBSEQUENTLY CALLED * !* ROUTINE THE STACK IS COLLAPSED TO THE LEVEL OF THIS ROUTINE AND A * !* RETURN IS MADE FROM THIS ROUTINE. * !* * !********************************************************************** integer temp, dact switch sw(0 : 127); ! 1 FOR EACH ACTIVITY record (pe)p !* if TARGET = 2900 start *stln_temp; !TO ALLOW NDIAGS TO EXIT FROM CONTROL finish else start *st_9,temp finish com36 = temp dact = 0; !HOLD LAST ACTIVITY !* ! MAIN LOOP OF THE FTRANS EXECUTIVE !* wait: ! CLOSE DOWN(COM_SECS TO CD) %IF 0 < COM_SECS TO CD <= 900 if stopping = yes start ; !REQUESTED TO STOP? cycle temp = 1, 1, lines -> out if FTP lines(temp)_status >= allocated repeat cycle temp = 0, 1, max fep fep down(temp) if feps(temp)_FTP available = yes !DISABLE COMMS STREAMS repeat stop finish out: if kicked # 0 start ; !ANY lineS KICKED INTO ACTION FTP check = on; !switch FTP check on cycle temp = kicked, 1, lines if kick(temp)&3 = 1 start ;!THIS LINE NOT STOPPED AND KICKED kick(temp) = 0 kicked = temp if FTP check = on and FTP stations(control entry)_service = open c and FTP stations(control entry)_max lines > 0 and FTP stations(control entry)_limit > 0 c and FTP lines(kicked)_status = unallocated then check FTP(kicked) !the non dedicted FTP lines are 'LOCAL' owned for general FTP !transactions from the FTP queue as a P station or as !Q stations for the outside world continue finish repeat kicked = 0 finish !SIT HERE WAITING FOR SOMETHING TO DO if mon level = 1 or mon level = 5 start select output(1) printstring(dt."SLEEPING, last activity costs pt/ms: ") if TARGET # 2900 start temp = dsfi(my name,my fsys,24,0,dsfis,dsfiia) pt = dsfiia(1) temp = dsfi(my name,my fsys,28,0,dsfis,dsfiia) ms = dsfiia(1) finish else start temp = dsfi(my name,my fsys,24,0,addr(pt)) temp = dsfi(my name,my fsys,28,0,addr(ms)) finish printstring(i to s(pt-ptl)." / ".i to s(ms-msl).snl) p=0 if TARGET # 2900 then temp = dtoff(p) else dtoff(p) if p_dest = 0 start printstring(dt."No Work".snl) if TARGET # 2900 then temp = dpoff(p) else dpoff(p) finish if TARGET # 2900 start temp = dsfi(my name,my fsys,24,0,dsfis,dsfiia) ptl = dsfiia(1) temp = dsfi(my name,my fsys,28,0,dsfis,dsfiia) msl = dsfiia(1) finish else start temp = dsfi(my name,my fsys,24,0,addr(ptl)) temp = dsfi(my name,my fsys,28,0,addr(msl)) finish print string(dt."POFF ") pt rec(p) select output(0); !BACK TO OPER finish else start p=0 if TARGET # 2900 then temp = dtoff(p) else dtoff(p) if p_dest = 0 then start if TARGET # 2900 then temp = dpoff(p) else dpoff(p) finish finish if dact # p_dest&127 start ; !SAME AS PREVIOUS ACTIVITY? dact = p_dest&127 ! temp = change context finish -> sw(dact); !GO DO SOME THING sw(clock tick): !tick of the clock ! UPDATE OPER( P_P1, OPER(P_P1)_DISPLAY TYPE, OPER(P %C ! _P1)_WHICH DISPLAY, OPER(P_P1)_WHICH PAGE, NO, "") fire clock tick clock ticks !IE WE REQUIRE TICKING TO CONTINUE FOR AT LEAST 1 REMOTE OR FILETRAN WAIT. -> wait sw(descriptor update): !update descriptors(p_p1) ->wait sw(solicited oper message): sw(unsolicited oper message): opmessage(p); -> wait; !OPERATOR MESSAGE sw(picture maintainance): picture manager(p,0,0,""); -> wait sw(open fsys): open file system(p_p1); -> wait; !NEW FILE SYSTEM ONLINE sw(user mess): !message from a user user message(p); -> wait sw(FTP input mess): FTP input message from fep(p); -> wait sw(FTP output reply mess): output message reply from fep(p); -> wait sw(FTP input control connect): sw(FTP input control connect reply): sw(FTP output control connect reply): sw(FTP input control enable reply): sw(FTP output control enable reply): sw(fep input control connect): open fep(p); -> wait sw(close control): handle close(p) -> wait sw(FTP connect): sw(FTP input connected): sw(FTP output connected): sw(FTP input control message): sw(FTP output control message): sw(FTP input disconnected): sw(FTP output disconnected): sw(FTP p command reply): sw(FTP p command sent): sw(FTP data input): sw(FTP q command reply): sw(FTP q command sent): sw(FTP command overflow): sw(FTP input aborted): sw(FTP output aborted): sw(FTP timed out): sw(FTP confirmation from spooler): FTP control(p,refresh line) if refresh line # 0 then refresh pic(FTP status summary display, refresh line, "") -> wait sw(spooler reply act): !This is a response after SPOOLR has processed A log request by DEXECMESS. !If it fails there is little we can do but record the fact. if p_p1 # 0 start select output(1) printstring(dt."Log transfer, SPOOLR replies with flag of ".itos(p_p1).snl) select output(0) finish -> wait !* ALL ILLEGAL ACTIVITIES COME HERE sw(*): print string("FTRANS BAD DACT "); pt rec(p) -> wait !* ! END OF FTRANS EXECUTIVE MAIN LOOP end ; !OF ROUTINE SWITCH GEAR !* !* !* !* routine kick FTP line(integer line) !********************************************************************** !* * !* SETS THE KICKED BIT FOR THE SPECIFIED line AND REMEMBERS THE * !* LOWEST NUMBERED KICKED line * !* * !********************************************************************** kick(line) = kick(line)!1; !SET KICKED BIT kicked = line if kicked = 0 or line < kicked end ; !OF ROUTINE KICK LINE !* !* stringfn i to s s(integer i, l) !*********************************************************************** !* * !* TURNS AN INTEGER INTO A STRING OF THE SPECIFIED LENGTH PADDING * !* WITH LEADING SPACES IF NECESSARY. * !* * !*********************************************************************** string (255) s s = i to s(i) s = " ".s while length(s) < l result = s end ; !OF STRINGFN I TO SS !* !* routine to doc string(record (document descriptorf)name document, byteintegername field, stringname value) field = 0 and return if value = "" field = x'ff' and return if document_string ptr + length(value) > 147 field = document_string ptr string(addr(document_string space) + document_string ptr) = value document_string ptr = document_string ptr + length(value) + 1 end string fn string at(record (FTP station f)name station, integer ptr) !This fn passes back a string from the string pool in the station !descriptor record. STRING (255) S S = string(addr(station_string space(0)) + ptr) RESULT = S end stringfn doc string(record (document descriptor f)name document, byteintegername ptr) if ptr = 0 then result = "" else c result = string(addr(document_string space) + ptr) end stringfn password doc string(record (password document descriptor f)name document, byteintegername ptr) if ptr = 0 then result = "" else c result = string(addr(document_string space) + ptr) end !* stringfn errs(integer flag) integer i; string (63) error if TARGET = 2900 then result = derrs(flag) ELSE START i = dflag(flag,error) result = error FINISH end !* !* string (23) fn dt !*********************************************************************** !* * !* RETURNS THE DATE AND TIME IN A FIXED FORMAT * !* * !*********************************************************************** result = "DT: ".date." ".time." " end ; !OF STRINGFN DT !* !* string (15) fn hms(integer secs) !*********************************************************************** !* * !* RETURNS THE GIVEN NUMBER OF SECONDS IN THE FORMAT HH.MM.SS * !* * !*********************************************************************** integer hrs, mins, scs, i string (15) s hrs = secs//3600 i = secs-hrs*3600 mins = i//60 scs = i-mins*60 if hrs > 0 then s = i to s(hrs)."h " else s = "" s = s.i to s(mins)."m " if s # "" or mins > 0 result = s.i to s(scs)."s" end ; !OF STRINGFN HMS !* !* integerfn compute priority( c integer type, resource, resource limit) resource = resource limit if resource > resource limit result = prtys(type)+max priority-(max priority* c resource)//resource limit end ; !OF INTEGERFN COMPUTE PRIORITY !* !* routine age queue(integer resource used) integer a, next resource used = queue_resource limit c if resource used > queue_resource limit a = ((max priority*resource used)//queue_resource limit)// c small weight next = queue_head while next # 0 cycle if list cells(next)_priority > 0 then c list cells(next)_priority = list cells(next)_priority+a c else list cells(next)_priority = list cells(next)_priority-a !IE UPDATE THE QUEUE LINKAGE TABLE'S COPY OF THE PRIORITY FOR THE DOCUMENT. next = list cells(next)_link repeat end ; !OF ROUTINE AGE QUEUE !* routine clock ticks !****************************************************** !* * !* handle a clock tick for FTP * !* * !****************************************************** integer i, next, set kick record (pe) p !Transfer control timing is organised as follows: !Each station has a CONNECT RETRY POINTER. This is incremented !each time a CONNECT ATTEMPT times out (Not with a CLEAR, and !hencne not entirley a satisfactory system). The increment drops back !to 0 to prevent loss of access due to congested other end. !It dictates the waiting time before the next connect attemp. !CONNECT RETRY TIME in each station is the actual figure in minutes !that has to yet elapse before a connection is attempted. This !is mirrored in the FTP TMIER filed of each document queued for !that station, but this is only to avoid excessive thrashing when !we look for a document to service for a line. The FTP TIMER field !can also have its own meaning when a single document is earmarked for !a fixed time delay (ie a DEFERRED document on size). in this case !it is not cleared down when CONNECT RETRY TIME is. set kick = no cycle i = 1,1,lines continue if FTP lines(i)_status <= allocated or c FTP lines(i)_timer = 0 FTP lines(i)_timer = FTP lines(i)_timer - 1 if FTP lines(i)_timer = 0 start !we have a time out on an FTP function. p = 0; p_dest = FTP timed out ! i<<7 FTP control(p,refresh line) if refresh line # 0 then refresh pic(FTP status summary display, refresh line, "") finish repeat !Now look at the FILETRAN queue for 'wait' timing cycle i = 1,1,ftp stns if FTP stations(i)_connect retry time > 0 start FTP stations(i)_connect retry time = FTP stations(i)_connect retry time - 1 if ftp stations(i)_connect retry time = 0 then set kick = yes finish repeat next = queue_head while next # 0 cycle if list cells(next)_FTP timer > 0 start list cells(next)_FTP timer = list cells(next)_FTP timer - 1 if list cells(next)_FTP timer = 0 start !a transfer has completed a wait, kick the lines list cells(next)_FTP flags = list cells(next)_FTP flags&FTP no fixed term delay !Take of the 'fixed' delaymarker(ie for Deffered transfers) set kick = yes finish finish next = list cells(next)_link repeat if set kick = yes start cycle i = 1,1,lines kick FTP line(i) repeat finish return end ; !of routine clock ticks !* routine fire clock tick !************************************************** !* * !* REQUEST A CLOCK TICK * !* * !************************************************** record (pe)p integer flag p = 0 p_dest = elapsed int p_p1 = my service number ! clock tick p_p2 = default clock tick flag = dpon3("", p, 0, 0, 6) end ; !OF ROUTINE FIRE CLOCK TICK. !* ; !OF ROUTINE POLL FEPS. !* !* routine set document timers(integer addr ptr,time, specific document) integer next next = queue_head while next # 0 cycle if specific document = 0 or specific document = list cells(next)_document start if list cells(next)_station ptr = addr ptr and c list cells(next)_FTP flags&FTP fixed term delay = 0 then c list cells(next)_FTP timer = time !only set the timer if the fixed term delay is off. exit if specific document # 0 finish !This specific document bit is for GUEST documents. (See ADD TO QUEUE for details) next = list cells(next)_link repeat !Also set the station CONNECT RETRY TIME FTP stations(addr ptr)_connect retry time = time return end ; !of routine set document timers !* routine check FTP(integer line) !************************************************************* !* * !* this routine looks at the FILETRAN queue to see if there * !* is a transfer that can be started and is not under any * !* restriction by waiting etc. * !* * !************************************************************* integer next, found one, i, j, count, fep, specific document string (75) caller, called, residue, guest address, s1, s2 record (linef)name FTP line record (FTP tablef)name FTP table record (FTP f) FTP record (document descriptorf)name document record (FTP stationf)name FTP station integerfn all numeric(stringname s) integer i result = yes if length(s) = 0 cycle i = 1,1,length(s) result = no unless x'30' <= byteinteger(addr(s)+i) <= x'39' repeat result = yes end count = 0 !first check to see if we have a P station slot available. cycle i = 1,1,lines count = count + 1 if FTP lines(i)_status >= active c and FTP lines(i)_status # deallocating and FTP lines(i)_station type = P station repeat if count >= FTP stations(control entry)_max lines - FTP stations(control entry)_q lines start select output(1) printstring(dt."FTP: Max P stations active, waiting.".snl) select output(0) FTP check = off return finish !ok to proceed as a potential P station. FTP line == FTP lines(line) FTP table == FTP tables(line) next = queue_head while next # 0 cycle if (list cells(next)_size+1023)>>10 <= FTP stations(control entry)_limit and list cells(next)_FTP timer = 0 c and (list cells(next)_size+1023)>>10 <= FTP stations(list cells(next)_station ptr)_limit c and FTP stations(list cells(next)_station ptr)_service = open start !ie the transfer is within the overall transfer limit, has no timer !set and the station can accept this size of transfer and it's service open. found one = yes if list cells(next)_station ptr = guest entry start document == record(document addr(list cells(next)_document)) guest address = docstring(document,document_guest address) finish cycle i = 1,1,lines if FTP lines(i)_station ptr = list cells(next)_ c station ptr and (FTP lines(i)_status = connecting c or FTP lines(i)_status = selected) start if FTP lines(i)_station ptr = guest entry start document == record(document addr(FTP lines(i)_document)) called = docstring(document,document_guest address) if mon level = 8 then c printstring("GUEST check for ".itos(i).snl.called.snl.guest address.snl) if called # guest address then -> not same if mon level = 8 then printstring("No connect".snl) finish !we are already trying a connection/allocation to that station, wait. found one = no if FTP lines(i)_station ptr = guest entry then j = list cells(next)_document c else j = 0 set document timers(list cells(next)_station ptr,connect delay,j) !ie set the delay timer for all transfers queued for this station. exit finish NOT SAME: repeat if found one = yes start !now check that this station is not to its individual simult. transfer !capacity, if it is set the delay timer on all docs for this station. !we still have a transfer to attempt count = 0 cycle i = 1,1,lines if FTP lines(i)_status >= active and FTP lines(i)_status # deallocating and FTP lines( c i)_station ptr = list cells(next)_station ptr c then count = count + 1 repeat if count >= FTP stations(list cells(next)_station ptr)_max lines start found one = no set document timers(list cells(next)_station ptr,station capacity retry time,0) finish finish fep = FTP stations(list cells(next)_station ptr)_fep if list cells(next)_station ptr = guest entry and document_ c specific fep # -1 then fep = document_specific fep if (feps(fep)_FTP available = no or feps(fep)_outgoing calls permitted = no c or (feps(fep)_comms type = NSI type and c FTP stations(list cells(next)_station ptr)_address type >= TS type) ) c or (list cells(next)_station ptr = guest entry c and document_specific fep = -1) start fep = -1 if list cells(next)_station ptr = guest entry then specific c document = list cells(next)_document else specific document = 0 unless list cells(next)_station ptr = guest entry and document_ specific fep # -1 start cycle i = 0,1,max fep if feps(i)_FTP available = yes and feps(i)_outgoing calls permitted = yes start if FTP stations(list cells(next)_station ptr)_address type = TS type start if feps(i)_comms type >= TS type {TS, X25 or BSP} then fep = i and exit finish else if feps(i)_comms type = NSI type and list cells(next)_ c station ptr # guest entry then fep = i and exit finish repeat finish select output(1) if fep # -1 then printstring(dt."FTP FEP ". c itos(fep)." chosen as alternative".snl) and select output(0) else start printstring(dt."FTP FEP ".i to s(FTP stations(list cells(next)_station ptr)_fep). c " not available(no alternative).".snl) select output(0) found one = no set document timers(list cells(next)_station ptr,station capacity retry time,specific document) finish finish if found one = yes start !still have a transfer. FTP line_station ptr = list cells(next)_station ptr !mark the document as being served by allocation attempt. FTP line_bytes transferred = 0 FTP line_timer = FTP selected timeout FTP line_status = selected FTP line_document = list cells(next)_document document == record(document addr(ftp line_document)) FTP line_user = document_user FTP line_station type = p station refresh pic(ftp status summary display,line,"") FTP = 0 if FTP stations(FTP line_station ptr)_address type = TS type then c FTP_type = 4 else FTP_type = 1; !allocate request FTP_pair ref = line FTP station == FTP stations(FTP line_station ptr) if FTP station_address type = TS type start caller = spoolFTP if document_user = "MAILER" then caller = caller.".".spoolmail if FTP line_station ptr = guest entry then called = docstring( c document,document_guest address) c else called = string(address cache addr+FTP station_address(1)) !Now check to see if PSS or IPSS acred required. if called -> s1.("(PSS)").s2 then called = s1."(".PSS.")".s2 c else if called -> s1.("(IPSS)").s2 then called = s1."(".IPSS.")".s2 called = called.".".string at(FTP station,FTP station_FTP) if c FTP line_station ptr # guest entry if document_user = "MAILER" and FTP line_station ptr # guest entry c then called = called.".".string at(FTP station,FTP station_mail) select output(1) printstring(dt."FTP TS outgoing call on ".called." by ".caller.snl) select output(0) byteinteger(addr(FTP_address)) = length(caller) + length(called) + 2 string(addr(FTP_address)+1) = called string(addr(FTP_address)+2+length(called)) = caller finish else start FTP_address = string(address cache addr+FTP stations(FTP line_station ptr)_address(1)) if FTP stations(FTP line_station ptr)_pss entry # 0 then c FTP_address = FTP_address.".F".itos(FTP stations(FTP line_station ptr)_ c pss entry) finish if TARGET = 2900 then FTP_length = length(FTP_address) + 1 + FTP std mess len FTP output message to fep(fep,FTP) return finish finish next = list cells(next)_link repeat FTP check = off; !since we found nothing there is no point for any other line. return end ; !of routine check FTP. !* !* integerfn sdestroy(string (6) user, string (11) file, c string (8) date, integer fsys, type) !******************************************************************** !* * !* SPECIAL DESTROY FOR FILES THAT MAY BE IN USE * !* * !******************************************************************** integer flag flag = ddestroy(user, file, date, fsys, type) result = flag unless flag = 40; ! CAN'T HANDLE OTHER FAILURES APART ! FROM 'IN USE' if TARGET # 2900 then flag = dcreate(user, "##", fsys, 4, 4, ada) c else flag = dcreate(user, "##", fsys, 4, 4); ! CREATE DUMMY FILE ! ZERO IT TO CLEAR VIOLAT result = flag if 0 # flag # 16; ! OK IF ALREADY THERE flag = dnewgen(user, file, "##", fsys) result = flag unless flag = 0 flag = ddestroy(user, file, date, fsys, type) result = flag end !* !* integerfn get block addresses(string (6) user, string (11) file, integer fsys, address) !******************************************************************** !* * !* THIS FUNCTION RETURNS THE NUMBER OF BLOCKS IN A FILE, THE * !* LENGTH OF EACH BLOCK IN EPAGES AND THE LENGTH OF THE LAST BLOCK * !* IN EPAGES. ALSO THE DISC ADDRESSES OF EACH BLOCK. THIS FUNCTION * !* IS SUPPOSED TO WORK FOR SECTION SIZES WHICH ARE MULIPLES OF THE * !* BLOCK SIZE. * !* NOTE: ALSO SETS THE GLOBAL VARIABLE "BLOCK SIZE" TO THE NUMBER * !* OF BYTES IN A BLOCK. * !* * !******************************************************************** recordformat sectf(integer sectsi, nsects, last sect, blk size, integerarray da(1 : 256)) record (sectf)disc sect record (daf)name daddr integer flag, mult, in last, inc, i, j, k !* if TARGET # 2900 start daddr == record(address) flag = dgetda(user, file, fsys, daddr_i) ! printstring("Raw DGETDA : ".htos(daddr_i(0),8)." ".htos(daddr_i(1),8). %c ! snl.htos(daddr_i(2),8)." ".htos(daddr_i(3),8)." ".htos(daddr_i(4),8).snl) move(12, addr(daddr_i(0)),addr(daddr_sparex)) ! printstring("blksi: ".htos(daddr_blksi,8)." nblks: ".htos(daddr_nblks,8). %c ! snl."last blk: ".htos(daddr_last blk,8)." ADDR blk1: ".htos(daddr_da(1),8).snl) finish else flag = dgetda(user, file, fsys, addr(disc sect)) !GET ADDRESSES OF DISC SECTIONS if flag = 0 start if TARGET # 2900 start block size = daddr_blksi*e page size result = flag finish block size = disc sect_blk size*epage size !ONLY REALLY NEEDS TO BE SET ONCE daddr == record(address) daddr_blk si = disc sect_blk size; !GET BLOCK SIZE IN E PAGES mult = disc sect_sectsi//disc sect_blk size !NUMBER OF BLOCKS IN A SECTION in last = (disc sect_last sect-1)//disc sect_blk size+1 !NUMBER OF BLOCKS IN LAST SECTION daddr_nblks = (disc sect_nsects-1)*mult+inlast !TOTAL NUMBER OF BLOCKS daddr_last blk = disc sect_last sect-(in last-1)* c disc sect_blk size !EPAGES IN LAST BLOCK k = 1 cycle i = 1, 1, disc sect_nsects; !EACH SECTION inc = 0 cycle j = 1, 1, mult; !EACH BLOCK IN SECTION daddr_da(k) = disc sect_da(i)+inc; !SET BLOCK DISC ADDRESSES exit if k = daddr_nblks k = k+1 inc = inc+disc sect_blk size repeat repeat finish result = flag end ; !OF INTEGERFN GET BLOCK ADDRESSES !* !* recordformat cf(integer dest, srce, string (23) s) routine opmessage(record (cf)name p) !******************************************************************** !* * !* THIS ROUTINE ACCEPTS MESSAGES FROM THE LOCAL OPERATOR EITHER * !* IN RESPONSE TO PROMPTS OR AS UNSOLICITED MESSAGES. * !* * !******************************************************************** string (41) s oper no = (p_srce>>8)&7; !REMEMBER OPER MESSAGE CAME FROM if p_dest&127 = solicited oper message start !SOLICITED OPER MESSAGE (I.E.PROMPT UP) if charno(p_s, length(p_s)) = nl start !FULL MESSAGE? length(p_s) = length(p_s)-1;!REMOVE NEWLINE s = oper(oper no)_command.p_s; !CONCATENATE TO PARTIAL COMMAND ALREADY RECEIVED oper(oper no)_command = "" finish else start ; !NOT A FULL MESSAGE SO APPEND oper(oper no)_command = oper(oper no)_command.p_s s = "" finish finish else s = p_s if s # "" start ; !IGNORE NULL LINES select output(1) print string(dt."FROM OPER".i to s(operno)." ".s.snl) select output(0) interpret command(s, "",p_SRCE & X'FFFFFF00' ) prompt(my name.":") if oper(oper no)_prompt on = yes finish end ; !OF ROUTINE OPMESSAGE !* !* recordformat pf(integer dest, srce,string (7) user, integer p3, p4, p5, p6) routine user message(record (pf)name p) !******************************************************************** !* * !* THIS ROUTINE RECEIVES MESSAGES FROM USERS EITHER AS REQUESTS TO * !* PUT DOCUMENTS IN QUEUES OR AS QUERIES ABOUT DOCUMENTS IN QUEUES * !* * !******************************************************************** record (pe)name pp string (255) s, t byteintegerarray mess(0:311) string (7) user, REMOTE user integer len, flag, ident, dlen, bin doc bin doc = no top: ident = 0 len = 311; !MAX SIZE OF MESSAGE PREPARED TO ACCEPT if TARGET # 2900 then flag = dmessage("",len,0,0,my fsys, c addr(mess(1))) else flag = dmessage("", len, 0, my fsys, addr(mess(1))) !GIVE ME NEXT MESSAGE if flag = 0 start if len > 255 then mess(0) = 255 else mess(0) = len if mon level = 1 start select output(1) cycle dlen = 0,1,len printstring(htos(mess(dlen),2)) repeat newline select output(0) finish s = string(addr(mess(0))) if s -> t.("BINDOC:").s start bin doc = yes !This is a full binary descriptor dlen = mess(0)-length(s)+1 !ie the start of the binary document in MESS if len-dlen+1 # 256 start !the record should have been 256 bytes! printstring("Bad BIN document length!".snl) len = 0 finish s = t."BINDOC:".s finish if len > 0 start ; !CHECK THERE WAS A MESSAGE if s -> t.("**").user.(" ").s c and s -> t.(": ").s start !REMOVE INFO NOT REQUIRED length(s) = length(s)-1 while 0 < length(s) c and charno(s, length(s)) = nl !STRIP NEWLINES length(user) = 6; !REMOVE BELL CHAR FROM USERNAME select output(1) if bin doc = no then print string(dt."FROM ".user." ".s.snl) c else printstring(dt."Document FROM ".user.snl) select output(0) if user # p_user start select output(1) print string(dt. c " ABOVE MESSAGE DISCARDED POFFED MESSAGE FROM ". c p_user.snl) select output(0) -> top finish if bin doc = yes start len = 256 interpret descriptor(user call, addr(mess(dlen)), len, user, ident, flag) finish else start if s -> ns1.("COMMAND ").s and ns1="" then c user command(s, user, flag) else flag = bad params finish finish else flag = bad params; !START OF MESSAGE INVALID finish else flag = bad params; !LENGTH INVALID finish ; !BAD FLAG FROM DIRECTOR if flag # 0 start select output(1) print string(dt."USER MESSAGE REPLY TO ".p_user. c " FLAG ".i to s(flag).snl) select output(0) finish pp == p pp_dest = pp_srce pp_srce = my service number!user mess pp_p1 = flag pp_p2 = ident flag = dpon3("", pp, 0, 0, 6); !REPLY TO USER MESSAGE RECEIVED end ; !OF ROUTINE USER MESSAGE !* !* !* routine update descriptors(integer fsys) !********************************************************************** !* * !* THIS ROUTINE UPDATES THE DOC DESCRIPTORS ON THE DEFINED FSYS * !* (AT LEAST THE FSYS , >= FSYS GIVEN, THAT IS ON LINE) * !* (ALL IF FSYS=-1). THE VALUE IN QUESTION IS 'PRIORITY' WHICH IS * !* AGED CONTINUOUSLY VIA THE VALUE HELD ON THE FTRANS SYS DISC * !* BUT THE 'PERMANENT' COPY ON THE FILE SYSTEM DISC IS ONLY UPDATED * !* PERIODICALLY ON THE CALL OF THIS ROUTINE TO AVOID EXCESSIVE * !* PAGING . * !* * !********************************************************************** integer j, n, next, flag record (document descriptorf)name document record (pe)p if fsys = -1 then n = 0 else n = fsys cycle !NOW FIND OUT WHICH FSYS(>= FSYS) IS NEXT ON LINE. cycle j=n, 1, max fsys exit if f systems(j)_addr#0 !IE THE FSYSTEM IS CONNECTED AND IS HENCE ON LINE. repeat n=j+1 exit if j=max fsys and f systems(j)_addr=0 !IE THIS COULD BE THE END OF ON LINE FSYS S. select output(1) printstring(dt."UPDATING DESCRIPTORS ON FSYS ".itos(j).snl) select output(0) next=queue_head while next#0 cycle if list cells(next)_document>>24 = j then start document==record(document addr(list cells(next)_document)) document_priority=list cells(next)_priority finish next=list cells(next)_link repeat exit if fsys#-1 or n>max fsys repeat if fsys#-1 and n<=max fsys start !PON OFF MESSAGE TO DO THE NEXT FILE SYSTEM UPDATE p=0 p_dest=my service number ! descriptor update p_p1=n flag=dpon3("", p, 0, 0, 6) finish end !* integerfn get next descriptor(integer fsys) !******************************************************************** !* * !* GETS THE NEXT FREE DOCUMENT DESCRIPTOR FROM THE SPOOL FILE * !* FREE POINTER CYCLES ROUND FILE LOOKING HOPEFULLY FOR THE OLDEST * !* FREE DESCRIPTORS SO AS NOT TO OVER WRITE RECENTLY USED ONES TO * !* PRESERVE A HISTORY OF WHAT HAS GONE ON * !* * !******************************************************************** record (fhf)name file header integer doc, flag record (document descriptorf)arrayname documents record (document descriptorf)arrayformat docaf(1 : max documents) if f systems(fsys)_addr # 0 start ; !CHECK THAT A SPOOL FILE IS THERE file header == record(f systems(fsys)_addr) documents == array(f systems(fsys)_addr+file header_start, docaf) doc = file header_free hole; !FIND NEXT FREE HOLE until doc = file header_free hole cycle !STOP WHEN WE COME ROUND AGAIN if documents(doc)_state = unused start !IS DESCRIPTOR UNUSED file header_free hole = doc+1 file header_free hole = 1 c if file header_free hole > max documents !WRAP ROUND flag = sdestroy(my name,ident to s(fsys<<24!doc),"",fsys,0) result = fsys<<24!doc finish doc = doc+1 doc = 1 if doc > max documents repeat select output(1) print string(dt."NO FREE DOCUMENT DESCRIPTORS FSYS ". c i to s(fsys).snl) select output(0) finish result = 0 end ; !OF INTEGERFN GET NEXT DESCRIPTOR !* !* routine user command(string (255) s, string (6) user, integername flag) constinteger commands = 1 conststring (7) array command(1 : commands) = c "DELETE" switch com(1 : commands) integerfnspec check param(string (255) s, integername ident) integerfnspec find document(string (6) user,integer ident) string (255) param1, param2 record (linef)name FTP line record (document descriptorf)name document record (pe) p integer i, ident, fsys, allow integer ignore delete fail ! ! !* fsys = -1 flag = dfsys(user, fsys) allow = no if flag = 0 start if s -> ("*").s start if TARGET # 2900 start flag = dsfi(user,fsys,38,0, dsfis, dsfiia) i = dsfiia(1) finish else flag = dsfi(user,fsys,38,0,addr(i)) if (i>>10)&1 = 1 then allow = yes !ie allow the extended version of QUEUE for this user. finish if s -> s.(" ").param1 start param2 = "" unless param1 -> param1.(",").param2 cycle i = 1, 1, commands -> com(i) if s = command(i) repeat finish flag = command not known finish return !* !* com(1): !delete file if param2 = "" start flag = check param(param1, ident) if flag = 0 start ; !VALID DOCUMENT IDENT document == record(document addr(ident)) if document_user = user start if document_state = queued start if document_FTP alias # 0 and document_mode of access &x'8000' # 0 c then ignore delete fail = yes else ignore delete fail = no flag = find document(user, ident) if flag = 0 start ; !FIND DOCUMENT IN QUEUE remove from queue( ident, flag) if flag = 0 start delete document(ident, flag) flag = 0 if ignore delete fail = yes flag = FTRANS file create fails c if flag # 0 finish finish finish else start if document_state = transferring start cycle i=1,1,lines FTP line == FTP lines(i) if FTP line_document = ident start if FTP line_status > awaiting sft start !we have found the FTP line on which the doc is active FTP line_user abort = yes p = 0 p_dest = i<<7 FTP control(p,refresh line) if refresh line # 0 then refresh pic(ftp status summary display, c refresh line, "") flag = ok return finish else flag = not in queue and return !if it isnt active it must already be aborting !or being completed so best to reply as above. finish repeat return finish flag = not in queue finish finish else flag = invalid descriptor finish finish else flag = bad params return !* !* integerfn check param(string (255) s, integername ident) integer afsys, i if length(s) = 6 start afsys = 0 cycle i = 1, 1, 2 result = invalid descriptor c unless '0' <= charno(s, i) <= '9' afsys = afsys*10+charno(s, i)-'0' repeat result = invalid descriptor c unless 0 <= afsys <= max fsys c and f systems(afsys)_addr # 0 ident = 0 cycle i = 3, 1, 6 result = invalid descriptor c unless '0' <= charno(s, i) <= '9' ident = ident*10+charno(s, i)-'0' repeat result = invalid descriptor c unless 1 <= ident <= max documents ident = afsys<<24!ident result = 0 finish result = invalid descriptor end ; !OF INTEGERFN CHECK PARAM !* !* integerfn find document(string (6) user,integer ident) integer next, id next = queue_head; !FIND FIRST DOCUMENT IN Q while next # 0 cycle ; !SCAN DOWN QUEUE id = list cells(next)_document; !PICK UP DOCUMENT IDENTIFIER if id = ident start ; !THE ONE WE ARE LOOKING FOR? if list cells(next)_user = user c then result = 0 else result = c invalid descriptor !CHECK THE CORRECT USER finish next = list cells(next)_link repeat result = not in queue end ; !OF INTEGERFN FIND DOCUMENT end ; !OF ROUTINE USER COMMAND !* !* integerfn find document(string (15) name, id, string (6) user, integername ident) !*********************************************************************** !* * !* ATTEMPTS TO FIND THE SPECIFIED DOCUMENT. ANY OR MANY OF THE PARAMS * !* MAY NOT BE SPECIFIED. * !* * !*********************************************************************** record (document descriptor f)name document integer next next = queue_head; !FIND FIRST DOCUMENT IN Q while next # 0 cycle ; !SCAN DOWN QUEUE ident = list cells(next)_document !PICK UP DOCUMENT IDENTIFIER if user = "" or list cells(next)_user = user start result = 0 if name = "" and (id = "" or id = ident to s(ident)) if name # "" start document == record(document addr(ident)) result = 0 if name = docstring(document,document_name) c and (id = "" or id = ident to s(ident)) finish finish next = list cells(next)_link repeat result = 1 end ; !OF INTEGERFN FIND DOCUMENT !* !* integerfn check params (string (255) c param, stringname q, name, user, ident) !*********************************************************************** !* * !* * !*********************************************************************** integer i, id, afsys q = ""; name = ""; user = ""; ident = "" if param -> q.(" ").param start ; !Q THE if 1 <= length(q) <= 15 start ; !RIGHT LT if param -> user.(" ").name start result = 0 if length(user) = 6 c and 1 <= length(name) <= 15 finish finish else result = 1 finish if length(param) = 6 start afsys = 0 cycle i = 1, 1, 2 result = 1 unless '0' <= charno(param, i) <= '9' afsys = afsys*10+charno(param, i)-'0' repeat result = 1 unless 0 <= afsys <= max fsys id = 0 cycle i = 3, 1, 6 result = 1 unless '0' <= charno(param, i) <= '9' id = id*10+charno(param, i)-'0' repeat result = 1 unless 1 <= id <= max documents ident = param result = 0 finish result = 1 end ; !OF ROUTINE CHECK PARAM !* !* routine interpret command(string (255) command, string (6) user, integer console) !*********************************************************************** !* * !* FTRANS COMMAND INTERPRETATION ROUTINE. INTERPRETS MAIN FRAME * !* OPERATOR COMMANDS AND INTERACTIVE USER * !* COMMANDS. THE STRING "COMMAND" CONTAINS THE COMMAND AND THE STRING * !* SOURCE IS THE PERSON WHO SENT THE COMMAND. * !* * !*********************************************************************** constinteger command limit = 69 switch swt(1 : command limit) integer i, j, k, l, line, flag, q no, id, fe, op no integer command length, link, special integer flags, next, after record (document descriptorf)name document record (pe)p string (0) zstr string (15) q, name, ident string (10) specific user string (31) param1, param2 string (63) reply, param string (63) array words(1:15) routinespec abort line(integer line) integerfnspec find FTP line(string (255) line) conststring (15) array comm(1 : command limit) = c "FEP", "LAST", "NEXT", "SERVICE", "CLOSEFEP", "OPENFEP", ""(6), "", "START", "STOP", "", "", "ABORT", ""(3), "TIDY", "PRINT", "MON", "PROMPT", "CONFIG", "", "FEPUP", "FEPDOWN", "LINE", ""(3), "", "Q", "", "", "DISPLAY", ""(4), "", "PRIORITY", "", "SETAUTOPOLL", "RUSH", "HOLD", "RELEASE", "DELETE", ""(4), ""(3), "CONNECTFE", "", "FTDELAY", "OPENFT","CLOSEFT","FT","FTLINES","FTLIMIT","", "DUMP","PSS","IPSS" !The following array of words are param checking flags used as follows: ! x00nnnnnn no checking to be done ! x01nnnnnn do checks ! xnnnnllnn minimum number of params ! xnnnnnnll maximum number of params (FF implies any number) constintegerarray comm flags(1 : command limit) = c x'00000000', x'01000000', x'01000000', x'00000000', x'01000202', x'01000202', x'01000101', x'01000101', x'01000101', x'01000303', x'01000000', x'01000101', x'01000101', x'01000101', x'01000001', x'01000303', x'01000303', x'01010101', x'01000102', x'01000202', x'01000101', x'01000101', x'01000001', x'01000101', x'01000101', x'01000002', x'01000101', x'01000101', x'01000101', x'01110101', x'01110101', x'01110001', x'01110001', x'01110002', x'01110002', x'01110001', x'01110001', x'01110102', x'01110000', x'01110001', x'01110001', x'01110101', x'01110101', x'01010202', x'01010202', x'01010101', x'01010101', x'01010101', x'01010101', x'01010102', x'01010304', x'01010303', x'01010101', x'01010101', x'010101FF', x'01100102', x'01100001', x'01000101', x'011100FF', x'01000102', x'01000001', x'01000001', x'01110002', x'01000102', x'01000102', x'01000102', x'01000101', x'01000101', x'01000101' integerfn get scr ( integer wd ) integer i i = stoi ( words ( wd )) if 0 <= i < screens per oper then param = "" else param = "SCREEN NO" result = i end { of get scr } integerfn get picture ( integer picture type, id1, string (15) id2 ) ! Returns no of file to create picture in. Returns file already in use if id's match, otherwise an empty file. Returns ! oldest file if none found. integer pic, free, lowest tick record (picturef) name picture free = 0 lowest tick = picture tick + 1 { higher than any in the picture records } cycle pic = 1, 1, max pic files picture == pictures(pic) exit if picture_base = 0 { not connected } if picture_picture type = picture type and picture_id1 = id1 and picture_id2 = id2 then free = pic if free = 0 and picture_screens=0=picture_count then free = pic { free file } repeat if free = 0 start cycle pic = 1, 1, max pic files if pictures(pic)_tick < lowest tick and picture_base # 0 then lowest tick = pictures(pic)_tick and free = pic repeat finish result = free end ; ! get picture ! ! routine requeue !*********************************************************************** !* * !* * !*********************************************************************** add to queue( id, 0,no,no,flag) if flag # 0 start print string("ADD ".ident to s(id)." TO QUEUE ". c " FAILS ".i to s(flag).snl) delete document(id, flag) print string("DELETE DOCUMENT ".ident to s(id). c " FAILS ".i to s(flag).snl) if flag # 0 finish end ; !OF ROUTINE REQUEUE integerfn get document(string (31) param) !*********************************************************************** !* * !* * !*********************************************************************** result = 1 if check params(param, q, name, user, ident) # 0 result = 1 if find document(name, ident, user, id) # 0 remove from queue( id, flag) if flag = 0 then document == record(document addr(id) c ) else print string("REMOVE ".ident to s(id). c " FROM QUEUE FAILS ".i to s( c flag).snl) result = flag end ; !OF INTEGERFN GET DOCUMENT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !GENERAL ROUTINES FOR THE COMMAND SET INTERPRETATION. integerfn resolve command integer elements; string (127) word ! elements = 0 cycle command -> (" ").command while length(command)>0 and charno(command,1)=' ' exit if command = "" elements = elements + 1 exit if elements = 16 if command -> word.(" ").command then start if length(word)>63 then length(word)=63 words(elements) = word continue finish length(command) = 63 if length(command) > 63 words(elements) = command exit repeat result = elements ! end !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !DO THE INITIAL CHECKS AGAINST THE ATRIBUTES WORD op no = oper no reply = "" command length = resolve command return if command length = 0 link = 0 cycle i = 1, 1, command limit if words(1) = comm(i) then link = i and exit repeat if link = 0 start reply = "INVALID COMMAND ".words(1) -> error finish flags = comm flags(link) -> swt(link) if flags >> 24 = 0 !IE DO NOT DO INITIAL CHECKS. unless (flags<<16)>>24 <= (command length - 1) <= flags&x'FF' start reply = "NUMBER OF PARAMS ?" -> error finish -> swt(link) !!!!!!!!!!!!!!!!FTP CONTROL FUNCTIONS!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !********************************************************** !Open up the system in one go. ! swt(4): status header change = yes cycle i = 2,1,FTP stns FTP stations(i)_service = open repeat FTP stations(control entry)_max lines = 25 FTP stations(control entry)_q lines = 12 FTP stations(control entry)_service = open FTP stations(control entry)_limit = 1000 cycle i = 1,1,lines kick(i) = kick(i)&1 kick FTP line(i) repeat return ! !************************************************************ !Open or close FTP service generally or to specific stations. ! swt(61): swt(62): status header change = yes if link = 61 then j = open else j = closed if command length = 1 start !a general open or close on FTP stations(control entry)_service FTP stations(control entry)_service = j if j = open then -> kick FTP lines else return finish if words(2) = ".ALL" start !set service latch to all stations. !Note then general service switch must be on before transactions start. cycle i = 2,1,FTP stns FTP stations(i)_service = j repeat if FTP stations(control entry)_service = open then -> kick FTP lines else return finish else start !we want to mark a specific station service status. cycle i = 1,1,FTP stns if string at(FTP stations(i),FTP stations(i)_shortest name) = words(2) start FTP stations(i)_service = j if FTP stations(control entry)_service = open then -> kick FTP lines else return finish repeat param = "Station" and -> parameter finish !************************************************************* !Give a general picture of the FTP situation. swt(63): status header change = yes if command length = 1 or ( command length = 2 and words ( 2 ) -> zstr.("#").words ( 2 ) ) start if command length = 2 start i = get scr ( 2 ) -> parameter unless param = "" finish else i = 0 p = 0 p_p2=get picture(FTP status summary display,0,"" ) p_p3 = i p_p4=console picture manager ( p,FTP status summary display,0,"" ) finish else start if command length = 3 start param = "SCREEN NO" and -> parameter unless words ( 3 ) -> zstr.("#").words ( 3 ) i = get scr ( 3 ) -> parameter unless param = "" finish else i = 0 j = stoi(words(2)) param = "line" and -> parameter unless 1 <= j <= lines p=0 p_p2=get picture(FTP line status display,j,"" ) p_p3 = i p_p4=console picture manager ( p,FTP line status display,j,"" ) finish return return !******************************************************** !Adjust the transaction go ahead for general or specifics swt(64): status header change = yes if command length = 3 start if length(words(2)) <= 2 then i = s to i(words(2)) else i = lines + 1 if 0<=i<=lines start !we are setting the overall total P and Q station transaction control. j = s to i(words(3)) if 0<=j<=lines start FTP stations(control entry)_max lines = i FTP stations(control entry)_q lines = j; !the minimum no. of listeners. if FTP stations(control entry)_service = open then -> kick FTP lines else return finish else param = " number of 'slaves'" and -> parameter finish else start !else we are setting controls for individual station. cycle i = 1,1,FTP stns if string at(FTP stations(i),FTP stations(i)_shortest name) = words(2) start j = s to i(words(3)) if 0<=j<=lines start FTP stations(i)_max lines = j if FTP stations(control entry)_service = open and FTP stations(i)_service = open then c -> kick FTP lines else return finish param = "number of lines" and -> parameter finish repeat param = "station" and -> parameter finish finish else start !we are just setting the general controls via max lines and !letting listeners(Q stations) default. i = s to i(words(2)) unless 0<=i<=lines then param = "number of lines" and return FTP stations(control entry)_max lines = i if i = 1 then FTP stations(control entry)_q lines = 0 else FTP stations(control entry)_q lines = i//2 if FTP stations(control entry)_service = open then -> kick FTP lines else return finish !******************************************************** !Set the transaction size limit generally or specifically swt(65): status header change = yes if command length = 2 start i = s to i(words(2)) param = "limit" and -> parameter unless 0<=i<=10000 FTP stations(control entry)_limit = i if FTP stations(control entry)_service = open then -> kick FTP lines else return finish else start cycle j = 1,1,FTP stns if string at(FTP stations(j),FTP stations(j)_shortest name) = words(2) start i = s to i(words(3)) param = "limit" and -> parameter unless 0<=i<=10000 FTP stations(j)_limit = i if FTP stations(j)_service = open and FTP stations(control entry)_service = open c then -> kick FTP lines else return finish repeat param = "station" and -> parameter finish kick FTP lines: cycle i = 1,1,lines kick FTP line(i) repeat return !*************************************************************** !Enquiry or set the connect fail retry delay array pointer. swt(60): cycle j = 1,1,FTP stns if string at(FTP stations(j),FTP stations(j)_shortest name) = words(2) start if command length = 2 start printstring(words(2)." delay is ".i to s(connect retry times( c FTP stations(j)_connect retry ptr))." m".snl) printstring(words(2)." connect in ".itos(FTP stations(j)_ c connect retry time)." m".snl) return finish i = s to i(words(3)) param = "pointer" and -> parameter unless 0<=i<=10 FTP stations(j)_connect retry ptr = i set document timers(j,connect retry times(i),0) return finish repeat param = "station" and -> parameter return !*********************************************************** !Look at the available FEPs swt(1): cycle i = 0,1,max fep if feps(i)_FTP available = yes start printstring(itos(i)." ".comms type(feps(i)_comms type)) if feps(i)_outgoing calls permitted = yes then printstring(" <out>") if feps(i)_incomming calls accepted = yes then printstring(" <in>") newline finish repeat return !************************************** !STOP FTRANS OR STOP SPECIFIED LINES. swt(15): if command length = 1 or words(2) = ".ALL" start if lines = 0 then stop cycle line = 1, 1, lines kick(line) = kick(line)!2; !SET STOP BIT abort line(line) if FTP lines(line)_status >= allocated repeat stopping = yes if command length = 1 update descriptors(-1); !IE UPDATE DOCUMENT DESCRIPTORS ON ALL THE FSYS finish else start line = find FTP line(words(2)) -> error if line = 0 or FTP lines(line)_status < allocated abort line(line) kick(line) = kick(line)!2; !SET STOP BIT finish return !************************************************ !DUMP the system buffers. swt(67): if command length = 2 and words(2) -> ("FE").words(2) start !DUMP the FEP control buffers. fe = s to i(words(2)) unless 0 <= fe <= max fep then param = "FEP" and -> parameter j = feps(fe)_ftp out buff con addr k = feps(fe)_ftp output cursor l = feps(fe)_ftp out buff length select output(1) cycle i = j,1,j+l-1 if i-j = k then printstring(" ** ") printstring(htos(byteinteger(i),2)) repeat printstring(snl."OUTPUT CONTROL CURSOR : ".itos(k).snl.snl) j = feps(fe)_ftp in buff con addr k = feps(fe)_ftp input cursor l = feps(fe)_ftp in buff length cycle i = j,1,j+l-1 if i-j = k then printstring(" ** ") printstring(htos(byteinteger(i),2)) repeat printstring(snl."INPUT CONTROL CURSOR : ".itos(k).snl) select output(0) printstring("Done".snl) finish return !******************************************** !SET THE FTRANS MONITOR LEVEL. swt(24): i = s to i(words(2)) param = "LEVEL" and -> parameter unless 0<=i<=9 monlevel = i return !****************************************** !SWITCH THE PROMPT ON OR OFF swt(25): reply = "ON OR OFF" and -> error unless words(2) = "ON" c or words(2) = "OFF" if words(2) = "ON" then oper(op no)_prompt on = yes c else oper(op no)_prompt on = no return !******************************************************* !PRINT THE FTRANS LOG TO SPOOLR swt(23): print log (1,lp) return !CODE FROM VOLUMS HERE !***************************** !DISPLAY A SPECIFIED DOCUMENT. swt(38): if command length = 3 start param = "SCREEN NO" and -> parameter unless words ( 3 ) -> zstr.("#").words ( 3 ) K = get scr ( 3 ) -> parameter unless param = "" finish else k = 0 param = "DOCUMENT" if length(words(2)) = 6 start cycle i = 1, 1, 6 -> parameter unless '0' <= charno(words(2), i) <= '9' repeat i = (charno(words(2), 1)-'0')*10+charno(words(2), 2)-'0' j = (charno(words(2), 3)-'0')*1000+(charno(words(2), 4)-'0')*100 c +(charno(words(2), 5)-'0')*10+charno(words(2), 6)-'0' -> parameter unless f systems(i)_addr # 0 c and 1 <= j <= max documents p = 0 p_p2 = get picture ( individual document display, i << 24 ! j, "" ) p_p3 = K p_p4 = console picture manager ( p, individual document display, i << 24 ! j, "" ) return finish else -> parameter !****************************************************************** !SETAUTOPOLL Set this document to be a AUTO requeue document for !the return of output from remote jobmills. Submit a document with !the command TRANSFER site(,),,job when FT service is closed and !then give this command on the document before opening service. !The document then will exist 'forever' swt(46): param = "DOCUMENT" -> parameter if get document(words(2)) # 0 document_auto requeue = yes requeue return !********************************************************** !RUSH: PUT A JOB AT MAX PRIORITY WITHIN ITS OWN PRIORITY swt(47): param = "DOCUMENT" -> parameter if get document(words(2)) # 0 document_priority = prtys(n priorities)+max priority document_priority = - document_priority requeue return !*********************** !RELEASE A HELD DOCUMENT swt(49): param = "DOCUMENT" -> parameter if get document(words(2)) # 0 document_priority = -document_priority c if document_priority < 0 requeue return !**************** !HOLD A DOCUMENT. swt(48): param = "DOCUMENT" -> parameter if get document(words(2)) # 0 document_priority = -document_priority c if document_priority > 0 requeue return !************************************************* !DELETE A DOCUMENT OR THE DOCUMENTS INDICATED BY !SUBSEQUENT PARAMETERS. swt(50): specific user = ""; q no = 0 if words(2) -> words(2).(".ALL") start !IE DELETE ALL A USER'S DOCS IN THE QUEUE. specific user = words(2) param = "USER" and -> parameter if length(specific user) # 6 finish else start !DELETE A SINGLE DOCUMENT. param = "DOCUMENT" and -> parameter if get document(words(2)) # 0 delete document(id, flag) printstring("DELETE ".ident to s(id)." FAILS ".i to s c (flag).snl) if flag # 0 return finish !COMPLETE THE MULTIPLE DELETE. next = queue_head while next # 0 cycle after = list cells(next)_link if specific user = "" or list cells(next)_user = specific user start j = list cells(next)_document remove from queue( j, flag) delete document(j, flag) if flag # 0 start printstring("DELETE ".ident to s(j)." FAILS ".i to s c (flag).snl) return unless mon level = 9 finish finish next = after repeat return !************************************************* !CHANGE THE PRIORITY OF A DOCUMENT swt(44): i = 0 cycle j = 1, 1, n priorities if words(3) = priorities(j) start i = j exit finish repeat param = "PRIORITY" and -> parameter if i = 0 if get document(words(2)) # 0 then param = "DOCUMENT" and c -> parameter cycle k = n priorities, -1, 1 if imod(document_priority) >= prtys(k) start j = imod(document_priority)-prtys(k) if document_priority > 0 then k = 0 else k = 1 exit finish repeat document_priority = prtys(i)+j document_priority = -document_priority if k # 0 requeue return !****************************************************** !ABORT ONE OR ALL LINES. swt(18): if words(2) = ".ALL" start cycle line = 1, 1, lines abort line(line) if FTP lines(line)_status >= allocated repeat finish else start line = find FTP line("FT".words(2)) param = "LINE" and -> parameter if line = 0 reply = "NOT REQUIRED" and -> error if FTP lines(line)_status < allocated abort line(line) finish return !********************************************************* !START A LINE (IE REMOVE STOP AND KICK) , OR ALL LINES. swt(14): if words(2) = ".ALL" start ; !START ALL LINES cycle line = 1, 1, lines kick(line) = kick(line)&1; !REMOVE STOP BIT kick FTP line(line) repeat finish else start line = find FTP line("FT".words(2)) param = "LINE" and -> parameter if line = 0 kick(line) = kick(line)&1 kick FTP line(line) finish return !******************************************************** !DISPLAY DETAILED PAGE OF QUEUE OR SIMPLE PAGE OF QUEUE swt(35): specific user = "" ; i = 0 if command length > 1 start if command length = 3 start param = "USER" and -> parameter unless length(words(2)) = 6 specific user = words ( 2 ) param = "SCREEN NO" and -> parameter unless words ( 3 ) -> zstr.("#").words ( 3 ) i = get scr ( 3 ) -> parameter unless param = "" finish else start if words ( 2 ) -> zstr.("#").words ( 2 ) start i = get scr ( 2 ) -> parameter unless param = "" finish else start param = "USER" and -> parameter unless length ( words ( 2 )) = 6 specific user = words ( 2 ) finish finish finish p = 0 p_p2 = get picture ( individual queue display, 0, specific user ) p_p3 = i p_p4 = console picture manager ( p, individual queue display, 0, specific user ) return !*************************************************** !SET THE FTRANS CONFIGURATION FILE (SPECIFIED FSYS) swt(26): j = s to i(words(2)) param = "FSYS" and -> parameter unless 0<=j<=max fsys if command length = 3 start reply = "<USER>.<FILENAME> ?" and -> error unless c words(3)->param1.(".").param2 and length(param1)=6 c and 1<=length(param2)<=11 if TARGET # 2900 start dsfis = words(3) i = dsfi(my name, j, 2, 1, dsfis, dsfiia) finish else i = dsfi(my name, j, 2, 1, addr(words(3))) print string("SET SFI 2 FAILS ".errs(i).snl) if i # 0 finish else start if TARGET # 2900 start i = dsfi(my name, j, 2, 0, dsfis, dsfiia) param = dsfis finish else i = dsfi(my name, j, 2, 0, addr(param)) if i = 0 then print string("CONFIG ".param.snl) c else print string("READ SFI 2 FAILS ".errs(i).snl) finish return !*************************************************** !SET the PSS and IPSS info. swt(68): swt(69): if link = 68 then PSS = words(2) else IPSS = words(2) return !************************************************* !DELETE ANY EXTRA FILES HANGING AROUND AS SPECIFIED swt(22): if words(2) = "SAFE" then special = yes and words(2) = ".ALL" c else special = no if words(2) # ".ALL" start i = s to i(words(2)) param = "FSYS" and -> parameter unless 0 <= i <= max fsys any extra files(i,no) finish else start cycle i = 0, 1, max fsys if f systems(i)_addr # 0 then any extra files(i,special) repeat finish return !******************************************* !MANUAL REPORT OF A LOST FEP(NORMALLY AUTOMATIC) swt(29): if length(words(2)) = 1 start i = charno(words(2), 1)-'0' if 0<=i<=max fep and feps(i)_FTP available = yes then fep down(i) return finish param = "FEP" -> parameter ! !********************************************************* !Permit or Withdraw INCOMMING or OUTGOING call access thro a particular FEP swt(5): swt(6): if length(words(2)) = 1 start i = charno(words(2), 1)-'0' if 0 <= i <= max fep and FEPs(i)_FTP available = yes start if words(3) = "IN" start if link = 5 then FEPs(i)_incomming calls accepted = no else c FEPs(i)_incomming calls accepted = yes return finish else if words(3) = "OUT" start if link = 5 then FEPs(i)_outgoing calls permitted = no else c FEPs(i)_outgoing calls permitted = yes return finish else reply = "F/CLOSE(OPEN)FEP IN(OUT) n" and -> error finish else param = "FEP" and -> parameter finish else param = "FEP" and -> parameter !************************************************ !CONNECT AN FEP (THAT HAS BEEN RELOADED ?) swt(58): swt(28): if link = 58 then printstring( c "CONNECTFE kick".snl) if length(words(2)) = 1 start i = charno(words(2), 1)-'0' if 0 <= i <= max fep and feps(i)_FTP available = no start p = 0 p_dest = i<<8!FTP input control connect open fep(p) return finish finish param = "FEP" -> parameter parameter: reply = "INVALID ".param error: printstring(reply.snl) return !* routine abort line(integer line) !*********************************************************************** !* * !* ABORT THE SPECIFIED STREAM BY CALLING THE APPROPRIATE SERVICE * !* ROUTINE * !* * !*********************************************************************** record (pe)p p = 0 p_dest = line<<7 FTP control(p,refresh line) if refresh line # 0 then refresh pic(ftp status summary display, refresh line,"") return end ; !OF ROUTINE ABORT line !* !* integerfn find FTP line(string (255) line) !*********************************************************************** !* * !* RETURNS THE INDEX INTO THE LINE ARRAY OF THE SPECIFIED LINE * !* RETURNS ZERO IF THE STREAM IN NOT FOUND * !* * !*********************************************************************** integer i cycle i = 1, 1, lines result = i if FTP lines(i)_name = line repeat reply = "NO SUCH LINE ".line result = 0 end ; !OF INTEGERFN FIND STREAM !* !* end ; !OF ROUTINE INTERPRET COMMAND !* routine move with overlap(integer length, from, to) ! Simple minded move, as opposed to %systemroutine move if TARGET = 2900 start *ldtb_x'18000000' *ldb_length *lda_from *cyd_0 *lda_to *mv_l =dr finish else move(length,from,to) end ; ! move with overlap ! ! ! ! integerfn generate pic(integer pic,picture type,id1 ,refresh, string (15) id2) integer linead, i, j, full, pic start, line, next string (3) p string (41)sline integername used switch picsw(1:max pic types) record (picturef)name picture if TARGET = 2900 start constbyteintegerarray blankline(1:41) = 32(40), x'85' finish else start constbyteintegerarray blankline (1:40) = 32(40) finish conststring (1)dot = "." conststring (1)sp = " " record (linef)name FTP line record (FTP tablef) name FTP table record (document descriptorf) name document ! ! stringfn padout ( string (255) s, byteinteger len, side ) ! pads s out to len characters with spaces,on left if side = 0, on right otherwise if length(s) > len then length(s) = len and result = s if side = 0 start s = " ".s while length(s) < len else s=s." " while length(s) < len finish result = s end ; ! padout ! routine put line sline = sline . " " while length(sline) < 40 move with overlap(length(sline),addr(sline)+1,linead) linead=linead+line len line=line+1 if line>max pic lines then full=1 end { of put line } routine build line ( integer i ) { for FTP summary } string (19) s FTP line == FTP lines(i) line addresses ( i ) = linead s = stream status type(FTP line_status) if FTP line_status = unallocated or FTP line_station type = P station then s = " ".s else s = "*".s sline = padout(itos(i),2,1).padout(s,18,1) unless FTP line_status = disconnecting or FTP line_status = deallocating c or FTP line_status = unallocated start if FTP line_station type =p station start if FTP line_document = 0 then sline = sline." " else sline=sline.FTP line_user finish else sline=sline.FTP tables(i)_username_value sline=padout(sline,28,1).padout(itos((FTP line_bytes transferred+1023)>>10),4,0)." " sline=sline.padout(string at(FTP stations(FTP line_station ptr),FTP stations c (FTP line_station ptr)_shortest name),7,1) if FTP line_station ptr # 0 finish put line end { of build line } ! if mon level = 6 then c PRINTSTRING("GenPic P".itos(pic)." TYPE".itos(picture type)." ID1".itos(id1)." ID2".id2.snl) picture == pictures(pic) picture_tick = picture tick pic start = picture_base+32 used==integer(picture_base+24) if refresh = no start picture_picture type = picture type picture_id1 = id1 picture_id2 = id2 move with overlap(line len,addr(blankline(1)),pic start); ! first blank line move with overlap(used-line len,pic start,pic start+line len) finish ! right overlap does rest of area line=1 linead = pic start full=0 ->picsw(picTURE TYPE) ! ! ! ! picsw(FTP status summary display): ! If id1 = 0, do whole summary, otherwise only update FT line 'id1' if TARGET # 2900 then sline = "EMAS 370 File Transfer Service ".time C ELSE sline = "EMAS 2900 File Transfer Service ".time put line if status header change = yes start if FTP stations (control ENTRY)_service = closed then sline = "CLOSED" else sline = "OPEN " sline = sline." ".padout(itos(FTP stations(control entry)_limit),5,0)."Kb ". c padout(itos(FTP stations(control entry)_max lines),3,0). c " Lines, ".padout(itos(FTP stations(control entry)_q lines),3,0). c " Listening" put line status header change = no finish if id1 # 0 start if line addresses ( id1 ) = 0 start { line is not yet displayed } linead = pic start + used line = used // line len + 1 if line > max pic lines then full = 1 if full = 0 then build line ( id1 ) else full = 2 finish else start linead = line addresses ( id1 ) line = ( linead - pic start ) // line len + 1 build line ( id1 ) { no need to check for overflow - this line has been written before } linead = pic start + used line = used // line len + 1 { frig for finish } finish finish else start { do whole summary } sline="No STATUS USER nKB STATION" put line cycle i=1,1,lines line addresses ( i ) = 0 if full = 0 then build line ( i ) else full = 2 repeat finish -> finish picsw(FTP line status display): FTP line == FTP lines(id1) FTP table == FTP tables(id1) sline = "File Transfer Details, line ".padout(itos(id1),2,0)." ".time put line sline = "Current Status: ".stream status type(FTP line_status) put line -> finish if FTP line_status = unallocated if FTP line_status = selected or FTP line_station type = p station c then sline = "Acting as MASTER with " else sline = "Acting as SLAVE with " if FTP line_station ptr > 0 then sline=sline.string at(FTP stations c (FTP line_station ptr),FTP stations(FTP line_station ptr)_shortest name) c else sline = sline."?" put line sline="" put line unless allocated <= FTP line_status < awaiting sft start sline = "Transfer details for ".ident to s (FTP line_document) put line sline = "Local user: " if FTP line_station type = p station start if FTP line_document = 0 then sline = sline." " else c document == record(document addr(FTP line_document))and sline=sline.document_user finish else sline = sline.FTP table_username_value put line sline = "Remote user: " if FTP line_station type = p station then sline =sline.docstring(document, document_external user ) c else sline = sline."?" put line sline="Local file name: " if FTP line_station type = p station then sline=sline.docstring(document,document_name) c else sline=sline.FTP table_filename_value put line sline = "Remote file name: " if FTP line_station type = p station then sline = sline.docstring(document,document_external name) c else sline = sline."?" put line if FTP line_station type = p station start sline = "Retries left: ".itos(document_FTP retry level) put line finish finish sline="Time out in ".itos(FTP line_timer)." mins." put line -> finish picsw(individual queue display): ! id1 irrelevant, id2 is specific user if one is specified ( excuse the English ) sline = "File Transfer Queue ".queue_name if queue_length = queue_max length then sline = sline." Full" if queue_length = 0 then sline = sline." Empty" sline = padout ( sline, 32, 1 ).time put line if queue_length = 0 then sline = " No" else sline = itoss ( queue_length, 3 ) sline = sline." Entries".itoss ( queue_max length, 4 )." Max".itoss ( queue_maxacr, 3 )." MaxACR" if queue_length > 0 start if queue_default time > 0 then sline = sline.padout ( hms ( queue_amount ), 11, 0 ) c else sline = sline. itoss (( queue_amount + 1023 ) >> 10 , 10 )."K" finish put line if queue_head # 0 start { any documents queued } sline = "POS IDENT USER NAME PRTY " if queue_default time <= 0 then sline = sline."SIZE" else sline = sline."TIME" put line i = 1 next = queue_head while next # 0 cycle if full = 0 start if id2 = "" or list cells ( next )_user = id2 start document == record ( document addr ( list cells ( next )_document )) unless document_start after date and time # 0 and document_start after date and time c > current packed dt then start sline = itoss ( i, 3 )." ".ident to s ( list cells ( next )_document )." ". c document_user." ".doc string ( document, document_name ) length ( sline ) = 29 if length ( sline ) > 29 sline = padout ( sline, 30, 1 ) if document_priority < 0 then sline=sline."HLD" else start p = "" cycle j = n priorities, -1, 1 if document_priority >= prtys ( j ) start p <- priorities ( j ) exit finish repeat sline = sline.p finish if document_forms # queue_default forms then sline = sline."F" else start if document_start after date and time # 0 and document_start after date and time c > current packed dt then sline = sline."A" else start if document_order # 0 then sline = sline."0" else sline = sline." " finish finish if document_time > 0 then sline = sline.itoss ( document_time, 5 )."S" c else sline = sline.itoss (( document_data length + 1023 ) >> 10, 5 )."K" put line finish finish i = i + 1 next = list cells ( next )_link finish else full = 2 repeat finish -> finish picsw(individual document display): ! id1 is ident, id2 irrelevant sline = padout ( "IDENT: ".ident to s ( id1 ), 32, 1 ).time put line document == record ( document addr ( id1 )) sline = "STATE: ".doc state ( document_state ) put line sline = "ORIGIN: " if doc string ( document, document_srce ) = "" then sline = sline."USER" else c sline = sline.doc string ( document, document_srce ) put line sline = "USER: ".document_user put line sline = "NAME: ".doc string ( document, document_name ) put line sline = "QUEUE: ".document_dest put line sline = "DELIVERY: ".doc string ( document, document_delivery ) put line sline = "RECEIVED: ".unpack date ( document_date and time received )." ".C unpack time ( document_date and time received ) put line if document_start after date and time # 0 start sline = "AFTER: ".unpack date ( document_start after date and time )." ".unpack time ( document_start after date and time ) put line finish if document_date and time started # 0 start sline = "STARTED: ".unpack date ( document_date and time started ). " ".unpack time ( document_date and time started ) put line finish if document_date and time deleted # 0 start sline = "DELETED: ".unpack date ( document_date and time deleted )." ".unpack time ( document_date and time deleted ) put line finish sline = "SIZE: ".padout ( itos ( document_data length ), 10, 1 ) sline = sline."START: ".itos ( document_data start ) if document_data start # 0 put line if document_priority < 0 then sline = "PRIORITY: Held" else start cycle i = n priorities, -1, 1 if document_priority >= prtys ( i ) then sline = "PRIORITY: ".priorities ( i ) and exit repeat finish put line if document_FTP alias # 0 start sline <- "NIFTP-80(B) transfer for ".docstring ( document, document_FTP alias ) put line finish sline = "MODE: ".modes ( document_mode ) put line if document_rerun = no then sline = "RERUN: No" else sline = "RERUN: Yes" if document_fails # 0 start sline = padout ( sline, 14, 1 )."FAIL ".itos ( document_fails ) finish if document_order # 0 start sline = padout ( sline, 20, 1 )."ORDER: ".itos ( document_order ) finish put line ! ! ! finish: if full=2 start ; ! pic o'flow line=line-2 linead=linead-(2*line len); ! back off two lines sline="*********** picture overflow ***********" put line finish used=(line-1)*line len; ! used length result =ok end ; ! generate pic ! ! ! routine picture manager(record (pe)name p,integer picture type,id1,string (15) id2) !*********************************************************************** !* called to create a picture: * !* p_srce=0,p_p1=0,p_p2=pic file,p_p3=screen on oper,p_p4=operno * !* called to refresh a picture: * !* p_srce=0,p_p1=1,p_p2=pic file * !* called to service external picture messages: * !* p_srce#0 * !* * !* * !* the basic sequence to display a picture is: * !* 1. connect request to cc. reply comes to caller. * !* 2. enable request to cc. reply comes to caller. * !* 3. display request to oper routed thru' cc. if successful, * !* oper's reply 'done' is routed back thru' cc to owner. if * !* unsuccessful (because oper has disconnected in the meantime) * !* reply comes from cc to caller. * !* * !* while a picture is on screen, we can receive asynchronous messages * !* direct from oper to owner, either to effect a frame change (when * !* operator has done pg f/b), or to notify that the picture is now * !* off screen and need no longer be refreshed. * !* * !* the top of screen line confirmed by oper 'done' is not required * !* to do frame changes since oper itself does the new line * !* calculation and tells us in frame change request. we do need it * !* to do display request on a refresh. it is thus recorded here at * !* the time the display request goes out rather than when the 'done' * !* is received from oper, which latter is thus redundant and can be * !* discarded. * !* * !* if display requests are issued here while an 'off-screen' is * !* waiting for us (ie oper has disconnected), these will generate * !* failures from cc on caller sno. it is impossible for us to see * !* these until after we have seen and actioned the 'off-screen' from * !* oper, so these cc failures too can be discarded. * !* * !* ie both types of messages poffed from cc (other than connect and * !* enable replies which are done on sync2) can be discarded. only * !* those poffed from oper direct (ie frame change and offscreen) need * !* to be actioned. * !* * !* if the caller is an interactive process, we do not do auto refresh * !* which could be dangerous if the process died. we simply generat:e it * !* once if need be and point the process at the picture file. * !* * !*********************************************************************** record (screenf)name screen integer pic,scr,operscreen,act,j,bits,oper n record (picturef)name picture switch sw(0 : 7) ! ! ! integerfn process no(integer srce) srce = srce >> 16 result = srce - com_sync2dest if srce > com_sync2dest result = srce - com_sync1dest end ! ! ! routine opout(string (255)s) printstring(s . " ") end ! ! ! integerfn screeno(integer stream) ! returns the screen number connected on stream integer i for i=0,1,max screen cycle result =i if screens(i)_stream=stream repeat result =-1; ! not found end ; ! screeno ! ! ! routine off screen(integer screen) ! clears down screen and pic descs, when no longer on screen record (picturef)name picture picture == pictures(screens(screen)_picture) picture_screens = picture_screens & (¬(1<<screen)); ! knock out bit for this screen screens(screen)=0 end ; ! off screen ! ! ! routine display request(integer stream,line) pictures(pic)_tick = picture tick p=0 p_dest=x'370006' p_srce=picture act; ! caller=owner p_p1=stream p_p6=line if mon level = 6 start PRINTSTRING("DisReq P:");pt rec(p);NEWLINE finish dpon(p) end ; ! display request ! ! ! if mon level = 6 start printstring("PM called : PTYPE ".itos(picture type)." ID1".itos(id1)." id2 ".id2.snl) ptrec(p) finish picture tick = picture tick + 1 ! start by computing an 'act' to simplify subsequent code act = 0 pic = p_p1 { in which case this is where pic no is } j = p_srce >> 16 if j = 0 start { internal call to create or refresh } p_p4=oper dest {! (autooper<<8)} if process no(p_p4)=1 { frig calls from autofile } pic=p_p2 act = p_p1 act = 2 if act = 0 {create} and p_p4 & x'00ff0000' = oper dest finish else start act = 3 {off screen from private process} act = 4 if j = x'37' { from comms controller } if j = x'32' start { from oper adaptor } act = 5 { not recognised } act = 6 if p_p6 >> 24 = 255 { off screen } act = 7 if p_p6 >> 24 = 0 { frame change } finish finish if act < 4 start { pic relevant so validate it } j = 0 if 1 <= pic <= max pic files start picture == pictures(pic) j = picture_base finish opout("Picture" . itos(pic) . " off") and return if j = 0 if act = 0 or act = 2 start { a create } if picture_screens=0=picture_count start { not currently in use } return unless generate pic(pic,picture type,id1,no, id2)=ok finish finish finish if mon level = 6 then PRINTSTRING("PicMan : sw ".itos(act).snl) -> sw(act) sw(0): { create from an interactive process } p_dest=p_p4!6 p_srce=picture act p_p1 = pic; ! local pic number p_p2=uinf_fsys; ! which fsys the picture files are on ! screen in p3 string(addr(p_p4))="PICTURE".itos(pic); ! the file name if mon level = 6 start PRINTSTRING("PicMan sw0 dpon : ");ptrec(p) finish dpon(p) picture_count=picture_count+1 return sw(1): { refresh } ! 'refresh pic' checks that there is at least one screen involved ! before coming here. there may be several as given by bits ! in picture_screens or in picture_count return unless generate pic(pic,picture type,id1,yes, id2)=ok ! thats all we do for private pics. it would be dangerous to fire pons ! at a process in case it dies. we let it rewrite on clock bits = picture_screens; ! get the bits for scr=0,1,max screen cycle if bits&1#0 start ; ! its on this screen screen==screens(scr) display request(screen_stream,screen_top) finish bits=bits>>1 repeat return sw(2): { create from real oper } oper n=(p_p4>>8)&x'FF'; ! which one operscreen=(p_p3<<4) ! oper n; ! device address for connect scr=oper n*screens per oper+p_p3; ! logical screen unless 0 <= oper n < screens per oper and 0<=scr<=max screen start opout("Screen out of bounds !!!!!!!") return finish ! first check if that pic is already on that screen return if screens(scr)_picture=pic ! p=0 { connect stream } p_dest=x'370001'; ! cc p_p1=1; ! output p_p2=uinf_sync1dest ! picture act; ! owner sno p_p3=x'8000000'!(operscreen<<16) if mon level = 6 then PRINTSTRING("PM CONNECT REQ".SNL) dout(p); ! and wait for reply if p_p2#0 start opout("Connect to screen fails.") return ; ! we haveny changed any descs yet finish ! so now oper has owner sno. ! ! now check if we already have another picture on this screen. ! we are about to reset the descs to the new pic, so we must ! clear down the old picture now. by the time we see the 'offscreen' ! it will have a stream we no longer have recorded and we will ! not be able to reset the picture desc. the unrecognised ! 'offscreen' will be discarded. off screen(scr) if screens(scr)_picture#0 ! now set up descs picture_screens=picture_screens!(1<<scr) screen==screens(scr) screen_picture=pic screen_stream=p_p1; ! back from connect screen_top=0; ! first line first frame ! p=0 { do enable } p_dest=x'370002'; ! cc p_p1=screen_stream p_p2=picture_p2; ! disc addr p_p3=picture_p3; ! tags p_p4=1; ! iso circ p_p5=32; ! start of pic in section p_p6=max pic lines * line len; ! length of pic if mon level = 6 then PRINTSTRING("PM ENABLE REQ".SNL) dout(p) if p_p2#0 start ; ! failed ! this can happen if the connected screen has already been ! reconnected and oper has disconnected us. there will be ! an offscreen on its way, but we clear it down now and discard ! the latter when it comes bearing a stream number we dont ! recognise. off screen(scr) opout("Enable pic failed"); ! log it for now return finish ! all set. display first frame display request(screen_stream,0) return sw(3): { off screen from private viewer } picture == pictures(p_p1) if picture_count>0 then picture_count=picture_count-1 c else opout("PPIC off when not on.") return sw(4): { from comms controller } ! either 'done' from oper indirect(srce act=x'c') ! or failed from cc after disconnect(srce act=6) ! discard both of these as detailed above if p_srce&x'FFFF'=6 start ; ! a cc failure. log it for now if mon level # 6 then select output(1) printstring("Display request refused by cc") select output(0) finish return sw(5): { unrecognised message from oper } opout("Bad picture message from oper") return sw(6): { off screen from oper } scr = screeno(p_p1) off screen(scr) if scr>=0 ! it might be <0 if we have already cleared this down before or ! after enable above, in which case it is discarded. return sw(7): { frame change from oper } scr=screeno(p_p1); ! get screen no connected to stream return if scr<0 ! we can get frame changes for one we've already cleared down ! at enable above. discard. screen==screens(scr) screen_top=p_p6&x'FFFFFF'; ! requested line pic = screen_picture display request(screen_stream,screen_top) end ; ! picture manager ! ! ! routine initialise pictures integer flag,i, pic, seg, gap string (11) file record (picturef)name picture recordformat daf((integer sectsi, nsects, last sect, spare, integerarray da(1:512) or integer sparex, integerarray i(0:514))) record (daf)da picture tick = 1 for pic=1,1,max pic files cycle pictures(pic) = 0 file="PICTURE".itos(pic) ! if TARGET # 2900 then flag = dcreate(uinf_user, file, uinf_fsys, c 8 << 2, 6, ada) else flag = dcreate(uinf_user, file, uinf_fsys, 8 << 2 {8 pages}, 6 {zero, vtemp}) if flag = 0 or flag = already exists start seg = 0 gap = 0 if TARGET # 2900 then flag = dconnect(uinf_user,file, c uinf_fsys,11,seg,gap) else c flag = dconnect(uinf_user, file, uinf_fsys, 11, 0, seg, gap) if flag = 0 start if TARGET = 2900 then flag = dgetda(my name, file, my fsys, addr(da)) c else start flag = dgetda(my name, file, my fsys, da_i) move(12, addr(da_i(0)), addr(da_sparex)) {to preserve common format} finish if flag = 0 start picture == pictures ( pic ) picture_base = seg << seg shift picture_p2 = da_da(1) { first - and only - section } picture_p3 = da_lastsect - 1 integer(picture_base) = 32 integer(picture_base + 4) = 32 integer(picture_base + 8) = 8 << 12 integer(picture_base+24)=max pic lines * line len; ! to get all formatted at first use finish else PRINTSTRING ( "DGETDA for ".FILE." fails : ".errs ( FLAG ).SNL ) finish else PRINTSTRING ( "DCONNECT ".FILE." fails : ".errs ( FLAG ).SNL ) finish else PRINTSTRING ( "DCREATE ".FILE." fails : ".errs ( FLAG ).SNL ) repeat ! for i=0,1,max screen cycle screens(i)=0 repeat end ; ! initialise pictures ! ! ! routine refresh pic(integer pic type, id1, string (15) id2 ) integer i record (pe)p record (picturef)name picture cycle i = 1, 1, max pic files picture == pictures ( i ) if picture_picture type = pic type and ( picture_id1 = id1 or pic type = FTP status summary display ) c and picture_id2 = id2 start { id1 is which FT line to update if nonzero and pic type is FTP summary so don't check } unless picture_screens = 0 = picture_count start p = 0 p_p1 = 1 { refresh } p_p2 = i picture manager(p,pic type,id1,id2) finish finish repeat end ; ! refresh pic stringfn ident to s(integer ident) !*********************************************************************** !* * !* TURNS A DOCUMENT IDENTIFIER INTO A STRING OF FIXED FORMAT * !* * !*********************************************************************** string (2) fsys string (4) rest fsys = i to s(ident>>24) fsys = "0".fsys if length(fsys) = 1 rest = i to s(ident&x'FFFFFF') rest = "0".rest while length(rest) < 4 result = fsys.rest end ; !OF STRINGFN IDENT TO S !* !* !* !* !*********************************************************** !The hashing routine for handling searches for HOST names. integer fn hashed(string (63) name) integer i, pt, n, h byte integer array x(0:15) const byte integer array prime(1:7)= 23, 19, 11, 7, 5, 13, 17 pt = (addr(x(7))>>3)<<3 longinteger(pt) = 0 n = addr(name) byteinteger(pt+i&7) = byteinteger(pt+i&7)!!byteinteger(n+i) for i = 0, 1, length(name) h = length(name)*29 h = h+prime(i)*byteinteger(pt+i) for i = 1, 1, 7 result = h&hash length end ; !of hashed integer fn lookup hasht(string (63) name) record (name f) name name entry integer h h = hashed(name) if pointers_hasht(h)#-1 start name entry == record(database conad + pointers_hasht ( h )) cycle if name=name entry_name then result = name entry_host entry exit if name entry_link = -1 name entry == record ( database conad + name entry_link ) repeat finish result = 0 end ; !of lookup hasht integer fn lookup host(string (63) name) integer i string (63) rest {uctranslate or lc?} i = lookup hasht(name) if i#0 then result = i unless name->(this ukac.".").rest start i = lookup hasht(this ukac.".".name); !prefix uk.ac if i#0 then result = i if name->name.(".").rest then result = lookup hasht(name); !for arpa. finish result = 0 end ; !of lookup host !END OF THE HASHING ROUTINES !* !* !* !* constbyteinteger file service = x'01' constbyteinteger mail service = x'02' routine interpret descriptor(integer call type, address, integername len, string (6) user,integername ident, flag) !*********************************************************************** !* * !* INTERPRETS AND IF VALID ACTS ON THE DOCUMENT DESCRIPTOR AT THE * !* SPECIFIED ADDRESS. * !* ON ENTRY: * !* ADDRESS = ADDRESS OF DESCRIPTOR * !* LEN = NUMBER OF BYTES IN DESCRIPTOR * !* USER = NAME OF SENDING PROCESS OR "" IF FROM AN INPUT STREAM * !* SRCE = NAME OF INPUT STREAM IF USER = "" * !* IDENT NOT SET * !* FLAG NOT SET * !* ON EXIT: * !* LEN = POSITION OF LAST CHARACTER INTERPRETED IN DESCRIPTOR * !* IDENT = DOCUMENT IDENTIFIER IF FLAG = 0 * !* FLAG = RESULT 0 SUCCESSFUL * !* * !*********************************************************************** record (document descriptorf)name document record (password document descriptor f)name password document record (document descriptorf)temp descr, ndocument record (fhf)name file header string (7) c string (100) field, p, s, s1, s2, guest address integer i, j, eq found, fsys, char, end, type, resource, seg,gap, station, specific fep routinespec set and check descriptor(string (7) c, string (100) p, integername f) !* routine to doc string(record (document descriptorf)name document, byteintegername field, stringname value) field = 0 and return if value = "" flag = descriptor full and return if document_string ptr + length(value) > 147 field = document_string ptr string(addr(document_string space) + document_string ptr) = value document_string ptr = document_string ptr + length(value) + 1 end !* routine to null docstring(record (document descriptor f)name document, byteinteger field) integer i,j,k return if field = 0 k = addr(document_string space) + field i = byteinteger(k) return if i = 0 cycle j = k ,1 ,k+i byteinteger(j) = 0 repeat !We have written 0s over the string entry. return end !* routine to password doc string(record (password document descriptorf)name document, byteintegername field, stringname value) field = 0 and return if value = "" flag = descriptor full and return if document_string ptr + length(value) > 127 field = document_string ptr string(addr(document_string space) + document_string ptr) = value document_string ptr = document_string ptr + length(value) + 1 end !* guest address = "" temp descr = 0; !SET ALL VALUES TO 0 OR "" OR -1 temp descr_string ptr = 1 temp descr_data start = -1 temp descr_data length = -1 temp descr_time = -1 temp descr_priority = -1 temp descr_output limit = -1 fsys = -1; !INTERNAL CAN BE SET BY USER !* if call type = user call start !We have here a 'trusted' call with a pre constructed document descriptor !which at the moment can only be a call for an NIFTP-B(80) transfer ident = 0 move(256, address, addr(ndocument_state)) p = docstring(ndocument,ndocument_FTP alias) select output(1) printstring(dt."user ".user." request for ".p.snl) select output(0) if p -> s.("[").field.("]").s1 and s=s1="" start if field -> s.("FEP").s1.(".").s2 and s = "" start field = s2 specific fep = stoi(s1) finish else specific fep = -1 guest address = field p = "GUEST" station = guest entry finish else station = lookup host(p) if station = 0 then flag = 4 and -> fails fsys = -1 if user = "MAILER" start !Mailer special case. if station # guest entry and FTP stations(station)_services c & mail service = 0 then flag = 4 and -> fails c = docstring(ndocument,ndocument_name) unless length(c) = 6 then flag = 6 and ->fails length(c) = 2 fsys = stoi(c) finish else start if station # guest entry and FTP stations(station)_ c services&file service = 0 then flag = 4 and -> fails flag = dfsys(user,fsys) if flag # 0 then flag = 1 and ->fails !now check that the user has pss priv.(temp until password/name !for gateway access can be picked up and passed with call) !FTP Station STATUS list. !0 General accesss station !1 PSS accreditation (bit 6) required !5 Masked (ALIAS) but can be seen in TRANSFERS(.ALL/*) enquiries !6 MASKED and is invisable even in TRANSFERS(.ALL/*) enquiry. !7 As 6 but requires ACR 9 for access. if FTP stations(station)_status = 1 start !ie status 1 implies accreditation check required(PSS) !which is priv bit 6 until level 3 addressing available. !status 2 is test only so include it in checks. if TARGET # 2900 start flag = dsfi(user, fsys, 38, 0, dsfis, dsfiia) j = dsfiia(1) finish else flag = dsfi(user,fsys,38,0,addr(j)) flag = 8 and ->fails if (j>>6)&1 = 0 finish finish ndocument_user = user ndocument_FTP retry level = 3 ndocument_try emas to emas = yes ndocument_rerun = yes ident = get next descriptor(fsys) if ident = 0 then flag = 2 and ->fails document == record(document addr(ident)) document = ndocument document_date and time received = current packed dt !FRIG for ERCC sites if p = "2988" or p = "2980" then p = "BUSH" and to docstring( c document,document_ftp alias,p) if p = "2972" then p = "EMAS" and to docstring(document,document_ftp alias,p) !END OF FRIG if guest address # "" start to docstring(document,document_guest address,guest address) to docstring(document,document_FTP alias,p) if document_FTP alias = x'ff' {full string space!} then flag = 4 and -> fails document_specific fep = specific fep finish if document_priority = -1 then type = queue_default priority c else type = document_priority document_priority requested = type if document_data length = 0 then document_data length = c FTP stations(station)_limit; !sensible choice in this case. resource = (document_data length + 1023)>>10 document_priority = compute priority(type, resource, queue_resource limit) if document_mode of access <= x'0003' or document_mode of access = x'4001' c or document_mode of access = x'2001' start !we are to send the file. flag = dtransfer(user, my name, docstring(document,document_srce), identtos(ident), fsys, fsys, 1) if flag # 0 start select output(1) printstring(dt."DTRANSFER for user request fails ".errs(flag).snl) select output(0) flag = 3 and ->fails finish seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(my name, identtos(ident),fsys,r!w,seg,gap) c else flag = dconnect(my name, identtos(ident), fsys, r!w, 0, seg, gap) if flag # 0 start select output(1) printstring(dt."DCONNECT of DTRANSFERed user request fails ".errs(flag).snl) select output(0) flag = 3 and ->fails finish file header == record(seg<<seg shift) document_data length = file header_end-file header_start document_data start = file header_start flag = ddisconnect(my name,identtos(ident),fsys,0) finish else if document_mode of access = x'8002' or document_mode of access = x'C001' start !we are to fetch the file document_data length = -1 document_data start = x'20' finish else flag = 7 and ->fails password document == record(password document addr(ident)) password document = 0 password document_string ptr = 1 if document_external password # 0 start field = doc string(document,document_external password) to null doc string(document,document_external password) to password doc string(password document,password document_external password,field) document_external password = set !we have copied the password to the secure descriptor and blanked out !the contents in the general descriptor. Marking the filed as set in the !secure descriptor. finish if document_FTP file password # 0 start field = doc string(document,document_FTP file password) to null doc string(document,document_FTP file password) to password doc string(password document,password document_FTP file password,field) document_FTP file password = set !we have copied the password to the secure descriptor and blanked out !the contents in the general descriptor. Marking the filed as set in the !secure descriptor. finish if document_special options # 0 start field = doc string(document,document_special options) to null doc string(document,document_special options) to password doc string(password document,password document_special options,field) document_special options = set !we have copied the password to the secure descriptor and blanked out !the contents in the general descriptor. Marking the filed as set in the !secure descriptor. finish add to queue(ident,FTP stations(station)_connect retry time,no,no,flag) if flag # 0 then flag = 5 and ->fails ident = (ident<<8)>>8 and flag = 0; !ie ok. return fails: ident = 0 return finish !* c = ""; p = ""; eq found = no; end = len-1 cycle len = 0, 1, end char = byte integer(address+len); !GET A CHARACTER if char = ',' or len = end start !END OF DESCRIPTOR p <- p.to string(char) if char # ',' c and char # nl and length(p) < 100 length(p) = length(p)-1 while length(p) > 1 c and charno(p, length(p)) = ' ' set and check descriptor(c, p, flag) return if flag # 0 c = ""; p = ""; eq found = no finish else start ; !NOT THE END OF A DESCRIPTOR if char # nl start if char # '=' start ; !NOT AN EQUALS if eq found = no start ;!EQUALS NOT FOUND YET if char # ' ' start ;!IGNORE SPACES IN COMMANDS c = c.to string(char) if length(c) < 7 finish finish else start if char # ' ' or p # "" start !ONLY IGNORE LEADING SPACES byteinteger(address+len) = '?' c if c = "PASS" p <- p.to string(char) if length(p) < 100 finish finish finish else eq found = yes finish finish repeat !* return !* !* !* routine set and check descriptor(string (7) c, string (100) p, integername flag) !*********************************************************************** !* * !* CHECK THE COMMAND AND ITS PARAMETER AND SET THE DESCRIPTOR IF OK * !* * !*********************************************************************** constinteger count = 24 conststring (7) array schedule params(1 : count) = c "USER", "PASS", "DEST", "SRCE", "NAME", "DELIV", "TIME", "PRTY", "COPIES", "FORMS", "MODE", "ORDER", "START", "LENGTH", "RERUN", "DECKS", "TAPES", "DISCS", "AFTER", "FSYS", "OUT", "OUTLIM", "OUTNAME", "DAPMINS" !* THE CONSTANTS BELOW SPECIFY THE RANGE OF VALUES WHICH CAN BE TAKEN !* BY THE PARAMETERS ABOVE. WHERE- !* BYTE 0 IF 0 = INTEGER IF 1 = STRING !* BYTE 1 IF = 1 IGNORE BYTE 3 !* BYTE 2 IF STRING THE MIN LENGTH IF INTEGER THE MIN VALUE !* BYTE 3 IF STRING THE MAX LENGTH IF INTEGER THE MAX VALUE constintegerarray schedule param values(1 : count) = c x'01000606', x'0100011F', x'0100010F', x'0100010F', x'0100010F', x'0100011F', x'00010100', x'01000305', x'000001FF', x'000000FF', x'01000303', x'000000FF', x'00010000', x'00010100', x'01000203', x'00000108', x'01000164', x'01000164', x'0100081F', x'00000063', x'0100010F', x'00010000', x'010001FF', x'00010000' constintegerarray errors(1 : count) = c invalid username, invalid password, invalid destination, invalid srce, invalid name, invalid delivery, invalid time, invalid priority, invalid copies, invalid forms, invalid mode, invalid order, invalid start, invalid length, invalid rerun, invalid decks, invalid tapes or discs, invalid tapes or discs, invalid start after, invalid fsys, invalid out, invalid outlim, invalid outname, invalid dap mins integer value, i, min, max, type flag = 0 cycle i = 1, 1, count if schedule params(i) = c start type = schedule param values(i)>>24 min = (schedule param values(i)>>8)&255 if (schedule param values(i)>>16)&255 # 0 c then max = x'7FFFFFFF' c else max = scheduleparam values(i)&255 if type = 0 start ; !INTEGER value = stoi(p) -> error if value = not assigned -> error unless min <= value <= max finish else start -> error unless min <= length(p) <= max finish return finish repeat flag = invalid descriptor return error: flag = errors(i) return !NOTE we only do the above cursory check fpr BATCH input over File Transfer. !The main checking will be done by spooler when the job is in. end ; !OF ROUTINE SET AND CHECK DESCRPTOR end ; !OF ROUTINE INTERPRET DESCRIPTOR !* !* integerfn document addr(integer ident) !*********************************************************************** !* * !* RETURNS THE ADDRESS OF THE DOCUMENT DESCRIPTOR "IDENT" * !* RETURNS ZERO IF IDENT IS NOT VALID * !* * !*********************************************************************** record (fhf)name file header integer fsys, doc fsys = ident>>24; doc = ident&x'FFFFFF' result = 0 unless f systems(fsys)_addr # 0 c and 1 <= doc <= max documents file header == record(f systems(fsys)_addr) result = f systems(fsys)_addr+file header_start+(doc-1)* c document entry size end ; !OF INTEGERFN DOCUMENT ADDR !* integerfn password document addr(integer ident) !*********************************************************************** !* * !* RETURNS THE ADDRESS OF THE DOCUMENT DESCRIPTOR "IDENT" * !* RETURNS ZERO IF IDENT IS NOT VALID * !* * !*********************************************************************** record (fhf)name file header integer fsys, doc fsys = ident>>24; doc = ident&x'FFFFFF' result = 0 unless f systems(fsys)_password addr # 0 c and 1 <= doc <= max documents file header == record(f systems(fsys)_password addr) result = f systems(fsys)_password addr+file header_start+(doc-1)* c password document entry size end ; !OF INTEGERFN PASSword DOCUMENT ADDR !* !* routine add to queue(integer ident, delay, all,fixed delay, integername flag) !*********************************************************************** !* * !* ADDS TO THE SPECIFIED QUEUE THE DOCUMENT SPECIFIED. * !* DOCUMENTS ARE QUEUED BY PRIORITY. * !* * !*********************************************************************** record (document descriptorf)name document string (71) s integer cell, next, previous, line, amount, i, remove, fsys integerarray sfi(1:18) flag = 0 fsys = ident >> 24 if TARGET # 2900 then flag = dsfi(my name,fsys,4,0,dsfis,sfi) c else flag = dsfi(my NAME, fsys, 4, 0, addr(sfi(1))) if flag # 0 start select output(1) printstring(dt."DSFI for FTRANS on fsys ".itos(fsys)." fails ".errs(flag).snl) select output(0) printstring("FTRANS DSFI fails ".errs(flag).snl) flag = queue full return finish if sfi(3) < 6 or sfi(6) < 1 start !either less than 6 file descriptors or 1 section descriptor left in that SPOOLR index select output(1) printstring(dt."SPOOLR index filling on ".itos(fsys).snl) select output(0) flag = queue full return finish document == record(document addr(ident)) if queue_length < queue_max length start !CHECK OK TO ADD TO QUEUE cell = free list if cell # 0 start ; !FREE LIST EMPTY? free list = list cells(cell)_link list cells(cell)_document = ident previous = 0 next = queue_head while next # 0 and imod(list cells(next)_priority) c >= imod(document_priority) cycle !CYCLE TILL END OF QUEUE OR PRIORITY < previous = next; !REMEMBER ENTRY next = list cells(previous)_link repeat if previous # 0 start ; !NOT ON HEAD OF QUEUE list cells(cell)_link = list cells(previous)_link !LINK IN NEW ENTRY list cells(previous)_link = cell finish else start ; !ON HEAD OF QUEUE list cells(cell)_link = queue_head queue_head = cell finish queue_length = queue_length+1 amount = document_data length list cells(cell)_size=amount queue_amount = queue_amount+amount list cells(cell)_priority=document_priority list cells(cell)_order = document_order list cells(cell)_user=document_user list cells(cell)_flags = 0 !we are dealing with general FTP queue s = docstring(document,document_FTP alias) i = lookup host(s) if i = 0 then i = guest entry list cells(cell)_station ptr = i if list cells(cell)_station ptr = guest entry and s # "GUEST" then c printstring(identtos(list cells(cell)_document).": ".s." ?".snl) and remove = yes else remove = no if delay > 0 start if all = no or s = "GUEST" start list cells(cell)_FTP timer = delay if fixed delay = yes or s = "GUEST" then list cells(cell)_FTP flags = c list cells(cell)_FTP flags ! FTP fixed term delay !put on the fixed(ie not to be reset) delay if required. finish else start i = queue_head while i # 0 cycle if list cells(i)_station ptr = list cells(cell)_station ptr start list cells(i)_FTP timer = delay list cells(i)_FTP flags = list cells(i)_FTP flags!FTP fixed term delay c if fixed delay = yes finish i = list cells(i)_link repeat FTP stations(list cells(cell)_station ptr)_connect retry time = delay c unless s = "GUEST" !Set the Station DELAY for ALL circumstance. !The GUEST stuff is because we want to treat GUEST in a different way !since it can have documents queued for many different TS addresses. !therefore we do not want to reflect one forced delay on one address to another. finish finish else list cells(cell)_FTP timer = c connect retry times(FTP stations(list cells(cell)_station ptr)_ c connect retry ptr) document_state = queued select output(1) print string(dt.document_dest." ".ident to s(ident). c " ".document_user.".".docstring(document,document_name)." QUEUED".snl) select output(0) cycle line = 1,1,lines kick FTP line(line) repeat finish else start print string("QUEUE FREE LIST EMPTY".snl) flag = all queues full finish if remove = yes then c remove from queue(ident,flag) !This happens if at IPL the document in the FTP queue has an !address of a station that has gone from the configuration. finish else flag = queue full end ; !OF ROUTINE ADD TO QUEUE !* !* routine delete document(integer ident, integername flag) !*********************************************************************** !* * !* ROUTINE TO DELETE A DOCUMENT AND ITS DESCRIPTOR. * !* * !*********************************************************************** record (document descriptorf)name document string (11) file integer fsys file = ident to s(ident) fsys = ident>>24 document == record(document addr(ident)) flag = ddestroy(my name, file, "", fsys, 0) if flag = 0 start select output(1) print string(dt.document_dest." ".file." ".document_user. ".".docstring(document,document_name)." DELETED".snl) select output(0) finish else start select output(1) print string(dt."DESTROY ".my name.".".file. c " FAILS ".errs(flag).snl) select output(0) finish document_date and time deleted = current packed dt document_state = unused end ; !OF ROUTINE DELETE DOCUMENT !* !* routine remove from queue(integer ident,integername flag) !*********************************************************************** !* * !* REMOVE THE SPECIFIED DOCUMENT DESCRIPTOR FROM THE QUEUE * !* * !*********************************************************************** record (document descriptorf)name document integer next, previous, amount flag = 0 next = queue_head while next # 0 and list cells(next)_document # ident cycle previous = next next = list cells(previous)_link repeat if next # 0 start if next = queue_head then queue_head = list cells(next) c _link else list cells(previous)_link = list cells( c next)_link list cells(next)_link = free list free list = next document == record(document addr(ident)) amount = document_data length amount = amount*document_copies if document_copies > 1 queue_length = queue_length-1 queue_amount = queue_amount-amount select output(1) print string(dt.document_dest." ".ident to s(ident)." " c .document_user.".".docstring(document,document_name)." UNQUEUED".snl) select output(0) finish else flag = not in queue end ; !OF ROUTINE REMOVE FROM QUEUE !* !* !* routine any queued(integer fsys) !*********************************************************************** !* * !* SEARCHES THE "SPOOLLIST" ON THE SPECIFIED FILE SYSTEM AND ADDS ANY * !* QUEUED DOCUMENTS TO THE APPROPRIATE QUEUE. DOCUMENTS WHICH WERE * !* BEING PROCESSED WHEN THE SYSTEM STOPPED ARE EITHER REQUEUED OR * !* DELETED DEPENDING ON THE VARIABLE "RERUN". * !* * !*********************************************************************** record (document descriptorf)arrayformat ddaf(1 : max documents) record (document descriptorf)arrayname documents record (document descriptorf)name document record (fhf)name file header string (2) sfsys integer doc no, flag, ident sfsys = i to s(fsys) file header == record(f systems(fsys)_addr) !MAP HEADER documents == array(f systems(fsys)_addr+file header_start, ddaf) !DOCUMENT ADDRS cycle doc no = 1, 1, max documents if documents(doc no)_state # unused start !IS DESCRIPTOR IN USE document == documents(doc no) if document_dest = FTP work dest then delete document(ident,flag) and continue flag = 1; ident = fsys<<24!doc no if document_state = queued or (document_state = transferring c and document_rerun = yes) start !REQUEUE? add to queue( ident, 0,no,no,flag) print string("ADD ".ident to s(ident). c " TO QUEUE ".document_dest." FAILS ". c i to s(flag).snl) if flag # 0 finish if flag # 0 start ; !DELETE IT! select output(1) print string(dt.document_dest." ".ident to s( c ident)." ".document_user.".".docstring(document,document_name). c " DELETED ".doc state(document_state). c " AT START UP".snl) select output(0) delete document(ident, flag) c if document_state # queued finish finish repeat end ; !OF ROUTINE ANY QUEUED !* !* routine connect or create(string (6) user, string (11) file, integer fsys, size, mode, flags, integername caddr) !*********************************************************************** !* * !* CONNECT OR CREATE A FILE. SETTING CADDR WITH THE CONNECT ADDRESS OR* !* ZERO IF UNSUCCESFUL. * !* * !*********************************************************************** record (fhf)name file header record (finff)file info integer flag, seg, gap, nkb string (31) filename caddr = 0; !SET RETURN CONNECT ADDRESS TO ZERO INITIALLY nkb = ((size+(e page size-1))&(-e page size))>>10 if TARGET # 2900 then flag = dfinfo(user,file,fsys,file info_offer,file info_i) c else flag = dfinfo(user, file, fsys, addr(file info)) if flag = 0 start if nkb # file info_nkb start flag = dchsize(user, file, fsys, nkb) if flag # 0 then print string("CHSIZE ".user.".". c file." FAILS ".errs(flag).snl) c else print string(user.".".file." SIZE CHANGED ". c i to s(nkb-file info_nkb)." KBYTES".snl) finish finish seg = 0; !ANY SEGMENT WILL DO gap = 0; !ANY GAP WILL DO if TARGET # 2900 then flag = dconnect(user,file,fsys,mode,seg,gap) c else flag = dconnect(user, file, fsys, mode, 0, seg, gap) unless flag = ok start ; !SUCCESSFULLY CONNECTED? filename = user.".".file unless flag = does not exist start !NO? THEN DID IT EXIST print string("CONNECT ".filename." FAILS ".errs(flag). c snl) !YES THEN FAILURE MESSAGE flag = ddestroy(user, file, "", fsys, 0) !TRY TO DESTROY IT finish else flag = ok if flag = ok start ; !SUCCESS OR DOES NOT EXIST if TARGET # 2900 then flag = dcreate(user, file, fsys, nkb, flags, ada) c else flag = dcreate(user, file, fsys, nkb, flags) !CREATE FILE if flag = ok start ; !CREATED OK? seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(user,file,fsys,r!w,seg,gap) c else flag = dconnect(user, file, fsys, r!w, 0, seg, gap) if flag = ok start ; !CONNECTED OK? caddr = seg<<seg shift; !SET CONNECT ADDRESS file header == record(caddr) !SET UP A FILE HEADDER file header_end = file header size file header_start = file header size file header_size = (size+e page size-1)&(- c e page size) file header_datetime = current packed dt finish else print string("CONNECT ".filename. c " FAILS ".errs(flag).snl) finish else print string("CREATE ".filename. c " FAILS ".errs(flag).snl) finish else print string("DESTROY ".filename." FAILS ". c errs(flag).snl) finish else caddr = seg<<seg shift; !ALREADY EXISTED SO RETURN CONNECT ADDRESS end ; !OF ROUTINE CONNECT OR CREATE !* !* routine any extra files(integer fsys,special) !*********************************************************************** !* * !* THIS ROUTINE CHECKS TO SEE IF THERE ARE ANY FILES IN FTRANS'S * !* INDEX WHICH DO NOT CORRESPOND TO A DOCUMENT DESCRIPTOR IN A QUEUE * !* ANY SUCH FILES FOUND ARE DELETED * !* THIS ROUTINE MUST ONLY BE CALLED WHEN ALL STREAMS ARE IDLE * !* * !*********************************************************************** record (document descriptorf)name document record (file inff)array temprec(0 : 1) integer maxrec, filenum, nfiles, flag, i, j, ident, afsys, next string (11) file max rec = 1; filenum = 0 if TARGET = 2900 then c flag = dfilenames(my name, temprec, filenum, maxrec, nfiles, fsys, 0) else flag = dfilenames(my name, filenum, maxrec, nfiles, c fsys, 0, temprec) if flag = 0 start if nfiles > 0 start print string("FSYS ".i to s(fsys)." FILES ".i to s( c nfiles).snl) max rec = nfiles begin record (file inff)array files(0 : max rec) if TARGET = 2900 then c flag = dfilenames(my name, files, filenum, max rec, c nfiles, fsys, 0) else flag = dfilenames(my name, filenum, max rec, c nfiles, fsys, 0, files) if flag = 0 start cycle i = 0, 1, nfiles-1 if charno(files(i)_name, 1) # '#' c and files(i)_use = 0 start !ONLY FILES NOT IN USE file = files(i)_name if length(file) = 6 start !DOCUMENT? afsys = 0 cycle j = 1, 1, 2 -> del unless '0' <= charno(file, j) <= '9' afsys = afsys*10+charno(file, j)-'0' repeat -> del unless afsys = fsys ident = 0 cycle j = 3, 1, 6 -> del unless '0' <= charno(file, j) <= '9' ident = ident*10+charno(file, j)-'0' repeat -> del unless 1 <= ident <= c max documents ident = afsys<<24!ident document == record(document addr( c ident)) next = queue_head while next # 0 cycle !SCAN DOWN QUEUE -> next if list cells(next)_ c document = ident !FOUND IT next = list cells(next)_link repeat if special = no or (document_state = unused and c document_dest # FTP work dest) start delete document(ident, flag) if flag = 0 then print string( c ident to s(ident)." DELETED".snl) c else print string("DELETE ". c ident to s(ident)." FAILS ".i to s c (flag).snl) finish -> next finish del: if special = no start flag = ddestroy(my name, file, "", fsys, 0) if flag = 0 then print string(file. c " DELETED".snl) else print string( c "DELETE ".file." FAILS ".errs(flag). c snl) finish next: finish repeat finish else print string("FILENAMES ".my name. c " FSYS ".i to s(fsys)." FAILS ".errs(flag). c snl) end finish else print string("FSYS ".i to s(fsys). c " NO FILES".snl) finish else print string("FILENAMES ".my name." FSYS ". c i to s(fsys)." FAILS ".errs(flag).snl) end ; !OF ROUTINE ANY EXTRA FILES !* !* routine open file system(integer fsys) !*********************************************************************** !* * !* FTRANS MAINTAINS A FILE INDEX ON EACH FILE SYSTEM AND THIS ROUTINE * !* OPENS THE FILES ON THE SPECIFIED FILE SYSTEM FOR USE, EITHER BY * !* CONNECTING THEM OR BY CREATING NEW FILES WHERE APPLICABLE. * !* WHEN A FILE SYSTEM IS OPEN THE APPROPRIATE VARIABLE (ON LINE) IN * !* IN THE RECORD ARRAY F SYSTEMS IS SET NON ZERO. SIMILARILY WHEN * !* A FILE IS OPEN FOR USE ITS CONNECT ADDRESS IS PLACED IN THE ARRAY * !* CONAD. THE ROUTINE CLOSE FILE SYSTEM DOES THE OPPOSITE OF THIS * !* ROUTINE FOR RECONFIGURATION PURPOSES. * !* * !*********************************************************************** record (fhf)name file header, password file header integer caddr, file size, flag, password caddr, password file size, new list string (11) file, password file string (2) sfsys new list = no sfsys = i to s(fsys) if f systems(fsys)_addr = 0 start ; !CHECK IF ALREADY OPEN file = "FTPLIST".sfsys; password file = "FTPPASS".sfsys file size = file header size+max documents* c document entry size password file size = file header size + max documents*password document entry size connect or create(my name, file, fsys, file size, r!w!sh, zerod, caddr) !CONNECT OR CREATE f systems(fsys)_addr = caddr; !STORE CONNECT ADDRESS connect or create(my name, password file, fsys, password file size, c r!w, zerod, password caddr) f systems(fsys)_password addr = password caddr f systems(fsys)_closing = no unless caddr = 0 start file header == record(caddr) if file header_end = file header_start start !NEW FILE? new list = yes file header_end = file size file header_free hole = 1 print string("NEW FTP LIST FSYS ".sfsys.snl) flag = dpermission(myname, "DIRECT", "", "", fsys, 6, r) print string( c "SET INDEX PERMISSION FOR DIRECT FAILS ".errs( c flag).snl) if flag # 0 flag = dpermission(myname,"","",file,fsys,1,r) if flag # 0 then printstring("DPERMISSION for general access fails ". c i to s(flag).snl) finish else start !the next two statements can go when all sites have vsn 31 flag = dpermission(myname,"","",file,fsys,1,r) if flag # 0 then printstring("DPERMISSION for REMOTE fails ". c i to s(flag).snl) any queued(fsys) finish finish else print string("NO FTP LIST FSYS ".sfsys.snl) unless password caddr = 0 start password file header == record(password caddr) if password file header_end = password file header_start start !A new file password file header_end = password file size printstring("NEW PASS LIST FSYS ".sfsys.snl) if new list = no then printstring("DISASTER PASS list on ". c sfsys.snl."lost. TRANSFERS will fail".snl) flag = dpermission(my name,"DIRECT","","",fsys,6,r) printstring("SET INDEX PERMISSION FOR DIRECT fails ".errs(flag).snl) c if flag # 0 finish finish else printstring("NO PASS LIST ON FSYS ".sfsys.snl) finish else print string("ALREADY OPEN FSYS ".sfsys.snl) end ; !OF ROUTINE OPEN FILE SYSTEM !* !* routine handle close(record (pe)name p) !****************************************************** !* WARNING OR OCCASION OF A FSYS OR A FEP CLOSING. * !* OR THE REMOVAL OF A CLOSE. * !****************************************************** integer i, j ! if p_p1 = 1 start !TOTAL OR PARTIAL FSYS CLOSE OR WITHDRAW. if p_p2 = 0 then j = yes if p_p2 = 2 then j = no !0 -> CLOSING, 2 -> WITHDRAW CLOSE. if p_p3 = -1 start !FOR ALL FILE SYSTEMS. cycle i = 0, 1, max fsys f systems(i)_closing = j repeat closing = j finish else start !ACTION ON AN INDIVIDUAL FSYS return if f systems(p_p3)_addr = 0; !NOT AVAILABLE. close fsys(p_p3) and return if p_p2 = 1; !IE CLOSE NOW f systems(p_p3)_closing = j if j = no start cycle i = 0, 1, max fsys if f systems(i)_addr # 0 and f systems(i)_closing # no then exit closing = no if i = max fsys repeat finish else closing = yes finish finish else start !FEP CLOSING. if p_p2 = 2 start cycle i = 0, 1, max fep feps(i)_closing = no repeat return finish return if feps(p_p3)_FTP available = no !CLOSING A PARTICULAR FEP. if p_p2 = 0 then feps(p_p3)_closing = yes c else fep down(p_p3) return finish end !* !* routine close fsys(integer fsys) !******************************************************** !* THIS ROUTINE CLOSES AN FSYS IN RESPECT TO ALL ACTIVITY* !********************************************************* integer line, flag, next, after, i record (pe)p string (15) file printstring("CLOSING FSYS ".i to s(fsys).snl) update descriptors(fsys) next = queue_head while next # 0 cycle after = list cells(next)_link if list cells(next)_document>>24 = fsys then c remove from queue( list cells(next)_document, flag) next = after repeat !NOW CLEAR THE LINES. cycle line = 1, 1, lines if FTP lines(line)_status > allocated and FTP lines(line)_document>>24 = fsys start p = 0 p_dest = line << 7 FTP control(p, refresh line) if refresh line # 0 then refresh pic(FTP status summary display, refresh line, "") finish repeat f systems(fsys)_addr = 0 f systems(fsys)_closing = no cycle i = 0, 1, max fsys exit if f systems(i)_addr # 0 and f systems(fsys)_closing = yes closing = no if i = max fsys repeat file = "FTPLIST".i to s(fsys) flag = ddisconnect(my name, file, fsys, 0) if flag # 0 then printstring(" DISCONNECT FTPLIST FAILS ". c errs(flag).snl) file = "FTPPASS".i to s(fsys) flag = ddisconnect(my name, file, fsys, 0) if flag # 0 then printstring(" DISCONNECT FTPPASS FAILS ". c errs(flag).snl) return end !* !* !* routine fep down(integer fe) !********************************************************************** !* * !* THIS ROUTINE DEALS WITH CLEARING UP OVER A LOST FEP IN 3 STEPS: * !* * !* 1) ANY STREAM THAT WAS CURRENTLY ALLOCATED THRO THE LOST FEP * !* IS STOPPED AND, IF ACTIVE, ABORTED. * !* * !* 2) THE CONTROL STREAMS FOR THE FRONT END ARE DISABLED * !* * !********************************************************************** integer line, i record (linef)name FTP line record (pe)p feps(fe)_FTP available = no !* !* STEP 1 !* cycle line = 1, 1, lines; !ROUND ALL STREAMS FTP line == FTP lines(line) if FTP line_status # unallocated start if FTP line_fep = fe start interpret command("ABORT ".itos(line),"",0) if FTP line_status > allocated if FTP line_status = deallocating or FTP line_status = connecting or c FTP line_status = selected start FTP line_status = unallocated refresh pic(ftp status summary display,line,"") FTP line_in stream status = unallocated FTP line_out stream status = unallocated FTP line_document = 0 FTP line_station ptr = 0 finish finish finish repeat !* !* STEP 2 !* feps(fe)_FTP input cursor = 0 feps(fe)_FTP output cursor = 0 p_dest = disable stream p_srce = fe<<8!FTP output reply mess p_p1 = feps(fe)_FTP input stream p_p2 = abort i = dpon3("", p, 0, 0, 6) p_dest = disable stream p_srce = fe<<8!FTP output reply mess p_p1 = feps(fe)_FTP output stream p_p2 = abort i = dpon3("", p, 0, 0, 6) p_dest = disconnect stream p_srce = fe<<8!FTP output reply mess p_p1 = feps(fe)_FTP input stream i = dpon3("", p, 0, 0, 6) p_dest = disconnect stream p_srce = fe<<8!FTP output reply mess p_p1 = feps(fe)_FTP output stream i = dpon3("", p, 0, 0, 6) end ; !OF ROUTINE FEP DOWN !* !* !* !* !********************************************************************** !********************************************************************* !FTP CONTROL ROUTINES FOLLOW routine FTP control(record (pe)name p,integername refresh line) !***************************************************************** !* * !* F.T.P. C O N T R O L M A I N M O D U L E * !* * !***************************************************************** record (fhf)name file header record (linef)name FTP line record (FTP tablef)name FTP table record (document descriptorf)name document integer dact, flag, line, ident, len, command length, command start, buffer offset, seconds integer data length, data start, reply start, command sent activity, mail ident, rate integer seg, gap, messages, limit, monitoring, table entry, delay,j, FTP timeout, old len, size if TARGET = 2900 start halfinteger transfer status finish else start shortinteger transfer status finish byteinteger type, subtype string (128) s, s1, s2, s3, ss string (11) state, mail state, extra info string (127) work string recordformat messf(stringname s) record (messf) array message(1:16) switch st(FTP connect : FTP confirmation from spooler ) switch time out(allocated : spooler called) routinespec connect routinespec disconnect routinespec deallocate routinespec abort FTP routinespec enable in(integer mode, reply) routinespec enable out(integer mode, reply, len, start, size, address) routinespec disable in(integer action, reply) routinespec disable out(integer action, reply) routinespec format command(integer addr, offset, integername new len, integer eor) routinespec interpret tcc(byteintegername type, subtype) if TARGET # 2900 start routinespec interpret comm(byteintegername type, shortintegername transfer status) finish else start routinespec interpret comm(byteintegername type, halfintegername transfer status) finish routinespec send block(integer reply, integername flag) integerfnspec accept block routinespec complete file handling(integername flag, stringname report) routinespec send mail routinespec generate(byteinteger type, subtype, integername len) routinespec send to spooler(integer type,ident,confirm) routinespec mail report(string (255) s, integer displ) routinespec create FTP work files(integername flag, INTEGER MAIL ONLY) routinespec input buffer connect routinespec output buffer connect routinespec buffer disconnect routinespec FTP log(string (127) message) routinespec evaluate negotiation(integer command start, reply start, c integername reply length, integer limit, byteintegername type) routinespec delete FTP document(integer ident) command start = 0; reply start = 0; len = 0 if 2 < mon level < 5 start select output(1) printstring(dt."FTP CONTROL(POFF): ") pt rec(p) select output(0) finish dact = p_dest & 127 FTP timeout = no line = (p_dest&x'FFFF')>>7 FTP line == FTP lines (line) table entry = line FTP table == FTP tables(line) if dact = 0 start !we have a locally issued abort. if ftp line_status = connecting and ftp line_in stream status = connecting c and ftp line_out stream status = connecting start !We are in a connecting state on both streams. !So we try an abort (DEALLOCATE) FTP line_in stream status = aborting FTP line_out stream status = aborting deallocate !We must watch for a connect reply crossover comming. FTP line_document = 0 FTP line_station ptr = 0 return finish return unless FTP line_in stream status = active if FTP line_user abort = yes then s = "User " else s = "" print string(s."Aborting ".FTP line_name.snl) abort FTP return finish unless line = 0 then refresh line = line if 2 < mon level < 5 then start FTP log(" (line ".itos(line).") CURRENT STATUS: ". c stream status type(FTP line_status)." ACT: ".FTP act(dact)) select output(0) finish if receiving data <= FTP line_status <= end of data acknowledge sent c then start ident = FTP line_document document == record(document addr(ident)) finish if p_p2 # 0 and FTP p command reply <= dact <= FTP data input start printstring("FTP (".itos(table entry).") Enable buffer fails ". c i to s(p_p2).snl) abort FTP return finish -> st(dact) st(FTP connect): !---------------------------------------------------------------------- !AN FTP STREAM PAIR IS ALLOCATED, ISSUE THE REQUIRED CONNECT if FTP stations(control entry)_service = closed start if FTP line_station type = P station start FTP line_station ptr = 0 FTP line_document = 0 finish FTP log(" service closed, not proceeding to connect.") deallocate return finish if FTP line_station type = P station start s = "P station" FTP stations(FTP line_station ptr)_last call = current packed dt FTP stations(FTP line_station ptr)_connect attempts = FTP stations( c FTP line_station ptr)_connect attempts + 1 finish else s = "Q station" s = s." for ".string at(FTP stations(FTP line_station ptr),FTP stations(FTP line_station ptr)_shortest name) FTP log(" connecting as a ".s) connect FTP line_status = connecting FTP line_user abort = no FTP line_timer = FTP default timeout return st(FTP input connected): !---------------------------------------------------------------------- !THE INPUT STREAM OF AN FTP PAIR IS CONNECTED. if FTP line_status = unallocated then FTP log( c " already unallocated on disconnect reply(fep down / connect attempt aborted?)") if p_p2 # 0 then start !THE CONNECTION HAS FAILED. FTP log(" CONNECT (IN) FAILS ".itos(p_p2).snl) if FTP line_station type = P station and FTP line_document # 0 start if FTP stations(FTP line_station ptr)_status # 2 then start ! if # 2 then it is a service station. j = FTP stations(FTP line_station ptr)_connect retry ptr if j = 10 then j = 1 else j = j + 1 FTP stations(FTP line_station ptr)_connect retry ptr = j set document timers(FTP line_station ptr,connect retry times(j),0) !We must reset the connect retry delay after the failure for the !documents queued for this station. finish else start !we have a test site so if connection fails delete the document. remove from queue(FTP line_document,flag) delete FTP document(FTP line_document) FTP log(" TEST station, document deleted.".snl) finish FTP line_document = 0 finish if FTP line_in stream status = aborting start !This is a connect abort and the deallocate reply has not yet been recieved. !It can overtake and in this case we will be in suspended state. FTP line_in stream status = allocated FTP log("Connect (IN) fail reply after abort, Deallocate reply to come.".snl) if FTP line_out stream status = allocated then FTP log("OUT reply ". c "already recieved.".snl) return !We return since the Deallocate was issued to trigger this sequence so !we await the reply to it now. finish if FTP line_in stream status = suspending and FTP line_status = deallocating start !We have already had the deallocate reply but are hanging around for the !connect fail reply before freeing the line. FTP line_in stream status = unallocated ftp log("Connect IN reply on delayed line reuse(connect abort).".snl) if FTP line_out stream status = unallocated start ftp log("Both IN and OUT fail replies recieved.".snl) FTP line_status = unallocated kick ftp line(line) return finish return finish FTP line_in stream status = allocated if FTP line_out stream status = active then disconnect if FTP line_out stream status = allocated then deallocate return finish FTP line_in comms stream = p_p1 FTP line_in stream status = active if FTP line_out stream status = allocated then disconnect -> FTP pair connected if FTP line_out stream status = active return st(FTP output connected): !---------------------------------------------------------------------- !THE OUTPUT STREAM OF AN FTP PAIR IS CONNECTED. if FTP line_status = unallocated then FTP log( c " already deallocated on connect reply (fep down / connect attempt abort?)") if p_p2 # 0 then start !THE CONNECTION HAS FAILED. FTP log(" CONNECT (OUT) FAILS ".itos(p_p2).snl) if FTP line_station type = P station and FTP line_document # 0 start if FTP stations(FTP line_station ptr)_status # 2 then start !ie = 2 implies service, 2 is test only. j = FTP stations(FTP line_station ptr)_connect retry ptr if j = 10 then j = 1 else j = j + 1 FTP stations(FTP line_station ptr)_connect retry ptr = j set document timers(FTP line_station ptr,connect retry times(j),0) !We must reset the connect retry delay after the failure for the !documents queued for this station. finish else start !we have a test site so if connection fails delete the document. remove from queue(FTP line_document,flag) delete FTP document(FTP line_document) FTP log(" TEST station, document deleted.".snl) finish FTP line_document = 0 finish if FTP line_out stream status = aborting start !This is a connect abort and the deallocate reply has not yet been recieved. !It can overtake and in this case we will be in suspended state. FTP line_out stream status = allocated FTP log("Connect (OUT) fail reply after abort, Deallocate reply to come.".snl) if FTP line_in stream status = allocated then FTP log("IN reply ". c "already recieved.".snl) return !We return since the Deallocate was issued to trigger this sequence so !we await the reply to it now. finish if FTP line_out stream status = suspending and FTP line_status = deallocating start !We have already had the deallocate reply but are hanging around for the !connect fail reply before freeing the line. FTP line_out stream status = unallocated ftp log("Connect OUT reply on delayed line reuse(connect abort).".snl) if FTP line_in stream status = unallocated start ftp log("Both IN and OUT fail replies recieved.".snl) FTP line_status = unallocated kick ftp line(line) return finish return finish FTP line_out stream status = allocated if FTP line_in stream status = active then disconnect if FTP line_in stream status = allocated then deallocate return finish FTP line_out comms stream = p_p1 FTP line_out stream status = active if FTP line_in stream status = allocated then disconnect -> FTP pair connected if FTP line_in stream status = active return FTP pair connected: if FTP line_station ptr = 0 start !Timing problem ? select output(1) printstring(dt." ZERO station ptr for line ".itos(line)." on CONNECT OK".snl) select output(0) disconnect return finish FTP log(" negotiating") FTP line_bytes transferred = 0 FTP line_transfer status = viable FTP line_status = active FTP line_pre abort status = active !The pre abort status is always set to 'active' except when !an ABORT takes place when it is used to remember the status before the abort. FTP line_offset = 0 FTP line_abort retry count = 0 FTP line_timer = FTP default timeout FTP line_output transfer pending = no FTP line_output buffer status = ready FTP stations(FTP line_station ptr)_connect retry ptr = 0 set document timers(FTP line_station ptr, 0,0) !Ie if the connection succeeds then no need to have any 'penalty' wait !before the next connect. if FTP line_station type = p station start !WE HAVE AN FTP P STATION CONNECTED. document == record(document addr(FTP line_document)) create FTP work files(flag,no) if flag # 0 start printstring("FTP (".itos(table entry).") work file create fails ".i to s(flag).snl) FTP stations(control entry)_service = closed disconnect return finish if document_state # queued start printstring("User terminates ".FTP line_name.snl) FTP line_document = 0 FTP stations(FTP line_station ptr)_connect retry ptr = 0 set document timers(FTP line_station ptr,0,0) FTP line_station ptr = 0 disconnect return finish !This only happens if user deletes the document during the connect phase. remove from queue(FTP line_document,flag) if flag # 0 start FTP log(" Remove ".identtos(FTP line_document)." fails ".itos(flag)) FTP line_document = 0 FTP line_station ptr = 0 disconnect return finish document_state = transferring FTP line_data transfer start = current packed dt FTP lines(line)_user = document_user output buffer connect generate(FTP sft, 0, len) buffer disconnect if document_mode of access > x'8000' then s = "from" else s = "to" if FTP table_mail = no then c mail report(document_user.mail mc.snl.snl. c "To: ".document_user.mail mc.snl. c "From: TRANSFER [fail]".snl. c "Subject: ".s." ".string at(FTP stations(FTP line_station ptr),FTP stations c (FTP line_station ptr)_shortest name)." : ".docstring(document,document_name). c snl.snl."Transfer of ".identtos(FTP line_document)." ".docstring(document,document_name). c snl, 0) and FTP table_mail displ = mail dis + length(document_user)*2 c else mail report(document_user.mail mc.snl.snl. c "Keywords: " .snl."To:".document_user.mail mc.snl. c "From:FTPMAN".snl."Comments:FTP".snl."References:".docstring(document, c document_name).snl.snl, 0) and FTP table_mail displ = mail dis-11 enable out(FTP command, FTP p command sent, len,buffer offset,1, FTP line_out block addr) enable in(FTP command, FTP command overflow) FTP line_status = sft sent return finish else start !WE HAVE A CONNECT AS A FTP Q STATION. create FTP work files(flag,no) if flag # 0 start printstring("FTP (".itos(table entry).") work file create fails ".i to s(flag).snl) FTP stations(control entry)_service = closed disconnect return finish enable in(FTP command, FTP command overflow) FTP line_status = awaiting sft FTP line_data transfer start = current packed dt return finish st(FTP p command reply): !---------------------------------------------------------------------- !AN INCOMING FTP KICK FROM A Q STATION. WE WILL ALWAYS GET HERE AS A !OF A HIGH LEVEL CONTROL ON THE INPUT STREAM SINCE AN INCOMING !COMMAND SHOULD NEVER EXCEED THE BUFFER SIZE. unless FTP timeout = yes start !thi may have been entered as a rseult of timeout or abort in !which case we have no input to read. command length = p_p5 FTP line_timer = (FTP table_timeout_value+59)//60 input buffer connect output buffer connect interpret comm(type, transfer status) if messages # 0 start cycle flag = 1,1,messages mail report("From ".string at(FTP stations(FTP line_station ptr),FTP stations c (FTP line_station ptr)_shortest name).": ".message(flag)_s.snl,0) FTP log(" records info: ".message(flag)_s) repeat finish if type = x'FF' then abort FTP and return !The command structure was corrupted. finish ! if FTP line_status = sft sent start !WE HAVE SENT AN SFT, THIS SHOULD BE OUR REPLY. if FTP stations(control entry)_limit < FTP stations(FTP line_station ptr)_limit then c limit = FTP stations(control entry)_limit else limit = FTP stations(FTP line_station ptr)_limit if 2 < mon level < 5 or mon level = 6 then monitoring = on else monitoring = off evaluate negotiation( command start, reply start, len, limit, type) if type = FTP rneg or type = FTP rpos start FTP stations(FTP line_station ptr)_last response = current packed dt FTP stations(FTP line_station ptr)_last call = 0 FTP stations(FTP line_station ptr)_connect attempts = 0 finish if type = FTP rneg start !OH WELL document == record(document addr(FTP line_document)) if document_FTP user flags & FTP no mail # 0 then FTP table_mail to send = no if transfer status # rejected deferred start if document_auto requeue = yes then ftp log(" ".ident to s(ftp line_document). c " requeued after RNEG (AUTO REQUEUE)".snl) else start FTP log(" transfer not viable..Deleting document.") document_FTP retry level = 0 finish finish FTP line_transfer status = transfer status !the evaluation will have built the STOP. format command(reply start,0,len,1) !so format it for FTP buffer disconnect enable out(FTP command, FTP p command sent, len,buffer offset,1, FTP line_out block addr) enable in(FTP command, FTP command overflow) FTP line_status = stop sent return finish if type = FTP rpos start !SO FAR SO GOOD. !note transfer remains viable. generate(FTP go, 0, len) buffer disconnect enable out(FTP command, FTP p command sent, len,buffer offset,1, FTP line_out block addr) enable in(FTP table_data control, FTP data input) FTP line_status = go sent return finish !after SFT SENT no other response is acceptable. FTP log(" SFT sent invalid response ".itos(type)) buffer disconnect abort FTP return finish ! if FTP line_status = stop sent start !WE ARE EXPECTING A STOP ACKNOWLEDGMENT if type = FTP stopack start buffer disconnect document == record(document addr(FTP line_document)) if FTP line_document # 0 !we first check to see if we had SFT->RNEG->STOP->STOPACK !sequence and if so decide if we can try another SFT (Usually !this happens if we first tried EMASTOEMAS private code) if rejected info <= FTP line_transfer status <= rejected attribute start !indeed it rejected attribute, was it an EMASTOEMAS call, if so !we could try open working... document_FTP retry level = 0 if document_auto requeue = no if FTP table_emas to emas = rejected and document_try emastoemas = yes start document_try emas to emas = no FTP log(" reports EMASTOEMAS rejection.") document_FTP retry level = 3 finish finish if transfer status = x'FF' then transfer status = FTP line_transfer status !We assume that, if no status is sent on the STOPACK, it is agreement. if FTP line_transfer status = aborted retry possible and c transfer status = aborted no retry then FTP line_transfer status = transfer status !ie agree to wishes of Q station on this point. !otherwise we have either failed completely or succeeded so clear up if FTP line_transfer status = satisfactory termination and c transfer status < aborted no retry then start state = " ok "; mail state = "0" if transfer status # satisfactory termination start !We have got a problem message back status x'2001' state = "fail" mail state = "1" finish if FTP line_document # 0 start if document_auto requeue = yes start ftp log(" ".ident to s(FTP line_document)." requeued after success ". c "(AUTO REQUEUE)".snl) requeue FTP document(FTP line_document,0,no,no) finish else delete FTP document(FTP line_document) finish if FTP table_mail = yes then mail report(mail state,FTP table_mail displ) c else mail report(state, FTP table_mail displ); !set keyword for mailer or the OK status. if FTP line_document # 0 and document_FTP user flags & FTP fail mail # 0 c then FTP table_mail to send = no if transfer status # satisfactory termination then mail report( c date." ".time." Transfer fails, see information from the External System".snl,0) c else mail report(date." ".time." Transfer successful".snl,0) seconds = current packed dt seconds = seconds - ftp line_data transfer start if ((FTP stations(FTP line_station ptr)_bytes + FTP line_ c bytes transferred) >>10 ) > 5000 start select output(1) printstring(dt."FTP Transfer rate for ".string at(FTP stations(FTP line c _station ptr),ftp stations(FTP line_station ptr)_shortest name)." has been ") rate =FTP stations(FTP line_station ptr)_bytes//FTP stations(FTP line_station ptr)_seconds printstring(itos(rate)." bytes/second") newline select output(0) FTP stations(FTP line_station ptr)_bytes = 0 FTP stations(FTP line_station ptr)_seconds = 0 finish FTP stations(FTP line_station ptr)_bytes = FTP stations(FTP line_ c station ptr)_bytes + FTP line_bytes transferred FTP stations(FTP line_station ptr)_seconds = FTP stations(FTP line_ c station ptr)_seconds + seconds if FTP line_activity = sender then s = "to " else s = "from " if FTP stations(FTP line_station ptr)_status = 1 then ss = " charge" else ss = "" if transfer status = satisfactory termination then start FTP log(" P ACCOUNT: ".FTP line_user." transfers ". c itos((FTP line_bytes transferred+1023)>>10)."k ".s.string at(FTP stations c (FTP line_station ptr),FTP stations(FTP line_station ptr)_shortest name).ss) FTP stations(FTP line_station ptr)_P transfers = FTP stations( c FTP line_station ptr)_P transfers + 1 FTP stations(FTP line_station ptr)_P kb = FTP stations(FTP line_station ptr)_ c P kb + (FTP line_bytes transferred+1023)>>10 if ftp table_mail = yes then FTP stations(FTP line_station ptr)_ c P mail = FTP stations(FTP line_station ptr)_P mail + 1 finish finish else start unless FTP line_transfer status = rejected deferred start if document_auto requeue = no start document_FTP retry level = document_FTP retry level-1 if c document_FTP retry level > 0 finish finish if FTP line_transfer status = aborted no retry and c document_auto requeue = no then document_FTP retry level = 0 !NOTE that when 'no resumption' is negotiated and I send back a !'aborted retry possible' then that means retry in new transfer at beginning if document_FTP retry level = 0 then start FTP log(" transfer fails, attempts exhausted..Deleting.") if FTP table_mail = yes then mail report("1",FTP table_mail displ); !set keyword for mailer. mail report("Transfer fails and has been deleted.".snl,0) delete FTP document(FTP line_document) finish else start if FTP line_transfer status = rejected deferred then delay = deferred delay c else if document_auto requeue = yes then delay = auto poll delay c else delay = transfer fail delay requeue FTP document(FTP line_document,delay,no,yes) FTP table_mail to send = no finish finish if FTP line_aux document # 0 then delete FTP document( c FTP line_aux document) and FTP line_aux document = 0 FTP line_document = 0 !here we now have the option to leave the transport service open !but our implementation will not as yet for the P stations. if FTP timeout = yes then abort FTP else disconnect return finish !No other response acceptable. FTP log(" STOP sent invalid response ".itos(type)) buffer disconnect abort FTP return finish !should never get here, if we do it is a FTRANS, not FTP, fault FTP log(" P station error, invalid state ".itos(FTP line_status)) buffer disconnect abort FTP return st(FTP p command sent): !---------------------------------------------------------------------- !A BLOCK HAS BEEN SENT TO A Q STATION. FTP line_timer = (FTP table_timeout_value+59)//60 FTP line_output buffer status = ready if FTP line_output transfer pending = yes start !we have an enable waiting to go. flag = dpon3("",FTP line_output transfer record,0, 0,6) FTP line_output buffer status = already enabled FTP line_output transfer pending = no FTP log(" pending transfer cleared.") finish ! if FTP line_status = sft sent or FTP line_status = stop sent c or FTP line_status = end of data sent then return ! if FTP line_status = quit sent start if aborted no retry <= FTP line_transfer status <= aborted retry possible c and FTP line_tcc subtype = awaiting data then abort FTP !If the transfer has timed out (we are receiver) then we have to !drag the line down when we have sent the quit since we cannot do !a complete abort of the data input which will screw us up(TS will !help perhaps with data resets ?) return finish ! if FTP line_status = transmitting data start send block(FTP p command sent, flag) if flag # 0 start !we have a sender error output buffer connect FTP line_tcc subtype = S error no resume generate(FTP es, S error no resume, len) mail report("Local Transmission failure".snl,0) buffer disconnect enable out(FTP data,FTP p command sent,len,buffer offset,1,FTP line_out block addr) FTP line_status = end of data sent return finish return finish ! output buffer connect ! if FTP line_status = go sent then start !AS A P STATION WE ARE READY TO RECEIVE OR TRANSMIT DATA. document == record(document addr(FTP line_document)) if document_FTP user flags & FTP no mail # 0 then FTP table_mail to send = no if FTP line_activity = sender start !WE ARE TO TRANSMIT A FILE. if FTP table_data control # no translation start !We need a work area for local translation. s = "LINEWRK".i to s(table entry) if TARGET # 2900 then flag = dcreate(my name, s, FTP line_document>>24, c ((block size//FTP emas to emas block division)*2)>>10, zerod!tempfi, ada) c else flag = dcreate(my name,s,FTP line_document>>24,((block size// c FTP emastoemas block division)*2)>>10, zerod!tempfi) !We assume the emastoemas blocks to be larger. flag = 0 if flag = already exists if flag # 0 start FTP log(" DCREATE translate work file fails ".errs(flag)) buffer disconnect abort FTP return finish finish if FTP table_emastoemas = yes and document_data start # 0 then c document_data length = document_data length + document_data start !This is done since we are to send the whole file including header. FTP line_bytes to go = document_data length if FTP table_emastoemas = yes then document_data start = 0 !We can safetly do this since if the negotiation is for inter emas !now then it surely will be next time(should this transfer fail). FTP line_block = (document_data start+block size)//block size FTP line_part blocks = 0 FTP line_vrecord length = 0 FTP line_split vrecord length = no FTP line_vbytes to go = 0 if FTP table_data type_value = x'0002' and FTP table_binary data c record & x'03' = 3 {UNSTRUCTURED BINARy DATA} start !It will go as tho it were a single record VARIABLE length record file. FTP line_Vrecord length = document_data length FTP line_vbytes to go = document_data length finish finish else start !WE ARE TO RECEIVE A FILE. if FTP table_file size_set = yes start if FTP table_file size_value < 64 then size = FTP table_file size_value else c if FTP table_file size_value <= block size>>10 then size = block size>>10 c else size = FTP table_file size_value finish else size = block size>>10 if TARGET # 2900 then flag = dcreate(my name, identtos(FTP line_document), c FTP line_document>>24, size, 0, ada) else c flag = dcreate(my name, identtos(FTP line_document), FTP line_document>>24, size, 0) unless flag = 0 or flag = already exists then start FTP line_tcc subtype = R error no resume FTP log(" fails to create recieving file ".itos(flag)) mail report("Local Receiver failure".snl,0) generate(FTP qr, R error no resume, len) buffer disconnect enable out(FTP data,FTP p command sent,len,buffer offset,1,FTP line_out block addr) enable in(FTP table_data control,FTP data input) FTP line_status = quit sent return finish document_data length = -1 FTP line_block = 0 FTP line_part blocks = 0 FTP line_bytes to go = 0 FTP line_parity = yes {We assume any parity until otherwise informed by a CS} FTP line_new FTP data record = yes !This field is used to indicate that the next block of data is the start of a new !FTP RECORD and (TEXT-FORMAT x0002 only) has ANSI control char at start. !Now initialise the fields that will be used if it is BINARY receive FTP line_records received = 0 FTP line_current vrecord length = 0 FTP line_current vrecord length addr = 0 FTP line_known to have records = 0 finish FTP line_bytes sent = 0 if FTP line_activity = receiver then FTP line_status = receiving c data and buffer disconnect and FTP line_timer = (FTP table_timeout_value+59)//60 and return !OTHERWISE WE ARE READY TO BEGIN TRANSMITTING A FILE generate(FTP ss, 0, len) if FTP table_emastoemas = yes then generate(FTP cs,x'C3',len) else c if FTP table_data type_value = x'0002' then generate(FTP cs,x'01',len) c else generate(FTP cs, X'C0', len) {This being zero parity IA5} buffer disconnect enable out(FTP data, FTP p command sent, len,buffer offset,1, FTP line_out block addr) FTP line_status = transmitting data return finish ! if FTP line_status = last block sent then start !WE HAVE ALREADY SENT THE LAST DATA BLOCK. if FTP table_data control # no translation then flag = ddestroy( c my name,"LINEWRK".itos(table entry),"",FTP line_document>>24,0) generate(FTP es, ok, len) buffer disconnect enable out(FTP data, FTP p command sent, len,buffer offset,1, FTP line_out block addr) FTP line_status = end of data sent FTP line_tcc subtype = ok; !ie ER[OK] sent. return finish ! if FTP line_status= end of data acknowledge sent start generate(FTP stop, 0, len) buffer disconnect enable out(FTP command, FTP p command sent, len,buffer offset,1, FTP line_out block addr) enable in(FTP command, FTP command overflow) FTP line_status = stop sent return finish buffer disconnect FTP log(" P station invalid command sent kick ".itos( c FTP line_status)) abort FTP return st(FTP q command reply): !---------------------------------------------------------------------- !INCOMMING BLOCK FROM A P STATION command length = p_p5 FTP line_timer = (FTP table_timeout_value+59)//60 input buffer connect output buffer connect interpret comm(type, transfer status) if messages # 0 start cycle flag = 1,1,messages FTP log(" records info: ".message(flag)_s) repeat finish if type = x'FF' then abort FTP and return !Command structure corrupted. ! if FTP line_status = awaiting sft start !WE ARE WAITING FOR THE P STATION TO SEND THE SFT if type = FTP sft start !THATS WHAT IT IS. FTP stations(FTP line_station ptr)_last q response by us = current packed dt if FTP stations(control entry)_limit < FTP stations(FTP line_station ptr)_limit then c limit = FTP stations(control entry)_limit else limit = FTP stations(FTP line_station ptr)_limit old len = len if 2 < mon level < 5 or mon level = 6 then monitoring = on else monitoring = off evaluate negotiation( command start, reply start, len, limit, type) !the evaluation will have built a RPOS or RNEG if FTP table_mode_value = take job input and type = FTP RPOS start !This is an incoming job..deal with the job scheduling here and change the !response to RNEG if necessary. work string = "DEST=BATCHFROMFTP,USER=".FTP table_username_value.",PASS=" work string = work string.FTP table_username password_value.",NAME=" if FTP table_filename_set = no then workstring = workstring."FTP_JOB" else workstring = work string. c FTP table_filename_value if FTP table_special options_set = yes start s1 = FTP table_special options_value if s1 -> s3.("PASS=").s2.(",").ss then s1 = s3.ss else c if s1 -> s3.("PASS=").s2 then s1 = s3 FTP table_special options_value = s1 select output(1) FTP log(" JOB input params: ".s1) select output(0) workstring <- workstring.",".s1 finish j = length(workstring) interpret descriptor(job call, addr(workstring)+1,j,"",FTP line_document,flag) if flag # 0 start FTP table_stopack message = "Job scheduling rejected." type = FTP RNEG FTP line_transfer status = rejected info len = old len FTP log("Job transfer rejected (".workstring.").") generate(type,0,len) finish else FTP log("JOB transfer accepted.") finish format command(reply start,0,len,1); !format it buffer disconnect enable out(FTP command, FTP q command sent, len,buffer offset,1, FTP line_out block addr) enable in(FTP command, FTP command overflow) if type = FTP rpos then start FTP line_status = rpos sent if ftp line_activity # sender and ftp table_mode_value = c take job output start ss = "to device " if ftp table_device type_set = yes start if ftp table_device type_value -> s1.("@").s then ss = ss.s1 else c ss = ss.ftp table_device type_value finish finish else if ftp line_activity # sender and ftp table_ c mode_value = take job input start ss = "of Job " if ftp table_filename_set = yes then ss = ss." ".ftp table_filename_value finish else ss = "of ".ftp table_filename_value if FTP line_activity = sender then s = "to " else s = "from" mail report(FTP table_username_value.mail mc.snl.snl. c "To: ".FTP table_username_value.mail mc. c snl."From: TRANSFER [ ok ]".snl.c "Subject: ".s." ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name)." : ". c FTP table_filename_value. c snl.snl."Externally initiated Transfer ".ss.snl,0) FTP table_mail displ = mail dis + length(FTP table_username_value)*2 if FTP table_username_value = "FTPMAN" and FTP table_mode_value = take job output c then FTP table_mail to send = no finish else start FTP line_status = rneg sent FTP line_transfer status = transfer status finish return finish FTP log(" expected SFT but got a ".itos(type)) buffer disconnect abort FTP return finish ! if FTP line_status = rneg sent or FTP line_status = awaiting stop start if type = FTP stop start if transfer status = x'FF' start if FTP line_status = awaiting stop start if FTP line_transfer status = satisfactory termination then c s = ", x'2000' :success assumed" and transfer status = satisfactory termination c else s = ", failure, x'3011' assumed" and transfer status = aborted retry possible finish else s = " after RNEG" FTP log(" No transfer status on STOP".s) finish if FTP line_status = awaiting stop and transfer status # c FTP line_transfer status then FTP log(" P station disagrees on TRANSFER-STATUS") FTP line_transfer status = transfer status unless FTP line_transfer status = aborted no retry !Agree with P unless we know that a retry is of no use. if transfer status = satisfactory termination start seconds = current packed dt seconds = seconds - ftp line_data transfer start if ((FTP stations(FTP line_station ptr)_bytes + FTP line_ c bytes transferred) >>10 ) > 2000 start FTP stations(FTP line_station ptr)_bytes = 0 FTP stations(FTP line_station ptr)_seconds = 0 finish FTP stations(FTP line_station ptr)_bytes = FTP stations(FTP line_ c station ptr)_bytes + FTP line_bytes transferred FTP stations(FTP line_station ptr)_seconds = FTP stations(FTP line_ c station ptr)_seconds + seconds mail report(date." ".time." Transfer Successful".snl,0) if FTP line_activity = sender then s = "to " else s = "from " if FTP stations(FTP line_station ptr)_status = 1 then ss = " (charge)" else ss = "" FTP log(" Q ACCOUNT: ".FTP table_username_value." transfers ". c itos((FTP line_bytes transferred+1023)>>10)."k ".s.string at(FTP stations c (FTP line_station ptr),FTP stations(FTP line_station ptr)_shortest name).ss) FTP stations(FTP line_station ptr)_Q transfers = FTP stations( c FTP line_station ptr)_Q transfers + 1 FTP stations(FTP line_station ptr)_Q kb = FTP stations(FTP line_station ptr)_ c Q kb + (FTP line_bytes transferred+1023)>>10 if ftp table_mail = yes then FTP stations(FTP line_station ptr)_ c Q mail = FTP stations(FTP line_station ptr)_Q mail + 1 finish else FTP table_mail to send = no generate(FTP stopack, 0, len) buffer disconnect enable out(FTP command, FTP q command sent, len,buffer offset,1, FTP line_out block addr) FTP line_status = stopack sent FTP line_timer = 2 !only have 2 min timeout here. return finish FTP log(" expected STOP but got a ".itos(type)) buffer disconnect abort FTP return finish ! if FTP line_status = rpos sent start if type = FTP go start !we have had a go from the p station so complete the transfer setup. ident = get next descriptor(FTP table_user fsys) if ident = 0 then start FTPlog(FTP line_name." no free descriptors!") s = "EMAS sys error" ->halt transfer finish FTP line_block = 0 FTP line_part blocks = 0 FTP line_bytes sent = 0 FTP line_bytes to go = 0 FTP line_user = FTP table_username_value if FTP line_activity = sender start !we are to send the file. if FTP table_data control # no translation start !the file needs to be pre processed. s = "LINEWRK".i to s(table entry) if TARGET # 2900 then flag = dcreate(my name,s,FTP table_user fsys, (( c block size//FTP emastoemas block division)*2)>>10,zerod!tempfi,ada) c else flag = dcreate(my name,s,FTP table_user fsys,((block size// c FTP emastoemas block division)*2)>>10, zerod!tempfi) !We assume the emastoemas blocks to be larger. flag = 0 if flag = already exists if flag # 0 start FTP log(" DCREATE translate work file fails ".errs(flag)) buffer disconnect abort FTP finish finish !otherwise we can send the file as it is flag = dtransfer(FTP table_username_value,my name,FTP table_filename_value, c ident to s(ident),FTP table_user fsys,FTP table_user fsys,3) if flag # 0 start FTP log(" DTRANSFER ".FTP table_username_value.".". c FTP table_filename_value." fails ".errs(flag)) s = "User file not FTP available" -> halt transfer finish document == record(document addr(ident)) document = 0 document_priority requested = 3; !std document_string ptr = 1 document_dest = FTP work dest FTP line_document = ident document_user = FTP table_username_value seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(my name,ident to s(ident),FTP table_user fsys, c r!w,seg,gap) else c flag = dconnect(my name,ident to s(ident),FTP table_user fsys, c r!w,0,seg,gap) if flag # 0 start FTP log(" DCONNECT ".ident tos(ident)." fails ". c errs(flag)) s = "EMAS sys error" -> halt transfer finish file header == record(seg<<seg shift) if FTP table_emastoemas = yes then document_data start = 0 else c document_data start = file header_start document_data length = file header_end - document_data start flag = ddisconnect(my name,ident to s(ident),FTP table_user fsys,0) FTP line_bytes to go = document_data length FTP line_block = (document_data start+block size)//block size FTP line_part blocks = 0 FTP line_vrecord length = 0 FTP line_split vrecord length = no FTP line_vbytes to go = 0 if FTP table_data type_value = x'0002' and FTP table_binary data c record & x'03' = 3 {UNSTRUCTURED BINARy DATA} start !It will go as tho it were a single record VARIABLE length record file. FTP line_Vrecord length = document_data length FTP line_vbytes to go = document_data length finish finish else start if FTP table_file size_set = yes start if FTP table_file size_value < 64 then size = FTP table_file size_value else c if FTP table_file size_value <= block size>>10 then size = block size>>10 c else size = FTP table_file size_value finish else size = block size>>10 if TARGET # 2900 then flag = dcreate(my name,ident to s(ident), c FTP table_user fsys,size,0,ada) else c flag = dcreate(my name,ident to s(ident),FTP table_user fsys,size,0) unless flag = 0 or flag = already exists start FTP log(" DCREATE ".identtos(ident)." fails ".errs(flag)) s = "EMAS sys error" -> halt transfer finish document == record(document addr(ident)) document = 0 document_priority = 1; !the lowest possible document_string ptr = 1 document_dest = FTP work dest if FTP table_device type_set = yes then to docstring( c document,document_name,FTP table_device type_value) else c to docstring(document,document_name,FTP table_filename_value) document_user = FTP table_username_value document_data length = -1 FTP line_new FTP data record = yes FTP line_document = ident buffer disconnect enable in(FTP table_data control, FTP data input) FTP line_status = receiving data FTP line_parity = yes {Assume no parity until otherwise informed by a CS} FTP line_timer = (FTP table_timeout_value+59)//60 !Now initialise the fields that will be used if it is BINARY receive. FTP line_records received = 0 FTP line_current vrecord length = 0 FTP line_current vrecord length addr = 0 FTP line_known to have records = 0 return finish generate(FTP ss, 0, len) if FTP table_emastoemas = yes then generate(FTP cs,x'C3',len) else c if FTP table_data type_value = x'0002' then generate(FTP cs,x'01',len) c else generate(FTP cs, X'C0', len) {being zero parity IA5} buffer disconnect enable out(FTP data, FTP q command sent, len,buffer offset,1, FTP line_out block addr) enable in(FTP table_data control, FTP data input) FTP line_status = transmitting data return finish if type = FTP stop start !we have a STOP after sending a RPOS, report on the response. if 2 < mon level < 5 or mon level = 6 then monitoring = on else monitoring = off evaluate negotiation(command start, reply start,len,limit,type) FTP line_transfer status = transfer status FTP table_mail to send = no generate(FTP stopack, 0, len) buffer disconnect enable out(FTP command, FTP q command sent, len,buffer offset,1, FTP line_out block addr) FTP line_status = stopack sent return finish FTP log(" gets invalid response to RPOS ".itos(type)) abort FTP return finish !we should never get here. FTP log(" Q station error, invalid state ". c i to s(FTP line_status)) buffer disconnect abort FTP return halt transfer: if FTP line_activity = sender start FTP line_tcc subtype = S error no resume mail report("Local Transmission failure".snl,0) generate(FTP es,S error no resume,len) buffer disconnect enable in(FTP table_data control,FTP data input) enable out(FTP data,FTP q command sent,len,buffer offset,1,FTP line_out block addr) FTP line_status = end of data sent return finish else start FTP line_tcc subtype = R error no resume mail report("Local Receiver failure".snl,0) generate(FTP qr, R error no resume,len) buffer disconnect enable out(FTP data,FTP q command sent,len,buffer offset,1,FTP line_out block addr) enable in(FTP table_data control,FTP data input) FTP line_status = quit sent return finish st(FTP q command sent): !---------------------------------------------------------------------- !A BLOCK HAS BEEN SENT TO A P STATION. FTP line_timer = (FTP table_timeout_value+59)//60 FTP line_output buffer status = ready if FTP line_output transfer pending = yes start !we have an enable waiting to go. flag = dpon3("",FTP line_output transfer record,0, 0,6) FTP line_output buffer status = already enabled FTP line_output transfer pending = no FTP log(" pending transfer cleared.") finish ! if FTP line_status = rpos sent or FTP line_status = rneg sent or c FTP line_status = end of data sent or FTP line_status = awaiting stop then return ! if FTP line_status = quit sent start if aborted no retry <= FTP line_transfer status <= aborted retry possible c and FTP line_tcc subtype = awaiting data then abort FTP !see p command sent for explanation. return finish ! if FTP line_status = stopack sent start !we have either failed completely or succeeded so clear up if FTP line_transfer status = satisfactory termination start if FTP table_mail to send = yes then send mail FTP table_mail to send = no FTP log(" Transaction terminates successfully.") finish delete FTP document(FTP line_document) if FTP line_document # 0 FTP line_document = 0 FTP line_status = awaiting sft enable in(FTP command,FTP command overflow) !ie we keep the transport service open and time out if no more from !the P station ( or indeed the P station may close the service and !we will get a line down) FTP line_timer = 1; !only keep open for one tick. FTP log(" negotiating") FTP line_bytes transferred = 0 FTP line_transfer status = viable FTP line_pre abort status = awaiting sft !The pre abort status is always set to 'active' except when !an ABORT takes place when it is used to remember the status before the abort. FTP line_offset = 0 FTP line_abort retry count = 0 FTP line_output transfer pending = no FTP line_output buffer status = ready FTP log(" records Q station transaction ends. WAITING.") return finish ! if FTP line_status = transmitting data start send block(FTP q command sent, flag) if flag # 0 start !we have a sender error. output buffer connect FTP line_tcc subtype = S error no resume mail report("Local Transmission failure".snl,0) generate(FTP es, S error no resume, len) buffer disconnect enable out(FTP data,FTP q command sent,len,buffer offset,1,FTP line_out block addr) FTP line_status = end of data sent return finish return finish ! if FTP line_status = last block sent start output buffer connect if FTP table_data control # no translation then flag = ddestroy( c my name,"LINEWRK".itos(table entry),"",FTP table_user fsys,0) generate(FTP es, 0, len) buffer disconnect enable out(FTP data, FTP q command sent, len,buffer offset,1, FTP line_out block addr) FTP line_status = end of data sent FTP line_tcc subtype = ok return finish ! if FTP line_status = end of data acknowledge sent start enable in(FTP command,FTP command overflow) FTP line_status = awaiting stop return finish !Cannot be anything else. FTP log(" Q station invalid command sent kick ".itos(FTP line_status)) abort FTP return st(FTP data input): !-------------------------------------------------------------------- !WE HAVE DATA TYPE OR TCC IPUT FOR FTP ! data length = p_p5 + FTP line_offset FTP line_offset = 0 FTP line_timer = (FTP table_timeout_value+59)//60 input buffer connect output buffer connect if FTP line_station type = p station then c command sent activity = FTP p command sent else c command sent activity = FTP q command sent ! if FTP line_status = receiving data or FTP line_status = quit sent start if FTP line_suspend = yes start !we have a suspend forced by tcc input interpret tcc(type, subtype) if type = FTP es start !we have ES[nn] from the sender if subtype = hold start !we have a hold response from our QR[H] buffer disconnect monitor and return finish if FTP data error <= subtype < FTP data abort start FTP line_transfer status = aborted retry possible unless FTP line_transfer c status = aborted no retry FTP log(" records ES[E] ".FTP errors(subtype)) mail report("Transmission failure at ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).snl,0) c unless FTP line_status = quit sent if FTP line_status = quit sent and FTP line_tcc subtype > FTP data error c then FTP line_status = receiving data !we do this to allow us to drop thro' and send an ER[E] FTP line_tcc subtype = subtype finish if subtype >= FTP data abort start !we have a sender instigated abort ES[A] FTP log(" records ES[A] ".FTP errors(subtype)) mail report("Transmission failure at ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).snl,0) FTP line_transfer status = aborted retry possible if FTP line_station type = p station start generate(FTP stop, 0, len) buffer disconnect enable out(FTP command,command sent activity,len,buffer offset,1, c FTP line_out block addr) enable in(FTP command,FTP command overflow) FTP line_status = stop sent finish else start buffer disconnect enable in(FTP command,FTP command overflow) FTP line_status = awaiting stop finish FTP line_suspend = no return finish if subtype = ok start if FTP line_status = quit sent and FTP line_tcc subtype > c FTP data error start !ie we have received a ES[OK] when the last we sent was QR[E] !so we ditch the input an wait for the ES[E]. buffer disconnect enable in(FTP table_data control,FTP data input) FTP line_suspend = no return finish !otherwise the ES[E] drops through to be handled after data check. finish finish else start unless type = FTP ss or type = FTP ms start !We let MS and SS drop through..any other trap here...We must !not ES[nn] so what is it ? if type = FTP CS start !It is a CODE SELECT if sub type & x'0F' = x'01' and FTP table_data type_value c # x'0002' {BINARY} then FTP log(" reports CS BINARY in non BINARY transfer") c and -> rec quit if sub type&X'03' = 2 then c ftp log(" reports CS not IA5 or PRIVATE CODE or BINARY on receive.") c and -> rec quit if sub type&X'F0' = X'C0' then ftp log(" reports NO PARITY". c " set on data receive.") and FTP line_parity = no finish else start FTP log(" records protocol error, TCC not ES whilst receiving") rec quit: generate(FTP qr, protocol R detected, len) FTP line_tcc subtype = protocol R detected buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1, c FTP line_out block addr) enable in(FTP table_data control,FTP data input) FTP line_transfer status = aborted retry possible FTP line_status = quit sent FTP line_suspend = no return finish finish FTP line_suspend = no finish finish if data length > 0 and FTP line_transfer status = viable start !only handle the data if the transfer is still viable. unless FTP line_status = quit sent and FTP line_tcc subtype > FTP data error start !should not handle the actual data if we have sent a QR[E] flag = accept block if flag # 0 start !we have detected a receiver error. FTP line_tcc subtype = flag mail report("Local Receiver failure".snl,0) generate(FTP qr, FTP line_tcc subtype, len) buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1,FTP line_out block addr) enable in(FTP table_data control,FTP data input) FTP line_status = quit sent FTP line_suspend = no return finish finish finish if FTP line_suspend = yes start !we have ahd an ES[OK] or an ES[E] FTP line_suspend = no if subtype = OK start !ie we have ES[OK] complete file handling(flag,s) if flag = -1 start !The transfer must invoke spooler so put the line to sleep for reply. FTP line_timer = 4 return finish spooler reply received: if flag # ok start !the transfer failed for some reason FTP log(" cannot complete transfer ".itos(flag)) FTP line_transfer status = aborted no retry mail report("Local Receiver failure ".errs(flag).snl,0) unless flag = 1 generate(FTP qr, R error no resume, len) if FTP line_station type = q station and s # "" c then FTP table_stopack message <- s FTP line_tcc subtype = R error no resume FTP line_status = quit sent finish else start !the transfer is complete as far as receiver is concerned FTP line_transfer status = satisfactory termination FTP line_tcc subtype = ok generate(FTP er, ok, len) finish finish else generate(FTP er, subtype, len) buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1,c FTP line_out block addr) if FTP line_status = quit sent then c enable in(FTP table_data control,FTP data input) else c FTP line_status = end of data acknowledge sent return finish buffer disconnect enable in(FTP table_data control,FTP data input) return finish ! if FTP line_status = end of data sent start !we have sent ES[nn] to the sender !and sre awaiting response. if FTP line_suspend = yes start !there must be a tcc if we have been suspended here. FTP line_suspend = no interpret tcc(type, subtype) if type = FTP er start !we have a tcc of ER[nn] if subtype = hold start if FTP line_tcc subtype # hold start !we should only have a ER[H] after a hold request. FTP log(" records ER[H] after ES[nn]") -> sender invalid command finish else start buffer disconnect monitor and return finish finish if subtype >= FTP data error start !we have an ER[E] from the receiver. if FTP line_tcc subtype >= FTP data error start !this is a response to out generated ES[E] FTP log(" records ER[E] ".FTP errors(subtype)) FTP line_transfer status = aborted retry possible finish else start !we have not sent ES[E] so fail. FTP log(" records ER[E] after ES[OK]") -> sender invalid command finish finish if subtype = ok then FTP line_transfer status = satisfactory termination if FTP line_station type = p station start generate(FTP stop, 0, len) buffer disconnect enable out(FTP command,command sent activity,len,buffer offset,1, c FTP line_out block addr) enable in(FTP command,FTP command overflow) FTP line_status = stop sent finish else start buffer disconnect enable in(FTP command,FTP command overflow) FTP line_status = awaiting stop finish return finish if type = FTP qr start !we have a receiver issued quit QR[nn] if subtype = hold start if FTP line_tcc subtype = ok start !acceptable state. buffer disconnect monitor and return finish else start ! ?? buffer disconnect monitor and return finish finish if subtype = ok start !stay as we are. buffer disconnect enable in(FTP table_data control,FTP data input) return finish if FTP data error <= subtype < FTP data abort start !we have a QR[E] from the receiver. FTP log(" records QR[E] ".FTP errors(subtype)) mail report("Receiver failure at ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).snl,0) if FTP line_tcc subtype = ok start !we have sent ES[OK] generate(FTP es, subtype, len) buffer disconnect if FTP line_output buffer status = already enabled then disable out(abort, FTP output aborted) enable out(FTP data,command sent activity,len,buffer offset,1, c FTP line_out block addr) finish !if we have sent ES[E] remain as we are. !but record the new failure subtype. FTP line_tcc subtype = subtype buffer disconnect enable in(FTP table_data control,FTP data input) return finish if subtype >= FTP data abort start !an abort has arrived from the receiver, QR[A] !we treat this the same for ES[OK] & ES[E] states. FTP log(" records QR[A] ".FTP aborts(subtype)) mail report("Receiver failure at ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).snl,0) FTP line_transfer status = aborted retry possible if FTP line_output buffer status = already enabled then c disable out(abort, FTP output aborted) !this will cause the current output to be aborted and then !if we are next to send a STOP (below) it will then be enabled. if FTP line_station type = p station start generate(FTP stop, 0, len) buffer disconnect enable out(FTP command,command sent activity,len,buffer offset,1, c FTP line_out block addr) enable in(FTP command,FTP command overflow) FTP line_status = stop sent finish else start buffer disconnect enable in(FTP command,FTP command overflow) FTP line_status = awaiting stop finish return finish finish finish !anything else is in protocol violation. -> sender invalid command finish ! if FTP line_status = transmitting data or FTP line_status = last block sent start !we are currently sending data. if FTP line_suspend = yes start !we must have a tcc input. FTP line_suspend = no interpret tcc(type, subtype) if type = FTP qr start !we have a quit from the receiver. if subtype >= FTP data abort start !abort requested by receiver, QR[A] FTP log(" records QR[A] ".FTP aborts(subtype)) mail report("Receiver failure at ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).snl,0) FTP line_transfer status = aborted retry possible if FTP line_output buffer status = already enabled then c disable out(abort, FTP output aborted) !ie if the output is enabled then abort it and on abort the STOP which ! (may be) generated below is enabled. if FTP line_station type = p station start generate(FTP stop, 0, len) buffer disconnect enable out(FTP command,command sent activity,len,buffer offset,1, c FTP line_out block addr) enable in(FTP command,FTP command overflow) FTP line_status = stop sent finish else start buffer disconnect enable in(FTP command,FTP command overflow) FTP line_status = awaiting stop finish return finish if subtype >= FTP data error start !error reported by receiving station. QR[E] FTP log(" records QR[E] ".FTP errors(subtype)) mail report("Receiver failure at ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).snl,0) FTP line_tcc subtype = subtype generate(FTP es, subtype, len) buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1, c FTP line_out block addr) enable in(FTP table_data control,FTP data input) FTP line_status = end of data sent return finish if subtype = hold start !QR[H] buffer disconnect monitor and return finish if subtype = ok start !QR[OK] received, act as per protocol FTP log(" records QR[OK] ?") generate(FTP es, ok, len) FTP line_tcc subtype = ok buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1, c FTP line_out block addr) enable in(FTP table_data control,FTP data input) FTP line_status = end of data sent return finish finish finish !any other command is in protocol violation -> sender invalid command finish !Else we are in a bit of trouble, perhaps we have had a race condition !between an abort and an enable response...What else? An ABORT will be the way !out even if the race condition is the cause (since the abort will not be !reissued and the original aborts reply, whatever status, will suffice to close) FTP log(" invalid state for data input ". c stream status type(FTP line_status)) buffer disconnect abort FTP return ! sender invalid command: FTP log(" INVALID COMMAND") mail report("Receiver failure at ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).snl,0) generate(FTP es, protocol S detected, len) FTP line_tcc subtype = protocol S detected buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1,FTP line_out block addr) enable in(FTP table_data control,FTP data input) FTP line_status = end of data sent return st(FTP confirmation from spooler): !--------------------------------------------------------------- !We asked spooler to take a transfered file and do something !to it. This is the reply. if p_p2 = no start {No confirmation is required} if p_p1 # 0 start !But there was a failure. select output(1) printstring(dt."SPOOLR replies ".itos(p_p1)." to FTP (". c itos(line).") unconfirm call for". FTP type desc(p_p3).snl) select output(0) finish else start select output(1) printstring(dt."SPOOLR replies success to FTP (". c itos(line).") unconfirm call for ". FTP type desc(p_p3).snl) select output(0) finish return finish select output(1) printstring(dt."SPOOLR replies with confirmation for FTP (".itos(line).")".snl) select output(0) input buffer connect; output buffer connect if FTP line_station type = p station then command sent activity = c FTP p command sent else command sent activity = FTP q command sent flag = 0; s = "" if p_p3 = FTP mail start if p_p1 = 1 start {fail} printstring("No/Full MAIL queue !!".snl) flag = 1 finish finish else if p_p3 = FTP job start if p_p1 # 0 start if p_p1 = 1 then printstring("No BATCH queue !!".snl) if p_p1 > 200 start !The job cannot be queued, submission error. s = "EMAS2900 Job submission fails ".my errs(p_p1) FTP log(s) finish flag = 1 finish finish else if p_p3 = FTP output start if p_p1 # 0 start if p_p1 = 2 then s = "Will be printed on the MAIN printer : LP" and flag = 0 if p_p1 = 1 then printstring("NO PRINT service !".snl) and flag = 1 if p_p1 > 200 start s = "Listing output fails ".my errs(P_P1) flag = 1 finish finish finish -> spooler reply received st(FTP input control message): !---------------------------------------------------------------------- !A HIGH LEVEL INPUT CONTROL MESSAGE FROM FEP. !WILL BE A TCC OR A COMMAND TERMINATION. if p_p3 = 0 start !THEN IT IS AN END OF PHASE TRIGGER. if awaiting sft <= FTP line_status <= rneg sent start !WE ARE AT COMMAND(NEGOTIATION) PHASE. if FTP line_station type = p station then c disable in(suspend, FTP p command reply) else c disable in(suspend, FTP q command reply) return finish if receiving data <= FTP line_status <= quit sent start FTP line_suspend = yes if FTP line_station type = p station then c disable in(suspend, FTP data input) else c disable in(suspend, FTP data input) return finish ftp log(" High level control message not expected!") abort ftp and return finish else start !LINE DOWN SITUATION. if FTP line_status = sft sent start FTP stations(FTP line_station ptr)_connect retry ptr = 1 set document timers(FTP line_station ptr,1,0) ! ie level 4 reject I think so hold off a bit. finish FTP log(" line down. status: ".STREAM STATUS TYPE(FTP LINE_STATUS)) if FTP line_status = stop sent start FTP log(" STOP sent, STOPACK could be comming(timing problem). Waiting") FTP line_timer = 1 !Wait for 1 clock tick return finish abort FTP if FTP line_in stream status = active FTP line_timer = FTP default timeout return finish st(FTP output control message): !------------------------------------------------------------------ !A HIGH LEVEL CONTROL MESSAGE FROM FEP FOR AN OUTPUT STREAM if p_p3 # 0 start if FTP line_status = sft sent start FTP stations(FTP line_station ptr)_connect retry ptr = 1 set document timers(FTP line_station ptr,1,0) ! ie level 4 reject I think so hold off a bit. finish FTP log(" line down .status: ".STREAM STATUS TYPE(FTP LINE_STATUS)) if FTP line_status = stop sent start FTP log(" STOP sent, STOPACK could follow(Timing problem). Waiting") FTP line_timer = 1 return finish abort FTP if FTP line_out stream status = active FTP line_timer = FTP default timeout return finish ftp log(" High level control message not expected!") abort ftp and return st(FTP command overflow): !-------------------------------------------------------------- !AN INPUT COMMAND HAS EXCEEDED THE BUFFER ALLOCATED !! FTP log(" records command overflow, DISASTER") abort FTP return st(FTP input disconnected): !---------------------------------------------------------------------- !THE FTP INPUT STREAM IS NOW DISCONNECTED. if p_p2 = 0 start FTP line_in stream status = allocated return unless FTP line_out stream status = allocated -> FTP pair disconnected finish !ELSE WE HAVE DISCONNECT FAILURE. FTP line_in stream status = allocated select output(1) printstring("FTP (".itos(table entry).") DISCONNECT (IN) FAILS ".itos(p_p2).snl) select output(0) -> FTP pair disconnected if FTP line_out stream status = allocated return st(FTP output disconnected): !---------------------------------------------------------------------- !THE FTP OUTPUT STREAM IS NOW DISCONNECTED. if p_p2 = 0 start FTP line_out stream status = allocated return unless FTP line_in stream status = allocated -> FTP pair disconnected finish !ELSE WE HAVE DISCONNECT FAILURE. FTP line_out stream status = allocated select output(1) printstring("FTP (".itos(table entry).") DISCONNECT (OUT) FAILS ".itos(p_p2).snl) select output(0) -> FTP pair disconnected if FTP line_in stream status = allocated return FTP pair disconnected: set document timers(FTP line_station ptr,connect retry times( c FTP stations(FTP line_station ptr)_connect retry ptr),0) if c ftp line_station ptr # 0 !ie we can now go ahead with other transactions to this site. flag = ddestroy(my name,"LINEIN".itos(table entry),"",my fsys,0) flag = ddestroy(my name,"LINEOUT".itos(table entry),"",my fsys,0) FTP line_pre abort status = active; !precautionary reset. deallocate FTP line_timer = FTP selected timeout return st(FTP input aborted): !---------------------------------------------------------------------- !THE FTP INPUT STREAM IS NOW ABORTED. if p_p2 # 0 start FTP log(" IN abort fails, comm stream ".comms stream status(p_p4)) if comm claiming <= p_p4 <= comm enabling start !ie the comms controller is handling VSI for stream, retry if FTP line_abort retry count = 50 start !that is a total of 50 for in and out streams of this line. printstring("FTP (".itos(table entry).") Hung !".snl) return finish FTP line_abort retry count = FTP line_abort retry count + 1 disable in(abort, FTP input aborted) return finish if comm connected < p_p4 < comm claiming then return !ie comms conn thinks it is aborting or suspending, wait. !otherwise it is connected so continue. finish FTP line_abort retry count = 0 if FTP line_status = end of data sent or FTP line_status = go sent c or (FTP line_status = quit sent and FTP line_tcc subtype # awaiting data) c or FTP line_status = stop sent or FTP line_status = awaiting stop start !we have had a time out as sender and have sent an abort so we must !go to command input mode. !we may also have sent a STOP. enable in(FTP command,FTP command overflow) return finish if FTP line_status = quit sent and FTP line_tcc subtype = awaiting data start !we must be receiver aborting input having timed out !we have not yet enabled the QR[A] as we are safer waiting !for this abort to occur first. FTP log(" input aborted for timeout.") flag = dpon3("",FTP line_output transfer record,0, 0,6) FTP line_output transfer pending = no FTP line_output buffer status = already enabled !after this quit has gone we will drag the connection down. return finish FTP line_in stream status = aborted return unless FTP line_out stream status = aborted -> FTP pair aborted st(FTP output aborted): !---------------------------------------------------------------------- !THE FTP OUTPUT STREAM IS NOW ABORTED. if p_p2 # 0 start FTP log(" OUT abort fails, comm stream ".comms stream status(p_p4)) if comm claiming <= p_p4 <= comm enabling start !ie the comms controller is handling VSI for stream, retry if FTP line_abort retry count = 50 start printstring("FTP (".itos(table entry).") Hung !".snl) return finish FTP line_abort retry count = FTP line_abort retry count + 1 disable out(abort, FTP output aborted) return finish if comm connected < p_p4 < comm claiming then return !ie comms conn thinks it is aborting or suspending, wait. !otherwise it is connected so continue. finish FTP line_abort retry count = 0 if FTP line_status = stop sent or FTP line_status = awaiting stop start !we are P or Q station (sender) and have had a QR[A] to !have got here so enable the output if required. return if FTP line_status = awaiting stop flag = dpon3("",FTP line_output transfer record,0, 0,6) FTP line_output transfer pending = no FTP line_output buffer status = already enabled return finish if FTP line_status = quit sent or FTP line_status = go sent c or FTP line_status = end of data sent start !we have had a time out and need to send the outstanding TCC and !take the corresponding station action. !OR we are transmitting and have recieved a QR[e] so we have !aborted in order to send the ES[e]. flag = dpon3("",FTP line_output transfer record,0, 0,6) FTP line_output transfer pending = no FTP line_output buffer status = already enabled if FTP line_status = end of data sent and r error resume <= c FTP line_tcc subtype <= r error no resume then return !IE we have aborted output after a QR[e] and now have sent a ES[e], await reply if FTP line_station type = p station start output buffer connect generate(FTP stop, 0, len) buffer disconnect command sent activity = FTP p command sent enable out(FTP command,command sent activity,len,buffer offset,1, c FTP line_out block addr) FTP line_status = stop sent finish else FTP line_status = awaiting stop return finish FTP line_out stream status = aborted return unless FTP line_in stream status = aborted -> FTP pair aborted FTP pair aborted: FTP line_status = aborted disconnect return st(FTP timed out): !--------------------------------------------------------------- !A time out on an FTP function. if FTP line_station type = p station then c command sent activity = FTP p command sent else c command sent activity = FTP q command sent -> time out(FTP line_status) time out(*): printstring("FTP (".itos(table entry).") Unexplained time out ".itos(FTP line_status).snl) return time out(spooler called): printstring("SPOOLER timeout !!".snl) FTP line_status = receiving data time out(receiving data): !this could be a P or Q station FTP line_transfer status = aborted retry possible if FTP line_output buffer status = already enabled start !if this is so then we are really in trouble so lets cut losses. FTP log("FTP (".itos(table entry).") data input times out and output already enabled!") abort FTP return finish output buffer connect FTP line_output buffer status = already enabled !we do this to prevent the QR[A] going before the input is aborted. generate(FTP qr, awaiting data, len) FTP line_tcc subtype = awaiting data buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1,FTP line_out block addr) FTP line_status = quit sent !note this will only be sent when this input abort replies. disable in(abort,FTP input aborted) FTP log(" data input timed out, abort issued.") FTP line_timer = (FTP table_timeout_value+59)//60 return time out(last block sent): time out(transmitting data): !the data transmitting is timed out FTP log(" records data transmission timeout.") abort FTP return time out(selected): time out(deallocating): if FTP line_status = deallocating then FTP log(" records time out on deallocate.") c else FTP log(" records time out on allocate.") FTP line_status = unallocated FTP line_station ptr = 0 FTP line_document = 0 kick FTP line(line) return time out(connecting): time out(active): FTP log(" records time out on connect/active.") if FTP line_station ptr # 0 start j = FTP stations(FTP line_station ptr)_connect retry ptr if j = 10 then j = 1 else j = j + 1 FTP stations(FTP line_station ptr)_connect retry ptr = j if FTP line_station type = P station then set document timers( c FTP line_station ptr,connect retry times(j),ftp line_document) finish FTP line_document = 0 if FTP line_in stream status = connecting and c FTP line_out stream status = connecting then start FTP line_in stream status = aborting FTP line_out stream status = aborting -> FTP pair disconnected finish disconnect return time out(disconnecting): FTP log(" records time out on disconnect") !well lets assume its gone !! FTP line_in stream status = allocated FTP line_out stream status = allocated -> FTP pair disconnected time out(aborting): FTP log(" records timeout in ABORTING state.") -> ftp pair aborted time out(stop sent): type = FTP stopack transfer status = x'ff' FTP timeout = yes FTP log(" records timeout on STOP sent, STOPACK assumed.") -> st(FTP p command reply) time out(awaiting sft): time out(awaiting stop): time out(rpos sent): time out(rneg sent): time out(sft sent): FTP log(" records time out on ".stream status type(FTP line_status)) FTP line_transfer status = aborted retry possible abort FTP return time out(end of data sent): FTP log(" records time out after ES[nn]") output buffer connect if FTP line_tcc subtype = ok then FTP line_tcc subtype = ER ok expected c else FTP line_tcc subtype = ER e expected generate(FTP es,FTP line_tcc subtype,len) buffer disconnect FTP line_pre abort status = FTP line_status enable out(FTP data,command sent activity,len,buffer offset,1,FTP line_out block addr) disable in(abort, FTP input aborted) FTP line_transfer status = aborted retry possible if FTP line_output transfer pending = yes then c disable out(abort,FTP output aborted) else start !if there was a transfer pending then the ES was hung so !abort else we are ok to issue the stop(p station) now. if FTP line_station type = p station start output buffer connect generate(FTP stop, 0, len) buffer disconnect enable out(FTP command,command sent activity,len,buffer offset,1, c FTP line_out block addr) FTP line_status = stop sent finish else FTP line_status = awaiting stop finish return time out(stopack sent): time out(go sent): time out(end of data acknowledge sent): time out(quit sent): FTP log(" records time out after ".stream status type(FTP line_status)) FTP line_transfer status = aborted retry possible if FTP line_status = end of data acknowledge sent or FTP line_status = stopack sent or c (FTP line_status = quit sent and FTP line_tcc subtype >= FTP data abort) c then abort FTP and return !ie it is useless to continue. disable in(abort, FTP input aborted) output buffer connect if FTP line_status = go sent then FTP line_tcc subtype = awaiting data if FTP line_status = quit sent then FTP line_tcc subtype = ES e expected generate(FTP qr, FTP line_tcc subtype, len) buffer disconnect enable out(FTP data,command sent activity,len,buffer offset,1,FTP line_out block addr) if FTP line_output transfer pending = yes then c disable out(abort,FTP output aborted) else start if FTP line_station type = p station then start output buffer connect generate(FTP stop, 0, len) buffer disconnect enable out(FTP command,command sent activity,len,buffer offset,1, c FTP line_out block addr) FTP line_status = stop sent finish else FTP line_status = awaiting stop finish return !********************************************************** !ROUTINES FOR FTP CONTROL FOLLOW HERE. routine send to spooler(integer type, ident, confirm) !********************************************************************* !* * !* Here we are to DEXECMESS a message to spooler to ask it to take * !* MAIL or a JOB or OUTPUT from a transfer. CONFIRM is set to * !* indicate that a reply is required. * !* * !********************************************************************* !The message is constructed as follows: ! <DESCRIPTOR> !where<DESCRIPTOR> is a 256 byte standard !descriptor. ! DESCRIPTOR_FTRANS ACTION is the action required of spooler. ! DESCRIPTOR_TYPE is the type of document from FTP (JOB/OUTPUT or MAIL) ! DESCRIPTOR_CONFIRM is passed to spooler and reflected back untouched. ! DESCRIPTOR_IDENT is the identity of the FTRANS document to transfer. ! !In reply FTRANS expects P_P3 to to have the value of DESCRIPTOR_TYPE ! P_P2 to be DESCRIPTOR_CONFIRM ! P_P1 to be the FLAG response to the action. ! If spooler is not FTP available then we abort and CLOSE the service. record (tran document descriptor f) sp integer flag move(256,document addr(ident),addr(sp_state)) sp_header = "BINDOC:" sp_FTRANS action = 1 sp_transfer ident = ident sp_type = type sp_confirm = confirm sp_tfsys = ident >> 24 flag = dexecmess("SPOOLR",line<<7 ! FTP confirmation from spooler, c (8 + document entry size), addr(sp)) if flag # 0 start if flag = 61 start !There is no spooler. printstring("SPOOLR DOWN ??".snl) abort FTP FTP stations(control entry)_service = closed finish select output(1) printstring(dt."DEXECMESS to SPOOLR fails ".errs(flag).snl) select output(0) finish else start select output(1) printstring(dt."SPOOLR called for FTP (".itos(line).")".snl) select output(0) finish end ; !of routine send to spooler routine connect !***************************************************** !* * !* TRY TO CONNECT THE FTP STREAM PAIR !* * !***************************************************** record (pe)p integer flag FTP line_in stream status = connecting p = 0 p_dest = connect stream p_srce = FTP input connected ! line << 7 p_p1 = 0; !IE INPUT p_p2 = my service number ! FTP input control message ! line <<7 p_p3 = FTP line_in stream ident flag = dpon3("", p, 0, 0, 6) FTP line_out stream status = connecting p = 0 p_dest = connect stream p_srce = FTP output connected ! line << 7 p_p1 = 1; !THE OUTPUT STREAM p_p2 = my service number ! FTP output control message ! line << 7 p_p3 = FTP line_ out stream ident flag = dpon3("", p, 0, 0, 6) end ; !OF CONNECT routine FTP log(string (127) message) select output(1) print string(dt."FTP (".itos(table entry).")".message.snl) select output(0) end routine abort FTP !************************************************************* !* * !* Abort an FTP line * !* * !************************************************************* FTP table_mail to send = no unless FTP line_status = awaiting sft c or (FTP timeout = yes and type = FTP stopack) !Ie we halt any mail report except when the successful transfer has !been initiated by us and only the response to a STOP X'2000' is lost. !Are we right to assume success ? return unless awaiting sft <= FTP line_status <= end of data acknowledge sent c or FTP line_status = active FTP line_pre abort status = FTP line_status if FTP line_pre abort status = active !Remember the original status when abort occured. FTP line_status = aborting FTP line_in stream status = aborting disable in(abort, FTP input aborted) FTP line_out stream status = aborting disable out(abort, FTP output aborted) end ; !of abort routine enable in(integer mode, reply) !************************************************************* !* * !* ENABLE AN INPUT FTP STREAM * !* * !************************************************************* record (pe)p integer flag, division if mode # FTP command and FTP table_emastoemas = yes then division = c FTP emastoemas block division else division = FTP block division p = 0 p_dest = enable stream p_srce = reply ! line << 7 p_p1 = FTP line_in comms stream p_p2 = FTP line_in block addr p_p3 = ((block size//FTP EMASTOEMAS BLOCK division)//epage size)-1 p_p4 = mode p_p5 = FTP line_offset; !OFFSET p_p6 = block size//division - p_p5 flag = dpon3("", p, 0, 0, 6) end ; !OF ENABLE IN. routine enable out(integer mode, reply, len, start, size, address) !************************************************************* !* * !* ENABLE OUTPUT ON AN FTP STREAM * !* * !************************************************************* record (pe)p integer flag p = 0 p_dest = enable stream p_srce = reply ! line << 7 p_p1 = FTP line_out comms stream p_p2 = address p_p3 = size p_p4 = mode p_p5 = start p_p6 = len if FTP line_output buffer status = ready start !all is clear to enable the buffer. FTP line_output transfer record = p !we remember this because 'output buffer connect' uses p_p5 !of this when the buffer is 'already enabled' flag = dpon3("", p, 0, 0, 6) FTP line_output buffer status = already enabled finish else start !there is an output already underway. if FTP line_output transfer pending = yes start !and there is also one outstanding !!! FTP log(" output enables out of sync ??") abort FTP return finish FTP line_output transfer pending = yes FTP line_output transfer record = p FTP log(" output transfer pending") finish end ; !OF ENABLE OUT routine disable out(integer action, reply) !************************************************************* !* * !* DISABLE AN FTP OUTPUTSTREAM * !* * !************************************************************* record (pe)p integer flag p = 0 p_dest = disable stream p_srce = reply ! line << 7 p_p1 = FTP line_out comms stream p_p2 = action flag = dpon3("", p, 0, 0, 6) end ; !OF DISABLE OUT routine disable in(integer action, reply) !************************************************************* !* * !* DISABLE AN FTP INPUT STREAM * !* * !************************************************************* record (pe)p integer flag p = 0 p_dest = disable stream p_srce = reply ! line << 7 p_p1 = FTP line_in comms stream p_p2 = action flag = dpon3("", p, 0, 0, 6) end ; !OF DISABLE IN routine disconnect !*************************************************** !* * !* DISCONNECT ONE OR BOTH STREAM PAIR FOR FTP * !* * !*************************************************** record (pe)p integer flag,i, delay string (11) name if FTP line_document # 0 start !we have had a non controlled termination. document == record(document addr(FTP line_document)) unless FTP line_station type = p station and FTP line_transfer status # c satisfactory termination then start if FTP line_station type = P station start FTP log(" P station reports SATISFACTORY TERMINATION, but no STOPACK") if FTP table_mail = yes then mail report("0",FTP table_mail displ) else c mail report(" ok ",FTP table_mail displ) if document_FTP user flags & FTP fail mail # 0 then c FTP table_mail to send = no else mail report(date." ".time." Transfer Successful ".snl,0) seconds = current packed dt seconds = seconds - ftp line_data transfer start if ((FTP stations(FTP line_station ptr)_bytes + FTP line_ c bytes transferred) >>10 ) > 2000 start FTP stations(FTP line_station ptr)_bytes = 0 FTP stations(FTP line_station ptr)_seconds = 0 finish FTP stations(FTP line_station ptr)_bytes = FTP stations(FTP line_ c station ptr)_bytes + FTP line_bytes transferred FTP stations(FTP line_station ptr)_seconds = FTP stations(FTP line_ c station ptr)_seconds + seconds if document_auto requeue = yes start FTP log(" ".ident to s(FTP line_document)." requeued after success". c "(AUTO REQUEUE)".snl) requeue FTP document(FTP line_document,0,no,no) finish if FTP line_activity = sender then s = "to " else s = "from " if FTP stations(FTP line_station ptr)_status > 0 then ss = " charge" else ss = "" FTP log(" P ACCOUNT: ".FTP line_user." transfers ". c itos((FTP line_bytes transferred+1023)>>10)."k ".s.string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).ss) FTP stations(FTP line_station ptr)_P transfers = FTP stations( c FTP line_station ptr)_P transfers + 1 FTP stations(FTP line_station ptr)_P kb = FTP stations(FTP line_station ptr)_ c P kb + (FTP line_bytes transferred+1023)>>10 if ftp table_mail = yes then FTP stations(FTP line_station ptr)_ c P mail = FTP stations(FTP line_station ptr)_P mail + 1 finish else start s = "" if FTP line_transfer status = satisfactory termination start seconds = current packed dt seconds = seconds - ftp line_data transfer start if ((FTP stations(FTP line_station ptr)_bytes + FTP line_ c bytes transferred) >>10 ) > 2000 start FTP stations(FTP line_station ptr)_bytes = 0 FTP stations(FTP line_station ptr)_seconds = 0 finish FTP stations(FTP line_station ptr)_bytes = FTP stations(FTP line_ c station ptr)_bytes + FTP line_bytes transferred FTP stations(FTP line_station ptr)_seconds = FTP stations(FTP line_ c station ptr)_seconds + seconds if FTP line_activity = sender then s = "to " else s = "from " if FTP stations(FTP line_station ptr)_status = 1 then ss = " (charge)" else ss = "" FTP log(" Q ACCOUNT: ".FTP line_user." transfers ". c itos((FTP line_bytes transferred+1023)>>10)."k ".s.string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name).ss) FTP stations(FTP line_station ptr)_Q transfers = FTP stations( c FTP line_station ptr)_Q transfers + 1 FTP stations(FTP line_station ptr)_Q kb = FTP stations(FTP line_station ptr)_ c Q kb + (FTP line_bytes transferred+1023)>>10 if ftp table_mail = yes then FTP stations(FTP line_station ptr)_ c Q mail = FTP stations(FTP line_station ptr)_Q mail + 1 s = " but transaction completed." mail report(date." ".time." Transfer Successful".snl,0) finish FTP log(" Q station abnormal termination".s) finish delete FTP document(FTP line_document) unless document_auto requeue = yes finish else start if receiving data <= FTP line_pre abort status <= end of data acknowledge sent start !The abort has come in the actual DATA transfer phase. if document_FTP retry level > 0 and document_auto requeue = no then document_FTP retry level = c document_FTP retry level - 1 if document_FTP retry level = 0 start !The attempts are exhausted..delete it. FTP log(" Transfer fails(aborted), attempts exhausted...Deleting.") mail report("Transfer fails (in disorder) after repeated attempts.".snl,0) if FTP table_mail = yes then mail report("1",FTP table_mail displ) FTP table_mail to send = yes finish finish if document_auto requeue = yes then delay = auto poll delay else c delay = transfer fail delay if FTP line_user abort = no and document_FTP retry level > 0 then requeue FTP document( c FTP line_document,delay,no,no) else delete FTP document( c FTP line_document) finish if FTP line_aux document # 0 then delete FTP document( c FTP line_aux document) and FTP line_aux document = 0 FTP line_document = 0 FTP line_pre abort status = active finish FTP line_user = "" !do we have a mail message to send to a user as a result of this transfer. if FTP table_mail to send = yes then send mail c else flag = ddestroy(my name,"LINEMAIL".itos(table entry),"",my fsys,0) buffer disconnect flag = ddestroy(my name,"LINEIN".itos(table entry),"",my fsys,0) flag = ddestroy(my name,"LINEOUT".itos(table entry),"",my fsys,0) if FTP line_in stream status = active or c FTP line_in stream status = aborted start FTP line_in stream status = disconnecting p = 0 p_dest = disconnect stream p_srce = FTP input disconnected ! line << 7 p_p1 = FTP line_in comms stream flag = dpon3("", p, 0, 0, 6) FTP line_status = disconnecting FTP line_timer = FTP default timeout finish if FTP line_out stream status = active or c FTP line_out stream status = aborted start FTP line_out stream status = disconnecting p = 0 p_dest = disconnect stream p_srce = FTP output disconnected ! line << 7 p_p1 = FTP line_out comms stream flag = dpon3("", p, 0, 0, 6) FTP line_status = disconnecting FTP line_timer = FTP default timeout finish end ; !OF ROUTINE DISCONNECT routine deallocate !************************************************ !* * !* DEALLOCATE THE STREAM PAIR. * !* * !************************************************** record (FTP f)FTP if feps(FTP line_fep)_FTP available = no start !the fep has gone down. FTP line_status = unallocated FTP line_in stream status = unallocated FTP line_out stream status = unallocated FTP line_station ptr = 0 FTP log(" reports fep down, deallocate assumed.") return finish FTP = 0 FTP_type = 3; !DEALLOCATE. FTP_pair ref = line FTP_length = FTP std mess len if TARGET = 2900 FTP_in ident = FTP line_in stream ident & x'FFFF' FTP_out ident = FTP line_out stream ident & x'FFFF' FTP output message to fep(FTP line_fep, FTP) FTP line_status = deallocating if FTP line_in stream status # aborting start FTP line_in stream status = deallocating FTP line_out stream status = deallocating finish return end ; !OF ROUTINE DEALLOCATE. routine send block(integer reply, integername flag) !************************************************************* !* * !* SEND THE SPECIFED BLOCK OUT ON THE FTP STREAM * !* * !************************************************************* record (daf)daddr longinteger align integer FTPr0, FTPr1, oldpos, wp, old wp, cp, l, ln, end integer start, blk size, len, seg, gap, top, structure, record length, short record, I,j, K,data end integer block division, max vrecord length !Note that 1) No Translation mode means take the file as it comes. !2) EMASTOEMAS means that the file is transmitted with its EMAS header. ! !Note that non inter EMAS transfers are done in smaller units than others !governed by the constants 'FTP emastoemas block division' & 'FTP block division' if FTP table_emastoemas = yes then block division = FTP emastoemas c block division else block division = FTP block division FTP line_bytes to go = FTP line_bytes to go - FTP line_bytes sent unless FTP line_bytes sent = 0 start if FTP line_part blocks = block division c then FTP line_block = FTP line_block + 1 finish if FTP line_part blocks = block division then FTP line_part blocks = 0 flag = get block addresses(my name, ident to s(ident), ident>>24, addr(daddr)) if flag = 0 start if daddr_nblks = FTP line_block then blk size = daddr_last blk-1 c else blk size = daddr_blksi-1 if FTP line_block = (document_data start+block size)//block size c and FTP line_part blocks = 0 then start = document_data start c else start = (block size//block division)*FTP line_part blocks if FTP line_part blocks = 0 and start # 0 start !only happens when transfer commences(after header) !note that send block assumes that document_data start is not !greater than one block division. If it is required at any time !then the routine must be rewritten. if FTP line_bytes to go + start > block size//block division c then len = block size//block division - start c else len = FTP line_bytes to go finish else start if FTP line_bytes to go > block size//block division c then len = block size//block division else len = FTP line_bytes to go finish FTP line_bytes sent = len if FTP line_bytes to go - FTP line_bytes sent = 0 then c FTP line_status = last block sent FTP line_part blocks = FTP line_part blocks + 1 FTP log(" send block: ".itos(FTP line_block)." sub block: ". c itos(FTP line_part blocks). " start: ".itos(start)." len: ".itos(len)) if FTP table_data control # no translation start !We have to do a pre process on the sub block to be sent FTP log(" Initiating translation to new length...") seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(my name,"LINEWRK".itos(table entry),ident>>24, c R!W,seg,gap) else flag = dconnect(my name,"LINEWRK".itos(table entry), c ident>>24,R!W,0,seg,gap) if flag # 0 start if flag = already connected then printstring("Warning, FT ". c itos(table entry)." (wrk) CONNECTED".snl) and flag = 0 if flag # 0 start FTP log(" Translate Work file connect fails ".errs(flag)) abort FTP return finish finish wp = seg << seg shift old wp = wp end = no seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(my name,ident to s(ident), ident>>24, c R!W,seg,gap) else flag = dconnect(my name, ident to s(ident), c ident>>24, R!W, 0, seg, gap) if flag # 0 start if flag = already connected then printstring("Warning, FT ". c itos(table entry)." (srce) CONNECTED".snl) and flag = 0 if flag # 0 start FTP log(" cannot connect original for translate! ".errs(flag)) abort FTP return finish finish cp = seg << seg shift + start + (block size*(FTP line_block-1)) top = cp + len !--------------------------------------------- !DATA FORMATING SECTION FOLLOWS ! if FTP table_data type_value = x'0002' start structure = FTP table_binary data record & x'03' record length = (FTP table_binary data record) >> 16 select output(1) printstring(dt."STRUCTURE ".itos(structure)." RECORDs ".itos(record length).snl) select output(0) unless 0 < structure < 4 start FTP log("**ERROR** Non standard DATA structure. Terminating transfer") flag = ddisconnect(my name,ident to s(ident),ident>>24,0) flag = ddisconnect(my name,"LINEWRK".itos(table entry),ident>>24,0) document_FTP retry level = 1 flag =1 return finish !---------------------------------------------------------------------- if structure = 1 {Fixed length records} start !we are to send FIXED LENGTH RECORD BINARY data. [ on sending we use BIN OFFSET to !remember if we have already sent n bytes of a data record !in the previous output enable] short record = no; data end = no cycle !handle a record at a time. l = top - cp ! l is data left in this block if l + FTP line_bin offset < record length then short record = yes else c l = record length - FTP line_bin offset cycle {each sub record in a record} if l < 63 start { less than 63 bytes in remainder of record} move(l, cp, wp+1) byteinteger(wp) = l if short record = yes start FTP line_bin offset = FTP line_bin offset + l data end = yes !We are at the end of a block but not a record boundary !so we must recall where we are in the record for next block cp = cp + l; wp = wp + l + 1 exit finish byteinteger(wp) = byteinteger(wp) ! x'80' !setting the RECORD bit cp = cp + l wp = wp + l + 1 if cp = top then data end = yes !we are at record end so exit exit finish move(63, cp, wp+1) byteinteger(wp) = 63 if short record = yes then FTPline_bin offset = FTP line_bin offset + 63 cp = cp + 63 l = l - 63 wp = wp + 64 if cp = top then data end = yes if l = 0 then byteinteger(wp - 64) = byteinteger(wp - 64) ! x'80' and exit repeat exit if data end = yes FTP line_bin offset = 0 {can reset here because we have had whole record} repeat finish else start !-------------------------------------------------------------------- !We have BINARY UNSTRUCTURED or VARIABLE LENGTH RECORDS. !The UNSTRUCTURED go in the same way but as one continuous variable !length record without the EOR at the end. !We use the halfword in the bottom two bytes for true VRECORD length !The whole interger is used to represent the inherent UNSTRUCTUED record length. data end = no if structure = 3 then max vrecord length = document_data length c else max vrecord length = record length cycle if FTP line_Vbytes to go = 0 and FTP line_split vrecord length = no start !We are at the start of a record. abort ftp and return if top-cp = 0 byteinteger(addr(FTP line_vrecord length)+2) = byteinteger(cp) if top-cp < 2 start !We do not have a complete record length in this block. FTP line_split vrecord length = yes exit finish byteinteger(addr(FTP line_vrecord length)+3) = byteinteger(cp+1) cp = cp + 2 FTP line_vbytes to go = FTP line_vrecord length - 2 exit if top-cp = 0 finish else if FTP line_split vrecord length = yes start !We have the start of a block with the second byte of the record length. byteinteger(addr(FTP line_vrecord length)+3) = byteinteger(cp) cp = cp + 1 FTP line_vbytes to go = FTP line_vrecord length - 2 exit if top-cp = 0 finish if FTP line_vrecord length > max vrecord length + 2{length} start FTP log("MAX BINARY RECORD length exceeded") mail report("BAD (too long) Binary (record) length".snl,0) flag = ddisconnect(my name,ident to s(ident),ident>>24,0) flag = ddisconnect(my name,"LINEWRK".itos(table entry),ident>>24,0) flag = 1; document_FTP retry level = 1; return finish l = top - cp cycle {Now deal with the block record by record} if FTP line_vbytes to go <= 63 start !We have the end of this record. if l < FTP line_vbytes to go start !But not enough data left to end the record. move(l,cp,wp+1) byteinteger(wp) = l FTP line_vbytes to go = FTP line_vbytes to go - l wp = wp + l + 1; cp = cp + l data end = yes exit finish !We have sufficient data. move(FTP line_vbytes to go,cp,wp+1) byteinteger(wp) = FTP line_vbytes to go if FTP table_binary data record & x'03' = 2 then byteinteger(wp) = c byteinteger(wp) ! x'80' {end of record for VARIABLE length record only} cp = cp + FTP line_vbytes to go wp = wp + FTP line_vbytes to go + 1 FTP line_vbytes to go = 0 if top-cp = 0 then data end = yes exit finish !More than a max sub record to go. if l < 63 start !But less than one sub record of data in this block. move(l,cp,wp+1) byteinteger(wp) = l FTP line_vbytes to go = FTP line_vbytes to go - l wp = wp + l + 1; cp = cp + l data end = yes exit finish move(63,cp,wp+1) byteinteger(wp) = 63 FTP line_vbytes to go = FTP line_vbytes to go - 63 cp = cp + 63 wp = wp + 64 l = l - 63 repeat exit if data end = yes repeat finish finish else start !-------------------------------------------------------------------- !We are dealing with TEXT open working. {OR PRE OSCOM FEP with free format that we must 'help along' for now} IF TARGET = 2900 START FTPr0 = x'58000000'!len FTPr1 = cp cycle old pos = FTPr1 *LDTB_FTPr0 *LDA_FTPr1 *LB_10 *PUT_x'A300' *JCC_8,<EOA> *MODD_1 *STD_FTPr0 -> nextnl EOA: end = yes FTPr1 = top nextnl: l = FTPr1 - old pos if end = no then ln = l-1 else ln = l cycle if ln <= 63 start l = ln if end = yes start exit if ln = 0 finish else ln = ln ! x'80' byteinteger(wp) = ln if l > 0 then move(l, cp, wp+1) wp = wp + l + 1; cp = cp + l + ln>>7 exit finish byteinteger(wp) = 63 move(63, cp, wp+1) wp = wp + 64; cp = cp + 63 ln = ln - 63 repeat exit if end = yes repeat FINISH ELSE START oldpos = cp cycle i = oldpos, 1, top-1 end = no {PRE OSCOM FEP} unless FTP table_text format_value = x'0080' start cycle j = i, 1, top-1 if byteinteger(j) = x'0A' start {NL} end = yes k = j exit finish repeat if end = no start ln = k-i i = k finish else ln = top - i {PRE OSCOM FEP} finish else start ln = top - i i = top - 1 finish cycle if ln <= 63 start l = ln if end = yes start exit if ln = 0 finish else ln = ln ! x'80' byteinteger(wp) = ln if l > 0 then move(l, cp, wp+1) wp = wp + l + 1; cp = cp + l + ln>>7 exit finish byteinteger(wp) = 63 move(63, cp, wp+1) wp = wp + 64; cp = cp + 63 ln = ln - 63 repeat exit if end = yes repeat FINISH finish !--------------------------------------------- !DATA FORMATTING SECTION ENDS if mon level = 4 or (mon level = 7 and ftp table_data type_value = x'0002') start select output(1); printstring(dt."FTP (".itos(table entry).") DATA OUTPUT: ") cycle j=old wp, 1, wp-1 printstring(htos(byteinteger(j), 2)) repeat newline; select output(0) finish flag = ddisconnect(my name,ident to s(ident),ident>>24,0) flag = ddisconnect(my name,"LINEWRK".itos(table entry),ident>>24,0) flag = get block addresses(my name,"LINEWRK".itos(table entry),ident>>24,addr(daddr)) if flag # 0 start FTP log(" get block addr wrk file fails ".errs(flag)) return finish blk size = daddr_last blk - 1 FTP log(" actual bytes sent: ".itos(wp - old wp)) enable out(FTP table_data control,reply,wp-old wp,0,blk size,daddr_da(1)) finish else enable out(FTP table_data control, reply, len, start, blk size, daddr_da(FTP line_block)) FTP line_bytes transferred = FTP line_bytes transferred + FTP line_bytes sent finish else start !we have an error FTP log(" get block addr fails ".errs(flag)) finish end ; !OF SEND BLOCK. integerfn accept block !*********************************************************************** !* * !* MOVE DATA FROM AN INPUT BUFFER TO A FILE EXTENDING THE FILE IF * !* NECESSARY * !* * !*********************************************************************** string (11) file integer seg, gap, size, fsys, i, j, flag, l, wp, cp, end of input, adjust, formatted, header, no format integer extra space, factor, binary mode, first pass record (fhf)name file header if mon level = 4 start select output(1); printstring(dt."FTP (".itos(table entry).") DATA INPUT: ") cycle j=0, 1, data length-1 printstring(htos(byteinteger(data start+j), 2)) repeat newline; select output(0) finish seg = 0; gap = 32; !8 MEGA BYTES if FTP table_data control = translate and FTP table_data type_value = c x'0002'{BINARY} then factor = 3 else factor = 1 {allow extra space for Vrec lengths} binary mode = no; !Set only if control mode is TRANSLATE and transfer is BINARY. no format = no; !only set for text_format x'0800'. formatted = no; !set to yes only for ANSI TEXT-FORMATTING (x'0002') file = ident to s(ident) fsys = ident>>24 if TARGET # 2900 then flag = dconnect(my name,file,fsys,r!w,seg,gap) else c flag = dconnect(my name, file, fsys, r!w, 0, seg, gap) if flag = 0 start file header == record(seg<<seg shift) if document_data length = -1 start ; !SET UP HEADER document_data start = file header size if FTP table_mail = yes then extra space = 80 else extra space = 0 file header_end = document_data start + extra space file header_start = document_data start + extra space file header_size = e page size file header_type = 3; !ISO INPUT (Assume this, change to DATA later if required) file header_datetime = current packed dt document_date and time received = file header_datetime finish size = file header_size if file header_end+(data length*factor) > size start ; !EXTEND size = size + block size !NOTE that even 'translate' mode input will result in a !file of less or equal length to the input IF open working is only chioice! !otherwise we shall have to expand on this extension. flag = dchsize(my name, file, fsys, size>>10) if flag # 0 start print string("FTP (".itos(table entry).") EXTEND ".my name.".".file. c " FAILS ".errs(flag).snl) flag = R error no resume -> error finish else file header_size = size finish if FTP table_data control = translate start !------------------------------------------------------------- !NONE DEFAULT. That is the FEP has done no assit and the subrecord !structure is intact. We have to do 'all our own work'. FTP log(" Unformatting the complete FTP sub-records") if FTP table_data type_value = x'0002'{BINARY} then binary mode = yes else start if FTP table_text format_value = x'0080' then no format = yes if FTP table_text format_value = x'0002' then formatted = yes finish wp = data start; cp = seg<<seg shift + file header_end end of input = data length + data start if document_data length = -1 then first pass = yes else first pass = no cycle header = byteinteger(wp) l = header&x'7F' if header = 0 start !This could be part of a TCC for which will will get a kick !from the FEP next. Check this out and if so move down the !buffer for re enable. if end of input - wp < 3 start FTP log(" partial TCC at buffer end!") move(end of input-wp, wp, data start) FTP line_offset = end of input - wp exit finish else l = 64 finish if l > 63 start !data error, incorrect sub record length! FTP log(" input sub record length > 63, count: ".i to s(wp-data start)) select output(1) cycle j=0,1,64 printstring(htos(byteinteger(wp+j),2)) repeat newline select output(0) flag = protocol R detected -> error finish if wp + l + 1 > end of input start !the last sub record is incomplete..leave for next input. move(end of input - wp, wp, data start) FTP line_offset = end of input - wp exit finish !--------------------------------------------------------------- if binary mode = no start {It is a TEXT transfer to unscramble} if formatted = yes and FTP line_new FTP data record = yes c and l # 0 {l#0 in for VAX SIR DBMS bug} start !IE it is ANSI text format and this is the start of a new stat record. j = byteinteger(wp+1) if j = x'20' then byteinteger(cp) = x'0A' else c if j = x'2B' then byteinteger(cp) = x'0D' else c if j = x'31' then byteinteger(cp)= x'0C' else c if j = x'30' or j = x'2D' then start byteinteger(cp) = x'0A' byteinteger(cp+1) = x'0A' if j = x'2D' then byteinteger(cp+2) = x'0A' and cp = cp + 1 cp = cp + 1 finish else FTP log("Non ANSI control char [space inserted]". c " (dec: ".itos(j).") in input buffer at displ ". c itos(wp+1-data start)) and byteinteger(cp) = X'20' cp = cp + 1 wp = wp + 1 l = l - 1 FTP line_new FTP data record = no finish if l > 0 start if FTP line_parity = yes start cycle i = 0,1,l-1 byteinteger(wp+1+i) = byteinteger(wp+1+i)&X'7F' !We must strip off the parity on text. repeat finish move(l, wp+1, cp) cp = cp + l finish if header&x'80' # 0 then start if formatted = yes then FTP line_new FTP data record = yes else c if no format = no then byteinteger(cp) = 10 and cp = cp + 1; !ie LF (NL record implication) finish finish else start !------------------------------------------------------------- !it is a BINARY transfer to unscramble. if FTP line_current vrecord length addr = 0 start !First entry of a new binary record if first pass = yes then extra space = 2 else extra space = 0 !Do this shift of 2 at the start to keep WORD alignment. FTP line_current vrecord length addr = cp + extra space cp = cp + 2 + extra space{Leave the two bytes for the record length} first pass = no finish if l > 0 start !We have some data move(l, wp+1, cp) cp = cp + l FTP line_current vrecord length = FTP line_current vrecord length + l finish if header & x'80' # 0 start !EOR is set on this sub record. if FTP line_current vrecord length > 65533 start !EOR shows existance of a record but it is greater than the !max binary record supported on EMAS. Only possiblity is that !it is a byte stream and this is the last data and the EOR is !an abberation on the part of the transmitting entity. !Lets assume this as we will trap it if there is more data. if wp + l + 1 < end of input start !But there is more data! FTP log(" VRECORD exceeds x'FFFF' in length. Terminated.") Mail Report("Incomming BINARY data has record in excess ". c "of 65533 bytes.".snl,0) flag = rerror no resume -> error finish !OK leave it as discussed. finish else start FTP line_current vrecord length = FTP line_current vrecord length +2 {+header} byteinteger(FTP line_current vrecord length addr) = c byteinteger(addr(FTP line_current vrecord length)+2) byteinteger(FTP line_current vrecord length addr + 1) = c byteinteger(addr(FTP line_current vrecord length)+3) !IE move in the record length. i = FTP line_known to have records FTP line_current vrecord length = FTP line_current v record length - 2 if i>>16 < FTP line_current vrecord length then c FTP line_known to have records = (FTP line_known to have c records ! x'ffff0000') & ((FTP line_current vrecord c length << 16)! x'0000ffff') if i # 0 and i & x'01' = 0 start !at the moment all records have been the same length. if i>>16 # FTP line_current vrecord length then c FTP line_known to have records = FTP line_known to c have records ! x'01' !Bottom bit set means it is variable length. finish FTP line_records received = FTP line_records received + 1 FTP line_current vrecord length = 0 FTP line_current vrecord length addr = 0 finish finish finish wp = wp + l + 1 exit unless wp < end of input repeat file header_end = cp - seg<<seg shift finish else start !------------------------------------------------------------- !This is DEFAULT. That is either INTER EMAS or free (x'0080') format. !The sub record stucture has been stripped by the FEP. if FTP table_emastoemas = yes and document_data length = -1 start !In this case we want to store the main part of the incomming !file header untill the whole file has been received and afterwards !overwrite the temporary file header with it. adjust = file header size move(adjust, data start, addr(FTP table_emastoemas header(0))) finish else adjust = 0 move(data length-adjust, data start+adjust, seg<<seg shift+file header_end) file header_end = file header_end+data length-adjust finish document_data length = file header_end-file header_start FTP line_bytes transferred = document_data length flag = ddisconnect(my name, file, fsys, 0) print string("FTP (".itos(table entry).") DISCONNECT ".my name.".".file." FAILS " c .errs(flag).snl) and flag = R error no resume and -> Xerror if flag # 0 result = 0 finish printstring("FTP (".itos(table entry).") CONNECT ".my name.".".file." FAILS ".errs(flag).snl) flag = R error no resume -> xerror error: i = ddisconnect(my name,file,fsys,0) print string("FTP (".itos(table entry).") DISCONNECT ".my name.".".file." FAILS ".errs(i).snl) if i # 0 xerror: FTP log(" receiver error detected.") result = flag end ; !OF ACCEPT BLOCK. routine complete file handling(integername flag, stringname report) !************************************************************* !* * !* COMPLETE THE FILE TRANSFER, WE ARE A RECeiVER. * !* * !************************************************************* integer i, seg, gap string (15) user, file, my file, newgen file string (127) tail flag = 0 report = "" user = document_user my file = ident to s(ident) ! if FTP line_bytes transferred = 0 start report = "No data has been received." mail report(report.snl,0) FTP log(report) flag = 1 return finish seg = 0; gap = 32 if TARGET # 2900 then flag = dconnect(my name, my file, ident>>24, R!W,seg, gap) else c flag = dconnect(my name, my file, ident>>24, r!w, 0, seg, gap) if flag # 0 start report = "Connect SPOOL file for header change fails ".errs(flag) FTP log(report) return finish file header == record(seg<<seg shift) size = (file header_end + epage size - 1) & (- epage size) flag = dchsize(my name, my file, ident>>24, size>>10) if flag # 0 start report = "Cannot adjust completed file size ".errs(flag) FTP log(report) return finish else file header_size = size if FTP table_data type_value = x'0002'{BINARY} start !We have to amend the header appropriately. File header_type = 4 {data} if FTP line_known to have records = 0 start !Unstructured data file File header_start = file header_start + 4 {record length offset} File header_binary record = 3 mail report("This is an unstructured data file.".snl,0) finish else start !It has a structure. File header_start = File header_start + 2 {offset} File header_records = FTP line_records received File header_binary record = FTP line_known to have records File header_binary record = (File header_binary record & x'FFFFFF00') ! X'02' {variable} mail report("This is a V (Max record: ".itos((File header_binary record)>>16). c ") Data file of ".itos(file header_records)." records.".snl,0) if FTP line_known to have records & x'03' = 0 then mail report( c "All the records are the same length.".snl,0) finish finish if FTP table_emastoemas = yes and FTP table_mail = no start !We have a file that has been transmitted to us with its full header !and we have stored the start of that header away until this point !while a temporary header controled the transfer of the data. Now overwrite !the temp header with the transmitted one. move(file header size, addr(FTP table_emastoemas header(0)), seg<<seg shift) finish if ftp table_mail = no then flag = ddisconnect(my name,my file,ident>>24,0) if flag # 0 start report = "Disconnect SPOOL file fails ".errs(flag) FTP log(report) return finish if FTP table_mail = yes start !It is a mail message. FTP table_mail to send = no if FTP line_station ptr # guest entry then c tail = string at(FTP stations(FTP line_station ptr),FTP stations(FTP line_station ptr)_shortest name) c else tail = "[".FTP table_calling address."]" string(seg<<seg shift + 16) = tail {The way to get the source to MAILER} flag = ddisconnect(my name,my file,ident>>24,0) if flag # 0 start report = "Disconnect SPOOL file fails ".errs(flag) FTP log(report) return finish document_dest = "MAIL" document_user = "FTRANS" buffer disconnect send to spooler(FTP mail,ident,yes) flag = -1; !to indicate the sleep for reply required. return finish if FTP table_mode_value = take job input start !This is JOB input so now add it to the BATCH queue. buffer disconnect tail = "DEST=BATCHFROMFTP,USER=".FTP table_username_value.",NAME=" if FTP table_filename_set = no then tail = tail."FTP_JOB" else c tail = tail.FTP table_filename_value if FTP table_special options_set = yes then tail <- tail.",".FTP table_special options_value to docstring(document,document_delivery,tail) send to spooler(FTP job,ident,yes) flag = -1 return finish if FTP table_mode_value = take job output or FTP table_mode_value = give job output c or document_FTP user flags&FTP local output # 0 then start !the tranfsered file is to go to a device. if (FTP table_mode_value = take job output or (ftp table_mode_value = c give job output and ftp table_device type_set = yes) ) and c FTP table_device type_value -> FTP table_device type_value. c ("@").tail then to docstring(document,document_delivery,tail) !ie the delivery can be included in the device type. if document_FTP user flags & FTP fail mail # 0 then FTP table_ c mail to send = no buffer disconnect if FTP table_mode_value = take job output or ( ftp table_mode_value = give job output c and ftp table_device type_set = yes) then document_dest <- FTP table_device type_value c else document_dest <- docstring(document,document_device type) send to spooler(FTP output,ident,yes) flag = -1 return finish file = doc string(document, document_name) if FTP table_mode_value = x'0002' or (FTP line_station type = p station c and document_FTP user flags & FTP overwrite # 0) then c newgen file = file and file = "T#TR".my file else newgen file = "" !we have been asked to replace an existing file flag = dtransfer(my name, user, my file, file, ident>>24, ident>>24, 1) if flag # 0 start report = " TRANSFER ".my file." TO ".user.".".file. c " FAILS ".errs(flag) FTP log(report) finish if newgen file # "" start flag = dnewgen(user,newgen file,file,ident>>24) if flag # 0 start if flag = 32 start flag = dtransfer(user,user,file,newgen file,ident>>24,ident>>24,1) if flag # 0 then report = "TRANSFER of file fails ".errs(flag) c and FTP log (report) and i = ddestroy(user,file,"",ident>>24,0) finish else start report = "NEWGEN of transferred file fails ".errs(flag) i = ddestroy(user,file,"",ident>>24,0) FTP log(report) finish finish finish return end ; !OF COMPLETE FILE HANDLING. routine input buffer connect !*************************************************************** !* * !* THIS ROUTINE CONNECTS THE INPUT FTP BUFFER . * !* * !*************************************************************** integer flag, seg, gap string (15) file file = "LINEIN".itos(table entry) seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(my name,file,my fsys,R!W,seg,gap) else c flag = dconnect(my name, file, my fsys, r!w, 0, seg, gap) monitor and return if flag # 0 and flag # 34 command start = seg <<seg shift data start = command start end ; !OF INPUT BUFFER CONNECT. routine output buffer connect !***************************************************************** !* * !* THIS ROUTINE CONNECTS THE FTP OUTPUT CONTROL BUFFER * !* * !***************************************************************** integer flag, seg, gap string (15) file file = "LINEOUT".itos(table entry) seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(my name,file,my fsys,R!W,seg,gap) else c flag = dconnect(my name, file, my fsys, r!w, 0, seg, gap) monitor and return if flag # 0 and flag # 34 if FTP line_output buffer status = already enabled start !ie the output buffer is enabled so we want to write the unused !page of it. if FTP line_output transfer record_p5 = 0 then c buffer offset = x'1000' else buffer offset = 0 finish else buffer offset = 0 reply start = seg <<seg shift + buffer offset return end ; !OF OUTPUT BUFFER CONNECT routine buffer disconnect !************************************************************** !* * !* THIS ROUTINE DISCONNECTS THE FTP CONTROL BUFFERS. * !* * !************************************************************** integer flag if command start # 0 then flag = ddisconnect(my name, "LINEIN".i to s(table entry), my fsys, 0) if reply start # 0 then flag = ddisconnect(my name, "LINEOUT".i to s(table entry), my fsys, 0) return end ; !OF BUFFER DISCONNECT routine delete FTP document(integer ident) !*********************************************************************** !* * !* Routine to delete an FTP document and its descriptor * !* * !*********************************************************************** record (document descriptorf)name document string (11) file integer fsys file = ident to s(ident) fsys = ident>>24 document == record(document addr(ident)) flag = ddestroy(my name, file, "", fsys, 0) if flag = 0 or flag = does not exist start FTP log(" ".document_dest." ". c file." ".document_user. c ".".doc string(document,document_name)." DELETED") finish else FTP log("FTP (".itos(table entry).") DESTROY ".my name.".".file. c " FAILS ".errs(flag)) document_date and time deleted = current packed dt document_state = unused end ; !OF ROUTINE DELETE FTP DOCUMENT routine mail report(string (255) s, integer displ) !***************************************************** !* * !* This routine adds a line to the MAIL reply area. * !* * !***************************************************** integer seg,gap,flag string (11) file seg = 0; gap = 0 file = "LINEMAIL".itos(table entry) if TARGET # 2900 then flag = dconnect(my name,file,my fsys,R!W,seg,gap) else c flag = dconnect(my name,file,my fsys,r!w,0,seg,gap) if flag = 32 start !Create the MAIL file create ftp work files(flag,yes) if flag # 0 start printstring("MAIL create fails ".errs(flag).snl) abort FTP return finish seg = 0; gap = 0 if TARGET # 2900 then flag = dconnect(my name,file,my fsys,R!W,seg,gap) else c flag = dconnect(my name,file,my fsys,r!w,0,seg,gap) finish if flag = 0 start file header == record(seg<<seg shift) if file header_end + length(s) > file header_size start FTP log(" MAIL reply area full") flag = ddisconnect(my name,"LINEMAIL".itos(table entry),my fsys,0) return finish if displ # 0 then move(length(s),addr(s)+1, c seg<<seg shift+file header_start+displ) else c move(length(s),addr(s)+1,seg<<seg shift+file header_end) c and file header_end = file header_end + length(s) flag = ddisconnect(my name,"LINEMAIL".itos(table entry),my fsys,0) return finish FTP log(" Connect MAIL file fails ".errs(flag)) end routine create FTP work files(integername flag, integer mail only) !************************************************************* !* * !* CREATE THE FTP INPUT AND OUTPUT BUFFERS * !* * !************************************************************* integer seg,gap record (daf)daddr string (11) file file = "LINEMAIL".itos(table entry) if TARGET # 2900 then flag = dcreate(my name,file,my fsys,x'1000'>>10, c zerod!tempfi,ada) else flag = dcreate(my name,file,my fsys,x'1000'>>10,zerod!tempfi) flag = 0 if flag = already exists if flag = 0 start seg=0;gap=0 if TARGET # 2900 then flag = dconnect(my name,file,my fsys,R!W,seg,gap) else c flag = dconnect(my name,file,my fsys,R!W,0,seg,gap) file header == record(seg<<seg shift) file header_start = x'20' file header_end = file header_start file header_size = x'1000' flag = ddisconnect(my name,file,my fsys,0) return if mail only = yes file = "LINEIN".i to s(table entry) if TARGET # 2900 then flag = dcreate(my name,file,my fsys,(block c size//FTP emastoemas block division)>>10,zerod!tempfi,ada) else c flag = dcreate(my name, file, my fsys, (block size//FTP emastoemas block division)>>10, ZEROD!tempfi) !We assume that the EMASTOEMAS mode will have the greatest size. flag = 0 if flag = already exists if flag = 0 start flag = get block addresses(my name, file, my fsys, addr(daddr)) if flag = 0 then FTP line_in block addr = daddr_da(1) else c printstring("FTP (".itos(table entry).") GET BLOCK ADDR FAILS ".i to s(flag).snl) c and return file = "LINEOUT".i to s(table entry) if TARGET # 2900 then flag = dcreate(my name,file,my fsys, c x'2000'>>10,zerod!tempfi,ada) else c flag = dcreate(my name, file, my fsys, x'2000'>>10, ZEROD!tempfi) flag = 0 if flag = already exists if flag = 0 start flag = get block addresses(my name, file, my fsys, addr(daddr)) if flag = 0 then FTP line_out block addr = daddr_da(1) else c printstring("FTP (".itos(table entry).") GET BLOCK ADDR(O) FAILS ".itos(flag).snl) c and return finish else printstring("FTP (".itos(table entry).") DCREATE ".file." FAILS ".itos(flag).snl) c and return finish else printstring("FTP (".itos(table entry).") DCREATE ".file." FAILS ".itos(flag).snl) c and return finish else printstring("FTP (".itos(table entry).") DCREATE ".file." FAILS ".errs(flag).snl) end ; !OF CREATE FTP WORK FILES routine format command(integer addr, offset, integername new len, integer eor) !************************************************************* !* * !* TRANSLATE THE GIVEN BYTES FROM A BYTE STREAM TO * !* AN FTP FORMATTED STREAM * !* * !************************************************************* integer i, k, wk addr, len len = new len monitor and return if offset + len > x'7FF' !SHOULD NOT BE TRANSLATING MORE THAN 1/2 EPAGE. wk addr = addr + x'800'; !WORK AREA IS TOP HALF OF PAGE. move(len, addr+offset, wk addr); !MOVE TO WORK AREA i = 0; k = 0 cycle if len - i <= 63 start !ONE SUB RECORD LEFT. byteinteger(addr+offset+k) = (len-i) ! eor << 7 !LENGTH OF SUBRECORD AND END OF RECORD MARK IF REQUIRED. move(len-i, wk addr+i, addr+offset+k+1) k = k + (len - i + 1) exit finish !MUST HAVE AT LEAST ONE SUB RECORD LEFT byteinteger(addr+offset+k) = 63; !MAX SUB RECORD LENGTH move(63, wk addr+i, addr+offset+k+1) k = k + 64 i = i + 63 repeat new len = k if 2 < mon level < 5 start select output(1); printstring(dt."FTP (".itos(table entry).") COMMAND OUTPUT: ") cycle i = 0, 1, new len-1 printstring(htos(byteinteger(addr+offset+i), 2)) repeat newline; select output(0) finish return end ; !OF FORMAT COMMAND. if TARGET # 2900 start routine interpret tcc(byteintegername type, subtype) !************************************************************* !* * !* INTERPRET THE THE TCC AT THE END OF THE INPUT BLOCK * !* AND REDUCE THE INPUT LENGTH BY THE TCC LENGTH * !* * !************************************************************* integer i, tcc len if FTP table_data control = FTP data then tcc len = 3 else tcc len = 2 if 2 < mon level < 5 start select output(1) if tcc len = 3 then printstring(dt."FTP TCC input in FTP DATA mode". c " requires 3 bytes. Data length is ".itos(data length).snl) else c printstring(dt."FTP TCC input in FTP DEFAULT mode requires 2 bytes.". c "Data length is ".itos(data length).snl) printstring(dt."FTP (".itos(table entry).") TCC INPUT: ") if data length >= tcc len start cycle i = data start+data length-tcc len, 1, data start+data length-1 printstring(htos(byteinteger(i), 2)) repeat finish else printstring("FTP (".itos(table entry).") LENGTH ???") newline; select output(0) finish -> error unless data length >= tcc len !IE THE INPUT MUST HAVE SPACE FOR A TCC AND END WITH A TCC data length = data length - tcc len type = byteinteger (data start+data length+tcc len-2) subtype = byteinteger(data start+data length+tcc len-1) return error: FTP log(" TCC length ??") type = x'FF' return end ; !OF INTERPRET TCC. routine interpret comm(byteintegername type,shortintegername transfer status) !************************************************************* !* * !* STRIP OFF FTP FORMAT AND EXTRACT THE COMMAND * !* * !************************************************************* integer i, j, k, l, len, cur pos, p count string (63) s if 2 < mon level < 5 start select output(1) printstring(dt."FTP (".itos(table entry).") COMMAND INPUT: ") cycle i = 0, 1, command length-1 printstring(htos(byteinteger(command start + i), 2)) repeat newline select output(0) finish cur pos = 0 cycle i=0, 1, command length-1 j = byteinteger(command start+i) if j&x'3F' > 0 start cycle k = 1, 1, j&x'3F' byteinteger(command start+cur pos)=byteinteger(command start+i+k) cur pos = cur pos + 1 repeat finish i = i + j&x'3F' if (j>>7)&1 = 1 start !END OF RECORD. if i # command length-1 start FTP log(" Command format incorrect") type = x'FF'; !ie force error. return finish exit finish repeat if cur pos <= 1 start !We do not have a 'minimum' command FTP log(" Incomplete COMMAND") type = x'ff' {force error} return finish command length = cur pos type = byteinteger(command start) !now get the transfer status if FTP available in the parameters. transfer status = x'FF' p count = byteinteger(command start + 1) messages = 0 cycle i = 1,1,16 message(i)_s == null string repeat return if p count = 0 k = command start + 2 cycle i = 1,1,p count !FIRST get rid of any parity on the string attributes. if byteinteger(K+1)&X'30' = X'30' start {STRING attribute} len = byteinteger(K+2) if len > 0 start cycle l = 0,1,len-1 byteinteger(K+3+l) = byteinteger(K+3+l)&X'7F' {take off top bit} repeat finish finish !SECOND Look for state_of_transfer if byteinteger(k) = x'0F' then start byteinteger(addr(transfer status)) = byteinteger(k+2) byteinteger(addr(transfer status)+1) = byteinteger(k+3) FTP log(" tran status: ".htos(transfer status,4)) finish unless 0<=byteinteger(k)<=x'80' start !the attributes are screwed up. FTP log(" command input attribute list corrupt.") type = x'FF' return finish if byteinteger(k) = x'71' then start messages = messages + 1 if messages <= 16 then message(messages)_s == string(k+2) finish j = byteinteger(k+1)&x'30' if j <=x'10' then k=k+2 and continue if byteinteger(k) = x'70' then s = string(k+2) and FTP log(s) if j = x'20' then k=k+4 And continue k=byteinteger(k+2)+k+3 repeat return end ; !OF INTERPRET COMM. finish else start routine interpret tcc(byteintegername type, subtype) !************************************************************* !* * !* INTERPRET THE THE TCC AT THE END OF THE INPUT BLOCK * !* AND REDUCE THE INPUT LENGTH BY THE TCC LENGTH * !* * !************************************************************* integer i, tcc len if FTP table_data control = FTP data then tcc len = 3 else tcc len = 2 if 2 < mon level < 5 start select output(1) if tcc len = 3 then printstring(dt."FTP TCC input in FTP DATA mode". c " requires 3 bytes. Data length is ".itos(data length).snl) else c printstring(dt."FTP TCC input in FTP DEFAULT mode requires 2 bytes.". c "Data length is ".itos(data length).snl) printstring(dt."FTP (".itos(table entry).") TCC INPUT: ") if data length >= tcc len start cycle i = data start+data length-tcc len, 1, data start+data length-1 printstring(htos(byteinteger(i), 2)) repeat finish else printstring("FTP (".itos(table entry).") LENGTH ???") newline; select output(0) finish -> error unless data length >= tcc len !IE THE INPUT MUST HAVE SPACE FOR A TCC AND END WITH A TCC data length = data length - tcc len type = byteinteger (data start+data length+tcc len-2) subtype = byteinteger(data start+data length+tcc len-1) return error: FTP log(" TCC length ??") type = x'FF' return end ; !OF INTERPRET TCC. routine interpret comm(byteintegername type,halfintegername transfer status) !************************************************************* !* * !* STRIP OFF FTP FORMAT AND EXTRACT THE COMMAND * !* * !************************************************************* integer i, j, k, l, len, cur pos, p count string (63) s if 2 < mon level < 5 start select output(1) printstring(dt."FTP (".itos(table entry).") COMMAND INPUT: ") cycle i = 0, 1, command length-1 printstring(htos(byteinteger(command start + i), 2)) repeat newline select output(0) finish cur pos = 0 cycle i=0, 1, command length-1 j = byteinteger(command start+i) if j&x'3F' > 0 start cycle k = 1, 1, j&x'3F' byteinteger(command start+cur pos)=byteinteger(command start+i+k) cur pos = cur pos + 1 repeat finish i = i + j&x'3F' if (j>>7)&1 = 1 start !END OF RECORD. if i # command length-1 start FTP log(" Command format incorrect") type = x'FF'; !ie force error. return finish exit finish repeat if cur pos <= 1 start !We do not have a 'minimum' command FTP log(" Incomplete COMMAND") type = x'ff' {force error} return finish command length = cur pos type = byteinteger(command start) !now get the transfer status if FTP available in the parameters. transfer status = x'FF' p count = byteinteger(command start + 1) messages = 0 cycle i = 1,1,16 message(i)_s == null string repeat return if p count = 0 k = command start + 2 cycle i = 1,1,p count !FIRST get rid of any parity on the string attributes. if byteinteger(K+1)&X'30' = X'30' start {STRING attribute} len = byteinteger(K+2) if len > 0 start cycle l = 0,1,len-1 byteinteger(K+3+l) = byteinteger(K+3+l)&X'7F' {take off top bit} repeat finish finish !SECOND Look for state_of_transfer if byteinteger(k) = x'0F' then start byteinteger(addr(transfer status)) = byteinteger(k+2) byteinteger(addr(transfer status)+1) = byteinteger(k+3) FTP log(" tran status: ".htos(transfer status,4)) finish unless 0<=byteinteger(k)<=x'80' start !the attributes are screwed up. FTP log(" command input attribute list corrupt.") type = x'FF' return finish if byteinteger(k) = x'71' then start messages = messages + 1 if messages <= 16 then message(messages)_s == string(k+2) finish j = byteinteger(k+1)&x'30' if j <=x'10' then k=k+2 and continue if byteinteger(k) = x'70' then s = string(k+2) and FTP log(s) if j = x'20' then k=k+4 And continue k=byteinteger(k+2)+k+3 repeat return end ; !OF INTERPRET COMM. FINISH routine send mail !**************************************************** !* Send MAIL to the user about the transfer * !**************************************************** integer mail ident string (11) name mail ident = get next descriptor(my fsys) if mail ident = 0 start FTP log(" MAIL reply fails, no FTRANS descriptors!") flag = ddestroy(my name,"LINEMAIL".itos(table entry),"",my fsys,0) finish else start flag = drename(my name,"LINEMAIL".itos(table entry),identtos(mail ident),my fsys) if flag # 0 start FTP log("MAIL rename fails..document already exists!") flag = ddestroy(my name,"LINEMAIL".itos(table entry),"",my fsys,0) finish else start document==record(document addr(mail ident)) document = 0 document_dest = "MAIL" document_user = "FTRANS" name = "FTP reply" to docstring(document,document_name,name) document_priority = 1; !really low, it dosent matter with mailer. !We have to send mail via SPOOLR. send to spooler(FTP mail, mail ident, no) finish finish end ; !of routine SEND MAIL routine generate(byteinteger type, subtype, integername len) !************************************************************* !* * !* GENERATE THE REQUIRED FTP COMAND OR TCC * !* * !************************************************************* integer start, i, op, value, param count switch comm(0:5) switch tran comm(0:7) record (password document descriptor f)name password document if TARGET # 2900 start routine add(byteinteger id,op,shortinteger bval,string (63) sval) integer addrs; byteinteger qual addrs = reply start + len byteinteger(addrs) = id byteinteger(addrs+1) = op if op&x'70' = bits start byteinteger(addrs+2) = byteinteger(addr(bval)) byteinteger(addrs+3) = byteinteger(addr(bval)+1) len = len + 4 finish else if op&x'70' = strings start string(addrs+2) <- sval len = length(sval)+3+len finish else len = len + 2 param count = param count + 1 end routine set bits(record (FTP bits) name bfield, byteinteger id,op, c shortinteger value,byteinteger set) add(id,op,value,"") bfield_set = set bfield_value = value bfield_qual = op end finish else start routine add(byteinteger id,op,halfinteger bval,string (63) sval) integer addrs; byteinteger qual addrs = reply start + len byteinteger(addrs) = id byteinteger(addrs+1) = op if op&x'70' = bits start byteinteger(addrs+2) = byteinteger(addr(bval)) byteinteger(addrs+3) = byteinteger(addr(bval)+1) len = len + 4 finish else if op&x'70' = strings start string(addrs+2) <- sval len = length(sval)+3+len finish else len = len + 2 param count = param count + 1 end routine set bits(record (FTP bits) name bfield, byteinteger id,op, c halfinteger value,byteinteger set) add(id,op,value,"") bfield_set = set bfield_value = value bfield_qual = op end finish routine set string(record (FTP strings) name sfield, byteinteger id,op, c string (63) value, byteinteger set) add(id,op,0,value) sfield_set = set sfield_value <- value sfield_qual = op end param count = 0 start = reply start if type <= FTP stopack then -> comm(type) else c -> tran comm(type&x'0F') comm(4): !the sft !NOTE 'SET' in the TABLE entry for a file transfer implies that !a fixed and non negotiable value is sent on the SFT. !Otherwise a negotiable entity has been sent and (may) require !a response. !First get the PASSWORD(secure) descriptor. password document == record(password document addr(FTP line_document)) byteinteger(start) = FTP sft len = 2 FTP table_mail to send = yes FTP table_data control = FTP data add(x'71',eq!strings,0,"EMAS 2900 NIFTP-B(80); VSN 4.0") if document_user = "MAILER" then FTP table_mail = yes !protocol id set bits(FTP table_protocol id,x'00',eq!bits,x'0100',yes) !---------------------------------------------------- !mode of access set bits(FTP table_mode,x'01',eq!bits,document_mode of access,yes) if document_mode of access < x'8000' then FTP line_activity = sender c else FTP line_activity = receiver !--------------------------------------------------- !data type op = bits ! eq ; i = yes if FTP line_activity = receiver start if document_FTP user flags&FTP binary read only # 0 or document_ c FTP user flags2&FTP text read only # 0 then document_try emas c to emas = no !If the data type is user specified then obey without question. if document_FTP user flags&FTP binary read only # 0 then c value = x'0002' {BINARY} c else if document_FTP user flags2&FTP text read only # 0 then c value = x'0001' {TEXT} else start op = bits ! le ! monitor value = x'0003' {TEXT or BINARY} i = no finish finish else start Value = X'0001' {ie TEXT for 'true' text and also all other non DATA files} if document_FTP user flags & FTP binary data # 0 start !It is a DATA file, only type to go as FTP BINARY out of EMAS. Value = X'0002' FTP table_binary data record = document_FTP data record finish finish set bits(FTP table_data type,x'20',op,value,i) unless document_FTP user flags&FTP binary read only # 0 start {TEXT etc} !-------------------------------------------------------- !text transfer code. if document_try emas to emas = yes then start if document_FTP user flags&(FTP non text or data ! FTP binary data) # 0 then c set bits(FTP table_text tran code,x'02',EQ!bits,x'0008',yes) else c set bits(FTP table_text tran code,x'02',LE!monitor!bits,x'0009',no) finish else if document_FTP user flags&FTP binary data = 0 then c set bits(FTP table_text tran code,x'02',eq!bits,x'0001',yes) !-------------------------------------------------------- !text format if document_FTP user flags & (FTP binary data ! FTP non text or data) = 0 OR C DOCSTRING(DOCUMENT,DOCUMENT_FTPALIAS) = "FSTORE" {TEMP FRIG} start !We have a text file so proceed. if FTP line_activity = sender c then value = x'0081' else value = x'0083' if document_ftp user flags & FTP ansi # 0 then c set bits(FTP table_text format,x'03',eq!bits,x'0002',yes) else c set bits(FTP table_text format,x'03',le!bits, value,no) !NOTE HERE we are saying two things ! 1) The user has specified that the (INcomming) file has ANSI control cahars ! 2) The choice is left to the Q station (WE will not expect it to choose ! ANSI for a file it will recieve so let this be a general value) finish !-------------------------------------------------------- finish {TEXT etc only} !------------------------------------------------------- !BIN word size and BIN format if document_FTP user flags & FTP binary data # 0 or (FTP line_activity = receiver c and document_FTP user flags2&FTP text read only = 0) start !We have a data file (Sender) set bits(FTP table_binary word size, x'24', eq!bits, x'0008', yes) finish !------------------------------------------------------ !max tran record size. if document_FTP user flags & FTP binary data # 0 and c (document_FTP data record &x'03') = 4 start if document_FTP data record&x'03' = 3 {UNSTRUCTURED} then set bits( c FTP table_max tran rec size,x'05',eq!bits,document_data length,yes) else c set bits(FTP table_max tran rec size,x'05', eq!bits,document_FTP data record>>16,yes) finish else c set bits(FTP table_max tran rec size,x'05',le!bits!monitor,x'ffff',no) !-------------------------------------------------------- !private code name if document_try emas to emas = yes then set string(FTP table_private c code name,x'09',eq!strings,private code,yes) !------------------------------------------------------- !now the file details etc. if document_external user # 0 then c set string(FTP table_username,x'42',eq!strings,doc string(document,document_external user),yes) if document_external password = set then c set string(FTP table_username password,x'44',eq!strings, c password doc string(password document,password document_external password),yes) set string(FTP table_filename,x'40',eq!strings,doc string( c document,document_external name),yes) if document_external name # 0 if document_FTP file password = set then set string(FTP table_file password, c x'45',eq!strings,password docstring(password document,password document_FTP file password),yes) !------------------------------------------------------ !Is the job going to or coming to a device. !Now the code handling auto polling return of output from remote jobmills. if document_mode of access = give job output and document_auto requeue = yes start document_device type = 0 document_ftp user flags = document_ftp user flags ! ftp no mail FTP log(" Auto output poll to ".string at(FTP stations(FTP line_station ptr) c ,ftp stations(ftp line_station ptr)_shortest name).snl) finish if document_mode of access = give job output and document_device type = 0 start !We are dragging job output without knowing where to..ask the other end. add(x'50',monitor!any!strings,0,"") add(x'51',monitor!any!strings,0,"") finish if document_device type # 0 start if FTP line_activity = sender start if doc string(document,document_device type) = "LP" then c op = monitor!eq!strings else op = eq!strings set string(FTP table_device type,x'50',op, doc string( c document,document_device type),yes) finish else start FTP table_device type_set = yes FTP table_device type_value <- docstring(document,document_device type) finish finish !------------------------------------------------------ !The special options field. if document_special options = set then set string(FTP table_special options, c x'80',eq!strings,password doc string(password document,password document_special options),yes) !---------------------------------------------------- !file size if FTP stations(control entry)_limit < FTP stations(FTP line_station ptr)_limit then limit = c FTP stations(control entry)_limit else limit = FTP stations(FTP line_station ptr)_limit if FTP line_activity = sender then I = document_data length if string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name) = "UMRCC.GFILE" then c I = 1 and limit = 1 !THIS HAS TO BE DONE IN THE SHORT TERM TO GET ROUND MANCHESTER'S !INABILITY TO IMPLEMENT IT'S Q STATION TO THE OW SPEC if FTP line_activity = sender then set bits(FTP table_file size, c x'60',eq!bits,( I +1023)>>10,yes) else c set bits(FTP table_file size,x'60',le!monitor!bits,limit,no) !---------------------------------------------------- !timeout set bits(FTP table_timeout,x'0D',eq!bits,x'0258',yes) byteinteger(start+1) = param count format command(start, 0, len, 1) RETURN comm(3): !RNEG, This is only generated here when BATCh scheduling parameters given !with a TAKE_JOB_INPUT transfer are at fault after the transfer itself whas !been oked by the main negotiation module. !The STOPACK message is used in this case to hold the info message. byteinteger(start) = type byteinteger(start+1) = 2 byteinteger(start+2) = x'0F' byteinteger(start+3) = x'22' IF TARGET # 2900 THEN SHORTinteger(start+4) = FTP line_transfer status ELSE C halfinteger(start+4) = FTP line_transfer status len = 6 add(x'71',eq!strings,0,FTP table_stopack message) !the format will be done in thsi case on return to the calling routine. return comm(1): !ie GO byteinteger(start) = type byteinteger(start+1)= 0 len = 2 format command(start, 0, len, 1) return comm(0): comm(5): !ie STOP and STOPACK byteinteger(start) = type byteinteger(start + 1) = 1 byteinteger(start + 2) = x'0F' byteinteger(start + 3) = X'22' IF TARGET # 2900 THEN SHORTinteger(start+4) = FTP line_transfer status ELSE C halfinteger(start + 4) = FTP line_transfer status len = 6 if type = FTP STOPACK and FTP table_stopack message # "" then c add(x'71',eq!strings,0,FTP table_stopack message) c and byteinteger(start + 1) = 2 format command(start,0,len,1) return tran comm(0): tran comm(2): tran comm(3): tran comm(6): tran comm(7): start = start + len; !may have more than one tcc to go out. byteinteger(start) = 0 byteinteger(start+1) = x'40'!TYPE byteinteger(start+2) = subtype len = len + 3 if 2 < mon level < 5 start select output(1); printstring(dt."FTP (".itos(table entry).") TCC OUTPUT: ") cycle i=0, 1, 2 printstring(h to s(byteinteger(start+i), 2)) repeat newline; select output(0) finish return end ; !OF GENERATE. !* routine evaluate negotiation(integer command start, reply start, c integername reply length, integer limit, byteintegername type) !**************************************************************************** !* * !* This routine is the general FTP-B(80) negotiation evaluation package. * !* It handles the following: * !* 1) A Q station recieving an SFT ,it generates an RPOS or RNEG * !* 2) A P station recieving a RPOS ,it generates a STOP or accept transfer * !* 3) A P station recieving a RNEG ,it reports and generates a STOP * !* 4) A Q station recieving a STOP after sending RPOS, reports only. * !* * !**************************************************************************** record (FTP tablef) name FTP wrk record (finff) finf record (fhf) name file header routinespec fill work entry(integer start) routinespec default table entry if TARGET # 2900 start routinespec add(byteinteger id,op, shortinteger bval, string (63) sval) routinespec reject(byteinteger id,op, shortinteger bval, string (63) sval, c shortinteger rej code) routinespec handle rneg integerfnspec try bits(record (FTP bits)name field, shortinteger value) integerfnspec try value(record (FTP bits)name field, shortinteger value) integerfnspec bits set(shortinteger value) finish else start routinespec add(byteinteger id,op, halfinteger bval, string (63) sval) routinespec reject(byteinteger id,op, halfinteger bval, string (63) sval, c halfinteger rej code) routinespec handle rneg integerfnspec try bits(record (FTP bits)name field, halfinteger value) integerfnspec try value(record (FTP bits)name field, halfinteger value) integerfnspec bits set(halfinteger value) finish integerfnspec validate filename(string (39) file) integer param count, flag, file type, seg, gap, i, j string (63) info, S, s1 routine uc tran(stringname string) integer i,j if length(string) > 0 start cycle i = 1,1,length(string) j = byteinteger(addr(string)+i) byteinteger(addr(string)+i) = j&95 if 'a'<=j<='z' repeat finish end ; !of routine UC TRAN param count = 0; reply length = 2 info = "" FTP wrk == FTP tables(0) if type = FTP rneg then handle rneg and return else fill work entry(command start) return if type = FTP STOP !NOTE Setting The string 'info' before a call of 'add' or 'reject' !ensures that an extra infromation message(x'71' type) is added to !the reply. 'info' will return from the called routine set to "" if FTP line_status = awaiting sft start type = FTP rpos default table entry FTP table_mail = FTP wrk_mail if FTP wrk_mail = yes; !note this in only for NSI. finish !ie a Q station so assume we will suceed and put defaults in the table !protocol identification if FTP line_status = awaiting sft start !ie a Q station. if FTP wrk_protocol id_set = no start !not given by p ! if FTP wrk_protocol id_qual & monitor # 0 then add(x'00',bits!eq,x'0100',"") FTP table_protocol id_value = x'0100' FTP table_protocol id_set = yes finish else start if FTP wrk_protocol id_value >> 8 # x'01' start info = "invalid protocol identification" reject(x'00',bits!eq,x'0100',"",rejected attribute) return finish FTP table_protocol id = FTP wrk_protocol id finish finish !no action for p station on rpos !Mode Of Access if FTP line_status = awaiting sft start if FTP wrk_mode_value & x'0100' # 0 start !resume wanted...no way yet info = "resume not permitted" reject(x'01',bits!eq,x'feff'&FTP wrk_mode_value,"",rejected attribute) return finish if FTP wrk_mode_set = no start reject(x'71',strings!eq,0,"no mode of access",rejected attribute) return finish if FTP wrk_mode_value & x'E000' = x'8000' start !ie Q to P file transfer if FTP wrk_mode_value <= x'8002' then FTP table_mode = FTP wrk_mode c else reject(x'01',bits!le,x'8003',"",rejected attribute) and return if FTP wrk_mode_qual & monitor # 0 then add(x'01',bits!eq,FTP wrk_mode_value,"") FTP line_activity = sender finish else if FTP wrk_mode_value & x'E000' = 0 start !ie it is P to Q file transfer if FTP table_mail = no start if FTP wrk_mode_value = X'0005' {MAKE_OR_APPEND} start !We do not support append, change to MAKE and warn. FTP wrk_mode_value = X'0001' add(x'71',eq!strings,0,"APPENDing not supported") finish if FTP wrk_mode_value <= x'0003' then FTP table_mode = FTP wrk_mode c else reject(x'01',bits!eq,x'0003',"",rejected attribute) and return if FTP wrk_mode_qual & monitor # 0 and FTP wrk_mode_value # x'0003' c then add(x'01',bits!eq,FTP table_mode_value,"") finish else FTP table_mode_value = x'0001' and FTP table_mode_set = yes !IE MAIL gets thro on 'any' file mode. FTP line_activity = receiver finish else if FTP wrk_mode_value & x'6000' # 0 start !P to Q job mode FTP line_activity = receiver if FTP wrk_mode_value = x'4001' start !take job output. if FTP wrk_device type_set = no and FTP wrk_device type qualifier_set = no start if FTP wrk_device type_qual&any # 0 or FTP wrk_device type_qual& c monitor # 0 start !wants us to choise..use LP FTP table_device type_value = "LP" FTP table_device type_set = yes finish else start info = "Device required with 'take job output'" reject(x'50',strings!any,0,"",rejected attribute) return finish finish else start FTP table_device type_value <- FTP wrk_device type_value. c FTP wrk_device type qualifier_value if FTP table_device type_value -> s1.(".").s and s1 = "" then FTP table_device type_value = s FTP table_device type_set = yes uc tran(FTP table_device type_value) finish FTP table_mode = FTP wrk_mode finish else start !It is TAKE_JOB_INPUT..let it thro. The scheduling is checked in the main module. FTP table_mode = FTP wrk_mode finish finish else if FTP wrk_mode_value & x'F000' > x'A000' start !Q to P job transfer !again not yet supported. FTP line_activity = sender info = "not yet supported" reject(x'01',bits!le,x'8003',"",rejected attribute) return finish else start info = "non defined mode of access!" reject(x'01',bits!any,0,"",rejected attribute) return finish finish else start !P station has rpos...what did we send? if FTP line_activity = sender and FTP table_mode_value = x'0003' start !we sent choice. s = "" if FTP wrk_mode_set = yes and FTP wrk_mode_value < x'0003' then c FTP table_mode_value = FTP wrk_mode_value else s = "Possibly " if FTP table_mode_value = x'0001' then mail report( c "Transfer will create a new file".snl,0) else mail report(s."Transfer will overwrite an existing file".snl,0) finish !this way we know the activity undertaken at the q station. finish !Now verify the file attributes. if FTP line_status = awaiting sft start !Q station if FTP table_mail = no start !don't do this checking for MAIL transactions. if FTP wrk_username_set = no start if FTP table_mode_value = x'4001' then FTP table_username_value = c "FTPMAN" and FTP table_username_set = yes and -> get fsys !else there should be a username. info = "no username given" reject(x'42',any!strings,0,"",rejected attribute) return finish else start FTP table_username = FTP wrk_username uc tran(FTP table_username_value) get fsys: FTP table_user fsys = -1 flag = dfsys(FTP table_username_value,FTP table_user fsys) if flag # 0 start info = "user not known" reject(x'42',ne!strings,0,FTP table_username_value,rejected attribute) return finish FTP line_user = ftp table_username_value {for picture update efficiency} finish unless FTP table_mode_value = x'4001' start if FTP wrk_file password_set = yes then add(x'71',eq!strings, c 0,"File password not required.") if FTP wrk_username password_set = no start info = "no username password given" reject(x'44',strings!any,0,"",rejected attribute) return finish else start FTP table_username password = FTP wrk_username password flag = d check bpass(FTP table_username_value,FTP table_username password_value, c FTP table_user fsys) if flag # 0 start info = "invalid username password" reject(x'44',ne!strings,0,FTP table_username password_value,rejected attribute) return finish finish finish finish else start FTP table_username_value = "MAILER" FTP table_user fsys = my fsys FTP line_user = "MAILER" finish if FTP wrk_filename_set = no start unless FTP table_mode_value = x'4001' or FTP table_mode_value = x'2001' c or (FTP wrk_device type_set = c yes and FTP table_mode_value = x'0001') or FTP table_mail = yes start !we need a file name if it is not for a device or MAIL. info = "No filename given" reject(x'40',strings!any,0,"",rejected attribute) return finish finish else start FTP table_filename = FTP wrk_filename if FTP table_mail = yes then flag = 1 else start uc tran(FTP table_filename_value) unless validate filename(FTP table_filename_value) = ok start !They have given a bad filename. info = FTP table_filename_value." is not a valid EMAS filename." reject(X'40',strings!ne,0,FTP table_filename_value,rejected info) return finish if TARGET # 2900 then flag = dfinfo(FTP table_username_value,FTP table_ c filename_value,FTP table_user fsys,finf_offer,finf_i) else c flag = dfinfo(FTP table_username_value,FTP table_filename_value,FTP table_user fsys,addr(finf)) finish if FTP line_activity = sender start !we are to send the file if flag # 0 start !the file isn't there! info = FTP table_username_value.".".FTP table_filename_value." not found." reject(x'40',ne!strings,0,FTP table_filename_value,rejected attribute) return finish finish else start !we are to receive the file if FTP table_mode_value = x'0003' start if flag = 0 then FTP table_mode_value = x'0002' else c FTP table_mode_value = x'0001' add(x'01',eq!bits,FTP table_mode_value,"") finish else if (FTP table_mode_value = x'0001' and flag = 0) c or (FTP table_mode_value = x'0002' and flag # 0) start if FTP table_mode_value = x'0001' then info = "File already exists" c else info = "File does not already exist" reject(x'01',ne!bits,FTP table_mode_value,"",rejected attribute) return finish finish finish finish !The Data Type for the transaction. if FTP line_status = awaiting sft start if FTP wrk_data type_set = no start !then we will assume the default of text. FTP wrk_data type_value = x'0001' FTP wrk_data type_qual = eq!bits FTP wrk_data type_set = yes FTP log("No data type on P sft, default assumed.") !we set wrk not table and fall through to the file type test. finish !not default but specifically defined or drop through from default assumption. if FTP line_activity = sender start seg = 0; gap = 0 flag = dpermission(FTP table_username_value,myname,"",ftp table_filename_value, c FTP table_user fsys,2,r) if flag = 0 start if TARGET # 2900 then flag = dconnect(FTP table_username_value, c FTP table_filename_value,FTP table_user fsys,R,seg,gap) else c flag = dconnect(FTP table_username_value,FTP table_filename_value, c FTP table_user fsys,R,0,seg,gap) finish if flag # 0 start reject(x'71',eq!strings,0,"file not available, try later",rejected deferred) return finish flag = dpermission(FTP table_username_value,myname,"",ftp table_filename_value, c FTP table_user fsys,3,r) file header == record(seg<<seg shift) file type = file header_type unless try bits(FTP wrk_text tran code,x'0008') = yes and c FTP wrk_private code name_value = private code start if file type = iso text start flag = ddisconnect(FTP table_username_value,FTP table_filename_value,FTP table_user fsys,0) if try bits(FTP wrk_data type,x'0001') = yes start !we can select text. FTP table_data type_set = yes if FTP wrk_data type_qual & monitor # 0 then add(x'20',eq!bits,x'0001',"") finish else if try bits(FTP wrk_data type,x'0002') = yes start !we are required to transmit text as binary info = "Text as binary not yet available." reject(x'20',eq!bits,x'0001',"",rejected attribute) return finish else start !any other reject. reject(x'20',eq!bits,x'0001',"",rejected attribute) return finish finish else start if file type = 4{DATA} start !We have a DATA file send as BINARY. if try bits(FTP wrk_data type,x'0002') = yes start !OK they will accept a binary transfer FTP table_data type_value = x'0002' FTP table_data type_set = yes FTP table_binary data record = file header_binary record if FTP wrk_data type_qual & monitor # 0 or FTP wrk_data type_qual c & op mask # eq then add(x'20',eq!bits,x'0002',"") flag = ddisconnect(FTP table_username_value,FTP table_filename_value,FTP table_user fsys,0) finish else start info = "File is binary and Binary transfers not supported by you." reject(x'20',eq!bits,x'0002',"",rejected attribute) return finish finish else start reject(x'71',eq!strings,0,"File is not TEXT or BINARY data",rejected info) flag = ddisconnect(FTP table_username_value,FTP table_filename_value,FTP table_user fsys,0) return finish finish finish else flag = ddisconnect(FTP table_username_value,c FTP table_filename_value,FTP table_user fsys,0) finish else start !we are to receive. unless try bits(FTP wrk_text tran code,x'0008') = yes and c FTP wrk_private code name_value = private code start if try bits(FTP wrk_data type,x'0001') = yes start !text,as yet, only option..chose it if FTP wrk_data type_qual&monitor # 0 then add(x'20',eq!bits,x'0001',"") FTP table_data type_set = yes finish else if try bits(FTP wrk_data type,x'0002') = Yes start FTP table_data type_value = x'0002' FTP table_data type_set = yes FTP table_data control = translate{ie no assist form the FEP in sub rec handling} if FTP wrk_data type_qual & monitor # 0 then add(x'20', c eq!bits,x'0002',"") finish else start reject(x'71',eq!strings,0,"Mixed data not supported",rejected attribute) return finish finish finish finish else start !P station has got an RPOS unless try bits(FTP wrk_text tran code, x'0008') = yes start !If inter emas has been accepted then don't bother with data type if FTP table_data type_set = yes start !we must be the sender and know the data type. if FTP wrk_data type_set = yes and FTP table_data type_value c # FTP wrk_data type_value start !The Q has sent RPOS with differing data type. ! info = "DATA-TYPE response unacceptable" mail report("Negotiation failure (".info.")".snl,0) handle RNEG FTP log("Q responds with wrong DATA-TYPE on RPOS") FTP table_emastoemas = rejected transfer status = rejected info return finish finish else start !We sent a choice(as reciever) so Q must respond if FTP wrk_data type_set = yes start !We have a response from Q on this if FTP wrk_data type_value = x'0001'{TEXT} start FTP table_data type = FTP wrk_data type finish else if FTP wrk_data type_value = x'0002'{BINARY} start FTP table_data type = FTP wrk_data type FTP table_data control = translate{no FEP assists on sub records} finish finish else start !EH? FTP log(" no DATA_TYPE response from Q !") info = "NO response by your Q on DATA_TYPE monitor. Protocol error" FTP table_emastoemas = rejected transfer status = rejected info return finish finish finish finish ! The Text Transfer Code. if FTP line_status = awaiting sft start if FTP wrk_text tran code_set = no and FTP table_data type_value = x'0001'{text} start !must assume default. FTP table_text tran code_set = yes if FTP wrk_text tran code_qual&monitor # 0 then add(x'02',eq!bits,x'0001',"") finish else start if try bits(FTP wrk_text tran code,x'0008') = yes start !we have a private code, is it emas-emas? unless FTP wrk_private code name_value = private code start info = "unknown private code name" finish else start FTP table_text tran code_value = x'0008' FTP table_text tran code_set = yes FTP table_private code name_set = yes FTP table_private code name_value = FTP wrk_private code name_value FTP table_emas to emas = yes FTP table_data control = no translation add(x'09',eq!strings,0,FTP table_private code name_value) add(x'02',eq!bits,x'0008',"") !Reflect the code type. finish finish if FTP table_private code name_set = no and FTP table_data type_value = x'0001'{TEXT} start !we have not accepted a private code, look at the options if try bits(FTP wrk_text tran code,x'0001') = yes start !we will accept IA5 text transfer. FTP table_text tran code_value = x'0001' FTP table_text tran code_set = yes finish else start !no other possible text code. reject(x'02',ne!bits,x'0004',"",rejected attribute) return finish finish if FTP table_data type_value = x'0001'{TEXT} and (FTP wrk_text tran code_qual&op mask # eq or c FTP wrk_text tran code_qual&monitor # 0) then add(x'02',eq!bits, c FTP table_text tran code_value,"") finish finish else start !P station has RPOS. if FTP table_text tran code_qual&monitor # 0 or c FTP table_text tran code_qual&op mask # eq or c (FTP table_text tran code_value = x'0008' and ((FTP wrk_text tran code_value c = x'0008' and FTP wrk_text tran code_ qual&op mask = eq) or c (FTP wrk_private code name_qual&op mask = eq and FTP wrk_private code c name_value = private code))) start !NOTE that the rule of INTER-EMAS is that the Q will on the RPOS !always send back text transfer code of EQ x'0008' ! !We sent choice or monitor or private code only. !or implied inter emas in DATA only transaction. if FTP table_text tran code_qual&op mask # eq and c FTP wrk_text tran code_qual&op mask # eq start if FTP table_data type_value = x'0002' then -> skip ttc !We do this since if it is BINARY the TTC does not matter(except EMAS private code) FTP log("Q fails to respond on RPOS to text tran code mon/choice.") FTP table_emas to emas = rejected transfer status = rejected info info = "No text tran code response on RPOS" mail report("Negotiation Failure".snl,0) handle rneg return finish FTP table_text tran code = FTP wrk_text tran code unless FTP table_text tran code_set = yes if FTP table_text tran code_value = x'0008' start !The private code has been selected. FTP log("----inter EMAS new style----") FTP table_emastoemas = yes FTP table_data control = no translation finish finish skip ttc: finish !Text Formatting if FTP table_data type_value = x'0001'{TEXT} start !HERE NOTE that we accept the following at release 3 level ! x'0001' OSI required level ! x'0002' ANSI control for INcomming transfer ONLY ! x'0080' FREE format..let the file thro as it is presented. if FTP table_emas to emas = no and FTP table_data type_value # X'0002' start !ie not EMAS intercommunication or Binary only transaction. if FTP line_status = awaiting sft start !Q station. if FTP wrk_text format_set = no start !assume the default. FTP log("Assuming Default Text Format") FTP table_text format_set = yes if FTP wrk_text format_qual&monitor # 0 then add(x'03',eq!bits,x'0001',"") finish else if FTP wrk_text format_qual&op mask = eq start !at the moment we are aiming at open working and 'free' format(x'0080') !and ANSI (x'0002')(INcomming transfers only) unless FTP wrk_text format_value & x'0081' # 0 or c (FTP wrk_text format_value & x'0083' # 0 and FTP line_activity = receiver) start reject(x'03',bits!le,x'0081',"",rejected attribute) return finish FTP table_text format = FTP wrk_text format finish else start !we are given a choice. if try bits(FTP wrk_text format,x'0001') = yes then c FTP table_text format_value = x'0001' else if c (try bits(FTP wrk_text format,x'0002') = yes and FTP line_activity = receiver) then c FTP table_text format_value = x'0002' else if c try bits(FTP wrk_text format,x'0080') = yes then c FTP table_text format_value = x'0080' else start !no other initially permitted info = "other text transfers under development" reject(x'03',bits!le,x'0083',"",rejected attribute) return finish FTP table_text format_set = yes finish if FTP wrk_text format_qual&monitor # 0 or FTP wrk_text format_qual&op mask # eq then c add(x'03',eq!bits,FTP table_text format_value,"") if FTP table_text format_value = x'0080' and FTP line_activity = sender c and {PRE OSCOM FEP only} TARGET = 2900 then FTP table_data control = no translation finish else start !WE are a P station and sent a choice. if FTP table_text format_set = no start !we have sent a choice and requested monitor. if FTP wrk_text format_qual&op mask # eq start !we have no response. FTP log("No text format monitor response(qual # eq)") transfer status = rejected info info = "No text format response on RPOS" mail report("Negotiation Failure".snl,0) handle rneg return finish unless (FTP wrk_text format_value & x'0081' # 0 or ( c FTP wrk_text format_value & x'0083' # 0 and FTP line_activity = receiver)) c and bits set(FTP wrk_text format_value) = 1 start FTP log("Q has not taken an acceptable text format choice") transfer status = rejected info info = "Unaccepted text format choice" mail report("Negotiation Failure".snl,0) handle rneg return finish FTP table_text format = FTP wrk_text format finish else if FTP wrk_text format_set = yes start !we already had a value in mind but Q knows better. if FTP wrk_text format_qual&op mask = eq and FTP wrk_text format_ c value & x'0081' # 0 and bits set(FTP wrk_text format_value) = 1 start FTP log("Q changes text format OK") FTP table_text format = FTP wrk_text format finish else start FTP log("Q screws text format negotiation") transfer status = rejected attribute info = "Text format negotiation screwed" mail report("Negotiation Failure".snl,0) handle rneg return finish finish if FTP table_text format_value = x'0080' and FTP line_activity = sender c and {PRE OSCOM FEP only} TARGET = 2900 then FTP table_data control = no translation finish finish finish !Device type. if FTP line_status = awaiting sft start if FTP wrk_device type_qual & monitor # 0 then start if FTP table_mode_value = x'4001' then add(x'50',eq!strings,0, c FTP table_device type_value) finish !only need to reply to a monitor for a device. finish else start if ftp table_mode_value = give job output start !This is a special case where job output is being dragged back and the !RPOS may include a device type from the run job JCL. if ftp wrk_device type_set = yes start ftp table_device type_value = ftp wrk_device type_value if ftp wrk_device type qualifier_set = yes then ftp table_device type_ c value = ftp table_device type_value.ftp wrk_device type qualifier_value ftp table_device type_set = yes finish finish else start if FTP wrk_device type_set = yes and FTP table_device type_set = yes start !sent a possible device and got one back. if FTP wrk_device type_value # FTP table_device type_value c and type # FTP rneg start mail report("External system chooses device: ". c FTP wrk_device type_value.snl,0) FTP table_device type = FTP wrk_device type finish finish finish finish !max transfer record size if FTP line_status = awaiting sft start !we will accept any value defaulting to infinity(x'ffff') if FTP wrk_max tran rec size_set = yes then c FTP table_max tran rec size = FTP wrk_max tran rec size else c FTP table _max tran rec size_set = yes if FTP wrk_max tran rec size_qual&monitor # 0 then c add(x'05',bits!eq,FTP table_max tran rec size_value,"") finish else start if FTP line_activity = sender and FTP table_emastoemas = no and c FTP table_data type_value = x'0002' and FTP wrk_max tran rec size_set = yes c and FTP wrk_max tran rec size_value < FTP table_max tran rec size_value start !We have a DATA file that cannot be transmitted RECORDS PRESERVED because !Q will not accept the MAX-TRAN-REC-SIZE. FTP log("Q cannot handle large enough RECORDS") info = "DATA file has too large records for your Q." mail report("DATA records too large for External Station to handle".snl,0) transfer status = rejected info handle rneg return finish else if FTP wrk_max tran rec size_set = yes then c FTP table_max tran rec size = FTP wrk_max tran rec size finish !Transmission Limit if FTP line_status = awaiting sft start if FTP wrk_tran limit_set = yes start !The P station has set a value on tran limit if FTP line_activity = sender and FTP wrk_tran limit_value < x'FFFF' start !It is only meaningful if we are sending and infinity not assumed. if finf_nkb+1 > FTP wrk_tran limit_value start info = "File requested larger than your TRANSMISSION-LIMIT" reject(X'06',eq!bits,finf_nkb+1,"",rejected info) return finish else FTP table_tran limit = FTP wrk_tran limit finish finish if FTP wrk_tran limit_qual&monitor # 0 then add(X'06',eq!bits,x'FFFF',"") finish else start if FTP wrk_tran limit_set = yes start if FTP line_activity = sender and FTP wrk_tran limit_value < x'ffff' start if FTP table_file size_value > FTP wrk_tran limit_value start info = "EMAS file in excess of your TRANSMISSION-LIMIT" mail report("Transfer is too large and is rejected.".snl,0) handle rneg return finish FTP table_tran limit = FTP wrk_tran limit finish finish finish !Now look at the file size !LET X25 mail in without FILE-SIZE at the moment if FTP table_mail = yes and FTP wrk_file size_set = no then c FTP wrk_file size_set = yes and FTP wrk_file size_value = 1 if FTP wrk_file size_set = yes and FTP wrk_file size_value = 0 then c FTP wrk_file size_value = 1 if FTP line_status = awaiting sft start !we are the Q station if FTP line_activity = sender start FTP table_file size_value = finf_nkb add(x'60',eq!bits,finf_nkb,"") finish else start if FTP wrk_file size_set = no start info = "No File size given, large transfer assumed ." FTP wrk_file size_set = yes FTP wrk_file size_value = 100 ! reject(x'60',any!bits,0,"",rejected attribute) ! %return finish FTP table_file size = FTP wrk_file size finish if FTP table_file size_value > limit then start reject(x'71',strings!eq,0,"File too large, try later",rejected deferred) return finish finish else start if FTP line_activity = receiver start !we are P station receiver !and we expect to be given a size. if FTP wrk_file size_set = no start FTP log("No file size from Q, 100k assumed.") FTP wrk_file size_value = 100 FTP wrk_file size_set = yes finish FTP table_file size = FTP wrk_file size if FTP table_file size_value > limit start FTP log("We shall exceed our own transfer limit!!!") !need to set document timer here! transfer status = rejected deferred info = "Try Later, Transfer too large for now" handle rneg return finish finish finish !BINARY_WORD_SIZE if FTP table_data type_value = x'0002' start !It is a binary transfer if FTP line_status = awaiting sft start if FTP wrk_binary word size_set = no start !We therefore assume the default. add(x'24',eq!bits,x'0008',"") finish else start unless try value(FTP wrk_binary word size, x'0008') = yes start !We only support BINARY_WORD_SIZE of 8 info = "Only BINARY_WORD_SIZE 8 supported" reject(x'24',eq!bits,x'0008',"",rejected attribute) return finish if FTP wrk_binary word size_qual&monitor # 0 or FTP wrk_binary word c size_qual&op mask # eq then add(x'24',eq!bits,x'0008',"") finish finish else start !We have RPOS if FTP wrk_binary word size_set = yes and FTP wrk_binary word size_value # c FTP table_binary word size_value start info = "BINARY_WORD_SIZE of 8 only supported." FTP log("Q cannot support BINARY_WORD_SIZE of 8") mail report("Cannot agree on Binary transfer, negotiation fails.".snl,0) transfer status = rejected info handle rneg return finish finish !BINARY_FORMAT {Does not matter since word size of 8 is only one supported.} finish !Now clear up the remaining attributes if FTP line_status = awaiting sft start !Initial restart mark. if FTP wrk_restart mark_qual&monitor # 0 then add(x'0B',eq!bits,0,"") !only need to reply to monitor !Timeout if FTP wrk_timeout_qual&monitor # 0 then add(x'0D',eq!bits,x'0258',""); !ie 10 mins !again only reply to monitor !Facilities !Q station only accepts default at the moment. if FTP wrk_facilities_qual&monitor # 0 or FTP wrk_facilities_set = yes c then add(x'0E',eq!bits,0,"") FTP table_facilities_set = yes finish !OK.. We now clear up if FTP line_status = awaiting sft start flag = reply length byteinteger(reply start) = FTP RPOS byteinteger(reply start + 1) = param count FTP log("RPOS sent.") fill work entry(reply start) !ie report on the RPOS finish return routine fill work entry(integer start) !This routine is entered to report on the contents of an incomming or !an outgoing command (determined by the 'start' address) and in the !case of an incomming command sets up the work table to be processed !with respect to the negotiation of the transfer. integerfnspec noffset if TARGET # 2900 start shortintegerfnspec hi(integer from) finish else start halfintegerfnspec hi(integer from) finish record (FTP bits) name bfield record (FTP strings) name sfield record (FTP bits) tran status switch att0,att2,att4,att5,att7 (0:15) integer offset, count, i ,pstart, attribute, qualifier offset = 2; count = byteinteger(start + 1) FTP wrk = 0 FTP log("Evaluating ".type descr(type)) if start = command start if count = 0 start !no parameters given , could be ok for RPOS but not SFT if FTP line_status = awaiting sft and start # reply start then c add(x'71',eq!strings,0,"No attributes on SFT!") FTP log("No attributes with command") return finish cycle i = 1,1,count !look at each attribute pstart = start + offset attribute = byteinteger(pstart) qualifier = byteinteger(pstart + 1) if attribute < x'10' then -> att0(attribute) if x'20' <= attribute <x'30' then -> att2(attribute - x'20') if x'40' <= attribute < x'50' then -> att4(attribute - x'40') if x'50' <= attribute < x'52' then -> att5(attribute - x'50') if attribute = x'60' then -> att6 if x'70'<= attribute < x'72' then -> att7(attribute - x'70') if attribute = x'80' then -> att8 FTP log("attribute not valid: ".h to s(attribute,2)) offset = noffset continue integerfn noffset if qualifier&form mask = strings then result = byteinteger(pstart+2)+3+offset c else if qualifier&form mask = bits then result = offset + 4 else result = offset + 2 end routine set string sfield_qual = qualifier unless qualifier&op mask = any then start sfield_set = yes sfield_value <- string(pstart + 2) finish offset = noffset if monitoring = on then FTP log("Attribute ".htos(attribute,2)." / ".qual descr((qualifier>>4)&x'03'). c " / ".op descr(qualifier&op mask).mon descr((qualifier&monitor)>>7)." / ".sfield_value) return end routine reject message(string (63) mess) if type = FTP rneg and start # reply start then c mail report(mess.snl,0) end routine set bits bfield_qual = qualifier unless qualifier&op mask = any then start bfield_set = yes bfield_value = hi(pstart) finish offset = noffset if monitoring = on then FTP log("Attribute ".htos(attribute,2)." / ".qual descr((qualifier>>4)&x'03'). c " / ".op descr(qualifier&op mask).mon descr((qualifier&monitor)>>7)." / ".htos(bfield_value,4)) return end if TARGET # 2900 start shortintegerfn hi(integer from) shortinteger i byteinteger(addr(i)) = byteinteger(from+2) byteinteger(addr(i)+1) = byteinteger(from+3) result = i end finish else start halfintegerfn hi(integer from) halfinteger i byteinteger(addr(i)) = byteinteger(from+2) byteinteger(addr(i)+1) = byteinteger(from+3) result = i end finish att0 (0): bfield == FTP wrk_protocol id set bits continue att0(1): bfield == FTP wrk_mode set bits; continue att0(2): bfield == FTP wrk_text tran code set bits; continue att0(3): bfield == FTP wrk_text format set bits; continue att0(4): bfield == FTP wrk_binary format set bits; continue att0(5): bfield == FTP wrk_max tran rec size set bits; continue att0(6): bfield == FTP wrk_tran limit set bits; continue att0(9): sfield == FTP wrk_private code name set string; continue att0(11): bfield == FTP wrk_restart mark set bits; continue att0(13): bfield == FTP wrk_timeout set bits; continue att0(14): bfield == FTP wrk_facilities set bits; continue att0(15): !transfer status. bfield == tran status set bits continue att0(*): att2(*): att4(*): att5(*): if monitoring = on then FTP log("Attribute not handled : ".htos(attribute,2)) add(attribute,any!attribute unknown,0,"") if type # FTP rneg and start # reply start offset = noffset continue att2(0): bfield == FTP wrk_data type reject message("Invalid file type".snl) set bits; continue att2(4): bfield == FTP wrk_binary word size set bits; continue att4(0): sfield == FTP wrk_filename reject message("External file name is rejected".snl) set string continue att4(2): sfield == FTP wrk_username reject message("External user name is rejected.".snl) set string; continue att4(4): sfield == FTP wrk_username password reject message("External user pass is rejected.".snl) set string; continue att4(5): sfield == FTP wrk_file password reject message("External file pass is rejected.".snl) set string continue att5(0): sfield == FTP wrk_device type reject message("External output device name is rejected.".snl) set string continue att5(1): sfield == FTP wrk_device type qualifier reject message("Device type".snl) set string continue att6: bfield == FTP wrk_file size set bits; continue att7(0): offset = noffset continue att7(1): !info msgs handled in main module already. offset = noffset continue att8: if (qualifier>>4)&x'03' # 3 then add(x'80',eq!strings,0,"STRING value only") c and offset = noffset else sfield == FTP table_special options and set string continue repeat end routine default table entry FTP table_stopack message = "" FTP table_mail to send = yes FTP table_data control = translate; !that is mode x'40' FTP table_data type_value = x'0001'; !ie text only FTP table_text tran code_value = x'0001'; !ie IA5 text FTP table_text format_value = x'0001'; !ie EOR implies NL if TARGET = 2900 then FTP table_max tran rec size_value = X'FFFF' C else FTP table_max tran rec size_value = -1 FTP table_timeout_value = x'0258' FTP table_binary word size_value = x'0008' end if TARGET # 2900 start routine add(byteinteger id,op,shortinteger bval,string (63) sval) integer addrs string (63) s addrs = reply start + reply length byteinteger(addrs) = id byteinteger(addrs+1) = op if op&form mask = bits start byteinteger(addrs+2) = byteinteger(addr(bval)) byteinteger(addrs+3) = byteinteger(addr(bval)+1) reply length = reply length + 4 finish else if op&form mask = strings start string(addrs+2) = sval reply length = length(sval)+3+reply length if id = x'71' then FTP log("info msg out: ".sval) finish else reply length = reply length + 2 param count = param count + 1 if info # "" start s = info info = "" add(x'71',eq!strings,0,s) finish end routine reject(byteinteger id,op,shortinteger bval,string (63) sval, shortinteger rej code) !this routine adds the transfer status to the attribute reply field !and generates a RNEG for this Q station to send. type = FTP RNEG add(id,op,bval,sval) add(x'0F',x'22',rej code,"") transfer status = rej code byteinteger(reply start) = type byteinteger(reply start+1)= param count FTP log("RNEG sent.") fill work entry(reply start) end routine handle rneg !this routine will report on a received RNEG(as P station) or will !generate a STOP if a received RPOS is unacceptable. if type = FTP RNEG start !we have received an RNEG from Q, report on it unless rejected info <= transfer status <= rejected deferred then start FTP log("bad transfer status :".itos(transfer status)) transfer status = rejected attribute finish unless transfer status = rejected deferred then mail report("Transfer rejected".snl,0) fill work entry(command start) finish else type = FTP RNEG add(x'0F',x'22',transfer status,"") byteinteger(reply start) = FTP STOP byteinteger(reply start+1) = param count FTP log("STOP sent.") fill work entry(reply start) end integerfn try bits(record (FTP bits)name field, shortinteger value) byteinteger op op = field_qual & op mask if op = eq and field_value = value then result = yes if op = ne and field_value # value then result = yes if op = le and field_value&value = value then result = yes if op = ge and field_value&value = field_value then result = yes if op = any then result = yes result = no end integerfn try value(record (FTP bits)name field, shortinteger value) byteinteger op op = field_qual & op mask if op = eq and field_value = value then result = yes if op = ne and field_value # value then result = yes if op = le and value <= field_value then result = yes if op = ge and value >= field_value then result = yes if op = any then result = yes result = no end integerfn bits set(shortinteger value) integer count, i count = 0 cycle i = 0,1,7 if (value>>i)&1 = 1 then count = count + 1 repeat result = count end finish else start routine add(byteinteger id,op,halfinteger bval,string (63) sval) integer addrs string (63) s addrs = reply start + reply length byteinteger(addrs) = id byteinteger(addrs+1) = op if op&form mask = bits start byteinteger(addrs+2) = byteinteger(addr(bval)) byteinteger(addrs+3) = byteinteger(addr(bval)+1) reply length = reply length + 4 finish else if op&form mask = strings start string(addrs+2) = sval reply length = length(sval)+3+reply length if id = x'71' then FTP log("info msg out: ".sval) finish else reply length = reply length + 2 param count = param count + 1 if info # "" start s = info info = "" add(x'71',eq!strings,0,s) finish end routine reject(byteinteger id,op,halfinteger bval,string (63) sval, halfinteger rej code) !this routine adds the transfer status to the attribute reply field !and generates a RNEG for this Q station to send. type = FTP RNEG add(id,op,bval,sval) add(x'0F',x'22',rej code,"") transfer status = rej code byteinteger(reply start) = type byteinteger(reply start+1)= param count FTP log("RNEG sent.") fill work entry(reply start) end routine handle rneg !this routine will report on a received RNEG(as P station) or will !generate a STOP if a received RPOS is unacceptable. if type = FTP RNEG start !we have received an RNEG from Q, report on it unless rejected info <= transfer status <= rejected deferred then start FTP log("bad transfer status :".itos(transfer status)) transfer status = rejected attribute finish unless transfer status = rejected deferred then mail report("Transfer rejected".snl,0) fill work entry(command start) finish else type = FTP RNEG add(x'0F',x'22',transfer status,"") byteinteger(reply start) = FTP STOP byteinteger(reply start+1) = param count FTP log("STOP sent.") fill work entry(reply start) end integerfn try bits(record (FTP bits)name field, halfinteger value) byteinteger op op = field_qual & op mask if op = eq and field_value = value then result = yes if op = ne and field_value # value then result = yes if op = le and field_value&value = value then result = yes if op = ge and field_value&value = field_value then result = yes if op = any then result = yes result = no end integerfn try value(record (FTP bits)name field, halfinteger value) byteinteger op op = field_qual & op mask if op = eq and field_value = value then result = yes if op = ne and field_value # value then result = yes if op = le and value <= field_value then result = yes if op = ge and value >= field_value then result = yes if op = any then result = yes result = no end integerfn bits set(halfinteger value) integer count, i count = 0 cycle i = 0,1,7 if (value>>i)&1 = 1 then count = count + 1 repeat result = count end finish integerfn validate filename(string (39) file) unless 1<= length(file) <=11 then result = 1 cycle i = 1,1,length(file) j = byteinteger(addr(file)+i) result = 1 unless (i>1 and '0' <= j <= '9') or 'A' <= j&95 <= 'Z' c or ( i>1 and j = '#' ) repeat result = ok end end ; !of routine evaluate negotiation end ; !of routine FTP CONTROL routine requeue FTP document(integer document,delay,all,fixed) !******************************************************** !* * !* this routine will put an FTP document back on the * !* queue with a time delay if required and on all docs * !* for the same FTP station if required. * !* * !******************************************************** integer flag if fsystems(document>>24)_addr= 0 start select output(1) printstring(dt."FTP (?) fsys off line, ".identtos(document)." requeue not done".snl) select output(0) return finish add to queue(document,delay,all,fixed,flag) if flag # 0 start printstring("FTP (?) ADD ".identtos(document)." TO QUEUE ". c " fails ".itos(flag).snl) delete document(document, flag) if flag # 0 then printstring("FTP (?) DELETE DOCUMENT ".identtos(document). c " fails ".itos(flag).snl) finish end ; !of routine requeue FTP document routine FTP input message from fep(record (pe)name p) !************************************************************* !* * !* THIS ROUTINE HANDLES THE CONTROL BUFFER MAINTAINED WITH * !* THE FRONT ENDS FOR FTP CONTROL PROCEDURES. * !************************************************************* integer fe, cursor, newcursor, line, j, i, address, buffer length, monitor,count,flag, pss entry, slen, addrs, mess control byte displ integerarray address component (1:15) string (31) base, pss, work string string (127) caller, called, residue, address string, extra string record (FTP tablef)name FTP table record (FTP f)FTP record (FTP stationf)name FTP station record (linef)name FTP line switch sw(1 : 4) !* routine monitor input(integer start, finish, addr) integer i cycle i=start, 1, finish print string(i to s(byteinteger(addr+i))." ") repeat newline end ; !OF ROUTINE MONITOR INPUT !* routine get(integer add, len) integer i cycle i = 0, 1, len-1; !GET LEN BYTES FROM CIRCULAR BUFFER byteinteger(add+i) = byteinteger(address+cursor) if TARGET # 2900 and i = 1 then mess control byte displ = cursor cursor = cursor+1 cursor = cursor-buffer length c if cursor >= buffer length repeat end ; !OF ROUTINE GET integerfn all numeric(stringname s) integer i result = yes if length(s) = 0 cycle i = 1,1,length(s) result = no unless x'30' <= byteinteger(addr(s)+i) <= x'39' repeat result = yes end !* if mon level = 1 or 2 < mon level < 5 then monitor = yes c else monitor = no if 2 < mon level < 5 then start select output(1) printstring(dt."FTP INPUT(POFF): ") pt rec(p) select output(0) finish fe = (p_dest>>8)&255; !GET FEP if feps(fe)_FTP available = no start select output(1) printstring(dt."MESSAGE FROM 'DOWN' FEP ".i to s(fe).snl) select output(0) return finish if p_p3 = x'01590000' start ; !FEP DOWN! fep down(fe) if feps(fe)_FTP available = yes return finish address = feps(fe)_FTP in buff con addr cursor = feps(fe)_FTP input cursor buffer length = feps(fe)_FTP in buff length new cursor = p_p2 if monitor = yes start select output(1) printstring(dt."OWN FTP CURSOR: ".itos(cursor)." FE".itos(fe). c " FTP CURSOR: ".itos(new cursor).snl) select output(0) finish while cursor # new cursor cycle if TARGET # 2900 start get(addr(FTP), FTP std mess len + 1) if FTP_control # 0 start !WE have had a shot of this one, dump it and carry on. select output(1) printstring(dt."DISCARDING problem message from FE".itos(fe). c "(will try for next(if any) message.".snl) monitor input(0,FTP std mess len,addr(FTP)) select output(0) if cursor # new cursor start get(addr(FTP), FTP std mess len + 1) if FTP_control # 0 start !We really are screwed. Should never happen. printstring("FE".itos(fe)." FTP control buffer".snl."Screwed ! Ring JH".snl) exit finish finish else exit finish byteinteger(address+mess control byte displ) = 1 {set the control bit} finish else start get(addr(FTP), FTP std mess len + 1) get(addr(FTP)+FTP std mess len + 1, FTP_length - FTP std mess len) c if FTP_length > FTP std mess len finish if monitor = yes then start select output(1) printstring(dt."FTP INPUT MESSAGE FROM FE".itos(fe)." ") if TARGET # 2900 then monitor input(0, FTP std mess len, addr(ftp)) c else monitor input(0, FTP_length, addr(FTP)) select output(0) finish -> sw(FTP_type) !* sw(1): sw(4): !------------------------------------------------------------- !AN ALLOCATE REQUEST OR REPLY FROM A FTRANS GENERATED !ALLOCATION REQUEST.( 1 is NSI, 4 is TS (X25 or BSP) ) if FTP_pair ref = 0 then start !THIS IS AN INITIAL CALL FROM THE FRONT END SO THE FTP !CALL IS BEING GENERATED EXTERNALY. if FTP stations(control entry)_service = closed or c FEPs(FE)_incomming calls accepted = no start !NO FTP SERVICE OFFERED IN THIS SESSION select output(1) printstring(dt."NO FTP SERVICE FTP AVAILABLE, call rejected".snl) select output(0) -> reply2 finish if TARGET = 2900 then i = FTP_length-FTP std mess len else c i = length(FTP_address) if i > 0 start !THERE MUST BE A STATION ADDRESS ATTACHED. count = 0; line = 0 cycle i = 1,1,lines if FTP lines(i)_status > unallocated and FTP lines(i)_status # c deallocating then count = count + 1 else start line = i if line = 0 and kick(i)&2 = 0; !ie not stopped. finish repeat if line = 0 or count >= FTP stations(control entry)_max lines start !no FTP lines FTP available for incoming call select output(1) printstring(dt."incomming FTP call rejected, no lines.".snl) select output(0) -> reply2 finish FTP line == FTP lines(line) FTP line_station ptr = 0 if FTP_type = 1 start ; !ie an NSI call. if FTP_address -> base.("F").pss then pss entry = stoi(pss) else c pss entry = 0 cycle i = 1,1,FTP stns if (pss entry # 0 and FTP stations(i)_pss entry = pss entry) or c (pss entry = 0 and string(address cache addr+ c FTP stations(i)_address(1)) = FTP_address) start !we recognise the station calling. FTP line_station ptr = i exit finish repeat finish else start !it is an TS allocation request. called <- string(addr(FTP_address)+1) caller <- string(addr(FTP_address)+2+length(called)) !We now have a long string adddres, handle this and rebuild a new address !string where all components are separated by '.' and are of length 14. !(at least 14, the CUDF will perhaps be corrupted but this does not matter) extra string = caller addrs= addr(extra string) slen = length(extra string) count = 1 select output(1) printstring(dt."FTP TS call from ".caller.snl) select output(0) address component(count) = addrs cycle i = 1,1,slen j = byteinteger(addrs+i) if x'2D' < j < x'30' or j = x'2B' or i = slen start !We have a separator or the end of the string. if i = slen then i = i + 1 byteinteger(address component(count)) = (addrs-1) + i - address component(count) exit if i > slen count = count + 1 address component(count) = addrs + i finish repeat residue = "" cycle i = 1,1,count address string = string(address component(i)) if i # 1 then residue = residue."." if all numeric(address string) = no then residue = residue.address string else start if length(address string) >= 14 then residue = residue.address string else c if length(address string) = 12 then residue = residue.address string."00" c else if length(address string) < 12 start address string = address string."00" address string = "0".address string while length(address string) # 14 residue = residue.address string finish finish repeat select output(1) printstring(dt."FTP TS call converted to ".residue.snl) select output(0) !Now we have a caller string like a.b.c.d... where all numeric elements of the !address proper are of style xxxxxxxxxxxxss. Try a match. address string = "" !Now look at the address for a refined location address. cycle i = 1,1,FTP stns continue if expanded addresses(i)_address type = BASE type {not Directories} cycle j = 1,1,4 if expanded addresses(i)_ptr(j) = no address then exit address string = string(address cache addr + expanded addresses(i)_ptr(j)) work string = "" if residue -> work string.(address string).residue start FTP line_station ptr = i if work string # "" start select output(1) printstring(dt."FTP TS unknown data before address ".work string.snl) select output(0) finish exit finish repeat exit if FTP line_station ptr # 0 repeat !Here would could and sometime shall check the residuals from the calling !station to see if it agrees with what we think it should be. finish if FTP line_station ptr = 0 then FTP line_station ptr = guest entry if FTP stations(FTP line_station ptr)_service = closed start select output(1) printstring(dt."No ".string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_shortest name)." FTP service".snl) select output(0) FTP line_station ptr = 0 -> reply2 finish else if FTP line_station ptr = guest entry start if FTP_type = 1 then caller = FTP_address select output(1) printstring(dt."FTP call from ".caller." unrecognised, GUESTed.".snl) select output(0) finish count = 0 cycle i = 1,1,lines if FTP lines(i)_status > unallocated and FTP lines(i)_station ptr c = FTP line_station ptr then count = count + 1 repeat if count >= FTP stations(FTP line_station ptr)_max lines + 1 start !'+1' since we will allow 1 q station over station capacity to !prevent possible P station line hogging with respect to a particular station if FTP line_station ptr = guest entry then base = "GUEST" else c base = string at(FTP stations(FTP line_station ptr) c ,FTP stations(FTP line_station ptr)_name) FTP line_station ptr = 0 select output(1) printstring(dt."FTP call from ".base." rejected, station capacity.".snl) select output(0) -> reply2 finish FTP table == FTP tables(line) FTP table = 0 if FTP line_station ptr = guest entry then FTP table_calling address = caller if FTP_type = 4 start select output(1) printstring(dt."FTP TS called field : ".called.snl) select output(0) unless called -> (spoolFTP).called or called -> ("X").called start select output(1) printstring(dt."FTP TS 'called' field wrong ".called.snl) select output(0) FTP line_station ptr = 0 -> reply2 finish if called # "" start if called -> address string.(spoolmail) and length(address string) = 1 start select output(1) printstring(dt."FTP TS MAIL call accepted".snl) select output(0) FTP table_mail = yes finish else start select output(1) printstring(dt."FTP TS (MAIL ?) call rejected. ".called." FILE only assumed.".snl) select output(0) ! FTP line_station ptr = 0 ! -> reply2 finish finish finish FTP line_status = allocated !WE HAVE CHOSEN THIS LINE FOR FTP SERVICE TO AN EXTERNAL CALL. FTP line_station type = q station FTP line_in stream ident = 14<<24!fe<<16!FTP_in ident FTP line_out stream ident = 14<<24!fe<<16!FTP_out ident FTP line_in stream status = allocated FTP line_out stream status = allocated FTP line_fep = fe FTP line_bytes transferred = 0 FTP_pair ref = line FTP_length = FTP std mess len if TARGET = 2900 FTP_type = 2 !NO NEED TO REFLECT THE ADDRESS. FTP output message to fep(fe, FTP) p = 0 p_dest = line<<7 ! FTP connect FTP control(p,refresh line) refresh pic(ftp status summary display,FTP_pair ref,"") -> check finish else start select output(1) printstring(dt."NO STATION ADDR ON INCOMING FTP CALL".snl) select output(0) -> reply2 finish finish else start !WE HAVE AN FEP REPLY TO A FTRANS INITIATED FTP CALL. !THIS REPLY CONTAINS ALLOCATION DETAILS FOR THE FTP STREAM PAIR. if FTP_in ident = 0 or FTP_out ident = 0 start !A FAILURE FROM FEP select output(1) printstring(dt."FEP REJECTS FTP OUTWARD CALL: ". itos( c FTP_in ident)." ".itos(FTP_out ident)." LINE: ".itos( c FTP_pair ref).snl) select output(0) FTP line == FTP lines(FTP_pair ref) remove from queue(FTP line_document,flag) requeue FTP document(FTP line_document,allocate fail delay,yes,no) FTP line_status = unallocated FTP line_document = 0 FTP line_station ptr = 0 -> check finish FTP line == FTP lines(FTP_pair ref) FTP tables(FTP_pair ref) = 0 if FTP line_status # selected start !FTRANS REALLY IS SCREWED WITH ITS FTP IF IT GETS HERE!! printstring("FTP SCREWED UP!!".snl) FTP stations(control entry)_service = closed ->check finish FTP line_status = allocated FTP line_in stream ident = 14<<24!fe<<16!FTP_in ident FTP line_out stream ident = 14<<24!fe<<16!FTP_out ident FTP line_in stream status = allocated FTP line_out stream status = allocated FTP line_fep = fe p = 0 p_dest = FTP_pair ref<<7!FTP connect FTP control(p,refresh line) refresh pic(ftp status summary display,FTP_pair ref,"") -> check finish sw(3): !------------------------------------------------------ !REPLY TO DEALLOCATE REQUEST ON STREAM PAIR. if FTP_pair ref = 0 start !SHOULD NOT HAPPEN. select output(1) printstring(dt."ZERO PAIR REF DEALLOCATE REPLY!!".snl) select output(0) ->check finish FTP line == FTP lines(FTP_pair ref) if FTP line_status = deallocating start select output(1) printstring(dt."FTP (".itos(FTP_pair ref).") TS diagnostics dec: ". c itos((FTP_in ident)>>8&X'FF')." ".itos(FTP_in ident&X'FF').snl) select output(0) if FTP line_in stream status = aborting or FTP line_out stream c status = aborting start select output(1) printstring(dt."Deallocate reply before connect abort reply, suspending.".snl) select output(0) FTP line_in stream status = suspending FTP line_out stream status = suspending FTP line_user = "" FTP line_station ptr = 0 -> check finish FTP line_status = unallocated refresh pic(ftp status summary display,FTP_pair ref,"") FTP line_in stream status = unallocated FTP line_out stream status = unallocated FTP line_user = "" FTP line_station ptr = 0 finish else start select output(1) printstring(dt."DEALLOCATE REPLY NOT EXPECTED : ".FTP line_name.snl) select output(0) finish kick FTP line(FTP_pair ref) -> check !* reply2: FTP_type = 2 reply: FTP output message to fep(fe, FTP) check: repeat feps(fe)_FTP input cursor = new cursor end !* routine FTP output message to fep(integer fe, record (FTP f)name FTP) !************************************************************* !* SEND A MESSAGE OUT ON THE FTRANS - FEP FTP CONTROL BUFFER * !************************************************************* record (pe)p integer cursor, buff len, flag, i, add, mess length !* routine put(integer address, len) integer i cycle i = 0, 1, len byteinteger(add+cursor) = byteinteger(address+i) cursor = cursor+1 cursor = cursor-buff len if cursor >= buff len repeat end ; !OF ROUTINE PUT !* !* if feps(fe)_FTP available = yes start cursor = feps(fe)_FTP output cursor add = feps(fe)_FTP out buff con addr buff len = feps(fe)_FTP out buff length if TARGET = 2900 then mess length = FTP_length else mess length = c FTP std mess len put(addr(FTP), mess length) if mon level = 1 or mon level= 3 start select output(1) print string(dt."FTP OUTPUT MESSAGE TO FE".i to s(fe)." ") cycle i = 0, 1, mess length print string(i to s(byteinteger(addr(FTP)+i)). c " ") repeat newline select output(0) finish p = 0 p_dest = stream control message p_srce = fe<<8!FTP output reply mess p_p1 = feps(fe)_FTP output stream p_p2 = cursor if feps(fe)_FTP suspend on output = yes then flag = dpon3("",p,0, 0,7) c and feps(fe)_FTP suspend on output = no else flag = dpon3("", p, 0, 0, 6) feps(fe)_FTP output cursor = cursor finish else start select output(1) printstring(dt."FTP FEP ".itos(fe)." down, output message discarded.".snl) select output(0) finish end ; !OF ROUTINE OUTPUT MESSAGE TO FEP !* !END OF FTP CONTROL ROUTINES !********************************************************************** !********************************************************************* !* !* !* routine output message reply from fep(record (pe)name p) integer fe if p_srce = stream control message start !It is a reply to a PON&CONTINUE for output on a cyclic buffer. !We want to see if we have wrapped round and if so we will !only PON&SUSPEND until the FE has caught up. fe = (P_dest&x'FF00')>>8 if p_dest&x'FF' = FTP output reply mess and feps(fe)_FTP output cursor < c p_p5 then feps(fe)_FTP suspend on output = yes if feps(fe)_FTP suspend on output = yes c then select output(1) and printstring(dt."Output Buffer Suspend set".snl) c and select output(0) finish else start select output(1) print string(dt."FTP OUTPUT CONTROL MESSAGE ") pt rec(p) select output(0) finish end ; !OF ROUTINE OUTPUT MESSAGE REPLY FROM FEP !* !* routine open fep(record (pe)name p) integer dact, which fe, flag switch FTP act(FTP input control connect : FTP output control enable reply) dact = p_dest&127 which fe = (p_dest>>8)&255 unless dact < FTP input control connect then -> FTP act(dact) !* !DUMMY act(fep input control connect): !connect input control stream !* FTP act(FTP input control connect): !connect FTP input control stream p = 0 p_dest = connect stream p_srce = which fe<<8!FTP input control connect reply p_p1 = feps(which fe)_FTP input stream p_p2 = my service number!which fe<<8!FTP input mess !INPUT HIGH LEVEL CONTROL MESSAGES TO THIS ACTIVITY p_p3 = 14<<24!which fe<<16!FTP in control stream flag = dpon3("", p, 0, 0, 6) return !* !* FTP act(FTP input control connect reply): !FTP input stream connect reply if p_p2 = 0 start feps(which fe)_FTP input stream = p_p1; !STORE COMMS STREAM ALLOCATED if (p_p6>>24) = 3 and STRING(ADDR(P_p6)) = "X25" then c printstring("FE".itos(which fe)." is TS X25".snl) c and feps(which fe)_comms type = TS type else if c ((p_p6>>24) = 3 and string(addr(p_p6)) = "BSP") then c printstring("FE".itos(which fe)." is TS BSP".snl) and c feps(which fe)_comms type = TS type else printstring( c "FE".itos(which fe)." is NSI".snl) c and feps(which fe)_comms type = NSI type p = 0 p_dest = connect stream p_srce = which fe<<8!FTP output control connect reply p_p1 = feps(which fe)_FTP output stream p_p2 = my service number!which fe<<8!FTP output reply mess !OUTPUT HIGH LEVEL CONTROL MESSAGES TO THIS ACTIVITY p_p3 = 14<<24!which fe<<16!FTP out control stream flag = dpon3("", p, 0, 0, 6) finish return !* !* FTP act(FTP output control connect reply): !FTP output stream connect reply if p_p2 = 0 start feps(which fe)_FTP output stream = p_p1 p_dest = enable stream p_srce = which fe<<8!FTP input control enable reply p_p1 = feps(which fe)_FTPinput stream p_p2 = feps(which fe)_FTP in buff disc addr p_p3 = feps(which fe)_FTP in buff disc blk lim p_p4 = 2<<4!1; !BINARY CIRCULAR p_p5 = feps(which fe)_FTP in buff offset p_p6 = feps(which fe)_FTP in buff length flag = dpon3("", p, 0, 0, 6) finish else print string("CONNECT FTP OUT line FE".i to s( c which fe)." FAILS ".i to s(p_p2).snl) return !* !* FTP act(FTP input control enable reply): !enable FTP input stream reply if p_p2 = 0 start p_dest = enable stream p_srce = which fe<<8!FTP output control enable reply p_p1 = feps(which fe)_FTP output stream p_p2 = feps(which fe)_FTP out buff disc addr p_p3 = feps(which fe)_FTP out buff disc blk lim p_p4 = 2<<4!1; !BINARY CIRCULAR p_p5 = feps(which fe)_FTP out buff offset p_p6 = feps(which fe)_FTP out buff length flag = dpon3("", p, 0, 0, 6) finish else print string("ENABLE FTP IN line FE".i to s( c which fe)." FAILS ".i to s(p_p2).snl) return !* !* FTP act(FTP output control enable reply): if p_p2 = 0 start feps(which fe)_FTP available = yes printstring("FE".itos(which fe)." FTP CONNECTED".snl) feps(which fe)_incomming calls accepted = yes feps(which fe)_outgoing calls permitted = yes finish else c printstring("ENABLE FTP OUT line FE".itos(which fe). c " FAILS ".itos(p_p2).snl) return end ; !OF ROUTINE OPEN FEP !* !* routine initialise !********************************************************************** !* * !* SETS UP GLOBAL VARIABLES, TABLES AND LISTS * !* AND CONNECTS FILES USED BY FTRANS ON THE ON-LINE FILE SYSTEMS. * !* * !********************************************************************** record (pe)p record (daf) FTP in disc addr, FTP out disc addr integer i, j, k, FTP in buff addr, FTP out buff addr integerarray a(0 : max fsys); !USED TO STORE FSYS NOS SUPLIED BY DIRECTOR !* system = "EMAS AMDAHL" if TARGET = 2900 then MAIL MC = "@29".ocptype(com_ocptype) and c mail dis = 33 else mail mc = "@AMDAHL" and mail dis = 35 if TARGET = 2900 then e page size = com_e page size<<10 c else e page size = 4096{NOt really 'e' page for non 2900}; !EXTENDED PAGE SIZE IN BYTES kicked = 0; !INITIALLY NO STREAMS KICKED mon level = no; !INITIALLY NO MONITORING stopping = no; !INITIALLY NOT STOPPING IPSS = ""; PSS = "" send message = "" fire clock tick status header change = no; !Just says whether the next update of the status report should do the header if lines > 0 start cycle i = 1,1,lines FTP lines(i)_status = unallocated kick(i) = 2; !INITIALLY ALL STREAMS STOPPED repeat finish cycle i = 0, 1, max oper oper(i)_prompt on = no; !INITIALLY NO OPER PROMPTS oper(i)_update rate = default oper update rate oper(i)_display type = all queues oper(i)_which display = 0 oper(i)_which page = 0 oper(i)_command = "" oper(i)_specific user="" repeat !* closing = no RETURN if lines = 0 cycle i = 0, 1, max fsys f systems(i)_addr = 0; !MARK ALL FILES AS NOT CONNECTED f systems(i)_password addr = 0 f systems(i)_closing = no repeat !* cycle i = 1, 1, list size-1; !SET UP FREE LIST OF POINTERS TO DOCUMENT DESCRIPTORS list cells(i)_link = i+1 repeat list cells(list size)_link = 0; !END OF LIST free list = 1; !HEAD OF LIST !* !* if TARGET = 2900 then get av fsys(j, a) c else i = d av fsys(j, a); !GET LIST OF AVAILABLE F SYSTEMS !* i = 0 cycle i = j-1,-1,0 open file system(a(i)); !OPEN CURRENTLY ON LINE FILE SYSTEMS ! k = change context repeat !************************************************* ! FEP INITIALISATION FOR FTP FOLLOWS. i = -1 connect or create(my name, "FTPINBUFF", my fsys, (max fep+1)* c fep io buff size, r!w, zerod, FTP in buff addr) connect or create(my name, "FTPOUTBUFF", my fsys, (max fep+1)* c fepio buff size, r!w, zerod, FTP out buff addr) if FTP in buff addr # 0 and FTP out buff addr # 0 start i = get block addresses(my name, "FTPINBUFF", my fsys, addr(FTP in disc addr)) if i = 0 start i = get block addresses(my name, "FTPOUTBUFF", my fsys, addr(FTP out disc addr)) if i = 0 start cycle i = 0, 1, max fep feps(i)_FTP available = no feps(i)_closing = no feps(i)_comms type = unknown type j = (fep io buff size*i)//block size+1 feps(i)_FTP input stream = 0;!STREAM TYPE feps(i)_FTP output stream = 1; !DITTO j = (fep io buff size*i)//block size+1 feps(i)_FTP in buff disc addr = FTP in disc addr_da(j) feps(i)_FTP out buff disc addr = FTP out disc addr_da( c j) if j = FTP in disc addr_nblks c then feps(i)_FTP in buff disc blk lim = c FTP in disc addr_last blk-1 c else feps(i)_FTP in buff disc blk lim = c FTP in disc addr_blksi-1 if j = FTP out disc addr_nblks c then feps(i)_FTP out buff disc blk lim = c FTP out disc addr_last blk-1 c else feps(i)_FTP out buff disc blk lim = c FTP out disc addr_blksi-1 feps(i)_FTPin buff con addr = FTP in buff addr+ c fep io buff size*i feps(i)_FTP out buff con addr = FTP out buff addr+ c fep io buff size*i feps(i)_FTP in buff offset = fep io buff size*i- c block size*(j-1) feps(i)_FTP out buff offset = fep io buff size*i- c block size*(j-1) feps(i)_FTP in buff length = fep io buff size feps(i)_FTP out buff length = fep io buff size feps(i)_FTP input cursor = 0 feps(i)_FTP output cursor = 0 feps(i)_FTP suspend on output = no p = 0 p_dest = i<<8!fep input control connect open fep(p) repeat i = 0 finish else printstring("GETDA FTPOUTBUFF FAILS". c errs(i).snl) finish else printstring("GETDA FTPINBUFF FAILS". c errs(i).snl) finish if i # 0 start FTP in buff addr = 0 FTP out buff addr = 0 finish initialise pictures !* end ; !OF ROUTINE INITIALISE !* !* end endoffile