$SET LIST STACK LINEINFO LISTINCL FORMAT $ ERRLIST 00000001 $SET LEVEL 2 00000002 PROCEDURE KERMIT (INIT); 01000000 ARRAY INIT[*]; 01001000 BEGIN 01002000 DEFINE 10000000 % PACKET LENGTH DEFINES 10001000 MYPAD = 10 # % # OF PAD CHARS (SET EXPERIMENTALLY) 10002000 , MYTIMOUT= 5 # % SECONDS TO WAIT BEFORE TIMEOUT 10002500 , MAXPACKET = 96 # % MAXIMUM LENGTH OF A PACKET 10003000 , MAXDATA = (MAXPACKET - 5) # % MOST DATA IN PACKET 10004000 , PADPACKETLENGTH = (MAXPACKET + MYPAD) # % MOST WE MIGHT RECEIVE10005000 , MAXINTEGER = 4"7FFFFFFFFF" # % LARGEST INTEGER ON B6800 10005250 , RETRYLIMIT = 10 # % NUMBER OF NAK RETRIES BEFORE ABORT 10005500 ; 10006000 REAL MARK, SEQ, STATE 11000000 , YOURMAXBUFF, YOURNPAD, YOURPAD, YOUREOL, YOURQUOTE, YOUR8BIT 11000250 , YOURREPEAT, YOURTIMOUT 11000500 ; 11000750 BOOLEAN DEBUGGING, RSLT, AUTOING; 11001000 FILE RMT (KIND=REMOTE,FRAMESIZE=8, MYUSE=IO 11002000 ,MAXRECSIZE=PADPACKETLENGTH,MINRECSIZE=1 11003000 ) 11004000 , FYLE (KIND=DISK, FRAMESIZE=8) 11004500 , DEBUGFILE (KIND=PRINTER, FRAMESIZE=8) 11005000 ; 11006000 ARRAY CTLCHARS [0:7]; % DYNAMIC TRUTHSET: CHARS NEEDING CTL QUOTING 11700000 DEFINE B = BOOLEAN # 120010020.01.002 , R = REAL # 120010040.01.002 , P = POINTER # 120010060.01.002 , INT = INTEGER # 120010080.01.002 , SIGNF = [46:1] # 1200101001.188.000 , LISTOF2(L1,L2) = L1,L2 #1200101201.188.004 , LISTOF3(L1,L2,L3) = L1,L2,L3 #1200101401.188.004 , LISTOF4(L1,L2,L3,L4) = L1,L2,L3,L4 #1200101601.188.004 , LISTOF5(L1,L2,L3,L4,L5) = L1,L2,L3,L4,L5 #1200101801.188.004 , LISTOF6(L1,L2,L3,L4,L5,L6) = L1,L2,L3,L4,L5,L6 #1200102001.188.004 , LISTOF7(L1,L2,L3,L4,L5,L6,L7) = L1,L2,L3,L4,L5,L6,L7 #1200102201.188.004 , LISTOF8(L1,L2,L3,L4,L5,L6,L7,L8) = L1,L2,L3,L4,L5,L6,L7,L8 #1200102401.188.004 , LISTOF9(L1,L2,L3,L4,L5,L6,L7,L8,L9)= L1,L2,L3,L4,L5,L6,L7,L8,L9 #1200102601.188.004 , FILEEOF = [9:1] # 1200102801.188.000 , FILEBRK = [13:1] # 1200103001.188.000 , ALLONES = REAL(NOT FALSE) # 1200103201.188.007 , ORD(X) = REAL(X,1) # %ORDINAL OF CHARACTER 120010340.01.002 , CHAR(X) = ((X).[7:48]) FOR 1 # % CHARACTER VALUE OF INTEGER 12001036 % OR ALPHA EXPRESSION 120010380.01.002 , ERRORCODEF = [47:47] # % FOR PUTTING A REAL VALUE INTO A BOOLEAN12001040 , POP(X) = X:=*.ERRORCODEF # 12001042 , POPPED(X) = (X).ERRORCODEF # 12001044 , PUSHIN(X) = (X) ERRORCODEF # 12001046 , BOOLINTOBOOL (B1,B2) = B2 & PUSHIN(B1) # 12001048 , REALINTOBOOL (R,B) = BOOLINTOBOOL (BOOLEAN(R),B)# 12001050 , LINKF = [19:20] # % STANDARD LINK FIELD 12001052 , SZ(X) = 0:X-1 # % FOR ARRAY DECLARATION 12001054 ; 12001056 PROCEDURE DUMPARRAY (WIRETAP,L,SOU,TYPE,INASCII); 12002010 VALUE L,SOU,TYPE,INASCII ; 12002020 FILE WIRETAP ; 12002030 REAL L, TYPE ; 12002040 POINTER SOU ; 12002050 BOOLEAN INASCII ; 12002060 COMMENT: PRODUCES A HEX AND ALPHANUMERIC DUMP OF THE CONTENTS OF AN 12002080 ARRAY TO A PRINTER FILE. 12002090 IT WILL LOOK SOMETHING LIKE: 12002100 12002110 -TYPE- C O N T E N T S O F T H E A R 12002120 C1D6D5E3C5D5 E3E240D6C640 E3C8C540C1D9 12002130 12002140 R A Y 12002150 D9C1E8 12002160 12002170 PARAMETERS: 12002180 WIRETAP: IS A PRINTER FILE ONTO WHICH THE DUMP IS MADE. 12002190 L: IS THE LENGTH (NUMBER OF CHARACTERS TO DUMP). 12002200 SOU: IS THE SOURCE POINTER -- POINTS TO THE FIRST CHARACTER 12002210 TO DUMP. 12002220 TYPE: SHOULD CONTAIN A SIX CHARACTER IDENTIFICATION MESSAGE.12002230 IT IS PRINTED ON THE DUMP TO THE LEFT OF THE ARRAY 12002240 CONTENTS. 12002250 INASCII: IF TRUE, THE ARRAY CONTENTS ARE CONSIDERED TO BE IN12002260 ASCII AND WILL BE TRANSLATED TO EBCDIC FOR THE 12002270 ALPHA PART OF THE DUMP. 12002280 ; 12002290 BEGIN 1200232001.188.001 ARRAY A1[0:9], A2[0:18], ED[0:20] %EDITED BY PICTURE 12002330 ; 1200234001.188.001 BOOLEAN BOO; 1200235001.188.001 REAL RM % REMAINING 1200236001.188.001 , CTS % CHARACTERS TO SHOW (ON THIS LINE) 1200237001.188.001 , BL % BLANKS TO PUT AT END 1200238001.188.001 , PLL % PRINT LINE LENGTH 12002390 ; 1200240001.188.001 POINTER PA2 1200241001.188.001 , SLO % SOURCE LEFT OFF 1200242001.188.001 ; 1200243001.188.001 PICTURE ALPHALINE( AXAXAXAXAXAXX AXAXAXAXAXAXX AXAXAXAXAXAXX 1200244001.188.001 AXAXAXAXAXAXX AXAXAXAXAXAXX AXAXAXAXAXAXX 1200245001.188.001 AXAXAXAXAXAXX AXAXAXAXAXAXX AXAXAXAXAXAXX 1200246001.188.001 ) 1200247001.188.001 , HEXLINE ( A(12)X A(12)X A(12)X 1200248001.188.001 A(12)X A(12)X A(12)X 1200249001.188.001 A(12)X A(12)X A(12)X 1200250001.188.001 ) 1200251001.188.001 ; 1200252001.188.001 1200253001.188.001 PA2:=P(A2); 1200254001.188.001 SLO:=SOU; 1200255001.188.001 RM :=L; 1200256001.188.001 REPLACE P(ED) BY TYPE FOR 6, " " FOR 20 WORDS; 1200257001.188.001 1200258001.188.001 DO 1200259001.188.001 BEGIN 1200260001.188.001 BL:=54-(CTS:=MIN(RM,54)); 1200261001.188.001 IF INASCII THEN % WHAT WE ARE WRITING IS IN ASCII 1200262001.188.001 BEGIN 1200263001.188.001 REPLACE P(A1,7) BY SLO:SLO FOR CTS; 1200264001.188.001 REPLACE PA2 BY P(A1,7) FOR CTS WITH ASCIITOEBCDIC 1200265001.188.001 , " " FOR BL 1200266001.188.001 END 1200267001.188.001 ELSE 1200268001.188.001 BEGIN 1200269001.188.001 REPLACE P(A1) BY SLO:SLO FOR CTS; 1200270001.188.001 REPLACE PA2 BY P(A1) FOR CTS, " " FOR BL 1200271001.188.001 END; 1200272001.188.001 REPLACE P(ED[1])+1 BY PA2 WITH ALPHALINE; 1200273001.188.001 PLL := IF WIRETAP.FRAMESIZE = 48 THEN 21 12002740 ELSE 126; 12002750 BOO:=WRITE(WIRETAP,PLL,ED); 12002760 1200277001.188.001 REPLACE PA2 BY P(A1,4) FOR CTS*2 WITH HEXTOEBCDIC 1200278001.188.001 , " " FOR BL*2; 1200279001.188.001 REPLACE P(ED) BY " " FOR 7 1200280001.188.001 , PA2 WITH HEXLINE; 1200281001.188.001 BOO:=WRITE(WIRETAP[SPACE 2],PLL,ED); 12002820 1200283001.188.001 REPLACE P(ED[1]) BY " " FOR 20 WORDS; 1200284001.188.001 END 12002850 UNTIL RM:=*-CTS = 0 12002860 END D E B U G W R I T E ; 12002870 DEFINE DEBUGARRAY (L,PTR,TYPE,INASCII)= 12003000 IF DEBUGGING THEN DUMPARRAY(DEBUGFILE,L,PTR,TYPE,INASCII) # 12004000 ; 12005000 DEFINE 13000000 % BASIC KERMIT TRANSFORMATION FUNCTIONS: 13001000 UNCHAR(X) = (ORD(X) -32) # % FROM PRINTABLE TO BINARY 13002000 , KERCHAR(X) = CHAR(X+32) # % BINARY TO PRINTABLE 13003000 , CTL(X) = (REAL(NOT(B(X)EQV B(64))).[7:8]) # %CTL TO PRINTABLE--13004000 , CTLCHAR(X) = CHAR(CTL(X)) # %OR VISE VERSA 13004500 ; 13005000 DEFINE AUTORCV = 48"BF" # % NDL -- AUTOMATICALLY RCV "D" PACKETS 18001000 , ASCIICRVAL = 13 # % DECIMAL VALUE OF AN ASCII CR 18002000 , ASCIILFVAL = 10 # % DECIMAL VALUE OF AN ASCII LF (OR NL) 18003000 18004000 , CAND (X,Y) = IF X THEN Y ELSE FALSE # 18005000 , COR (X,Y) = IF X THEN TRUE ELSE Y # 18006000 ; 18007000 DEFINE % PACKET TYPE CODES (FOR INTERNAL COMMUNICATIONS) 19000000 % DATA PACKETS (EVEN) 19001000 DATA_TYPE = 0 # 19002000 , AUTO_TYPE = 2 # 19003000 % CONTROL PACKETS (ODD) 19004000 , ACK_TYPE = 1 # 19005000 , NAK_TYPE = 3 # 19006000 , S_TYPE = 5 # % SEND PACKET 19007000 , F_TYPE = 7 # % FILE SPEC PACKET 19008000 , Z_TYPE = 9 # % EOF PACKET 19009000 , B_TYPE = 11 # % BREAK PACKET 19010000 , ERR_TYPE = -1 # % BAD NEWS, "E" PACKET, IO ERROR, OR FAULT 19011000 ; 19012000 REAL PROCEDURE ACCUM_CHECKSUM (CH,L); 20000000 VALUE CH,L; 20001000 POINTER CH; % FIRST CHAR TO CHECKSUM 20002000 REAL L; % # OF CHARS TO CHECKSUM 20003000 BEGIN 20004000 REAL A; % ACCUMULATOR 20005000 20006000 DO 20007000 BEGIN 20008000 A:=*+ ORD(CH); 20009000 CH:=*+ 1 20010000 END 20011000 UNTIL L:=*- 1 = 0; 20012000 A:=A.[7:8]; 20013000 ACCUM_CHECKSUM:=(A + A.[7:2]).[5:6]; 20014000 END A C C U M C H E C K S U M ; 20015000 ASCII ARRAY PKT[0:PADPACKETLENGTH]; % PACKET GOES HERE 22000000 REAL PKL; % LENGTH OF PACKET 22001000 DEFINE % PACKET CONTROL CHARACTERS 22002000 MARK_CHAR = PKT[0] # 22003000 , COUNT_CHAR = PKT[1] # % # CHARS IN PACKET 22004000 , SEQ_CHAR = PKT[2] # % MESSAGE # 22005000 , TYPE_CHAR = PKT[3] # % TYPE OF PACKET 22006000 , FIRST_DATA = PKT[4] # % FIRST CHAR OF DATA 22007000 ; 22008000 DEFINE % VALUES RETURNED FROM PGET 22009000 % PACKET IS OK: 22010000 PG_OK = 0 # % PACKET IS OK 22011000 % IO ERRORS (NO PACKET RECEIVED): 22012000 , PG_TIMEOUT = 1 # % TIMEOUT 22013000 , PG_EOF = 2 # % EOF 22014000 , PG_IOERR = 3 # % IO ERROR ON RECV 22015000 % BADLY FORMED PACKET 22016000 , PG_NOMARK = 4 # % NO MARK (SOH) CHARACTER FOUND 22017000 , PG_SHORT = 5 # % PACKET SHORTER THAN LENGTH CHAR SEZ 22018000 , PG_CKSM = 6 # % CHECKSUM ERROR 22019000 % PACKET OUT OF SEQUENCE 22020000 , PG_SQHIGH = 7 # % SEQ IN PACKET = SEQ + 1 22021000 , PG_SQLOW = 8 # % SEQ IN PACKET = SEQ - 1 22022000 , PG_SEQERR = 9 # % WAY OUT OF SEQUENCE 22023000 ; 22024000 REAL PROCEDURE PGET(TL); 22025000 VALUE TL; 22025250 BOOLEAN TL; % TIME LIMIT -- IF TRUE ENFORCE TIME LIMIT ON RCV: 22025500 COMMENT: THIS IS THE PRIMITIVE PACKET GET ROUTINE. IT READS THE 22026000 DATACOM FILE TO TRY AND GET A PACKET. IT MAY TIMEOUT, 22027000 GET AN IO ERROR OR RECEIVE SOMETHING. IF IT GETS SOMETHING 22028000 IT LOOKS FOR A MARK (SOH) WHICH SIGNALS A KERMIT PACKET. 22029000 IF A MARK IS FOUND, THE PACKET IS TRANSLATED TO ASCII, ALIGNED22030000 TO THE PREDEFINED LOCATIONS OF THE PACKET CONTROL CHARACTERS 22031000 AND VERIFIED AS A GOOD PACKET. A ZERO IS RETURNED IF A VALID 22032000 PACKET HAS BEEN RECEIVED. A NON-ZERO VALUE SIGNALS SOME KIND 22033000 OF ABNORMAL CONDITION. THE POSSIBLE VALUES RETURNED ARE 22034000 DEFINED ABOVE. IT IS UP TO THE CALLER TO TAKE THE APPROPRIATE22035000 ACTION WHEN AN ABNORMALL CONDITION OCCURS. 22036000 22037000 IF A PACKET IS RECEIVED FROM THE AUTO RECEIVE HANDLER IN NDL 22038000 (NDL HAS VERIFIED THE PACKET, ACKED IT, AND HANDLED CONTROL 22039000 CHARACTER QUOTING) THE PACKET WILL BE PRECEDED BY 48"BF". 22040000 THIS AUTORCV CODE IS PLACED IN MARK_CHAR WITH THE PACKET 22041000 CONTENTS (CONVERTED TO ASCII) IMMEDIATELY FOLLOWING. 22042000 22043000 PKL IS SET TO THE LENGTH OF THE DATA PORTION OF THE PACKET. 22044000 ; 22045000 BEGIN 22046000 REAL S; 22047000 POINTER PP; 22048000 22049000 IF TL THEN RMT.TIMELIMIT:= YOURTIMOUT; % ENFORCE TIME LIMIT? 22049500 IF RSLT:=READ (RMT,PADPACKETLENGTH,PKT) THEN 22050000 BEGIN 22051000 IF DEBUGGING THEN 22052000 WRITE (DEBUGFILE,<8"RECV ERR: ",H12>,REAL(RSLT)); 22053000 PGET:= 22054000 IF RSLT.[15:1] THEN PG_TIMEOUT 22055000 ELSE 22056000 IF RSLT.[9:1] THEN PG_EOF 22057000 ELSE PG_IOERR 22058000 END 22059000 ELSE % HANDLE GOOD RECIVE HERE--IS IT A GOOD PKT? 22060000 BEGIN 22061000 PKL:= RMT.CURRENTRECORD; 22062000 DEBUGARRAY (PKL,PKT,8"> IN >",COR(AUTOING,PKT=AUTORCV)); 22063000 IF PKT= AUTORCV THEN 22064000 BEGIN 22064500 PKL:=*-1; % DON'T COUNT AUTORCV CHAR 22065000 AUTOING:= TRUE % MAKE A NOTE THAT WE'RE AUTO RECEIVING 22065500 END 22067500 ELSE % NOT AUTO "D" PKT FROM NDL 22069000 BEGIN 22070000 SCAN PP:PKT FOR PKL:PKL UNTIL = MARK; 22071000 IF PKL< 5 THEN % NO MARK OR TOO SHORT TO BE VALID PACKET 22072000 PGET:= PG_NOMARK 22073000 ELSE 22074000 BEGIN 22075000 IF AUTOING THEN 22076100 BEGIN 22076200 % JUST GOT OUT OF NDL AUTO RECV. THERE IS NO 22076225 % PADDING BEFORE THE PACKET, AND THE SEQ CHAR HAS 22076250 % BEEN VERIFIED BY NDL. THE COUNT, SEQ, AND TYPE 22076275 % CHARACTERS ARE IN ASCII, BUT THE REST ARE IN 22076280 % EBCDIC 22076290 AUTOING:= FALSE; 22076300 REPLACE MARK_CHAR BY PP:PP FOR 4; % MK,CNT,SEQ,TYPE 22076320 REPLACE FIRST_DATA BY PP FOR PKL-4 22076325 WITH EBCDICTOASCII; 22076350 SEQ:= UNCHAR(SEQ_CHAR) % RE-SYNC 22076400 END 22076500 ELSE REPLACE MARK_CHAR BY PP FOR PKL WITH EBCDICTOASCII;22076750 IF PKL < PKL:=UNCHAR(COUNT_CHAR) THEN 22077000 PGET:= PG_SHORT 22078000 ELSE 22079000 IF ACCUM_CHECKSUM (COUNT_CHAR,PKL) NEQ 22080000 UNCHAR((COUNT_CHAR)+PKL) 22081000 THEN PGET:= PG_CKSM 22082000 ELSE % CHECKSUM OK 22083000 BEGIN 22084000 PKL:=* -3; % JUST COUNT OF DATA BYTES 22085000 IF S:= UNCHAR(SEQ_CHAR) - SEQ.[5:6] NEQ 0 22086000 THEN % OUT OF SEQUENCE 22087000 PGET:= 22088000 IF S = 1 THEN PG_SQHIGH 22089000 ELSE IF S = -1 THEN PG_SQLOW 22090000 ELSE PG_SEQERR 22091000 ELSE % GOOD PACKET 22091250 IF TYPE_CHAR = 7"Y" THEN % ACK PACKET 22091500 SEQ:= *+1 22091750 END END END END; 22092000 22093000 RMT.TIMELIMIT:= 0 22094000 END P G E T ; 22095000 EBCDIC ARRAY OPKT[0:MAXPACKET]; % LENGTH MAY CHANGE IF PADDING REQ'D 24000000 BOOLEAN PROCEDURE PPUT (PTYPE,DATAL); 24001000 COMMENT: PRIMITIVE PUT ROUTINE: 24002000 FORMATS AND SENDS A PACKET OF THE TYPE ENCODED IN PTYPE. THE 24003000 TYPE, SEQ AND COUNT FIELDS WILL BE SET TO PROPER VALUES. DATAL 24004000 BYTES OF DATA (IN ASCII) ARE ASSUMED TO BE PRESENT STARTING AT 24005000 FIRST_DATA. NO QUOTING IS DONE BY PPUT, AND THUS MUST BE DONE 24006000 BEFORE CALLING PPUT. PPUT WILL CALCULATE A CHECKSUM AND INSERT 24007000 IT INTO THE PACKET. THE PACKET IS THEN SENT TO THE REMOTE 24008000 COMPUTER. 24009000 24010000 THE STATUS WORD FROM THE WRITE TO THE REMOTE COMPUTER IS 24011000 RETURNED. THE NORMAL VALUE RETURNED IS THUS FALSE, BUT WILL 24012000 BE TRUE IN THE CASE OF AN IO ERROR. 24013000 ; 24014000 VALUE PTYPE,DATAL; 24015000 REAL PTYPE; % CODE FOR TYPE OF PACKET TO SEND 24016000 REAL DATAL; % # OF CHARS TO SEND--THEY START AT FIRST_DATA 24017000 BEGIN 24018000 POINTER CKSM; % POINTS TO LOCATION FOR CHECKSUM BYTE 24019000 BOOLEAN RSLT; 24020000 24021000 CKSM:= OPKT; 24022000 THRU YOURNPAD DO REPLACE CKSM:CKSM BY CHAR(YOURPAD); 24023000 REPLACE CKSM:OPKT BY CHAR(MARK), KERCHAR(DATAL+3) 24024000 ,KERCHAR(SEQ.[5:6]); 24025000 ; 24026000 CASE PTYPE OF 24027000 BEGIN 24028000 (DATA_TYPE) : REPLACE CKSM:CKSM BY 7"D"; 24029000 (ACK_TYPE) : REPLACE CKSM:CKSM BY 7"Y"; 24030000 (NAK_TYPE) : REPLACE CKSM:CKSM BY 7"N"; 24031000 (S_TYPE) : REPLACE CKSM:CKSM BY 7"S"; 24032000 (F_TYPE) : REPLACE CKSM:CKSM BY 7"F"; 24033000 (Z_TYPE) : REPLACE CKSM:CKSM BY 7"Z"; 24034000 (B_TYPE) : REPLACE CKSM:CKSM BY 7"B"; 24035000 ELSE : REPLACE CKSM:CKSM BY 7"E"; 24036000 PTYPE:= ERR_TYPE 24037000 END; 24038000 REPLACE CKSM:CKSM BY FIRST_DATA FOR DATAL; 24039000 24040000 REPLACE CKSM BY KERCHAR(ACCUM_CHECKSUM(OPKT[1],DATAL+3)); 24041000 IF CKSM = 7" " THEN % THIS IS TROUBLESOME TO KERMIT ON THE ALTOS 24042000 BEGIN 24043000 REPLACE CKSM:=*+1 BY 7"X"; % MAKE IT SEE THE CHECKSUM 24044000 DATAL:=*+1 % AND BE SURE THE EXTRA CHAR IS SENT 24045000 END; 24046000 24047000 REPLACE CKSM+1 BY CHAR(YOUREOL); 24048000 24049000 REPLACE OPKT BY OPKT FOR DATAL:=*+6 WITH ASCIITOEBCDIC; 24050000 24051000 DEBUGARRAY (DATAL,OPKT,8"< OUT<",FALSE); 24052000 WHILE RMT.CENSUS > 0 DO % FLUSH EXTRA MSG 24053000 RSLT:= READ(RMT,0,PKT); 24054000 IF NOT RSLT THEN 24055000 IF NOT RSLT:= WRITE(RMT[STOP],DATAL,OPKT) THEN 24055250 IF PTYPE = ACK_TYPE THEN SEQ:=*+1; 24055500 PPUT:= IF RSLT THEN RSLT 24056000 ELSE IF PTYPE=ERR_TYPE THEN TRUE % REPORT TYPE ERROR 24057000 ELSE FALSE % OR OK 24058000 END P P U T ; 24059000 % SEND AN ERROR MESSAGE TO ABORT OTHER END WITH THIS DEFINE 25000000 POINTER PERREND; % POINT TO END OF ERROR MESSAGE 25001000 25002000 DEFINE ERROUT(MSG) = % NOTE: MSG IS AN ASCII STRING 25003000 BEGIN 25004000 REPLACE PERREND:FIRST_DATA BY MSG; 25005000 PPUT (ERR_TYPE,DELTA(FIRST_DATA,PERREND)) 25006000 END # 25007000 ; 25008000 25009000 25010000 25011000 25012000 REAL PROCEDURE GETPACKET(TL); 30000000 VALUE TL; 30000250 BOOLEAN TL; % TIMELIMIT -- TRUE IF A TIMELIMIT 30000500 COMMENT: 30001000 THE PURPOSE OF GETPACKET IS TO RETRIEVE THE NEXT VALID PACKET 30002000 FROM THE REMOTE COMPUTER. GETPACKET WILL NAK IMPROPERLY 30003000 FORMED PACKETS AND WILL NAK IN THE CASE OF A TIMEOUT. IF TOO 30004000 MANY NAKS ARE SENT (AS DEFINED BY RETRYLIMIT), GETPACKET WILL 30005000 ACT AS IF IT HAD JUST RECEIVED AN ERROR (ABORT) PACKET. AN 30006000 ERROR PACKET WILL ALSO BE REPORTED IN THE CASE OF AN IO ERROR 30007000 ON THE READ OF THE REMOTE FILE. 30008000 30009000 GETPACKET HANDLES CONTROL QUOTING. ANY CONTROL CHARACTERS IN 30010000 THE PACKET WHICH WERE QUOTED FOR TRANSFER THROUGH THE DATACOM 30011000 LINK WILL BE RESTORED. THE PACKET TYPE WILL BE CONVERTED TO 30012000 THE PACKET TYPE CODE AND RETURNED BY THE GETPACKET PROCEDURE. 30013000 THE DATA CONTAINED IN THE PACKET MAY BE ACCESSED STARTING AT 30014000 FIRST_DATA. THE DATA FROM AN AUTO_TYPE PACKET WILL START AT 30015000 COUNT_CHAR. THE COUNT OF NUMBER OF BYTES OF DATA WILL BE 30016000 FOUND IN PKL. 30017000 ; 30018000 BEGIN 30019000 REAL E % ERROR CODE RETURNED FROM PGET 30020000 , RETRY % COUNTDOWN OF RETIES LEFT BEFORE ABORT 30021000 ; 30022000 DEFINE DONE (RETURNV) = 30023000 BEGIN 30024000 E:= 0; % GET OUT OF THE NAK LOOP 30025000 GETPACKET:= RETURNV 30026000 END # 30027000 , ACK = 30028000 BEGIN 30028500 IF PPUT(ACK_TYPE,0) THEN DONE(ERR_TYPE) 30029000 END # 30030000 , NAK = 30032000 BEGIN 30033000 IF DECREMENTRETRY THEN % TOO MANY RETRIES 30034000 DONE(ERR_TYPE) 30035000 ELSE 30036000 IF PPUT(NAK_TYPE,0) THEN 30037000 DONE(ERR_TYPE) % UNSUCCESSFUL XMIT 30038000 %ELSE LOOP BACK FOR ANOTHER TRY 30039000 END # 30040000 ; 30041000 DEFINE % ASCII CHARACTER HEX EQUIVALENTS (CASE WON'T TAKE 7"X") 30042000 ASC_CHAR_B = 4"42" # 30043000 , ASC_CHAR_D = 4"44" # 30044000 , ASC_CHAR_F = 4"46" # 30045000 , ASC_CHAR_S = 4"53" # 30046000 , ASC_CHAR_Z = 4"5A" # 30047000 ; 30048000 BOOLEAN PROCEDURE DECREMENTRETRY; 30049000 BEGIN 30050000 POINTER P1; 30051000 IF RETRY:=*-1 < 0 THEN 30052000 BEGIN 30053000 ERROUT (7"TOO MANY UNSUCCESSFUL ATTEMPTS TO RECEIVE"); 30054000 DECREMENTRETRY:= TRUE; 30056000 END 30057000 END D E C R E M E N T R E T R Y ; 30058000 PROCEDURE UNQUOTE; 30059000 BEGIN 30060000 POINTER P1,P2; 30061000 REAL L; 30062000 30063000 L:= PKL; 30064000 P1:= P2:= FIRST_DATA; 30065000 30066000 WHILE L>0 DO 30067000 BEGIN 30068000 REPLACE P2:P2 BY P1:P1 FOR L:L UNTIL = YOURQUOTE; 30069000 IF L>0 THEN % FOUND A QUOTE 30070000 IF L=1 THEN % SHOULD NEVER BE 30071000 BEGIN 30072000 REPLACE P2:P2 BY P1:P1 FOR 1; 30073000 L:=*-1 30074000 END 30075000 ELSE 30076000 BEGIN 30077000 PKL:=*-1; % PACKET WILL BE SHORTER--NO MORE QUOTE 30078000 IF P1:=*+1 = CHAR(YOURQUOTE) THEN % QUOTE QUOTE % 30079000 REPLACE P2:P2 BY YOURQUOTE % = QUOTE % 30080000 ELSE REPLACE P2:P2 BY CTLCHAR(ORD(P1)); 30081000 P1:=*+1; % POINT PAST QUOTED CHAR 30082000 L:=*-2 30083000 END END 30084000 END U N Q U O T E ; 30085000 % GETPACKET STATEMENTS: 30086000 30087000 RETRY:= RETRYLIMIT; 30088000 30089000 DO 30090000 IF E:=PGET(TL) = 0 THEN % GOT A GOOD PACKET 30091000 IF MARK_CHAR = AUTORCV THEN % ALREADY NAKED AND DEQUOTED 30092000 GETPACKET:= AUTO_TYPE % BY THE NDL 30093000 ELSE % NORMAL PACKET-- WHAT DO WE DO WITH THIS KIND? 30094000 CASE ORD(TYPE_CHAR) OF 30095000 BEGIN 30096000 (ASC_CHAR_D) : UNQUOTE; 30097000 (ASC_CHAR_S) : GETPACKET:= S_TYPE; 30098000 (ASC_CHAR_F) : UNQUOTE; 30099000 GETPACKET:= F_TYPE; 30100000 (ASC_CHAR_Z) : ACK; 30101000 GETPACKET:= Z_TYPE; 30102000 (ASC_CHAR_B) : ACK; 30103000 GETPACKET:= B_TYPE; 30104000 ELSE: ACK; 30105000 GETPACKET:= ERR_TYPE 30106000 END CASE 30107000 ELSE % BAD PACKET OR NO PACKET AT ALL RECEIVED 30108000 CASE E-1 OF % WHAT KIND OF ERROR? 30109000 BEGIN 30110000 NAK; % TIMEOUT 30111000 DONE(ERR_TYPE); % EOF 30112000 DONE(ERR_TYPE); % OTHER IO ERROR 30113000 IF DECREMENTRETRY THEN DONE(ERR_TYPE); % NO MARK 30114000 NAK; % SHORT 30115000 NAK; % BAD CHECKSUM 30116000 NAK; % WE MISSED A PACKET 30117000 BEGIN % IT MISSED OUR ACK-- TRY ACKING AGAIN 30118000 SEQ:=*-1; 30119000 ACK 30120000 END; 30121000 NAK; % BAD SEQ 30122000 END 30123000 UNTIL E=0; 30124000 END G E T P A C K E T ; 30125000 BOOLEAN PROCEDURE PUTPACKET(PTYPE, DATAL); 35000000 COMMENT: 35001000 PUTPACKET ADDS ACKNOWLEDGEMENT TO THE SERVICES PROVIDED BY 35002000 PPUT. PUTPACKET WILL SEND THE PACKET REPEATEDLY UNTIL EITHER 35003000 AN ACK PACKET IS RECEIVED, AN IO ERROR OCCURS OR UNTIL THE 35004000 NUMBER OF RETRIES ATTEMPTED EQUAL THE VALUE IN RETRYLIMIT. 35005000 IF THE PACKET IS SUCCESSFULLY SENT AND ACKNOWLEDGED, PUTPACKET 35006000 RETURNS A VALUE OF FALSE. IF PUTPACKET FAILS IN ITS MISSION 35007000 IT RETURNS A TRUE VALUE AFTER ATTEMPTING TO NOTIFY THE REMOTE 35008000 COMPUTER THAT THIS PROGRA IS NOW ABORTING. 35009000 35010000 THE PARAMETERS TO PUTPACKET ARE THE SAME AS THOSE TO PPUT, AND 35011000 THE DATA IS NOT MODIFIED, MOVED, OR OTHERWISE CHANGED BEFORE 35012000 BEING SENT ON TO PPUT. 35013000 ; 35014000 VALUE PTYPE, DATAL; 35015000 REAL PTYPE % CODE FOR TYPE OF PACKET BEING SENT 35016000 , DATAL % NUMBER OF BYTES TO SEND 35017000 ; 35018000 BEGIN 35019000 REAL RETRY, GETCODE; 35020000 BOOLEAN RSLT; 35021000 35022000 PROCEDURE SENDFAILURENOTICE; 35023000 BEGIN 35024000 ERROUT (7"TOO MANY FAILED ATTEMPTS TO SEND A PACKET"); 35026000 PUTPACKET:= TRUE % LET CALLER KNOW OF OUR FAILURE 35029000 END; 35030000 DEFINE ABORT = % WHEN THINGS ARE TOO DISMAL 35031000 BEGIN 35032000 RETRY:= 0; 35033000 PUTPACKET:= TRUE; 35034000 PPUT(ERR_TYPE,0); % ATTEMPT TO LET REMOTE KNOW 35035000 END # 35036000 , TRYAGAIN = % GOT NAK OR EQUIVALENT 35037000 BEGIN 35038000 IF RETRY:=*-1 = 0 THEN SENDFAILURENOTICE 35039000 END # 35040000 ; 35041000 35042000 RETRY:= RETRYLIMIT; 35043000 WHILE RETRY > 0 DO 35044000 35045000 IF RSLT:= PPUT(PTYPE,DATAL) THEN % IO ERROR--FAILURE 35046000 BEGIN 35047000 RETRY:= 0; % LEAVE LOOP 35048000 PUTPACKET:= RSLT; % RETURN NOTICE OF OUR FAILURE 35049000 PPUT (ERR_TYPE,0); % MAKE A DOUBTFUL ATTEMPT TO NOTIFY THE 35050000 % REMOTE COMPUTER OF OUR FAILURE 35051000 END 35052000 ELSE % SENT PACKET OK--NOW GET ACKNOWLEDGMENT 35053000 35054000 CASE PGET(TRUE) OF 35055000 BEGIN 35056000 % GOT A GOOD PACKET -- IS IT AN ACK? 35057000 IF TYPE_CHAR=7"Y" THEN RETRY:=0 % SUCCESS !!! 35058000 ELSE 35059000 IF TYPE_CHAR=7"E" THEN % DISMAL FAILURE ON OTHER END 35060000 BEGIN 35061000 RETRY:= 0; 35062000 PUTPACKET:= TRUE % PASS ON OUR FAILURE 35063000 END 35064000 ELSE TRYAGAIN; % TREAT ANYTHING ELSE AS A NAK 35065000 35066000 % NOT A GOOD PACKET (IN VARIOUS FLAVORS): 35067000 TRYAGAIN; % TIMEOUT 35068000 ABORT; % EOF 35069000 ABORT; % IO ERROR 35070000 TRYAGAIN; % NOT A PACKET 35071000 TRYAGAIN; % SHORT 35072000 TRYAGAIN; % CHECKSUM ERROR 35073000 RETRY:=0; % IT'S ON NEXT PACKET--ASSUME ACK MISSED35074000 TRYAGAIN; % PRIOR PACKET NUMBER--MAY BE BAD NEWS 35075000 TRYAGAIN % BAD PACKET NUMBER 35076000 END CASE; 35077000 END P U T P A C K E T ; 35078000 PROCEDURE GETINIT; % EXTRACT INITIALIZATION VALUES FROM SEND-INIT 40000000 % PACKET OR FROM ACK OF OUR SEND-INIT 40001000 BEGIN 40002000 REAL CHARNBR; 40003000 POINTER PCH; % POINTER TO CURRENT CHAR 40004000 40005000 % ESTABLISH DEFAULTS: 40006000 YOURMAXBUFF:= MAXPACKET; 40007000 YOURQUOTE:= 7"#"; 40008000 YOUR8BIT:= 7"N"; 40009000 40010000 % NOW GET THE SPECIFIC VALUES FROM OTHER KERMIT 40011000 PCH:= FIRST_DATA; 40012000 WHILE PKL> 0 AND CHARNBR < 11 DO 40013000 BEGIN 40014000 IF PCH NEQ 7" " THEN 40016000 CASE CHARNBR OF 40017000 BEGIN 40018000 YOURMAXBUFF:= UNCHAR(PCH); % BUFSZ 40019000 IF YOURTIMOUT:= UNCHAR(PCH) = MYTIMOUT THEN % TIMOUT40020000 YOURTIMOUT:=*+ 1; % PREVENT CONTINUOUS COLLISIONS 40021000 YOURNPAD:= UNCHAR(PCH); % NPAD 40022000 YOURPAD:= CTL(ORD(PCH)); % PAD 40023000 YOUREOL:= UNCHAR(PCH); % EOL 40024000 YOURQUOTE:= ORD(PCH); % QUOTE 40025000 YOUR8BIT:= ORD(PCH); % 8 BIT QUOTE 40026000 ; % CHKTYPE 40027000 YOURREPEAT:= ORD(PCH); % REPEAT QUOTE 40028000 ;; % RESERVED 40029000 END; 40030000 PCH:=*+1; PKL:=*-1; 40030500 CHARNBR:=*+ 1 40031000 END; 40032000 IF DEBUGGING THEN WRITE(DEBUGFILE,*/,YOURMAXBUFF, YOURTIMOUT 40033000 ,YOURNPAD, YOURPAD 40034000 ,YOUREOL, YOURQUOTE, YOUR8BIT 40035000 ,YOURREPEAT 40036000 ); 40037000 40038000 % SET BIT IN CONTROL CHAR TRUTHSET FOR CONTROL QUOTE CHAR: 40039000 CTLCHARS[YOURQUOTE.[7:3]].[(31-YOURQUOTE.[4:5]):1]:= 1; 40040000 END G E T I N I T ; 40041000 REAL PROCEDURE SETINIT; % RETURNS COUNT OF CHARACTERS SET IN BUILD 42000000 BEGIN 42001000 REPLACE FIRST_DATA BY KERCHAR(94) % BLKSZ 42002000 ,KERCHAR(MYTIMOUT) % TIMOUT 42003000 ,KERCHAR(MYPAD) % NPAD 42004000 ,CTLCHAR(0) % PAD 42005000 ,KERCHAR(ASCIICRVAL) % EOL 42006000 ,7"#" % QUOTE 42007000 ,7" " % NO 8 BIT QUOTING 42008000 ,7"1" % CHKTYPE 42009000 ,7" " % REPEAT-- NOT YET IMPLEMENTD42010000 ; 42011000 SETINIT:=9 42012000 END S E T I N I T ; 42013000 BOOLEAN PROCEDURE SEND_DATA (MRSZ); 60000000 VALUE MRSZ; 60001000 REAL MRSZ; % MAXRECSIZE 60002000 BEGIN 60003000 EBCDIC ARRAY FREC [0:MRSZ+1]; 60004000 BOOLEAN RTN, DONE; % TEMP STORAGE FOR VALUE RETURNED, LOOP CONTROL 60005000 REAL SZ, SZ2; 60006000 POINTER P1,P2; 60007000 REAL I,J; 60008000 REAL FL,PL; % FILE AND PACKET CHARS LEFT 60009000 POINTER FP,PP; % FILE AND PACKET POINTERS 60010000 TRUTHSET NULLBLANK (48"00"" "); 60011000 DEFINE 60012000 YOURMAXDATA = YOURMAXBUFF - 5 # 60012500 , RESETPKT = % START BUILDING A NEW DATA PACKET 60013000 BEGIN 60014000 PP:= FIRST_DATA; 60015000 PL:= YOURMAXDATA 60016000 END # 60017000 , UNLOOP = 60018000 BEGIN 60019000 SEND_DATA:= DONE:= TRUE; 60020000 FL:= -1; % GET OUT OF LOOP 60021000 END # 60022000 , SENDIT = 60023000 IF PUTPACKET (DATA_TYPE,YOURMAXDATA-PL) THEN 60024000 UNLOOP 60025000 ELSE 60026000 RESETPKT # 60027000 , ERR(X) = 60028000 BEGIN 60029000 ERROUT(X); 60030000 UNLOOP 60031000 END # 60032000 ; 60033000 60034000 RESETPKT; % START A NEW DATA PACKET 60035000 60036000 DO 60037000 IF RTN:= READ(FYLE,MRSZ,FREC) THEN 60038000 IF RTN.[9:1] THEN % EOF: 60039000 BEGIN 60040000 SENDIT; % SEND ANYTHING LEFT IN BUFFER 60041000 DONE:= TRUE % AND EXIT LOOP 60042000 END 60043000 ELSE 60044000 ERR (7"IO ERROR ENCOUNTERED IN READ OF FILE") 60045000 ELSE 60046000 BEGIN 60047000 % REMOVE TRAILING BLANKS (AND NULLS FOLLOWING) 60048000 P2:= FREC; SZ2:= MRSZ; 60049000 DO % TRUNCATE TRAILING SPACES AND NULLS 60050000 BEGIN 60051000 SCAN P1:P2 FOR SZ:SZ2 UNTIL IN NULLBLANK; 60052000 SCAN P2:P1 FOR SZ2:SZ WHILE = 8" "; 60053000 SCAN P2:P2 FOR SZ2:SZ2 WHILE = 0; 60054000 END 60055000 UNTIL SZ2 = 0; 60056000 60057000 % COUNT WHAT REMAINS, CONVERT IT TO ASCII 60058000 % AND PLACE CRLF RECORD DELIMITER AT END 60059000 REPLACE FREC BY FREC FOR FL:= MRSZ-SZ WITH EBCDICTOASCII 60060000 , CHAR(ASCIICRVAL), CHAR(ASCIILFVAL); 60061000 FL:= *+2; % ADD CR AND LF TO COUNT 60062000 FP:= FREC; 60063000 60064000 % QUOTE CONTROL CHARACTERS, DIVIDE UP INTO PACKETS AND 60065000 % SEND OUT THE PACKETS: 60066000 WHILE FL > 0 DO % DON'T NEED NEW READ OF INPUT FILE 60067000 BEGIN 60068000 I := MIN(FL,PL); 60069000 REPLACE PP:PP BY FP:FP FOR J:I UNTIL IN CTLCHARS[0]; 60070000 FL:=*- (I-J); 60071000 PL:=*- (I-J); 60072000 60073000 IF J > 0 THEN % POINTING TO CTL CHAR--QUOTE IT 60074000 BEGIN 60075000 IF PL=1 THEN SENDIT % NO ROOM FOR IT 60076000 ELSE 60077000 BEGIN 60078000 IF FP=CHAR(YOURQUOTE) THEN 60079000 % REPRESENT QUOTE CHAR BY QUOTE QUOTE: 60080000 REPLACE PP:PP BY FP FOR 1, FP FOR 1 60081000 ELSE 60082000 REPLACE PP:PP BY CHAR(YOURQUOTE) 60083000 , CTLCHAR(ORD(FP)); 60084000 FP:=*+ 1; 60085000 FL:=*- 1; 60086000 PL:=*- 2; 60087000 END END; 60088000 60089000 IF PL = 0 THEN SENDIT % NEED TO SEND PACKET 60090000 END END 60091000 UNTIL DONE; 60092000 END SEND_DATA; 60093000 BOOLEAN PROCEDURE SEND_INIT; 65000000 BEGIN 65001000 REAL L,E; 65002000 POINTER P1; 65003000 BOOLEAN DONE; 65004000 65005000 DEFINE ABORT = 65006000 BEGIN 65007000 SEND_INIT:= TRUE; 65008000 E:= 0 65009000 END # 65010000 , SHUTDOWN = 65011000 BEGIN 65012000 ERROUT(7"IO ERROR"); 65013000 ABORT 65014000 END # 65015000 , TRYAGAIN = # 65016000 ; 65017000 65018000 SEQ:= 0; 65019000 65020000 DO % LOOP UNTIL SUCCESSFUL SEND AND ACK OR ABOSLUTE FAILURE 65021000 BEGIN 65022000 L:= SETINIT; 65023000 IF PPUT(S_TYPE,L) THEN % IO ERROR 65024000 SHUTDOWN 65025000 ELSE % SENT S PACKET--NOW GET ACK 65026000 CASE E:= PGET(TRUE) OF 65027000 BEGIN 65028000 IF TYPE_CHAR = 7"Y" THEN % GOT GOOD PKT--IS IT ACK? 65029000 GETINIT % YES ACK, GET SPECS 65030000 ELSE 65031000 IF TYPE_CHAR = 7"E" THEN ABORT % ERROR ON OTHER END 65032000 ELSE E:= 1; % ANYTHING ELSE SEEN AS NAK--TRY AGAIN 65033000 65034000 TRYAGAIN; % TIMEOUT 65035000 ABORT; % EOF 65036000 SHUTDOWN; % IO ERROR 65037000 TRYAGAIN; % NOT A PACKET 65038000 TRYAGAIN; % SHORT PACKET 65039000 TRYAGAIN; % CHECKSUM ERROR 65040000 SEQ:=*+ 1; % BAD SEQ: ADAPT TO IT AND TRY AGAIN 65041000 SEQ:=*- 1; % BAD SEQ: ADAPT TO IT AND TRY AGAIN 65042000 SEQ:=*+ 1 % BAD SEQ: TRY TO ADAPT 65043000 END END 65044000 UNTIL E = 0 65045000 END SEND_INIT; 65046000 PROCEDURE SEND; 69000000 BEGIN 69001000 POINTER P1; 69002000 69003000 YOUREOL:= ASCIICRVAL; % DEFAULT EOL CHAR 69004000 69005000 IF BOOLEAN(FYLE.AVAILABLE) THEN 69006000 IF NOT FYLE.ATTERR THEN % COMPATABLE ATTRIBUTES 69007000 IF FYLE.BLOCKSTRUCTURE = VALUE(FIXED) THEN 69008000 BEGIN 69009000 WRITE(RMT,<4"07">); % DEL -- LET 'EM KNOW WE'RE UP 69010000 WHEN(1); % ALLOW TIME FOR OTHER END TO GET READY 69010500 69010750 IF SEND_INIT THEN % COULD NOT INITIATE COMMUNICATIONS 69011000 ELSE 69012000 BEGIN 69013000 69014000 % SEND THE REMOTE FILE NAME BACK TO REMOTE SYSTEM 69015000 SCAN P1:P(INIT) UNTIL = 0; 69016000 REPLACE FIRST_DATA BY P(INIT) FOR OFFSET(P1)+1 69017000 WITH EBCDICTOASCII; 69018000 IF PUTPACKET (F_TYPE,OFFSET(P1)+1) THEN 69019000 % FAILED SEND 69019500 ELSE 69020000 69021000 % SEND CONTENTS OF FILE 69022000 IF SEND_DATA (IF FYLE.FRAMESIZE=48 THEN 69023000 6 * FYLE.MAXRECSIZE 69024000 ELSE FYLE.MAXRECSIZE 69025000 ) 69026000 THEN % COULD NOT SEND ENTIRE FILE 69027000 CLOSE(FYLE) 69028000 ELSE 69029000 BEGIN 69030000 CLOSE(FYLE); 69031000 IF PUTPACKET(Z_TYPE,0) THEN % SEND EOF 69032000 ELSE PUTPACKET (B_TYPE,0) % BREAK--DONE 69033000 END END END 69034000 ELSE WRITE(RMT,<"FILE STRUCTURE IS NOT READABLE BY KERMIT" 69035000 4"3D">) 69035500 ELSE % SYSTEM SHOULD HAVE SENT FILE ATTR ERR MSG 69036000 ELSE WRITE(RMT,<8"THE FILE YOU REQUESTED IS NOT AVAILABLE"4"3D">) 69037000 END SEND; 69038000 BOOLEAN PROCEDURE RCV_DATA(MINREC,MAXREC); 70000000 VALUE MINREC,MAXREC; 70001000 REAL MINREC,MAXREC; 70002000 BEGIN 70003000 REAL T,LI,L2,LO; % PACKET TYPE, CHARACTER COUNTS 70004000 POINTER PI,PO; % INPUT AND OUTPUT POINTERS 70005000 EBCDIC ARRAY OUTBUFF[0:MAXREC-1]; 70006000 DEFINE CR=47"0D"#, LF=47"0A"#; 70007000 TRUTHSET NEWLINE (CR OR LF); 70008000 70009000 DEFINE FORWARD(X)= 70010000 BEGIN 70011000 PI:=*+(X); 70012000 LI:=*-(X) 70013000 END # 70014000 , CLEAROUTBUFF = 70015000 BEGIN 70016000 LO:= 0; % NO CHARS IN BUFFER 70017000 REPLACE PO:= OUTBUFF BY 8" " FOR MAXREC 70018000 END # 70019000 ; 70020000 70021000 $SET OMIT= NDLSETUP 70021250 DEFINE INITAUTO= PPUT(ACK_TYPE,0) #; % NDL DOES NOT SUPPORT AUTO RCV70021500 $POP OMIT SET OMIT= NOT NDLSETUP 70021750 BOOLEAN PROCEDURE INITAUTO; % NDL SUPPORTS AUTO RECV 70022000 % % INITIATE NDL AUTOMATIC DATA PACKET RECEIVE 70023000 BEGIN 70024000 REPLACE PKT BY AUTORCV, KERCHAR(YOURNPAD),KERCHAR(YOURPAD) 70025000 , KERCHAR(0), KERCHAR(SEQ.[5:6]),8"D"; 70026000 INITAUTO:= WRITE(RMT[STOP],6,PKT); 70027000 DEBUGARRAY (6,PKT,8"AUTINT",TRUE); 70028000 END; 70029000 $POP OMIT 70029500 BOOLEAN PROCEDURE REINIT; % NDL DROPPED OUT OF AUTO RECEIVE 70030000 BEGIN 70031000 IF NOT INITAUTO THEN % SENT INIT TO NDL OK 70032000 BEGIN 70033000 REPLACE COUNT_CHAR BY FIRST_DATA FOR PKL; % LIKE AN AUTOPKT70034000 REINIT:= TRUE; % TRUE RESULT INDICATES SUCCESS 70035000 END 70036000 END REINIT; 70037000 70038000 % RCV_DATA STATEMENTS: 70039000 CLEAROUTBUFF; % PREPARE OUTPUT BUFFER AND POINTER 70040000 70041000 % PUT NDL INTO AUTO RECEIVE MODE: 70042000 IF INITAUTO THEN % FAILED 70043000 RCV_DATA:= TRUE % REPORT FAILURE TO RECEIVE FILE 70044000 ELSE 70045000 70046000 %LOOP FOR EVERY DATA PACKET 70047000 WHILE 70048000 IF LO > MAXREC THEN FALSE % ABORT EXIT 70049000 ELSE 70050000 IF BOOLEAN(T:= GETPACKET(FALSE)) THEN 70051000 FALSE % NOT DATA PACKET 70051500 ELSE % DATA PACKET--AUTO OR OTHERWISE 70052000 IF T = DATA_TYPE THEN 70053000 REINIT % GOOD PACKET--BUT ALSO RESTART NDL AUTO70054000 ELSE TRUE % GOOD AUTO PACKET--CONTINUE LOOPING 70055000 DO 70056000 BEGIN 70057000 PI:= COUNT_CHAR; % DATA PART OF PACKET STARTS HERE 70057250 LI:= PKL; % LENGTH OF DATA IN PACKET 70057500 70057750 % BREAK INTO LOGICAL RECORDS: 70058000 DO 70059000 BEGIN 70060000 SCAN PI FOR L2:LI UNTIL IN NEWLINE; 70061000 L2:= LI-L2; % # CHARS TO END OF LINE 70062000 LI:= *-L2; % # CHARS LEFT IN INPUT AFTER THIS LINE 70063000 IF LO:=*+L2 > MAXREC THEN % RECORD TOO LARGE 70064000 BEGIN 70065000 LI:=0; % SIMULATE END OF PACKET TO EXIT LOOP 70066000 ERROUT(7"RECORD TOO LONG TO FIT INTO FILE"); 70067000 RCV_DATA:= TRUE; % REPORT FAILURE TO CALLER 70068000 END 70069000 ELSE 70070000 BEGIN 70071000 REPLACE PO:PO BY PI:PI FOR L2 WITH ASCIITOEBCDIC; 70072000 IF LI > 0 THEN % STILL DATA CHARS IN PKT 70072500 IF PI IN NEWLINE THEN % END OF A RECORD 70073000 BEGIN 70074000 IF PI=CR THEN 70075000 IF CAND (LI>1, PI+1=LF) THEN 70075500 FORWARD(2) % CRLF 70076000 ELSE FORWARD(1) % CR 70077000 ELSE FORWARD(1); % LF 70078000 WRITE (FYLE,MAX(MINREC,LO),OUTBUFF); 70079000 70080000 CLEAROUTBUFF 70081000 END END END 70082000 UNTIL LI=0 % LOOP UNTIL END OF INPUT REC 70083000 END; % LOOP UNTIL ALL PACKETS HAVE BEEN RECEIVED 70084000 70085000 % CLOSE FILE...IF SUCCESSFULLY RECEIVED ENTIRE FILE THE FILE 70086000 % IS CLOSED WITH LOCK, OTHERWISE JUST RELEASED 70087000 IF T = Z_TYPE THEN % GOT EOF PACKET 70088000 LOCK(FYLE,CRUNCH) 70089000 ELSE 70089250 BEGIN 70089500 CLOSE(FYLE); 70090000 RCV_DATA:= T= ERR_TYPE % DO NOT WAIT FOR BREAK IF ERROR 70090250 END 70090500 END RCV_DATA; 70091000 BOOLEAN PROCEDURE RCV_INIT; 75000000 BEGIN 75001000 REAL E; % ERROR CODE FROM PGET 75002000 DEFINE TRYAGAIN = % E IS ALREADY NON-ZERO SO CONTINUE LOOP75003000 BEGIN 75004000 IF PPUT (NAK_TYPE,0) THEN ABORT 75005000 END # 75006000 , ABORT = 75007000 BEGIN 75008000 RCV_INIT:= TRUE; % NOTIFY CALLER OF FAILURE 75009000 E:= 0 % GET OUT OF LOOP 75010000 END # 75011000 , SHUTDOWN = 75012000 BEGIN 75013000 ERROUT(7"IO ERROR"); % TRY TO TELL REMOTE 75014000 ABORT % NOW GO AWAY 75015000 END # 75016000 , SYNC_SEQ = % GOT AN UNEXPECTED SEQ VALUE 75017000 BEGIN 75018000 SEQ:= ORD(SEQ_CHAR); % CHANGE OUR EXPECTATION 75019000 TRYAGAIN 75020000 END # 75021000 ; 75022000 75023000 DO % LOOP UNTIL AN S-PACKET IS RECEIVED 75024000 CASE E:= PGET(TRUE) OF 75025000 BEGIN 75026000 % A GOOD PACKET-- IS IT AN "S" PACKET? 75027000 IF TYPE_CHAR = 7"S" THEN 75028000 BEGIN 75029000 GETINIT; % EXTRACT S PACKET PARAMETERS 75030000 E:= SETINIT; % SET UP ACK PACKET PARAMETERS 75031000 IF PPUT(ACK_TYPE,E) THEN % AND SEND ACK 75032000 ABORT % FATAL IO ERROR 75033000 ELSE E:= 0 % SUCCESS -- GET OUT OF LOOP 75034000 END 75035000 ELSE 75036000 IF TYPE_CHAR = 7"E" THEN 75037000 ABORT % INDICATE FATAL ERROR--EXIT LOOP 75038000 ELSE % TREAT ANY OTHER PACKET AS A NAK 75039000 E:= 1; % AND LOOP BACK FOR MORE 75040000 75041000 % NO PACKET RECEIVED: 75042000 TRYAGAIN; % TIMEOUT 75043000 ABORT; % EOF 75044000 SHUTDOWN; % IO ERROR 75045000 TRYAGAIN; % NOT A PACKET 75046000 TRYAGAIN; % SHORT PACKET 75047000 TRYAGAIN; % CHECKSUM ERROR 75048000 SYNC_SEQ; % 75049000 SYNC_SEQ; % OUT OF SEQUENCE--RESET SEQ AND RETRY 75050000 SYNC_SEQ; % 75051000 END CASE 75052000 UNTIL E=0 75053000 END RCV_INIT; 75054000 PROCEDURE RECV; 79000000 BEGIN 79001000 % IF CAND(NOT FYLE.NEWFILE, FYLE.RESIDENT) THEN 79002000 % WRITE(RMT,<8"A FILE ALREADY EXISTS WITH THE SAME NAME AS " 79004000 % 8"THE FILE YOU WISHED TO CREATE" 4"3D">) 79005000 % ELSE 79006000 IF COR(FYLE.BLOCKSTRUCTURE=VALUE(FIXED) 79007000 ,FYLE.BLOCKSTRUCTURE=VALUE(EXTERNAL) AND 79008000 FYLE.KIND=VALUE(REMOTE) OR FYLE.KIND=VALUE(PRINTER) 79009000 OR FYLE.KIND=VALUE(TAPE) 79010000 ) 79011000 THEN % ACCEPTABLE BLOCK STRUCTURE 79012000 BEGIN 79013000 FYLE.OPEN:= TRUE; 79014000 WHEN(1); % ACCOMODATE POKEY APPLE 79014500 IF FYLE.ATTERR THEN % TELL OTHER END WE'VE FAILED 79015000 WRITE(RMT,<4"3D">) % BY SENDING A NAK 79016000 ELSE 79017000 BEGIN 79018000 WRITE(RMT,<4"07">); % DEL TO LET 'EM KNOW WE'RE READY 79019000 IF RCV_INIT THEN % UNABLE TO ESTABLISH 79020000 ELSE % KERMIT TALKING TO KERMIT OK 79021000 % GET AND IGNORE FILE ID PACKET 79022000 IF GETPACKET(TRUE) = F_TYPE THEN 79023000 BEGIN 79024000 79024250 % ACTUAL FILE TRANSFER: 79024500 IF NOT RCV_DATA 79025000 (IF FYLE.MINRECSIZE=0 THEN 79025050 FYLE.MAXRECSIZE 79025100 ELSE FYLE.MINRECSIZE 79025150 ,FYLE.MAXRECSIZE 79025200 ) 79025250 THEN 79025500 IF GETPACKET(TRUE) NEQ B_TYPE THEN 79026000 ERROUT(7"CAN ONLY RECEIVE ONE FILE") 79027000 END END END 79028000 ELSE WRITE(RMT,<8"ILLEGAL BLOCKSTRUCTURE"4"3D">) 79029000 END R E C V ; 79030000 % OUTER BLOCK STATEMENTS START HERE: 90000000 90002000 REPLACE P(CTLCHARS,0) BY 4"0000FFFFFFFF" FOR 1 WORDS, 0 FOR 2 WORDS 90003000 , 4"000000000001" FOR 1 WORDS 90004000 , P(CTLCHARS,0) FOR 4 WORDS 90005000 ; % SET UP DYNAMIC TRUTHSET--LATER ADD CTL QUOTE90006000 YOURTIMOUT:= MYTIMOUT+1; % THE TWO TIMEOUTS SHOULD BE DIFFERENT 90007000 MARK:=1; % MARK DEFAULTS TO ASCII SOH CHARACTER 90008000 DEBUGGING:= BOOLEAN(MYSELF.TASKVALUE); 90009000 90011000 IF FYLE.MYUSE = VALUE(IN) THEN SEND 90012000 ELSE RECV 90013000 END. 99999999