PROGRAM KERMIT (INPUT,OUTPUT); CONST OUTPUTFILE = '@LIST'; INPUTFILE = '@DATA'; NL = '<012>'; CR = '<015>'; SEND_QCHR = '#'; REC_ELN = '<4>'; MARK = '<1>'; NAMELENGTH = 15; MAXBUFF = 100; (* Maximun packet length can handle *) TYPE PACHEADER = RECORD SEQ : INTEGER; PTYPE : CHAR; CHECK : CHAR; END; PACDATA = RECORD DATA : PACKED ARRAY [ 1 .. MAXBUFF] OF CHAR; LENGTH : INTEGER END; NAMETYPE = PACKED ARRAY [ 1 .. NAMELENGTH] OF CHAR; VAR DISK,OUTSCREEN,INSCREEN: TEXT; SEND_ELN, REC_QCHR: CHAR; SEND_MLEN, REC_MLEN :INTEGER; EIGHTBIT,CENDLN,KCHAR_ELN, DEBUG , IGNORE_PARMS:BOOLEAN; INCLUDE BOOLEAN.PAS; (* Need for XXOR and XAND funtion call *) (* _______________________________________________________________ Opens screen files *) PROCEDURE OPEN_SCREEN; BEGIN RESET(OUTSCREEN,OUTPUTFILE); RESET(INSCREEN,INPUTFILE,MAXBUFF*2) END; (* _______________________________________________________________ opens files 1. Opens the three files 2. Enacts a delay 3. Possible MODES 'C' = rewrite file 'R' = reset file *) PROCEDURE OPEN_FILE(DATANAME:NAMETYPE;MODE:CHAR); VAR FILENAME: STRING 20; Y,INDEX :INTEGER; BEGIN FOR Y := 1 TO NAMELENGTH DO IF DATANAME[Y] <> ' ' THEN APPEND(FILENAME,DATANAME[Y]); IF DEBUG = TRUE THEN BEGIN WRITELN('OPENING FILE MODE - ',MODE); WRITELN(' LENGTH OF STRING: ',LENGTH(FILENAME)); END; IF MODE = 'C' THEN REWRITE(DISK,FILENAME) ELSE RESET (DISK,FILENAME, 200); OPEN_SCREEN; END; (* _______________________________________________________________ Increments the sequence number *) FUNCTION ADDSEQ (INDEX:INTEGER):INTEGER; BEGIN IF (INDEX+1) = 64 THEN ADDSEQ := 0 ELSE ADDSEQ := INDEX+1 END; (* _______________________________________________________________ Returns the KERMIT type Ascii character *) FUNCTION KCHAR (NUMBER:INTEGER) :CHAR; BEGIN KCHAR := CHR (NUMBER + 32) END; (* _______________________________________________________________ Return the KERMIT type integer value of a CHAR *) FUNCTION UNKCHAR (BYTE:CHAR) :INTEGER; BEGIN UNKCHAR := (ORD(BYTE) - 32); END; (* _______________________________________________________________ Returns the integer value for a control character *) FUNCTION CTL (VALUE:INTEGER):INTEGER; BEGIN CTL := XXOR (VALUE , 64) END; (* _______________________________________________________________ Return a one byte checksum 1. If CTYPE = 'C' then the sum is Changed if the character is a control character, REC_QCHR or NL then then actual sent value is automatically added to SUM 2. If CTYPE <> 'C' then just a Straight checksum is produced 3. The XAND function is used *) FUNCTION CHECKSUM (HEADER:PACHEADER ; DATA:PACDATA; CTYPE:CHAR): CHAR; VAR VAL,HVAL:INTEGER; X,SUM :WHOLE; BEGIN SUM := DATA.LENGTH + 3 + 32; SUM := SUM + HEADER.SEQ + 32; SUM := SUM + ORD (HEADER.PTYPE); FOR X := 1 TO DATA.LENGTH DO BEGIN HVAL := ORD(DATA.DATA[X]); VAL := XAND(HVAL,127); IF ((VAL <= 31) OR (VAL = 127)) AND (CTYPE = 'C') THEN SUM := SUM + ORD(REC_QCHR) + CTL(HVAL)+1 ELSE IF (VAL=ORD(REC_QCHR)) AND (CTYPE = 'C') THEN SUM := SUM + ORD(REC_QCHR)+HVAL+1 ELSE SUM := SUM + HVAL; END; SUM := XAND(SUM,255); X := SUM + ( XAND(SUM,192) DIV 64 ); CHECKSUM := KCHAR ( XAND(X,63) ) END; (* _______________________________________________________________ Assembles packet form and writes Packet out *) PROCEDURE SEND_PACKET (HEADER:PACHEADER ; DATA:PACDATA); VAR PACKET : PACKED ARRAY [ 1 .. MAXBUFF+10] OF CHAR; X, INDEX :INTEGER; BEGIN IF DEBUG THEN BEGIN WRITELN('SENDING PACKET'); WRITELN(' SEQUENCE: ',HEADER.SEQ); WRITELN(' DATA.LENGTH: ',DATA.LENGTH) END; X := 0; PACKET[(X+1)] := MARK; PACKET[(X+2)] := KCHAR(DATA.LENGTH+3); PACKET[(X+3)] := KCHAR(HEADER.SEQ); PACKET[(X+4)] := HEADER.PTYPE; X := X+4; FOR INDEX := 1 TO DATA.LENGTH DO PACKET[(X+INDEX)] := DATA.DATA[INDEX]; X := X + DATA.LENGTH; PACKET[(X+1)] := HEADER.CHECK; PACKET[(X+2)] := SEND_ELN; WRITE (OUTSCREEN, PACKET:(X+2) ); IF DEBUG THEN BEGIN WRITELN('Packet length: ',X+2); WRITELN('SENT PACKET') END; END; (* _______________________________________________________________ Creates a zero length data control packet *) PROCEDURE CREATE_CONTROL_PACKET (VAR HEADER:PACHEADER; VAR DATA:PACDATA; PACTYPE:CHAR; INDEX:INTEGER); BEGIN HEADER.PTYPE := PACTYPE; HEADER.SEQ := INDEX; DATA.LENGTH := 0; HEADER.CHECK := CHECKSUM (HEADER, DATA, 'S') END; (* _______________________________________________________________ Reads in a packet from the screen 1. MARK must contain the mark character 2. Default for HEADER.PTYPE = ' ' 3. Default for HEADER.SEQ = -1 4. Packet must not contain the EOF character - REC_ELN - 5. If CHECK = S at entry control de-quoting is not done 6. There are three possible returned values for CHECK ' ' = receive okay 'E' = Checksum wrong, EOF marker before whole Packet can be read, or can't find MARK 'T' = timed out when reading packet (Unimplimented) *) PROCEDURE RECEIVE_PACKET (VAR HEADER:PACHEADER; VAR DATA:PACDATA; VAR CHECK:CHAR); VAR PACKET : PACKED ARRAY [1 .. MAXBUFF+10] OF CHAR; X,Y, LOOP :INTEGER; HCHECK,BYTE : CHAR; DEQUOTE :BOOLEAN; BEGIN IF DEBUG THEN BEGIN WRITELN ('RECEIVING: ') END; X := 0; IF CHECK <> 'S' THEN DEQUOTE := TRUE ELSE DEQUOTE := FALSE; CHECK := ' '; REPEAT X := X+1; IF EOF(INSCREEN) THEN BEGIN RESET(INSCREEN); X := X+1 END; READ (INSCREEN, BYTE); IF DEBUG THEN WRITELN('SEARCH FOR MARK, GOT: ',ORD(BYTE)) UNTIL (BYTE = MARK) OR (X = 6); IF X = 6 THEN CHECK := 'E'; X := 1; HEADER.SEQ := -1; HEADER.PTYPE := ' '; FOR X := 1 TO 3 DO BEGIN IF EOF(INSCREEN) THEN CHECK := 'E' ELSE READ(INSCREEN,BYTE); IF DEBUG THEN WRITELN('READING BYTE- GOT: ',ORD(BYTE)); IF X = 1 THEN DATA.LENGTH := UNKCHAR(BYTE) - 3; IF X = 2 THEN HEADER.SEQ := UNKCHAR (BYTE); IF X = 3 THEN HEADER.PTYPE := BYTE END; Y := 0; X := 1; LOOP := 1; IF EOF(INSCREEN) THEN CHECK := 'E' ELSE READ(INSCREEN,BYTE); WHILE (LOOP <= DATA.LENGTH) AND (CHECK <> 'E') DO BEGIN IF DEBUG THEN WRITELN(DATA.LENGTH,' READING BYTE, GOT: ',ORD(BYTE)); IF Y = 1 THEN BEGIN Y := 2; IF CHR(XAND(ORD(BYTE),127)) = REC_QCHR THEN DATA.DATA[X] := BYTE ELSE DATA.DATA[X] := CHR(CTL(ORD(BYTE))) END; IF (BYTE=REC_QCHR) AND (Y=0) AND DEQUOTE THEN BEGIN Y := 1; DATA.LENGTH := DATA.LENGTH - 1 END; IF Y = 0 THEN DATA.DATA[X] := BYTE ELSE IF Y=2 THEN Y := 0; IF EOF(INSCREEN) THEN CHECK := 'E' ELSE READ(INSCREEN,BYTE); IF Y <> 1 THEN BEGIN X:= X+1; LOOP := LOOP +1 END END; IF CHECK <> 'E' THEN BEGIN HEADER.CHECK := BYTE; IF DEQUOTE THEN HCHECK := CHECKSUM(HEADER,DATA,'C') ELSE HCHECK := CHECKSUM(HEADER,DATA,'S'); IF NOT( HEADER.CHECK = HCHECK) THEN CHECK := 'E' END; RESET(INSCREEN); IF DEBUG THEN BEGIN WRITELN('FINISHED RECEIVING PACKET'); WRITELN(' SEQUENCE: ',HEADER.SEQ); WRITELN(' HEADER.PTYPE: ',HEADER.PTYPE); WRITELN(' DATA-LENGTH: ',DATA.LENGTH); WRITELN(' CHECK:',CHECK); WRITELN(' HEADER.CHECK: ',HEADER.CHECK); WRITELN(' RETURNED CHECKSUM: ',HCHECK) END END; (* _______________________________________________________________ Extracts the information from initial packet 1. sets SEND_MLEN, SEND_ELN *) PROCEDURE SET_DEFAULTS ( HEADER:PACHEADER; DATA:PACDATA ); BEGIN IF DEBUG THEN WRITELN('SETTING DEFAULTS'); IF (DATA.LENGTH => 1) AND (DATA.DATA[1] <> ' ') THEN SEND_MLEN := UNKCHAR (DATA.DATA[1]) ELSE SEND_MLEN := 80; IF (DATA.LENGTH => 5) AND (DATA.DATA[5] <> ' ') THEN IF KCHAR_ELN THEN SEND_ELN := CHR(UNKCHAR(DATA.DATA[5])) ELSE SEND_ELN := DATA.DATA[5] ELSE SEND_ELN := CR; IF (DATA.LENGTH => 6) AND (DATA.DATA[6] <> ' ') THEN REC_QCHR := DATA.DATA[6] ELSE REC_QCHR := '#'; IF DEBUG THEN BEGIN WRITELN('HAVE SET DEFAULTS'); WRITELN(' QUOTE CHAR FROM OTHER KERMIT: ',REC_QCHR); WRITELN(' MAX LENGTH OF SEND PACKET: ', SEND_MLEN); WRITELN(' SEND-EOLN CHAR (ASCII): ',ORD(SEND_ELN)) END END; (* _______________________________________________________________ Creates a packet for the initial connection *) PROCEDURE CREATE_SEND_INIT (VAR HEADER:PACHEADER; VAR DATA:PACDATA; INDEX: INTEGER); VAR X : INTEGER; BEGIN IF DEBUG THEN WRITELN('CREATING SEND-INIT PACKET'); HEADER.PTYPE := 'S'; HEADER.SEQ := INDEX; DATA.LENGTH := 10; WITH DATA DO BEGIN DATA[1] := KCHAR(REC_MLEN); (* Max packet lenth *) DATA[2] := KCHAR(15); (* sec. before time out *) DATA[3] := KCHAR(0); (* # of pad char need *) DATA[4] := ' '; (* pad character *) IF KCHAR_ELN THEN DATA[5] := KCHAR(ORD(REC_ELN)) ELSE DATA[5] := REC_ELN; DATA[6] := SEND_QCHR; (* Char for control quote *) DATA[7] := 'N'; (* No 8 Bit quote *) DATA[8] := '1'; (* Normal checksum *) DATA[9] := ' '; (* No repeat char *) DATA[10] := KCHAR(0) (* Capacity byte *) END; FOR X := 11 TO 14 DO DATA.DATA[X] := ' '; HEADER.CHECK := CHECKSUM (HEADER,DATA,'S'); IF DEBUG THEN WRITELN('HAVE CREATED SEND INIT PACKET') END; (* _______________________________________________________________ Sends packet until E or Y or B reply received 1. Will not do anything if REPLY initially E 2. Possible values of REPLY on exit are E and Y 3. If Initial value of REPLY = S dequoting will not be done on receive *) PROCEDURE SEND_LOOP (HEADER:PACHEADER; DATA:PACDATA; VAR REPLY:CHAR); VAR HOLD :PACHEADER; HOLDDATA :PACDATA; CHECK ,HREPLY :CHAR; TRYS :INTEGER; BEGIN IF DEBUG THEN WRITELN('STARTING SEND LOOP'); TRYS := 1; IF REPLY = 'S' THEN HREPLY := 'S' ELSE HREPLY := ' '; IF NOT(REPLY = 'E') THEN REPLY := ' '; WHILE NOT ((REPLY = 'Y') OR (REPLY = 'E')) DO BEGIN SEND_PACKET (HEADER, DATA); REPEAT CHECK := HREPLY; RECEIVE_PACKET (HOLD, HOLDDATA, CHECK); IF CHECK = 'E' THEN HOLD.SEQ := -1; IF CHECK = 'T' THEN HOLD.SEQ := -1; IF HOLD.SEQ = ADDSEQ(HEADER.SEQ) THEN HOLD.SEQ := -1; UNTIL (HOLD.SEQ = -1) OR (HOLD.SEQ=HEADER.SEQ); IF HOLD.SEQ = -1 THEN REPLY := ' ' ELSE REPLY := HOLD.PTYPE; IF TRYS <= 5 THEN TRYS := TRYS+1 ELSE REPLY := 'E' END; IF DEBUG THEN WRITELN('FINISHING SEND LOOP') END; (* _______________________________________________________________ Creates file header packet *) PROCEDURE CREATE_FILE_HEADER (VAR HEADER:PACHEADER; VAR DATA:PACDATA; INDEX:INTEGER ;DATAFILE:NAMETYPE); VAR X :INTEGER; BEGIN IF DEBUG THEN WRITELN('CREATING FILE HEADER'); HEADER.PTYPE := 'F'; HEADER.SEQ := INDEX; X := 1; WHILE (X < NAMELENGTH) AND (DATAFILE[X] <> ' ') DO BEGIN DATA.DATA[X] := DATAFILE[X]; X := X+1 END; DATA.LENGTH := X - 1; HEADER.CHECK := CHECKSUM (HEADER,DATA,'S'); IF DEBUG THEN WRITELN('CREATED FILE HEADER') END; (* _______________________________________________________________ Creates a data packet 1. The XAND function is used, and a character is QUOTED if it should be quoted with the high bit turned OFF regardless of the actual value of the high bit *) PROCEDURE CREATE_DATA_PACKET (VAR HEADER:PACHEADER; VAR DATA:PACDATA; INDEX:INTEGER); VAR X,Y,VALUE,HVALUE :INTEGER; BYTE :CHAR ; BEGIN IF DEBUG THEN BEGIN WRITELN('CREATING DATA PACKET'); WRITELN(' SEND_MLEN:', SEND_MLEN); END; HEADER.PTYPE := 'D'; HEADER.SEQ := INDEX; X := 1; WHILE NOT( EOF(DISK) ) AND ((X+4) <= (SEND_MLEN-7)) DO BEGIN READ (DISK,BYTE); VALUE := ORD (BYTE); HVALUE := XAND(VALUE,127); IF NOT EIGHTBIT THEN BEGIN VALUE := HVALUE; BYTE := CHR(VALUE) END; Y := X; IF (HVALUE <= 31) OR (HVALUE = 127) THEN BEGIN DATA.DATA[X] := SEND_QCHR; X := X+1; DATA.DATA[X] := CHR( CTL(VALUE) ) END; IF HVALUE = ORD(SEND_QCHR) THEN BEGIN DATA.DATA[X] := SEND_QCHR; X := X+1; DATA.DATA[X] := BYTE; END; IF (BYTE = NL) AND CENDLN THEN BEGIN DATA.DATA[X] := 'M'; X := X+1; DATA.DATA[X] := SEND_QCHR; X := X+1; DATA.DATA[X] := 'J' END; IF Y = X THEN DATA.DATA[X] := BYTE; X := X+1; END; DATA.LENGTH := X-1; HEADER.CHECK := CHECKSUM (HEADER, DATA,'S'); IF DEBUG THEN WRITELN('HAVE CREATED DATA PACKET') END; (* _______________________________________________________________ Does the send routine to send DATAFILE 1. the files must be open 2. closes the files *) PROCEDURE SEND_ROUTINE(DATAFILE:NAMETYPE); VAR HEADER, HOLD_HEADER:PACHEADER; DATA, HOLD_DATA : PACDATA; INDEX : INTEGER; REPLY : CHAR; BEGIN INDEX := 0; CREATE_SEND_INIT (HEADER, DATA, INDEX); REPEAT SEND_PACKET(HEADER,DATA); REPLY := 'S'; RECEIVE_PACKET(HOLD_HEADER,HOLD_DATA,REPLY); IF DEBUG THEN BEGIN WRITELN(HOLD_HEADER.PTYPE,'-',REPLY,'-'); REPLY := ' '; END; UNTIL ((HOLD_HEADER.PTYPE = 'Y') AND (REPLY = ' ')); IF NOT IGNORE_PARMS THEN SET_DEFAULTS (HOLD_HEADER, HOLD_DATA); INDEX := ADDSEQ(INDEX); CREATE_FILE_HEADER ( HEADER, DATA, INDEX, DATAFILE); SEND_LOOP (HEADER, DATA, REPLY); WHILE NOT( EOF(DISK) OR (REPLY = 'E') ) DO BEGIN INDEX := ADDSEQ (INDEX); CREATE_DATA_PACKET (HEADER,DATA,INDEX); SEND_LOOP (HEADER, DATA, REPLY) END; INDEX := ADDSEQ (INDEX); CREATE_CONTROL_PACKET (HEADER, DATA, 'Z' , INDEX); SEND_LOOP (HEADER, DATA, REPLY ); INDEX := ADDSEQ (INDEX); CREATE_CONTROL_PACKET (HEADER,DATA, 'B', INDEX); SEND_LOOP (HEADER, DATA, REPLY); CLOSE (DISK); CLOSE (OUTSCREEN); CLOSE (INSCREEN) END; (* ------------------------------------------------------------------ *) PROCEDURE SEND; VAR X:INTEGER; DATAFILE:NAMETYPE; BEGIN WRITE(' Name of the file: '); FOR X:= 1 TO NAMELENGTH DO IF NOT(EOLN(INPUT)) THEN READ(DATAFILE[X]) ELSE DATAFILE[X] := ' '; READLN; OPEN_FILE(DATAFILE,'R'); SEND_ROUTINE(DATAFILE); END; (* ------------------------------------------------------------------ Receives data packets and constructs file 1. Opens up DISK and closes it 2. HEADER and DATA must be the F packet 3. Will receive D packets until Z packet (end of file) 4. Changes CR LF to NL *) PROCEDURE RECEIVE_LOOP(VAR HEADER:PACHEADER; VAR DATA:PACDATA); VAR X,F,R,INDEX:INTEGER; REPLY,RTYPE :CHAR; DATAFILE :NAMETYPE; BEGIN IF DEBUG THEN WRITELN('STARTING RECEIVE_LOOP'); INDEX := HEADER.SEQ+1; FOR X:= 1 TO NAMELENGTH DO IF (DATA.DATA[X] <> ' ') AND (X <= DATA.LENGTH) THEN DATAFILE[X] := DATA.DATA[X] ELSE DATAFILE[X] := ' '; OPEN_FILE(DATAFILE,'C'); CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ); SEND_PACKET(HEADER,DATA); RTYPE := ' '; WHILE (RTYPE <> 'Z') AND (RTYPE <> 'E') DO BEGIN RECEIVE_PACKET(HEADER,DATA,REPLY); RTYPE := HEADER.PTYPE; IF DEBUG THEN WRITELN('Index - ',INDEX); IF REPLY = ' ' THEN BEGIN IF (HEADER.SEQ = INDEX) AND (RTYPE = 'D') THEN BEGIN INDEX := ADDSEQ(INDEX); R := 0; F := -3; FOR X:= 1 TO DATA.LENGTH DO BEGIN DATA.DATA[(X-R)] := DATA.DATA[X]; IF DATA.DATA[X] = '<15>' THEN F := X; IF (DATA.DATA[X] = '<12>') AND (F=X-1) AND CENDLN THEN BEGIN R := R+1; DATA.DATA[(X-R)] := NL END; END; DATA.LENGTH := DATA.LENGTH - R; IF DEBUG THEN BEGIN WRITELN('R offset is - ',R); WRITELN('Writting Disk- ',DATA.LENGTH); END; WRITE(DISK,DATA.DATA:DATA.LENGTH) END; CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ) END; IF REPLY <> ' ' THEN CREATE_CONTROL_PACKET(HEADER,DATA,'N',HEADER.SEQ); SEND_PACKET(HEADER,DATA) END; CLOSE(DISK); IF DEBUG THEN WRITELN('FINISHING RECEIVE_LOOP') END; (* ------------------------------------------------------------------ The secondary Receive Routine set up this way to facilitate server implimentation *) PROCEDURE RECEIVE_ROUTINE(VAR HEADER:PACHEADER; VAR DATA:PACDATA); VAR X:INTEGER; REPLY:CHAR; BEGIN IF NOT IGNORE_PARMS THEN SET_DEFAULTS(HEADER,DATA); CREATE_SEND_INIT(HEADER,DATA,0); HEADER.PTYPE := 'Y'; HEADER.CHECK := CHR(ORD(HEADER.CHECK) +6); SEND_PACKET(HEADER,DATA); REPEAT REPLY := 'S'; RECEIVE_PACKET(HEADER,DATA,REPLY); IF REPLY <> ' ' THEN BEGIN CREATE_CONTROL_PACKET(HEADER,DATA,'N',HEADER.SEQ); SEND_PACKET(HEADER,DATA) END; IF (REPLY = ' ') AND (HEADER.PTYPE<>'B') THEN RECEIVE_LOOP(HEADER,DATA) UNTIL (HEADER.PTYPE = 'E') OR (HEADER.PTYPE = 'B'); IF HEADER.PTYPE <> 'E' THEN BEGIN CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ); SEND_PACKET(HEADER,DATA) END END; (* ------------------------------------------------------------------ *) PROCEDURE RECEIVE; VAR HEADER:PACHEADER; DATA:PACDATA; REPLY :CHAR; BEGIN OPEN_SCREEN; REPLY := 'S'; RECEIVE_PACKET(HEADER,DATA,REPLY); WHILE (REPLY <> ' ') DO BEGIN CREATE_CONTROL_PACKET(HEADER,DATA,'N',0); SEND_PACKET(HEADER,DATA); REPLY := 'S'; RECEIVE_PACKET(HEADER,DATA,REPLY); END; RECEIVE_ROUTINE(HEADER,DATA); END; (* ------------------------------------------------------------------ *) PROCEDURE SERVER; VAR DATAFILE:NAMETYPE; CHECK:CHAR; HEADER:PACHEADER; DATA:PACDATA; X:INTEGER; BEGIN WRITELN('Server started. You may return to micro'); REPEAT OPEN_SCREEN; REPEAT CHECK := 'S'; RECEIVE_PACKET(HEADER,DATA,CHECK); UNTIL (CHECK=' '); IF HEADER.PTYPE = 'R' THEN BEGIN IF DEBUG THEN WRITELN('SERVER BEGINNING SEND'); FOR X:= 1 TO NAMELENGTH DO IF DATA.LENGTH => X THEN DATAFILE[X] := DATA.DATA[X] ELSE DATAFILE[X] := ' '; OPEN_FILE(DATAFILE,'R'); SEND_ROUTINE(DATAFILE); END; IF HEADER.PTYPE = 'S' THEN BEGIN IF DEBUG THEN WRITELN('SERVER BEGINNING RECEIVE'); RECEIVE_ROUTINE(HEADER,DATA); END; UNTIL HEADER.PTYPE = 'G'; CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ); SEND_PACKET(HEADER,DATA); END; (* ------------------------------------------------------------------ USER INTERFACE ROUTINES ----------------------------------------------------------------- *) (* _______________________________________________________________ Displays value of Kermit parameters *) PROCEDURE DISPLAY_DEFAULTS; BEGIN WRITELN; WRITELN(' Sending End of line character (ASCII): ',ORD(SEND_ELN)); WRITELN(' Maximum Sending packet length: ',SEND_MLEN); WRITELN(' Maximum Receiving packet length: ',REC_MLEN); WRITELN(' Quote character used in receiving: ',REC_QCHR); WRITE(' Eigth bit I-O: '); IF DEBUG THEN WRITELN('ON') ELSE WRITELN('OFF'); WRITE(' Debug flag: '); IF DEBUG THEN WRITELN('ON') ELSE WRITELN('OFF'); WRITE(' Ignore the parameters other Kermit sends: '); IF IGNORE_PARMS THEN WRITELN('ON') ELSE WRITELN('OFF'); WRITE(' Make the EOLN character printable in SEND INIT: '); IF KCHAR_ELN THEN WRITELN('ON') ELSE WRITELN('OFF'); WRITE(' Change CRLF to NL on input and the reverse on output: '); IF CENDLN THEN WRITELN('ON') ELSE WRITELN('OFF'); WRITELN END; (* _______________________________________________________________ Allows one to change the initial default settings *) PROCEDURE CHANGE_DEFAULTS; VAR STATE,CHOICE :CHAR; OPTION :CHAR; VALUE : INTEGER; FUNCTION GET_ON:BOOLEAN; BEGIN REPEAT WRITE('Input choice (Y=ON , N=OFF): '); READLN(CHOICE); IF NOT((CHOICE='Y') OR (CHOICE='N')) THEN WRITELN('Invalid entry') UNTIL (CHOICE='Y') OR (CHOICE='N'); IF CHOICE = 'Y' THEN GET_ON := TRUE ELSE GET_ON := FALSE END; BEGIN WRITE('Change: '); IF EOLN(INPUT) THEN OPTION := ' ' ELSE READ(OPTION); READLN; WRITE('<27>','<30>','<30>','<30>','<30>','<30>','<30>'); WRITE('<30>','<30>','<30>',' '); CASE OPTION OF 'E' : BEGIN VALUE := ORD(CR); WRITE('ASCII number of SEND EOL character: '); READLN(VALUE); SEND_ELN := CHR(VALUE) END; 'S' : BEGIN WRITE('Maximum Length of Send Packet: '); READLN(VALUE); IF EIGHTBIT THEN SEND_MLEN := VALUE ELSE SEND_MLEN := XAND(VALUE,95); END; 'R' : BEGIN WRITE('Maximum Length of Receive Packet: '); READLN(VALUE); IF EIGHTBIT THEN REC_MLEN := VALUE ELSE REC_MLEN := XAND(VALUE,95); END; 'Q' : BEGIN VALUE := ORD('#'); WRITE('ASCII number of QUOTE character: '); READLN(VALUE); REC_QCHR := CHR(VALUE) END; '8' : EIGHTBIT := GET_ON; 'D' : DEBUG := GET_ON; 'C' : CENDLN := GET_ON; 'I' : IGNORE_PARMS := GET_ON; 'M' : KCHAR_ELN := GET_ON; 'H' : BEGIN WRITELN; WRITELN; WRITELN(' E - End of line character for sending packets'); WRITELN(' D - Debug flag'); WRITELN(' S - Maximun Length of Send Packet'); WRITELN(' R - Maximun Length of Receive Packet'); WRITELN(' M - Make EOLN printable in SEND INIT'); WRITELN(' 8 - Use eight bit I-O'); WRITELN(' C - Change NL to CRLF and CRLF to NL'); WRITELN(' Q - Quote character in receiving'); WRITELN(' H - this Help message'); WRITELN(' I - Ignore the parameters set by other Kermit'); WRITELN END; OTHERWISE WRITELN('INVALID ENTRY'); END; WRITELN END; (* _______________________________________________________________ *) PROCEDURE MAIN; VAR OPTION: CHAR; BEGIN REC_QCHR := '#'; SEND_ELN := CR; SEND_MLEN := 74; REC_MLEN := 94; KCHAR_ELN := TRUE; IGNORE_PARMS := TRUE; DEBUG := FALSE; EIGHTBIT := FALSE; CENDLN := TRUE; REPEAT WRITE ('KERMIT-DG> '); READLN (OPTION); CASE OPTION OF 'S' : SEND ; 'R' : RECEIVE; 'I' : SERVER; 'E' : WRITELN('TERMINATING'); 'C' : CHANGE_DEFAULTS; 'D' : DISPLAY_DEFAULTS; OTHERWISE WRITELN ('BAD INPUT') END UNTIL ( OPTION = 'E'); END; (* ------------------------------------------------------------------ The Program block ----------------------------------------------------------------- *) BEGIN MAIN END.