home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / aospascal / aosk2.pas < prev    next >
Pascal/Delphi Source File  |  2020-01-01  |  22KB  |  922 lines

  1. PROGRAM     KERMIT (INPUT,OUTPUT);
  2.  
  3. CONST
  4.     OUTPUTFILE = '@LIST';
  5.     INPUTFILE = '@DATA';
  6.     NL = '<012>';
  7.     CR = '<015>';
  8.     SEND_QCHR = '#';
  9.     REC_ELN = '<4>';
  10.     MARK = '<1>';
  11.     
  12.     NAMELENGTH = 15;
  13.     MAXBUFF = 100;   (* Maximun packet length can handle *)
  14.  
  15. TYPE
  16.     PACHEADER = RECORD
  17.         SEQ : INTEGER;
  18.         PTYPE : CHAR;
  19.         CHECK : CHAR;
  20.     END;
  21.     PACDATA = RECORD
  22.         DATA :  PACKED ARRAY [ 1 .. MAXBUFF] OF CHAR;
  23.         LENGTH : INTEGER
  24.     END;
  25.  
  26.     NAMETYPE = PACKED ARRAY [ 1 .. NAMELENGTH] OF CHAR;
  27.  
  28. VAR
  29.     DISK,OUTSCREEN,INSCREEN: TEXT;
  30.  
  31.     SEND_ELN, REC_QCHR: CHAR;
  32.     SEND_MLEN, REC_MLEN :INTEGER;
  33.     EIGHTBIT,CENDLN,KCHAR_ELN, DEBUG , IGNORE_PARMS:BOOLEAN;
  34.  
  35.     
  36. INCLUDE BOOLEAN.PAS;       (* Need for XXOR and XAND funtion call *)
  37.  
  38. (* _______________________________________________________________
  39.         Opens screen files
  40. *)
  41. PROCEDURE OPEN_SCREEN;
  42. BEGIN
  43.     RESET(OUTSCREEN,OUTPUTFILE);
  44.     RESET(INSCREEN,INPUTFILE,MAXBUFF*2)
  45. END;
  46.  
  47. (* _______________________________________________________________
  48.         opens files
  49.     1. Opens the three files
  50.     2. Enacts a delay
  51.     3. Possible MODES
  52.         'C' = rewrite file
  53.         'R' = reset file
  54. *)
  55. PROCEDURE OPEN_FILE(DATANAME:NAMETYPE;MODE:CHAR);
  56.  
  57. VAR
  58.     FILENAME: STRING 20;
  59.     Y,INDEX :INTEGER;
  60.  
  61. BEGIN
  62.     FOR Y := 1 TO NAMELENGTH  DO
  63.         IF DATANAME[Y] <> ' '
  64.            THEN APPEND(FILENAME,DATANAME[Y]);
  65.     IF DEBUG = TRUE THEN
  66.         BEGIN
  67.              WRITELN('OPENING FILE MODE - ',MODE);
  68.               WRITELN('     LENGTH OF STRING: ',LENGTH(FILENAME));
  69.         END;
  70.  
  71.     IF MODE = 'C'
  72.         THEN REWRITE(DISK,FILENAME)
  73.         ELSE RESET (DISK,FILENAME, 200);
  74.     OPEN_SCREEN;
  75. END;
  76.  
  77. (* _______________________________________________________________
  78.         Increments the sequence number
  79. *)
  80. FUNCTION ADDSEQ (INDEX:INTEGER):INTEGER;
  81.  
  82. BEGIN
  83.     IF (INDEX+1) = 64  THEN ADDSEQ := 0
  84.                ELSE ADDSEQ := INDEX+1
  85. END;
  86.  
  87.  
  88. (* _______________________________________________________________
  89.                  Returns the KERMIT type Ascii character
  90. *)
  91. FUNCTION KCHAR (NUMBER:INTEGER) :CHAR;
  92. BEGIN
  93.     KCHAR := CHR (NUMBER + 32)
  94. END;
  95.  
  96. (* _______________________________________________________________
  97.         Return the KERMIT type integer value of a CHAR
  98. *)
  99. FUNCTION UNKCHAR (BYTE:CHAR) :INTEGER;
  100. BEGIN
  101.     UNKCHAR := (ORD(BYTE) - 32);
  102. END;
  103.  
  104. (* _______________________________________________________________
  105.         Returns the integer value for a control character
  106. *)
  107. FUNCTION CTL (VALUE:INTEGER):INTEGER;
  108. BEGIN
  109.     CTL := XXOR (VALUE , 64)
  110. END;
  111.  
  112. (* _______________________________________________________________
  113.          Return a one byte checksum
  114.     1. If CTYPE = 'C' then the sum is Changed if the character is
  115.        a control character, REC_QCHR or NL then then actual
  116.         sent value is automatically added to SUM
  117.     2. If CTYPE <> 'C' then just a Straight checksum is produced
  118.     3. The XAND function is used
  119. *)
  120. FUNCTION CHECKSUM (HEADER:PACHEADER ; DATA:PACDATA; CTYPE:CHAR): CHAR;
  121.  
  122. VAR
  123.     VAL,HVAL:INTEGER;
  124.     X,SUM :WHOLE;
  125.  
  126. BEGIN
  127.     SUM := DATA.LENGTH + 3 + 32;
  128.     SUM := SUM + HEADER.SEQ + 32;
  129.     SUM := SUM + ORD (HEADER.PTYPE);
  130.     FOR X := 1 TO DATA.LENGTH DO
  131.         BEGIN
  132.             HVAL  := ORD(DATA.DATA[X]);
  133.             VAL := XAND(HVAL,127);
  134.             IF ((VAL <= 31) OR (VAL = 127)) AND (CTYPE = 'C')
  135.             THEN SUM := SUM + ORD(REC_QCHR) + CTL(HVAL)+1
  136.             ELSE IF (VAL=ORD(REC_QCHR)) AND (CTYPE = 'C')
  137.                 THEN SUM := SUM + ORD(REC_QCHR)+HVAL+1
  138.                 ELSE SUM := SUM + HVAL;
  139.         END;
  140.     SUM := XAND(SUM,255);
  141.     X := SUM + ( XAND(SUM,192) DIV 64 );
  142.     CHECKSUM := KCHAR ( XAND(X,63) )
  143. END;
  144.  
  145. (* _______________________________________________________________
  146.          Assembles packet form and writes Packet out
  147. *)
  148. PROCEDURE SEND_PACKET (HEADER:PACHEADER ; DATA:PACDATA);
  149.  
  150. VAR
  151.     PACKET : PACKED ARRAY [ 1 .. MAXBUFF+10] OF CHAR;
  152.     X, INDEX :INTEGER;
  153.  
  154. BEGIN
  155.     IF DEBUG THEN
  156.         BEGIN
  157.              WRITELN('SENDING PACKET');
  158.             WRITELN('     SEQUENCE: ',HEADER.SEQ);
  159.             WRITELN('     DATA.LENGTH: ',DATA.LENGTH)
  160.         END;
  161.  
  162.         
  163.     X := 0;
  164.  
  165.     PACKET[(X+1)] := MARK;
  166.     PACKET[(X+2)] := KCHAR(DATA.LENGTH+3);
  167.     PACKET[(X+3)] := KCHAR(HEADER.SEQ);
  168.     PACKET[(X+4)] := HEADER.PTYPE;
  169.     X := X+4;
  170.  
  171.     FOR INDEX := 1 TO DATA.LENGTH  DO
  172.         PACKET[(X+INDEX)] := DATA.DATA[INDEX];
  173.     X := X + DATA.LENGTH;
  174.  
  175.     PACKET[(X+1)] := HEADER.CHECK;
  176.     PACKET[(X+2)] := SEND_ELN;
  177.     WRITE (OUTSCREEN, PACKET:(X+2) );
  178.     IF DEBUG THEN
  179.        BEGIN
  180.         WRITELN('Packet length: ',X+2);
  181.          WRITELN('SENT PACKET')
  182.        END;
  183. END;
  184.  
  185. (* _______________________________________________________________
  186.                Creates a zero length data control packet
  187. *)
  188. PROCEDURE CREATE_CONTROL_PACKET (VAR HEADER:PACHEADER; VAR DATA:PACDATA;
  189.             PACTYPE:CHAR; INDEX:INTEGER);
  190.  
  191. BEGIN
  192.     HEADER.PTYPE := PACTYPE;
  193.     HEADER.SEQ := INDEX;
  194.     DATA.LENGTH := 0;
  195.     HEADER.CHECK := CHECKSUM (HEADER, DATA, 'S')
  196. END;
  197.     
  198.  
  199. (* _______________________________________________________________
  200.          Reads in a packet from the screen
  201.      1. MARK must contain the mark character
  202.      2. Default for HEADER.PTYPE = ' '
  203.      3. Default for HEADER.SEQ = -1
  204.     4. Packet must not contain the EOF character -  REC_ELN -
  205.     5. If CHECK = S at entry control de-quoting is not done
  206.     6. There are three possible returned values for CHECK
  207.         ' ' = receive okay
  208.         'E' = Checksum wrong, EOF marker before whole
  209.             Packet can be read, or can't find MARK
  210.         'T' = timed out when reading packet (Unimplimented)
  211.  
  212. *)
  213. PROCEDURE RECEIVE_PACKET (VAR HEADER:PACHEADER; VAR DATA:PACDATA; VAR CHECK:CHAR);
  214.  
  215. VAR
  216.     PACKET : PACKED ARRAY [1 .. MAXBUFF+10] OF CHAR;
  217.     X,Y, LOOP :INTEGER;
  218.     HCHECK,BYTE : CHAR;
  219.     DEQUOTE :BOOLEAN;
  220.  
  221. BEGIN
  222.     IF DEBUG THEN
  223.         BEGIN
  224.             WRITELN ('RECEIVING: ')
  225.         END;
  226.  
  227.     X := 0;
  228.     IF CHECK <> 'S' THEN DEQUOTE := TRUE
  229.             ELSE DEQUOTE := FALSE;
  230.     CHECK := ' ';
  231.     REPEAT
  232.         X := X+1;
  233.         IF EOF(INSCREEN) THEN
  234.             BEGIN
  235.                 RESET(INSCREEN);
  236.                 X := X+1
  237.             END;
  238.         READ (INSCREEN, BYTE);
  239.         IF DEBUG THEN
  240.             WRITELN('SEARCH FOR MARK, GOT: ',ORD(BYTE))
  241.     UNTIL (BYTE = MARK) OR (X = 6);
  242.     IF X = 6 THEN CHECK := 'E';
  243.  
  244.     X := 1;
  245.     HEADER.SEQ := -1;
  246.     HEADER.PTYPE := ' ';
  247.      FOR X := 1 TO 3 DO
  248.         BEGIN
  249.            IF EOF(INSCREEN) THEN CHECK := 'E'
  250.                     ELSE READ(INSCREEN,BYTE);
  251.            IF DEBUG THEN
  252.                WRITELN('READING BYTE- GOT: ',ORD(BYTE));
  253.            IF X = 1 THEN
  254.             DATA.LENGTH := UNKCHAR(BYTE) - 3;
  255.            IF X = 2 THEN
  256.             HEADER.SEQ := UNKCHAR (BYTE);
  257.            IF X = 3 THEN
  258.                 HEADER.PTYPE := BYTE
  259.         END;
  260.  
  261.     Y := 0;
  262.         X := 1;
  263.     LOOP := 1;
  264.     IF EOF(INSCREEN) THEN CHECK := 'E'
  265.               ELSE READ(INSCREEN,BYTE);
  266.     
  267.     WHILE (LOOP <= DATA.LENGTH) AND (CHECK <> 'E') DO
  268.         BEGIN
  269.            IF DEBUG THEN
  270.             WRITELN(DATA.LENGTH,' READING BYTE, GOT: ',ORD(BYTE));
  271.            IF Y = 1 THEN
  272.             BEGIN
  273.               Y := 2;
  274.               IF CHR(XAND(ORD(BYTE),127)) = REC_QCHR
  275.                   THEN DATA.DATA[X] := BYTE
  276.                   ELSE DATA.DATA[X] := CHR(CTL(ORD(BYTE)))
  277.             END;
  278.            IF (BYTE=REC_QCHR) AND (Y=0) AND DEQUOTE
  279.             THEN BEGIN
  280.                 Y := 1;
  281.                 DATA.LENGTH := DATA.LENGTH - 1
  282.                  END;
  283.            IF Y = 0
  284.             THEN DATA.DATA[X] := BYTE
  285.             ELSE IF Y=2 THEN Y := 0;
  286.  
  287.            IF EOF(INSCREEN) THEN CHECK := 'E'
  288.                     ELSE READ(INSCREEN,BYTE);
  289.            IF Y <> 1 THEN
  290.             BEGIN
  291.                 X:= X+1;
  292.                 LOOP := LOOP +1
  293.             END
  294.         END;     
  295.     
  296.        IF CHECK <> 'E' THEN
  297.        BEGIN
  298.         HEADER.CHECK := BYTE;
  299.         IF DEQUOTE
  300.             THEN HCHECK := CHECKSUM(HEADER,DATA,'C')
  301.             ELSE HCHECK := CHECKSUM(HEADER,DATA,'S');
  302.         IF NOT( HEADER.CHECK = HCHECK)
  303.             THEN CHECK := 'E'
  304.        END;
  305.     RESET(INSCREEN);
  306.  
  307.     IF DEBUG THEN
  308.         BEGIN
  309.             WRITELN('FINISHED RECEIVING PACKET');
  310.             WRITELN('       SEQUENCE: ',HEADER.SEQ);
  311.             WRITELN('   HEADER.PTYPE: ',HEADER.PTYPE);
  312.             WRITELN('    DATA-LENGTH: ',DATA.LENGTH);
  313.             WRITELN('          CHECK:',CHECK);
  314.             WRITELN('         HEADER.CHECK: ',HEADER.CHECK);
  315.             WRITELN('    RETURNED CHECKSUM: ',HCHECK)
  316.         END
  317. END;
  318.  
  319. (* _______________________________________________________________
  320.          Extracts the information from initial packet
  321.      1. sets SEND_MLEN, SEND_ELN
  322. *)
  323. PROCEDURE SET_DEFAULTS ( HEADER:PACHEADER; DATA:PACDATA );
  324.  
  325. BEGIN
  326.     IF DEBUG THEN WRITELN('SETTING DEFAULTS');
  327.     IF (DATA.LENGTH => 1) AND (DATA.DATA[1] <> ' ')
  328.           THEN SEND_MLEN := UNKCHAR (DATA.DATA[1])
  329.         ELSE SEND_MLEN := 80;
  330.     
  331.     IF (DATA.LENGTH => 5) AND (DATA.DATA[5] <> ' ')
  332.           THEN IF KCHAR_ELN
  333.               THEN SEND_ELN := CHR(UNKCHAR(DATA.DATA[5]))
  334.              ELSE SEND_ELN := DATA.DATA[5]
  335.         ELSE SEND_ELN := CR;
  336.  
  337.     IF (DATA.LENGTH => 6) AND (DATA.DATA[6] <> ' ')
  338.         THEN REC_QCHR := DATA.DATA[6]
  339.         ELSE REC_QCHR := '#';
  340.     IF DEBUG THEN
  341.       BEGIN
  342.          WRITELN('HAVE SET DEFAULTS');
  343.         WRITELN('   QUOTE CHAR FROM OTHER KERMIT: ',REC_QCHR);
  344.         WRITELN('   MAX LENGTH OF SEND PACKET: ', SEND_MLEN);
  345.         WRITELN('   SEND-EOLN CHAR (ASCII): ',ORD(SEND_ELN))
  346.        END
  347. END;
  348.  
  349. (* _______________________________________________________________
  350.          Creates a packet for the initial connection
  351. *)
  352. PROCEDURE CREATE_SEND_INIT (VAR HEADER:PACHEADER; VAR DATA:PACDATA; INDEX: INTEGER);
  353.  
  354. VAR
  355.     X : INTEGER;
  356.  
  357. BEGIN
  358.     IF DEBUG THEN WRITELN('CREATING SEND-INIT PACKET');
  359.     HEADER.PTYPE := 'S';
  360.     HEADER.SEQ := INDEX;
  361.     DATA.LENGTH := 10;
  362.     WITH DATA
  363.         DO BEGIN
  364.             DATA[1] := KCHAR(REC_MLEN);  (* Max packet lenth *)
  365.             DATA[2] := KCHAR(15); (* sec. before time out *)
  366.             DATA[3] := KCHAR(0);   (* # of pad char need *)
  367.             DATA[4] := ' ';     (* pad character *)
  368.             IF KCHAR_ELN
  369.                 THEN DATA[5] := KCHAR(ORD(REC_ELN))
  370.                 ELSE DATA[5] := REC_ELN;
  371.             DATA[6] := SEND_QCHR;    (* Char for control quote *)
  372.             DATA[7] := 'N';     (* No 8 Bit quote *)
  373.             DATA[8] := '1';     (* Normal checksum *)
  374.             DATA[9] := ' ';     (* No repeat char *)
  375.             DATA[10] := KCHAR(0)    (* Capacity byte *)
  376.         END;
  377.     FOR X := 11 TO 14 DO
  378.         DATA.DATA[X] := ' ';
  379.     HEADER.CHECK := CHECKSUM (HEADER,DATA,'S');
  380.     IF DEBUG THEN WRITELN('HAVE CREATED SEND INIT PACKET')
  381. END;
  382.  
  383. (* _______________________________________________________________
  384.          Sends packet until E or Y or B reply received
  385.     1. Will not do anything if REPLY initially E
  386.     2. Possible values of REPLY on exit are E and Y
  387.     3. If Initial value of REPLY = S
  388.          dequoting will not be done on receive
  389. *)
  390. PROCEDURE SEND_LOOP (HEADER:PACHEADER; DATA:PACDATA; VAR REPLY:CHAR);
  391.  
  392. VAR
  393.     HOLD :PACHEADER;
  394.     HOLDDATA :PACDATA;
  395.     CHECK ,HREPLY :CHAR;
  396.     TRYS :INTEGER;
  397.  
  398. BEGIN
  399.     IF DEBUG THEN WRITELN('STARTING SEND LOOP');
  400.     TRYS := 1;
  401.     IF REPLY = 'S' THEN HREPLY := 'S'
  402.                ELSE HREPLY := ' ';        
  403.     IF NOT(REPLY = 'E') THEN REPLY := ' ';
  404.     WHILE NOT ((REPLY = 'Y') OR (REPLY = 'E'))
  405.         DO BEGIN
  406.             SEND_PACKET (HEADER, DATA);
  407.             REPEAT
  408.                CHECK := HREPLY;
  409.                RECEIVE_PACKET (HOLD, HOLDDATA, CHECK);
  410.                IF CHECK = 'E' THEN HOLD.SEQ := -1;
  411.                IF CHECK = 'T' THEN HOLD.SEQ := -1;
  412.                IF HOLD.SEQ = ADDSEQ(HEADER.SEQ) THEN
  413.                 HOLD.SEQ := -1;
  414.             UNTIL (HOLD.SEQ = -1) OR (HOLD.SEQ=HEADER.SEQ);
  415.             IF HOLD.SEQ = -1  THEN REPLY := ' '
  416.                       ELSE REPLY := HOLD.PTYPE;
  417.             IF TRYS <= 5
  418.                 THEN TRYS := TRYS+1
  419.                 ELSE REPLY := 'E'
  420.         END;
  421.     IF DEBUG THEN WRITELN('FINISHING SEND LOOP')
  422. END;
  423.  
  424. (* _______________________________________________________________
  425.          Creates file header packet
  426. *)
  427. PROCEDURE CREATE_FILE_HEADER (VAR HEADER:PACHEADER; VAR DATA:PACDATA;
  428.                 INDEX:INTEGER ;DATAFILE:NAMETYPE);
  429.  
  430. VAR
  431.     X :INTEGER;
  432.  
  433. BEGIN
  434.     IF DEBUG THEN
  435.         WRITELN('CREATING FILE HEADER');
  436.     HEADER.PTYPE := 'F';
  437.     HEADER.SEQ := INDEX;
  438.     X := 1;
  439.     WHILE (X < NAMELENGTH) AND (DATAFILE[X] <> ' ') DO
  440.         BEGIN
  441.             DATA.DATA[X] := DATAFILE[X];
  442.             X := X+1
  443.         END;
  444.     DATA.LENGTH := X - 1;
  445.     HEADER.CHECK := CHECKSUM (HEADER,DATA,'S');
  446.     IF DEBUG THEN
  447.         WRITELN('CREATED FILE HEADER')
  448. END;
  449.  
  450. (* _______________________________________________________________
  451.          Creates a data packet
  452.     1. The XAND function is used, and a character is QUOTED if
  453.         it should be quoted with the high bit turned OFF
  454.         regardless of the actual value of the high bit
  455. *)
  456. PROCEDURE CREATE_DATA_PACKET (VAR HEADER:PACHEADER; VAR DATA:PACDATA; INDEX:INTEGER);
  457.  
  458. VAR
  459.     X,Y,VALUE,HVALUE :INTEGER;
  460.     BYTE :CHAR ;
  461.  
  462. BEGIN
  463.     IF DEBUG THEN
  464.         BEGIN
  465.              WRITELN('CREATING DATA PACKET');
  466.             WRITELN('   SEND_MLEN:', SEND_MLEN);
  467.         END;
  468.     HEADER.PTYPE := 'D';
  469.     HEADER.SEQ := INDEX;
  470.     
  471.     X := 1;
  472.     WHILE   NOT( EOF(DISK) ) AND ((X+4) <= (SEND_MLEN-7)) DO
  473.        BEGIN
  474.         READ (DISK,BYTE);
  475.         VALUE := ORD (BYTE);
  476.         HVALUE := XAND(VALUE,127);
  477.         IF NOT EIGHTBIT THEN
  478.            BEGIN
  479.              VALUE := HVALUE;
  480.             BYTE := CHR(VALUE)
  481.             END;
  482.         Y := X;
  483.         IF (HVALUE <= 31) OR (HVALUE = 127) THEN
  484.                BEGIN
  485.                DATA.DATA[X] := SEND_QCHR;
  486.                X := X+1;
  487.                DATA.DATA[X] := CHR( CTL(VALUE) )
  488.             END;
  489.         IF HVALUE  =  ORD(SEND_QCHR)  THEN
  490.             BEGIN
  491.                  DATA.DATA[X] := SEND_QCHR;
  492.               X := X+1;
  493.               DATA.DATA[X] := BYTE;
  494.             END;
  495.         IF (BYTE = NL) AND CENDLN THEN
  496.             BEGIN
  497.               DATA.DATA[X] := 'M';
  498.                     X := X+1;
  499.               DATA.DATA[X] := SEND_QCHR;
  500.               X := X+1;
  501.               DATA.DATA[X] := 'J'
  502.             END;
  503.         IF Y = X THEN
  504.             DATA.DATA[X] := BYTE;
  505.         X := X+1;
  506.        END;
  507.     DATA.LENGTH :=  X-1;
  508.     HEADER.CHECK := CHECKSUM (HEADER, DATA,'S');
  509.     IF DEBUG THEN WRITELN('HAVE CREATED DATA PACKET')
  510. END;
  511.  
  512.     
  513. (* _______________________________________________________________
  514.                 Does the send routine to send DATAFILE
  515.     1. the files must be open
  516.     2. closes the files
  517. *)
  518. PROCEDURE SEND_ROUTINE(DATAFILE:NAMETYPE);
  519.  
  520. VAR
  521.     HEADER, HOLD_HEADER:PACHEADER;
  522.     DATA, HOLD_DATA : PACDATA;
  523.     INDEX : INTEGER;
  524.     REPLY : CHAR;
  525.  
  526. BEGIN
  527.     INDEX := 0;
  528.  
  529.     CREATE_SEND_INIT (HEADER, DATA, INDEX);
  530.     REPEAT
  531.         SEND_PACKET(HEADER,DATA);
  532.         REPLY := 'S';
  533.         RECEIVE_PACKET(HOLD_HEADER,HOLD_DATA,REPLY);
  534.         IF DEBUG THEN
  535.             BEGIN
  536.             WRITELN(HOLD_HEADER.PTYPE,'-',REPLY,'-');
  537.             REPLY := ' ';
  538.             END;
  539.     UNTIL ((HOLD_HEADER.PTYPE = 'Y') AND (REPLY = ' '));
  540.     IF NOT IGNORE_PARMS THEN
  541.         SET_DEFAULTS (HOLD_HEADER, HOLD_DATA);
  542.  
  543.     INDEX := ADDSEQ(INDEX);
  544.     CREATE_FILE_HEADER ( HEADER, DATA, INDEX, DATAFILE);
  545.     SEND_LOOP (HEADER, DATA, REPLY);
  546.  
  547.     WHILE NOT( EOF(DISK) OR (REPLY = 'E') )
  548.         DO BEGIN
  549.             INDEX := ADDSEQ (INDEX);
  550.             CREATE_DATA_PACKET (HEADER,DATA,INDEX);
  551.             SEND_LOOP (HEADER, DATA, REPLY)
  552.         END;
  553.  
  554.     INDEX := ADDSEQ (INDEX);
  555.     CREATE_CONTROL_PACKET (HEADER, DATA, 'Z' , INDEX);
  556.     SEND_LOOP (HEADER, DATA, REPLY );
  557.  
  558.     INDEX := ADDSEQ (INDEX);
  559.     CREATE_CONTROL_PACKET (HEADER,DATA, 'B', INDEX);
  560.     SEND_LOOP (HEADER, DATA, REPLY);
  561.  
  562.     CLOSE (DISK);
  563.     CLOSE (OUTSCREEN);
  564.     CLOSE (INSCREEN)
  565. END;
  566.  
  567. (* ------------------------------------------------------------------
  568.  
  569. *)
  570. PROCEDURE SEND;
  571.     
  572. VAR
  573.     X:INTEGER;
  574.     DATAFILE:NAMETYPE;
  575.  
  576. BEGIN
  577.     WRITE(' Name of the file: ');
  578.     FOR X:= 1 TO NAMELENGTH DO
  579.          IF NOT(EOLN(INPUT))
  580.             THEN READ(DATAFILE[X])
  581.             ELSE DATAFILE[X] := ' ';
  582.     READLN;
  583.     OPEN_FILE(DATAFILE,'R');
  584.     SEND_ROUTINE(DATAFILE);
  585. END;
  586.  
  587. (* ------------------------------------------------------------------
  588.         Receives data packets and constructs file
  589.     1. Opens up DISK and closes it
  590.     2. HEADER and DATA must be the F packet
  591.     3. Will receive D packets until Z packet (end of file)
  592.     4. Changes CR LF to NL
  593. *)
  594. PROCEDURE RECEIVE_LOOP(VAR HEADER:PACHEADER; VAR DATA:PACDATA);
  595.  
  596. VAR
  597.     X,F,R,INDEX:INTEGER;
  598.     REPLY,RTYPE :CHAR;
  599.     DATAFILE :NAMETYPE;
  600.  
  601. BEGIN
  602.     IF DEBUG THEN WRITELN('STARTING RECEIVE_LOOP');
  603.  
  604.     INDEX := HEADER.SEQ+1;
  605.  
  606.     FOR X:= 1 TO NAMELENGTH DO
  607.         IF (DATA.DATA[X] <> ' ') AND (X <= DATA.LENGTH)
  608.             THEN DATAFILE[X] := DATA.DATA[X]
  609.             ELSE DATAFILE[X] := ' ';
  610.     OPEN_FILE(DATAFILE,'C');
  611.     CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ);
  612.     SEND_PACKET(HEADER,DATA);
  613.  
  614.  
  615.         RTYPE :=  ' ';
  616.     WHILE (RTYPE <> 'Z') AND (RTYPE <> 'E') DO
  617.        BEGIN
  618.            RECEIVE_PACKET(HEADER,DATA,REPLY);
  619.            RTYPE := HEADER.PTYPE;
  620.            IF DEBUG THEN WRITELN('Index - ',INDEX);
  621.            IF  REPLY = ' ' THEN
  622.           BEGIN
  623.              IF (HEADER.SEQ = INDEX) AND (RTYPE = 'D')
  624.               THEN BEGIN
  625.                   INDEX := ADDSEQ(INDEX);
  626.                   R := 0;
  627.                   F := -3;
  628.                   FOR X:= 1 TO DATA.LENGTH DO
  629.                 BEGIN
  630.                   DATA.DATA[(X-R)] := DATA.DATA[X];
  631.                   IF DATA.DATA[X] = '<15>' THEN F := X;
  632.                   IF (DATA.DATA[X] = '<12>') AND (F=X-1)
  633.                     AND CENDLN THEN
  634.                          BEGIN
  635.                          R := R+1;
  636.                         DATA.DATA[(X-R)] := NL
  637.                          END;
  638.                 END;
  639.                   DATA.LENGTH := DATA.LENGTH - R;
  640.                   IF DEBUG  THEN
  641.                 BEGIN
  642.                    WRITELN('R offset is - ',R);
  643.                    WRITELN('Writting Disk- ',DATA.LENGTH);
  644.                 END;
  645.                      WRITE(DISK,DATA.DATA:DATA.LENGTH)
  646.               END;
  647.                      CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ)
  648.           END;
  649.            IF REPLY <> ' ' THEN
  650.            CREATE_CONTROL_PACKET(HEADER,DATA,'N',HEADER.SEQ);
  651.            SEND_PACKET(HEADER,DATA)
  652.        END;
  653.  
  654.     CLOSE(DISK);
  655.     IF DEBUG THEN WRITELN('FINISHING RECEIVE_LOOP')
  656. END;
  657.  
  658. (* ------------------------------------------------------------------
  659.         The secondary Receive Routine
  660.     set up this way to facilitate server implimentation
  661. *)
  662. PROCEDURE RECEIVE_ROUTINE(VAR HEADER:PACHEADER; VAR DATA:PACDATA);
  663.  
  664. VAR
  665.     X:INTEGER;
  666.     REPLY:CHAR;
  667.  
  668. BEGIN
  669.     IF NOT IGNORE_PARMS THEN
  670.         SET_DEFAULTS(HEADER,DATA);
  671.  
  672.     CREATE_SEND_INIT(HEADER,DATA,0);
  673.     HEADER.PTYPE := 'Y';
  674.     HEADER.CHECK := CHR(ORD(HEADER.CHECK) +6);
  675.     SEND_PACKET(HEADER,DATA);
  676.  
  677.     REPEAT
  678.          REPLY := 'S';
  679.          RECEIVE_PACKET(HEADER,DATA,REPLY);
  680.          IF REPLY <> ' ' THEN
  681.          BEGIN
  682.            CREATE_CONTROL_PACKET(HEADER,DATA,'N',HEADER.SEQ);
  683.                SEND_PACKET(HEADER,DATA)
  684.          END;
  685.          IF  (REPLY = ' ') AND (HEADER.PTYPE<>'B') THEN
  686.             RECEIVE_LOOP(HEADER,DATA)
  687.     UNTIL (HEADER.PTYPE = 'E') OR (HEADER.PTYPE = 'B');
  688.  
  689.     IF HEADER.PTYPE <> 'E' THEN
  690.         BEGIN
  691.            CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ);
  692.            SEND_PACKET(HEADER,DATA)
  693.         END
  694. END;
  695.  
  696. (* ------------------------------------------------------------------
  697.  
  698. *)
  699. PROCEDURE RECEIVE;
  700.  
  701. VAR
  702.     HEADER:PACHEADER;
  703.     DATA:PACDATA;
  704.     REPLY :CHAR;
  705.  
  706. BEGIN
  707.     OPEN_SCREEN;
  708.     REPLY := 'S';
  709.     RECEIVE_PACKET(HEADER,DATA,REPLY);
  710.     WHILE (REPLY <> ' ') DO
  711.         BEGIN
  712.             CREATE_CONTROL_PACKET(HEADER,DATA,'N',0);
  713.             SEND_PACKET(HEADER,DATA);
  714.             REPLY := 'S';
  715.             RECEIVE_PACKET(HEADER,DATA,REPLY);
  716.         END;
  717.     RECEIVE_ROUTINE(HEADER,DATA);
  718. END;
  719.  
  720. (* ------------------------------------------------------------------
  721.  
  722. *)
  723. PROCEDURE SERVER;
  724.  
  725. VAR
  726.     DATAFILE:NAMETYPE;
  727.     CHECK:CHAR;
  728.     HEADER:PACHEADER;
  729.     DATA:PACDATA;
  730.     X:INTEGER;
  731.  
  732. BEGIN
  733.     WRITELN('Server started.  You may return to micro');
  734.     REPEAT
  735.         OPEN_SCREEN;
  736.     REPEAT
  737.         CHECK := 'S';
  738.         RECEIVE_PACKET(HEADER,DATA,CHECK);
  739.     UNTIL (CHECK=' ');
  740.     
  741.     IF HEADER.PTYPE = 'R' THEN
  742.       BEGIN
  743.         IF DEBUG THEN WRITELN('SERVER BEGINNING SEND');
  744.         FOR X:= 1 TO NAMELENGTH DO
  745.             IF DATA.LENGTH => X
  746.                 THEN DATAFILE[X] := DATA.DATA[X]
  747.                 ELSE DATAFILE[X] := ' ';
  748.         OPEN_FILE(DATAFILE,'R');
  749.         SEND_ROUTINE(DATAFILE);
  750.       END;
  751.     IF HEADER.PTYPE = 'S' THEN
  752.        BEGIN
  753.         IF DEBUG THEN WRITELN('SERVER BEGINNING RECEIVE');
  754.         RECEIVE_ROUTINE(HEADER,DATA);
  755.        END;
  756.     UNTIL HEADER.PTYPE = 'G';
  757.  
  758.     CREATE_CONTROL_PACKET(HEADER,DATA,'Y',HEADER.SEQ);
  759.     SEND_PACKET(HEADER,DATA);
  760. END;
  761.  
  762. (* ------------------------------------------------------------------
  763.  
  764.         USER INTERFACE ROUTINES
  765.  
  766.    ----------------------------------------------------------------- *)
  767.  
  768. (* _______________________________________________________________
  769.         Displays value of Kermit parameters
  770. *)
  771. PROCEDURE DISPLAY_DEFAULTS;
  772. BEGIN
  773.     WRITELN;
  774.     WRITELN(' Sending End of line character (ASCII): ',ORD(SEND_ELN));
  775.     WRITELN(' Maximum Sending packet length: ',SEND_MLEN);
  776.     WRITELN(' Maximum Receiving packet length: ',REC_MLEN);
  777.     WRITELN(' Quote character used in receiving: ',REC_QCHR);
  778.     WRITE(' Eigth bit I-O: ');
  779.     IF DEBUG THEN WRITELN('ON')
  780.          ELSE WRITELN('OFF');
  781.     WRITE(' Debug flag: ');
  782.     IF DEBUG THEN WRITELN('ON')
  783.          ELSE WRITELN('OFF');
  784.     WRITE(' Ignore the parameters other Kermit sends: ');
  785.     IF IGNORE_PARMS THEN WRITELN('ON')
  786.             ELSE WRITELN('OFF');
  787.     WRITE(' Make the EOLN character printable in SEND INIT: ');
  788.     IF KCHAR_ELN THEN WRITELN('ON')
  789.              ELSE WRITELN('OFF');
  790.     WRITE(' Change CRLF to NL on input and the reverse on output: ');
  791.     IF CENDLN  THEN WRITELN('ON')
  792.            ELSE WRITELN('OFF');
  793.     WRITELN
  794. END;
  795.  
  796. (* _______________________________________________________________
  797.        Allows one to change the initial default settings
  798. *)
  799. PROCEDURE CHANGE_DEFAULTS;
  800.     
  801. VAR
  802.     STATE,CHOICE :CHAR;
  803.     OPTION :CHAR;
  804.     VALUE : INTEGER;
  805.  
  806.    FUNCTION GET_ON:BOOLEAN;
  807.        BEGIN
  808.         REPEAT
  809.             WRITE('Input choice (Y=ON , N=OFF): ');
  810.             READLN(CHOICE);
  811.             IF NOT((CHOICE='Y') OR (CHOICE='N'))
  812.                 THEN WRITELN('Invalid entry')
  813.         UNTIL (CHOICE='Y') OR (CHOICE='N');
  814.         IF CHOICE = 'Y'
  815.             THEN GET_ON := TRUE
  816.             ELSE GET_ON := FALSE
  817.        END;
  818.  
  819. BEGIN
  820.     WRITE('Change: ');
  821.     IF EOLN(INPUT)
  822.         THEN OPTION := ' '
  823.         ELSE READ(OPTION);
  824.     READLN;
  825.     WRITE('<27>','<30>','<30>','<30>','<30>','<30>','<30>');
  826.     WRITE('<30>','<30>','<30>','      ');
  827.     CASE OPTION OF
  828.         'E' : BEGIN
  829.               VALUE := ORD(CR);
  830.               WRITE('ASCII number of SEND EOL character: ');
  831.               READLN(VALUE);
  832.               SEND_ELN := CHR(VALUE)
  833.               END;
  834.         'S' : BEGIN
  835.               WRITE('Maximum Length of Send Packet: ');
  836.               READLN(VALUE);
  837.               IF EIGHTBIT
  838.                 THEN SEND_MLEN := VALUE
  839.                 ELSE SEND_MLEN := XAND(VALUE,95);
  840.               END;
  841.         'R' : BEGIN
  842.               WRITE('Maximum Length of Receive Packet: ');
  843.               READLN(VALUE);
  844.               IF EIGHTBIT
  845.                 THEN REC_MLEN := VALUE
  846.                 ELSE REC_MLEN := XAND(VALUE,95);
  847.               END;
  848.         'Q' : BEGIN
  849.               VALUE := ORD('#');
  850.               WRITE('ASCII number of QUOTE character: ');
  851.               READLN(VALUE);
  852.               REC_QCHR := CHR(VALUE)
  853.               END;
  854.         '8' : EIGHTBIT := GET_ON;
  855.         'D' : DEBUG := GET_ON;
  856.         'C' : CENDLN := GET_ON;
  857.         'I' : IGNORE_PARMS := GET_ON;
  858.         'M' : KCHAR_ELN := GET_ON;
  859.         'H' : BEGIN
  860.              WRITELN;
  861.              WRITELN;
  862.              WRITELN(' E - End of line character for sending packets');
  863.              WRITELN(' D - Debug flag');
  864.              WRITELN(' S - Maximun Length of Send Packet');
  865.              WRITELN(' R - Maximun Length of Receive Packet');
  866.              WRITELN(' M - Make EOLN printable in SEND INIT');
  867.              WRITELN(' 8 - Use eight bit I-O');
  868.              WRITELN(' C - Change NL to CRLF and CRLF to NL');
  869.              WRITELN(' Q - Quote character in receiving');
  870.              WRITELN(' H - this Help message');
  871.              WRITELN(' I - Ignore the parameters set by other Kermit');
  872.              WRITELN
  873.               END;
  874.         OTHERWISE
  875.         WRITELN('INVALID ENTRY');
  876.     END;
  877.     WRITELN
  878. END;
  879.  
  880. (* _______________________________________________________________
  881.  
  882. *)
  883. PROCEDURE MAIN;
  884.  
  885. VAR
  886.     OPTION: CHAR;
  887.     
  888. BEGIN
  889.     REC_QCHR := '#';
  890.     SEND_ELN := CR;
  891.     SEND_MLEN := 74;
  892.     REC_MLEN := 94;
  893.     KCHAR_ELN := TRUE;
  894.     IGNORE_PARMS := TRUE;
  895.     DEBUG := FALSE;
  896.     EIGHTBIT := FALSE;
  897.     CENDLN := TRUE;
  898.     REPEAT
  899.         WRITE ('KERMIT-DG> ');
  900.         READLN (OPTION);
  901.           CASE OPTION OF
  902.             'S' : SEND ;
  903.             'R' : RECEIVE;
  904.             'I' : SERVER;
  905.             'E' : WRITELN('TERMINATING');
  906.             'C' : CHANGE_DEFAULTS;
  907.             'D' : DISPLAY_DEFAULTS;
  908.           OTHERWISE
  909.             WRITELN ('BAD INPUT')
  910.           END
  911.     UNTIL ( OPTION = 'E');
  912. END;
  913.  
  914. (* ------------------------------------------------------------------
  915.         The Program block
  916.  
  917.    -----------------------------------------------------------------
  918. *)
  919. BEGIN
  920.     MAIN
  921. END.
  922.