home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / harris800 / h800ker.pas < prev    next >
Pascal/Delphi Source File  |  2020-01-01  |  70KB  |  2,642 lines

  1.   PROGRAM Kermit(input,output,file3,file4,file5,
  2.                 file6,file7,file8,file9,filen,filet);
  3.  
  4. LABEL
  5.   9999;             { used only to simulate a "halt" instruction }
  6.  
  7.  
  8. CONST
  9.  
  10.  
  11.   bufsize=128;
  12.   lf=12B;
  13.   return=15B;
  14.   formfeed=14B;
  15.   controlbar=28;
  16.   CTRLC=3;
  17.   mask= 177B;
  18.  
  19.   { standard file descriptors. subscripts in open, etc. }
  20.   STDIN = 1;              { these are not to be changed }
  21.   STDOUT = 2;
  22.   lineout = 3;
  23.   linein = 4;
  24.  
  25.   { other io-related stuff }
  26.   IOERROR = 0;    { status values for open files }
  27.   IOAVAIL = 1;
  28.   IOREAD = 2;
  29.   IOWRITE = 3;
  30.   MAXOPEN = 9;   { maximum number of open files }
  31.  
  32.   { universal manifest constants }
  33.   ENDFILE = -1;
  34.   ENDSTR = 0;     { null-terminated strings }
  35.   MAXSTR = 100;   { longest possible string }
  36.   CONLENGTH = 20; { length of constant string }
  37.   FILENAMELENGTH = 17;  { length of file name for Bind }
  38.   MAXERRORS = 50;  { maximum number of errors kept if remote }
  39.  
  40.   { ascii character set in decimal }
  41.   BACKSPACE = 8;
  42.   TAB = 9;
  43.   NEWLINE = 10;
  44.   BLANK = 32;
  45.   EXCLAM = 33;    { ! }
  46.   DQUOTE = 34;    { " }
  47.   SHARP = 35;     { # }
  48.   DOLLAR = 36;    { $ }
  49.   PERCENT = 37;   { % }
  50.   AMPER = 38;     { & }
  51.   SQUOTE = 39;    { ' }
  52.   ACUTE = SQUOTE;
  53.   LPAREN = 40;    { ( }
  54.   RPAREN = 41;    { ) }
  55.   STAR = 42;      { * }
  56.   PLUS = 43;      { + }
  57.   COMMA = 44;     { , }
  58.   MINUS = 45;     { - }
  59.   DASH = MINUS;
  60.   PERIOD = 46;    { . }
  61.   SLASH = 47;     { / }
  62.   COLON = 58;     { : }
  63.   SEMICOL = 59;   { ; }
  64.   LESS = 60;      { < }
  65.   EQUALS = 61;    { = }
  66.   GREATER = 62;   { > }
  67.   QUESTION = 63;  { ? }
  68.   ATSIGN = 64;    { @ }
  69.   LBRACK = 91;    { [ }
  70.   BACKSLASH = 92; { \ }
  71.   ESCAPE = BACKSLASH; {  changed  - used to be @ }
  72.   RBRACK = 93;    { ] }
  73.   CARET = 94;     { ^ }
  74.   UNDERLINE = 95; { _ }
  75.   GRAVE = 96;     { ` }
  76.   LETA = 97;      { lower case ... }
  77.   LETB = 98;
  78.   LETC = 99;
  79.   LETD = 100;
  80.   LETE = 101;
  81.   LETF = 102;
  82.   LETG = 103;
  83.   LETH = 104;
  84.   LETI = 105;
  85.   LETJ = 106;
  86.   LETK = 107;
  87.   LETL = 108;
  88.   LETM = 109;
  89.   LETN = 110;
  90.   LETO = 111;
  91.   LETP = 112;
  92.   LETQ = 113;
  93.   LETR = 114;
  94.   LETS = 115;
  95.   LETT = 116;
  96.   LETU = 117;
  97.   LETV = 118;
  98.   LETW = 119;
  99.   LETX = 120;
  100.   LETY = 121;
  101.   LETZ = 122;
  102.   LBRACE = 123;   { left brace }
  103.   BAR = 124;      { | }
  104.   RBRACE = 125;   { right brace }
  105.   TILDE = 126;    { ~ }
  106.  
  107.  
  108.   SOH          = 1;       (* ascii SOH character *)
  109.   CR           = 13;      (* CR *)
  110.   DEL          = 127;     (* rubout *)
  111.  
  112.   DEFTRY       = 10;      (* default for number of retries *)
  113.   DEFTIMEOUT   = 12;      (* default time out *)
  114.   MAXPACK      = 94;      (* max is 94 ~ - ' ' *)
  115.   DEFDELAY     = 5;       (* delay before sending first init *)
  116.   NUMPARAM     = 6;       (* number of parameters in init packet *)
  117.   DEFQUOTE     = SHARP;   (* default quote character  *)
  118.   DEFPAD       = 0;       (* default number OF padding chars  *)
  119.   DEFPADCHAR   = 0;       (* default padding character  *)
  120.   DEFDUPLEX    = false;   (* default duplex is full duplex *)
  121.   (* SYSTEM DEPENDENT *)
  122.  
  123.   DEFEOL  = CR;
  124.   DEFEOLTYPE    = 2;
  125.  
  126.   (* 1 = LineFeed
  127.    2 = CrLf
  128.    3 = Just Cr *)
  129.  
  130.   FLEN1 = 8;
  131.   FLEN2 = 8;
  132.   PFILE     = 'KERMIT.P            ';
  133.   TRACEFILE = 'KERMIT.T         ';
  134.   TEMPFILE  = 'TEMP.K              ';
  135.   lp = 'LP:                 ';
  136.  
  137.  
  138.   NUMBUFFERS = 5;         (* Number of buffers *)
  139.  
  140.   (* packet types *)
  141.  
  142.   TYPEB  = 66; (* ord('B') *)
  143.   TYPED  = 68; (* ord('D') *)
  144.   TYPEE  = 69; (* ord('E') *)
  145.   TYPEF  = 70; (* ord('F') *)
  146.   TYPEN  = 78; (* ord('N') *)
  147.   TYPES  = 83; (* ord('S') *)
  148.   TYPET  = 84; (* ord('T') *)
  149.   TYPEY  = 89; (* ord('Y') *)
  150.   TYPEZ  = 90; (* ord('Z') *)
  151.  
  152.   MAXCMD = 10;
  153.  
  154. TYPE
  155.  
  156.   character = -128..127;  { byte-sized. ascii + other stuff }
  157.   string = ARRAY [1..MAXSTR] OF character;
  158.   mstring = PACKED ARRAY [1..FILENAMELENGTH] OF char;
  159.   vstring = RECORD
  160.               len : integer;
  161.               ch  : ARRAY [1..MAXSTR] OF char;
  162.             END;
  163.   cstring = PACKED ARRAY [1..CONLENGTH] OF char;
  164.   filedesc = IOERROR..MAXOPEN;
  165.  
  166.  
  167.   (* Data Types for Kermit *)
  168.  
  169.  
  170.   Packet = RECORD
  171.              mark : character;       (* SOH character *)
  172.              count: character;       (* # of bytes following this field *)
  173.              seq  : character;       (* sequence number modulo 64  *)
  174.              ptype: character;       (* d,y,n,s,b,f,z,e,t  packet type *)
  175.              data : string;          (* the actual data *)
  176.              (* chksum is last validchar in data array *)
  177.              (* eol is added, not considered part of packet proper *)
  178.            END;
  179.  
  180.   Command = (Transmit,Receive,Print,SetParm,Invalid);
  181.  
  182.   KermitStates = (FileData,Init,Break,FileHeader,EOFile,Complete,Abort);
  183.  
  184.   EOLtype = (LineFeed,CrLf,JustCr);
  185.  
  186.   Words = (Low,High);
  187.   Stats = ARRAY [Low..High] OF integer;
  188.  
  189.   Ppack = 1..NUMBUFFERS;
  190.  
  191.   CType = RECORD
  192.             check: integer;
  193.             PacketPtr : integer;
  194.             i : integer;
  195.             fld : integer;
  196.             t : character;
  197.             finished : boolean;
  198.             restart : boolean;
  199.             control : boolean;
  200.             good : boolean;
  201.           END;
  202.  
  203.   InType = (abortnow,nothing,CRin);
  204.  
  205. VAR
  206.  
  207.   ch         : char;
  208.   done       : boolean;
  209.   HalfDuplex : boolean;
  210.   BindStatus : integer;
  211.  
  212.   file3    : text;      { output to other computer }
  213.   file4    : text;      { input from other computer }
  214.   file5    : text;      { assigned to a file to send or receive }
  215.   file6    : text;
  216.   file7    : text;
  217.   file8    : text;
  218.   file9    : text;
  219.   filen    : text;      { check for a file's existance }
  220.   filet    : text;      { trace output }
  221.   filemode : ARRAY [1..MAXOPEN] OF IOERROR..IOWRITE;
  222.  
  223.   cmdargs  : 0..MAXCMD;
  224.   cmdlin   : string;
  225.   cmdidx   : ARRAY [1..MAXCMD] OF 1..MAXSTR;
  226.  
  227.  
  228.  
  229.   (* Variables for Kermit *)
  230.  
  231.   aline    : string;
  232.   DiskFile : filedesc;
  233.   SaveState : kermitstates;
  234.   NextArg  : integer;   (* next argument to process *)
  235.   Local    : boolean;   (* local/remote flag *)
  236.   MaxTry   : integer;
  237.   n,J      : integer;   (* packet number *)
  238.   NumTry   : integer;   (* times this packet retried *)
  239.   OldTry   : integer;
  240.   Pad      : integer;    (* padding to send *)
  241.   MyPad    : integer;    (* number of padding characters I need *)
  242.   PadChar  : character;
  243.   MyPadChar: character;
  244.   RunType  : command;
  245.   State    : kermitstates; (* current state of the automaton *)
  246.   MyTimeOut:  integer;     (* when i want to be timed out *)
  247.   TheirTimeOut  : integer;
  248.   Delay    : integer;
  249.   SizeRecv, SizeSend : integer;
  250.   SendEOL, SendQuote : character;
  251.   myEOL,myQuote: character;
  252.   EOLforFile : EOLtype;
  253.   ParmFile : string;
  254.   NumSendPacks : integer;
  255.   NumRecvPacks : integer;
  256.   NumACK : integer;
  257.   NumNAK : integer;
  258.   NumACKrecv : integer;
  259.   NumNAKrecv : integer;
  260.   NumBADrecv : integer;
  261.   RunTime: integer;
  262.   ChInFile, ChInPack : Stats;
  263.   Verbosity: boolean;     (* true to print verbose messages *)
  264.   Trace: boolean;         (* true to write trace info in KERMIT.T file *)
  265.   OneWayOnly : boolean;   (* used for testing *)
  266.   Debug : boolean;
  267.   TtyMode : (Cooked,Raw);
  268.   KeptErrors : ARRAY [1..MAXERRORS] OF cstring;  (* keep errors if remote *)
  269.   NumKeptErrors : integer;
  270.  
  271.   Buf : ARRAY [1..NUMBUFFERS] OF packet;
  272.   ThisPacket : Ppack; (* current packet being sent *)
  273.   LastPacket : Ppack; (* last packet sent *)
  274.   CurrentPacket : Ppack; (* current packet received *)
  275.   NextPacket : Ppack; (* next packet being received *)
  276.   InputPacket : Ppack; (* save input to do debug *)
  277.  
  278.   TOPacket : packet; (* Time_Out Packet *)
  279.   TimeLeft : integer; (* until Time_Out *)
  280.  
  281.   FromConsole : InType;   (* Input from Console during receive *)
  282.  
  283.   PackControl : CType;  (* variables for receive packet routine *)
  284.  
  285.   { prims -- primitive functions and procedures   }
  286.  
  287. PROCEDURE SYSINIT; ALIEN;
  288.   { System dependent initialize }
  289.  
  290. FUNCTION CONNECT(DUPLEX : BOOLEAN): BOOLEAN; ALIEN;
  291.   { Connect to remote host computer--we are local.
  292.     Echange characters between host and terminal until
  293.     user presses escape code.  DUPLEX is false for full
  294.     duplex, true for half duplex.  Return false if this
  295.     Kermit is host only (no connection possible) }
  296.  
  297. FUNCTION GETIN(VAR TIMEREMAINING : INTEGER; VAR FROMCONSOLE : INTYPE):
  298.   CHARACTER; ALIEN;
  299.   { If connected, get character from host;
  300.     otherwise, get character from terminal.
  301.     Decrement timeremaining for each full second you wait;
  302.     give up when timeleft gets to zero.
  303.     If connected to host computer, and user types a character,
  304.     set fromconsole accordingly }
  305.  
  306. PROCEDURE XMTCHAR(C : CHAR); ALIEN;
  307.   { If connected, send character to host;
  308.     otherwise send character to terminal }
  309.  
  310. PROCEDURE SYSFINISH; ALIEN;
  311.   { If connected, disconnect.  System depedent clean up. }
  312.  
  313. PROCEDURE SLEEP(T: INTEGER); ALIEN;
  314.   { Delay for T seconds }
  315.  
  316. PROCEDURE TTYRAW; ALIEN;
  317.   { For host mode--put terminal into character by character mode.
  318.     When in this mode, only GETIN and XMTCHAR are used to talk
  319.     to the tty }
  320.  
  321. PROCEDURE TTYCOOKED; ALIEN;
  322.   { Return terminal to normal I/O mode }
  323.  
  324. PROCEDURE FLUSH; ALIEN;
  325.   { Flush any pending output }
  326.  
  327. PROCEDURE FILECREATE(FILENAME : MSTRING); ALIEN;
  328.   { Create a file }
  329.  
  330. PROCEDURE FIXNAME(VAR FILENAME : STRING); ALIEN;
  331.   { Fix up file name before sending it to other Kermit.
  332.     Argument is 1 character per word in least significant bits }
  333.  
  334. FUNCTION BITWISE(i,j,result00,result01,result10,result11:integer):integer;
  335.   { Perform bit-wise logical operation on two integers given the
  336.     truth table:
  337.                            |  bit in j=0  |  bit in j=1  |
  338.                ------------+--------------+--------------+
  339.                bit in i=0  |   result00   |   result01   |
  340.                ------------+--------------+--------------+
  341.                bit in i=1  |   result10   |   result11   |
  342.                ------------+--------------+--------------+
  343.  
  344.     For negative numbers, use the fact that on a two's complement
  345.     machine the bit-wise NOT of an integer "n" is "-1 - n".
  346.     This works on machines that are not two's complement also,
  347.     as long as we consistently use "-1 - n" as the NOT,
  348.     and know how to interpret negative results. }
  349. VAR bit, result: integer;
  350. BEGIN
  351.   if i < 0 then
  352.     BITWISE := BITWISE(-1-i,j,result10,result11,result00,result01)
  353.   else if j < 0 then
  354.     BITWISE := BITWISE(i,-1-j,result01,result00,result11,result10)
  355.   else if result00 <> 0 then
  356.     BITWISE := -1 - BITWISE(i,j,0,1-result01,1-result10,1-result11)
  357.   else
  358.     BEGIN
  359.       result := 0;
  360.       bit := 1;
  361.       WHILE (i > 0) AND (j > 0) DO
  362.         BEGIN
  363.           IF odd(i) THEN
  364.             IF odd(j) THEN result := result + bit*result11
  365.             ELSE result := result + bit*result10
  366.           ELSE IF odd(j) THEN result := result + bit*result01;
  367.           i := i DIV 2;
  368.           j := j DIV 2;
  369.           bit := bit + bit;
  370.         END;
  371.       BITWISE := result + bit*(i*result10 + j*result01);
  372.     END;
  373. END;
  374.  
  375. FUNCTION IAND(i,j:integer):integer;
  376. BEGIN
  377.   IAND := BITWISE(i,j,0,0,0,1);
  378. END;
  379.  
  380. FUNCTION IOR(i,j:integer):integer;
  381. BEGIN
  382.   IOR := BITWISE(i,j,0,1,1,1);
  383. END;
  384.  
  385. PROCEDURE fdbind(fd: filedesc; intname: mstring);
  386. BEGIN
  387.   CASE fd OF
  388.     1: bind(input,intname,BindStatus);
  389.     2: bind(output,intname,BindStatus);
  390.     3: bind(file3,intname,BindStatus);
  391.     4: bind(file4,intname,BindStatus);
  392.     5: bind(file5,intname,BindStatus);
  393.     6: bind(file6,intname,BindStatus);
  394.     7: bind(file7,intname,BindStatus);
  395.     8: bind(file8,intname,BindStatus);
  396.     9: bind(file9,intname,BindStatus);
  397.   END;
  398. END;
  399.  
  400. PROCEDURE fdclose(fd: filedesc);
  401. BEGIN
  402.   CASE fd OF
  403.     1: close(input);
  404.     2: close(output);
  405.     3: close(file3);
  406.     4: close(file4);
  407.     5: close(file5);
  408.     6: close(file6);
  409.     7: close(file7);
  410.     8: close(file8);
  411.     9: close(file9);
  412.   END;
  413. END;
  414.  
  415. FUNCTION fdeof(fd: filedesc): boolean;
  416. BEGIN
  417.   CASE fd OF
  418.     1: fdeof := eof(input);
  419.     2: fdeof := eof(output);
  420.     3: fdeof := eof(file3);
  421.     4: fdeof := eof(file4);
  422.     5: fdeof := eof(file5);
  423.     6: fdeof := eof(file6);
  424.     7: fdeof := eof(file7);
  425.     8: fdeof := eof(file8);
  426.     9: fdeof := eof(file9);
  427.   END;
  428. END;
  429.  
  430. FUNCTION fdeoln(fd: filedesc): boolean;
  431. BEGIN
  432.   CASE fd OF
  433.     1: fdeoln := eoln(input);
  434.     2: fdeoln := eoln(output);
  435.     3: fdeoln := eoln(file3);
  436.     4: fdeoln := eoln(file4);
  437.     5: fdeoln := eoln(file5);
  438.     6: fdeoln := eoln(file6);
  439.     7: fdeoln := eoln(file7);
  440.     8: fdeoln := eoln(file8);
  441.     9: fdeoln := eoln(file9);
  442.   END;
  443. END;
  444.  
  445. PROCEDURE fdread(fd: filedesc; VAR ch: char);
  446. BEGIN
  447.   CASE fd OF
  448.     1: read(input,ch);
  449.     2: read(output,ch);
  450.     3: read(file3,ch);
  451.     4: read(file4,ch);
  452.     5: read(file5,ch);
  453.     6: read(file6,ch);
  454.     7: read(file7,ch);
  455.     8: read(file8,ch);
  456.     9: read(file9,ch);
  457.   END;
  458. END;
  459.  
  460. PROCEDURE fdreadln(fd: filedesc);
  461. BEGIN
  462.   CASE fd OF
  463.     1: readln(input);
  464.     2: readln(output);
  465.     3: readln(file3);
  466.     4: readln(file4);
  467.     5: readln(file5);
  468.     6: readln(file6);
  469.     7: readln(file7);
  470.     8: readln(file8);
  471.     9: readln(file9);
  472.   END;
  473. END;
  474.  
  475. PROCEDURE fdreset(fd: filedesc);
  476. BEGIN
  477.   CASE fd OF
  478.     1: reset(input);
  479.     2: reset(output);
  480.     3: reset(file3);
  481.     4: reset(file4);
  482.     5: reset(file5);
  483.     6: reset(file6);
  484.     7: reset(file7);
  485.     8: reset(file8);
  486.     9: reset(file9);
  487.   END;
  488. END;
  489.  
  490. PROCEDURE fdrewrite(fd: filedesc);
  491. BEGIN
  492.   CASE fd OF
  493.     1: rewrite(input);
  494.     2: rewrite(output);
  495.     3: rewrite(file3);
  496.     4: rewrite(file4);
  497.     5: rewrite(file5);
  498.     6: rewrite(file6);
  499.     7: rewrite(file7);
  500.     8: rewrite(file8);
  501.     9: rewrite(file9);
  502.   END;
  503. END;
  504.  
  505. PROCEDURE fdwrite(fd: filedesc; ch: char);
  506. BEGIN
  507.   CASE fd OF
  508.     1: write(input,ch);
  509.     2: IF TtyMode = Cooked THEN write(output,ch)
  510.        ELSE IF Trace THEN write(filet,ch);
  511.     3: write(file3,ch);
  512.     4: write(file4,ch);
  513.     5: write(file5,ch);
  514.     6: write(file6,ch);
  515.     7: write(file7,ch);
  516.     8: write(file8,ch);
  517.     9: write(file9,ch);
  518.   END;
  519. END;
  520.  
  521. PROCEDURE fdwriteln(fd: filedesc);
  522. BEGIN
  523.   CASE fd OF
  524.     1: writeln(input);
  525.     2: IF TtyMode = Cooked THEN writeln(output)
  526.        ELSE IF Trace THEN writeln(filet);
  527.     3: writeln(file3);
  528.     4: writeln(file4);
  529.     5: writeln(file5);
  530.     6: writeln(file6);
  531.     7: writeln(file7);
  532.     8: writeln(file8);
  533.     9: writeln(file9);
  534.   END;
  535. END;
  536.  
  537. PROCEDURE WriteCharacter;
  538. BEGIN
  539.   write(ch);
  540. END;
  541.  
  542.   PROCEDURE stiphalt; (* used by external procedures for halt *)
  543.    BEGIN
  544.      GOTO 9999;
  545.    END;
  546.  
  547.   { initio  -- initialize open file list }
  548.   PROCEDURE initio;
  549.   VAR
  550.     i :     filedesc;
  551.    BEGIN
  552.      filemode[STDIN] := IOREAD;
  553.      filemode[STDOUT] := IOWRITE;
  554.      filemode[lineout] := IOWRITE;
  555.      filemode[linein] := IOREAD;
  556.  
  557.      { connect STDOUT to user's      terminal ... }
  558.      fdrewrite(STDOUT);
  559.  
  560.      { initialize rest of files      }
  561.      FOR i := linein+1 TO MAXOPEN DO
  562.      filemode[i] := IOAVAIL;
  563.  
  564.  
  565.    END;
  566.  
  567.  
  568.   { getc (UCB) -- get one character from standard input }
  569.   FUNCTION getc (VAR c : character) : character;
  570.   VAR
  571.     ch : char;
  572.    BEGIN
  573.      IF eof
  574.       THEN
  575.       c := ENDFILE
  576.       ELSE
  577.       IF eoln
  578.        THEN
  579.         BEGIN
  580.           readln;
  581.           c := NEWLINE
  582.         END
  583.        ELSE
  584.         BEGIN
  585.           read(ch);
  586.           c := ord(ch)
  587.         END;
  588.      getc := c
  589.    END;
  590.  
  591.   { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
  592.   { getcf (UCB) -- get one character from file }
  593.   FUNCTION getcf (VAR c: character; fd : filedesc) : character;
  594.   VAR
  595.     ch : char;
  596.    BEGIN
  597.      IF (filemode[fd] <> IOREAD)
  598.       THEN
  599.        BEGIN
  600.          writeln('called getcf without file.mode=IOREAD'); stiphalt;
  601.        END;
  602.      IF (fd = STDIN)
  603.       THEN
  604.       getcf := getc(c)
  605.       ELSE
  606.       IF fdeof(fd)
  607.        THEN
  608.        c := ENDFILE
  609.        ELSE
  610.        IF fdeoln(fd)
  611.         THEN
  612.          BEGIN
  613.            fdreadln(fd);
  614.            c := NEWLINE
  615.          END
  616.         ELSE
  617.          BEGIN
  618.            fdread(fd, ch);
  619.            c := ord(ch)
  620.          END;
  621.      getcf := c
  622.    END;
  623.  
  624.   { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
  625.   { getline (UCB) -- get a line from file }
  626.   FUNCTION getline (VAR s : string; fd : filedesc;
  627.                     maxsize : integer) : boolean;
  628.   VAR
  629.     i : integer;
  630.     c : character;
  631.    BEGIN
  632.      i := 1;
  633.       REPEAT
  634.        s[i] := getcf(c, fd);
  635.        i := i + 1
  636.       UNTIL (c = ENDFILE) OR (c = NEWLINE) OR (i >= maxsize);
  637.      IF (c = ENDFILE)
  638.       THEN   { went one too far }
  639.       i := i - 1;
  640.      s[i] := ENDSTR;
  641.      getline := (c <> ENDFILE)
  642.    END;
  643.  
  644.   { putcf (UCB) -- put a single character on file fd }
  645.   PROCEDURE putcf (c : character; fd : filedesc);
  646.    BEGIN
  647.      if (fd = lineout) then
  648.          xmtchar(CHR(c))
  649.      ELSE
  650.      IF c = NEWLINE
  651.       THEN
  652.        fdwriteln(fd)
  653.       ELSE
  654.        fdwrite(fd, chr(c))
  655.    END;
  656.  
  657.   { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
  658.   { putstr (UCB) -- put out string on file }
  659.   PROCEDURE putstr (VAR s : string; f : filedesc);
  660.   VAR
  661.     i : integer;
  662.    BEGIN
  663.      i := 1;
  664.      WHILE (s[i] <> ENDSTR) DO
  665.       BEGIN
  666.         putcf(s[i], f);
  667.         i := i + 1
  668.       END
  669.    END;
  670.  
  671.   { open  -- open a file for reading or   writing         }
  672.   FUNCTION Sopen (VAR name : string; mode :   integer) : filedesc;
  673.   VAR
  674.     i :     integer;
  675.     intname : mstring;
  676.     found : boolean;
  677.    BEGIN
  678.      i := 1;
  679.      WHILE (name[i] <> ENDSTR) AND (name[i] <> NEWLINE) AND
  680.       (i <= FILENAMELENGTH)    DO
  681.        BEGIN
  682.          if name[i] >= LETA then name[i] := name[i] - 32;  { upper case }
  683.          intname[i] := chr(name[i]);
  684.          i := i + 1
  685.        END;
  686.      FOR i := i      TO FILENAMELENGTH DO
  687.      intname[i]      := ' ';              { pad name         with blanks }
  688.      { find a free slot      in openlist }
  689.      Sopen := IOERROR;
  690.      found := false;
  691.      i := 1;
  692.      WHILE (i <= MAXOPEN) AND (NOT found) DO
  693.       BEGIN
  694.         IF (filemode[i] = IOAVAIL)
  695.          THEN
  696.           BEGIN
  697.             fdbind(i,intname);
  698.             IF (BindStatus <> 0) AND (mode = IOWRITE) THEN
  699.               BEGIN
  700.                 FILECREATE(intname);
  701.                 fdbind(i,intname);
  702.               END;
  703.             IF BindStatus = 0 THEN
  704.               BEGIN
  705.                 filemode[i] :=     mode;
  706.                 IF (mode = IOREAD)
  707.                  THEN
  708.                   fdreset(i)
  709.                  ELSE
  710.                   fdrewrite(i);
  711.                 Sopen:=i;
  712.               END
  713.             ELSE Sopen := 0;
  714.             found := true
  715.           END;
  716.         i := i + 1
  717.       END
  718.    END;
  719.  
  720.   PROCEDURE Sclose (fd : filedesc);
  721.    BEGIN
  722.      IF      (fd > STDOUT) AND (fd <= MAXOPEN)
  723.       THEN
  724.        BEGIN
  725.          filemode[fd] := IOAVAIL;
  726.          fdclose(fd);
  727.        END
  728.    END;
  729.  
  730.   { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
  731.   { itoc - convert integer n to char string in s[i]... }
  732.   FUNCTION itoc (n : integer; VAR s : string; i : integer)
  733.     : integer;      { returns end of s }
  734.    BEGIN
  735.      IF (n < 0)
  736.       THEN
  737.        BEGIN
  738.          s[i] := ord('-');
  739.          itoc := itoc(-n, s, i+1)
  740.        END
  741.       ELSE
  742.        BEGIN
  743.          IF (n >= 10)
  744.           THEN
  745.           i := itoc(n DIV 10, s, i);
  746.          s[i] := n MOD 10 + ord('0');
  747.          s[i+1] := ENDSTR;
  748.          itoc := i + 1
  749.        END
  750.    END;
  751.  
  752.   { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
  753.   { length -- compute length of string }
  754.   FUNCTION length (VAR s : string) : integer;
  755.   VAR
  756.     n : integer;
  757.    BEGIN
  758.      n := 1;
  759.      WHILE (s[n] <> ENDSTR) DO
  760.      n := n + 1;
  761.      length := n - 1
  762.    END;
  763.  
  764.   { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
  765.   { scopy -- copy string at src[i] to dest[j] }
  766.   PROCEDURE scopy (VAR src : string; i : integer;
  767.                    VAR dest : string; j : integer);
  768.    BEGIN
  769.      WHILE (src[i] <> ENDSTR) DO
  770.       BEGIN
  771.         dest[j] := src[i];
  772.         i := i + 1;
  773.         j := j + 1
  774.       END;
  775.      dest[j] := ENDSTR
  776.    END;
  777.  
  778.   { copyright (c) 1981 university of toronto computing services }
  779.   { isupper -- true if c is upper case letter }
  780.   { kludge version for omsi pascal }
  781.   FUNCTION isupper (c : character) : boolean;
  782.    BEGIN
  783.      isupper := (c >= ord('A')) AND (c <= ord('Z'))
  784.    END;
  785.  
  786.   { Copyright (C) 1981 by Bell Laboratories, Inc., and Whitesmiths Ltd. }
  787.   { index -- find position of character c in string s }
  788.   FUNCTION index (VAR s : string; c : character) : integer;
  789.   VAR
  790.     i : integer;
  791.    BEGIN
  792.      i := 1;
  793.      WHILE (s[i] <> c) AND (s[i] <> ENDSTR) DO
  794.      i := i + 1;
  795.      IF (s[i] = ENDSTR)
  796.       THEN
  797.       index := 0
  798.       ELSE
  799.       index := i
  800.    END;
  801.  
  802.   FUNCTION getarg(n:integer;VAR   s:string;maxsize:integer): BOOLEAN;
  803.     (* return the nth argument *)
  804.    BEGIN
  805.      IF      ((n<1) OR (cmdargs<n))
  806.       THEN
  807.       getarg :=       false
  808.       ELSE
  809.        BEGIN
  810.          scopy(cmdlin,cmdidx[n],s,1);
  811.          getarg  := true
  812.        END;
  813.    END;
  814.  
  815.   FUNCTION nargs: integer; (* returns number arguments *)
  816.    BEGIN
  817.      nargs := cmdargs
  818.    END;
  819.  
  820.   PROCEDURE CtoS((* Using *) x:cstring; (* Returning *) VAR s:string);
  821.     (* convert constant to STIP string *)
  822.   VAR
  823.     i : integer;
  824.    BEGIN
  825.      FOR i:=1 TO CONLENGTH DO
  826.      s[i] := ord(x[i]);
  827.      s[CONLENGTH+1] := ENDSTR;
  828.    END;
  829.  
  830.   PROCEDURE PutCon((* Using *) x:cstring;
  831.                    (* Using *)      fd:filedesc);
  832.     (* output literal preceeded by NEWLINE *)
  833.   VAR
  834.     i: integer;
  835.     s: string;
  836.    BEGIN
  837.      s[1] := NEWLINE;
  838.      s[2] := ENDSTR;
  839.      putstr(s,fd);
  840.      CtoS(x,s);
  841.      putstr(s,fd);
  842.    END;
  843.  
  844.   FUNCTION Exists((* Using *) name:string): (* Returning *) boolean;
  845.     (* returns true if file exists *)
  846.   VAR
  847.     i :     integer;
  848.     intname : mstring;
  849.    BEGIN
  850.      i := 1;
  851.      WHILE (name[i] <> ENDSTR) AND (name[i] <> NEWLINE) AND
  852.       (i <= FILENAMELENGTH) DO
  853.        BEGIN
  854.          intname[i] := chr(name[i]);
  855.          i := i + 1
  856.        END;
  857.      FOR i := i      TO FILENAMELENGTH DO
  858.      intname[i]      := ' ';              { pad name         with blanks }
  859.      bind(filen,intname,BindStatus);
  860.      Exists := (BindStatus = 0);
  861.    END;
  862.  
  863.   PROCEDURE PutNum((* Using *) n:integer;
  864.                    (* Using *) fd:filedesc);
  865.     (* Ouput number *)
  866.   VAR
  867.     s: string;
  868.     dummy: integer;
  869.    BEGIN
  870.      s[1] := BLANK;
  871.      dummy := itoc(n,s,2);
  872.      putstr(s,fd);
  873.    END;
  874.  
  875.   PROCEDURE initcmd;  (*  read command line *)
  876.   VAR
  877.     idx     : 1.. MAXSTR;
  878.     i:integer;
  879.     prom:cstring;
  880.     dummy : boolean;
  881.    BEGIN
  882.      prom := 'KERMIT-H>           ';        (*         Prompt  *)
  883.      PutCon(prom,STDOUT);
  884.      dummy :=  getline(cmdlin,STDIN,MAXSTR);
  885.      IF (cmdlin[1] <> ENDSTR)
  886.       THEN
  887.       FOR i:= 1       TO length(cmdlin) DO begin
  888.       IF isupper(cmdlin[i])
  889.        THEN cmdlin[i]:=cmdlin[i] + 32;
  890.        IF (cmdlin[i]=newline) then CMDLIN[I]:=ENDSTR;
  891.        end;
  892.  
  893.      cmdargs :=      0;    (*  initialize *)
  894.  
  895.      idx := 1;
  896.  
  897.      WHILE (cmdlin[idx]<>endstr)
  898.      DO
  899.       BEGIN
  900.         WHILE (cmdlin[idx]=blank) DO
  901.         idx := idx+1;
  902.         IF (cmdlin[idx]<>endstr)
  903.          THEN
  904.           BEGIN
  905.             cmdargs := cmdargs+1;
  906.             cmdidx[cmdargs] := idx;
  907.             WHILE  (cmdlin[idx]<>endstr)
  908.                    AND (cmdlin[idx]<>BLANK) DO
  909.             idx     := idx+1;
  910.             cmdlin[idx]     := ENDSTR;
  911.             idx     := idx+1;
  912.           END;
  913.       END;
  914.    END;
  915.  
  916.   PROCEDURE AddTo((* Updating *) VAR sum : Stats;
  917.                   (* Using *)  inc:integer);
  918.  
  919.     (* This is used to avoid integer overflows
  920.      without using 'reals' *)
  921.  
  922.    BEGIN
  923.      sum[Low] := sum[Low] + inc;
  924.      IF (sum[Low] >= 1000)
  925.       THEN
  926.        BEGIN
  927.          sum[High] := sum[High] +1;
  928.          sum[Low ] := sum[Low] - 1000;
  929.        END;
  930.    END;
  931.  
  932.   PROCEDURE OverHd((* Using *)  p,f: Stats;
  933.                    (* Returning *) VAR o:integer);
  934.  
  935.     (* Calculate OverHead as % *)
  936.     (* 0verHead := (p-f)*100/f *)
  937.  
  938.    BEGIN
  939.      o:= 0;
  940.    END;
  941.  
  942.   PROCEDURE CalRat((* Using *) f: Stats;
  943.                    (* Using *) t:integer;
  944.                    (* Returning *) VAR r:integer);
  945.  
  946.     (* Calculate Effective Baud Rate *)
  947.     (* Rate = f*10/t *)
  948.  
  949.    BEGIN
  950.      r := 0;
  951.    END;
  952.  
  953.   FUNCTION UnChar((* Using *) c:character): (* Returning *) character;
  954.     (* reverse of makechar *)
  955.    BEGIN
  956.      UnChar := c-BLANK
  957.    END;
  958.  
  959.   PROCEDURE PutOut( p : Ppack); (* Output Packet *)
  960.   VAR
  961.     i : integer;
  962.    BEGIN
  963.      IF (Pad >0)
  964.       THEN
  965.       FOR i := 1 TO Pad DO
  966.       putcf(PadChar,LineOut);
  967.      WITH Buf[p] DO
  968.       BEGIN
  969.         putcf(mark,LineOut);
  970.         putcf(count,LineOut);
  971.         PutCon ( 'Sending Packet...   ',STDout);
  972.         PutNum(Unchar(seq),STDout);
  973.         putcf(seq,LineOut);
  974.         putcf(ptype,LineOut);
  975.         putstr(data,LineOut);
  976.       END;
  977.    END;
  978.  
  979.   PROCEDURE StartTimer;
  980.    BEGIN
  981.      TimeLeft := TheirTimeOut;
  982.    END;
  983.  
  984.   PROCEDURE StopTimer;
  985.    BEGIN
  986.      TimeLeft := MaxInt;
  987.    END;
  988.  
  989.   FUNCTION MakeChar((* Using *) c:character): (* Returning *) character;
  990.     (* convert integer to printable *)
  991.    BEGIN
  992.      MakeChar := c+BLANK;
  993.    END;
  994.  
  995.   FUNCTION IsControl((* Using *) c:character): (* Returning *) boolean;
  996.     (* true if control *)
  997.    BEGIN
  998.      IsControl := (c=DEL ) OR (c < BLANK );
  999.    END;
  1000.  
  1001.   FUNCTION IsPrintable((* Using *) c:character): (* Returning *) boolean;
  1002.     (* opposite of iscontrol *)
  1003.    BEGIN
  1004.      IsPrintable := NOT IsControl(c);
  1005.    END;
  1006.  
  1007.   FUNCTION Ctl((* Using *) c:character): (* Returning *) character;
  1008.     (* c XOR 100 *)
  1009.    BEGIN
  1010.      IF IsControl(c)
  1011.       THEN
  1012.       c := c+64
  1013.       ELSE
  1014.       c := c-64;
  1015.      Ctl := c;
  1016.    END;
  1017.  
  1018.   FUNCTION IsValidPType((* Using *) c:character): (* Returning *) boolean;
  1019.     (* true if valid packet type *)
  1020.    BEGIN
  1021.      IsValidPType := (c =TYPEB) OR (c=TYPED) OR (c=TYPEE) OR (c=TYPEF)
  1022.      OR (c=TYPEN) OR (c=TYPES) OR (c=TYPET) OR (c=TYPEY) OR (c=TYPEZ)
  1023.    END;
  1024.  
  1025.   FUNCTION CheckFunction((* Using *) c:integer): (* Returning *) character;
  1026.     (* calculate checksum *)
  1027.   VAR
  1028.     x: integer;
  1029.    BEGIN
  1030.      (*   CheckFunction := (c + ( c AND 300 ) /100 ) AND 77; *)
  1031.      x := (c MOD 256 ) DIV 64;
  1032.      x := x+c;
  1033.      CheckFunction := x MOD 64;
  1034.    END;
  1035.  
  1036.   PROCEDURE EnCodeParm((* Updating *) VAR data:string);  (* encode parameters *)
  1037.   VAR
  1038.     i: integer;
  1039.    BEGIN
  1040.      FOR i:=1 TO NUMPARAM DO
  1041.      data[i] := BLANK;
  1042.      data[NUMPARAM+1] := ENDSTR;
  1043.      data[1] := MakeChar(SizeRecv);     (* my biggest packet *)
  1044.      data[2] := MakeChar(MyTimeOut);         (* when I want timeout*)
  1045.      data[3] := MakeChar(MyPad);             (* how much padding *)
  1046.      data[4] := Ctl(MyPadChar);              (* my padding character *)
  1047.      data[5] := MakeChar(myEOL);             (* my EOL *)
  1048.      data[6] := MyQuote;                     (* my quote char *)
  1049.    END;
  1050.  
  1051.   PROCEDURE DeCodeParm((* Using *) VAR data:string); (* decode parameters *)
  1052.    BEGIN
  1053.      SizeSend := UnChar(data[1]);
  1054.      TheirTimeOut := UnChar(data[2]);   (* when I should time out *)
  1055.      Pad := UnChar(data[3]);            (* padding characters to send  *)
  1056.      PadChar := Ctl(data[4]);           (* padding character *)
  1057.      SendEOL := UnChar(data[5]);        (* EOL to send *)
  1058.      SendQuote := data[6];              (* quote to send *)
  1059.    END;
  1060.  
  1061.   PROCEDURE ReadParm ((* Updating *) VAR Parms:string);
  1062.   VAR
  1063.     dummy : boolean;
  1064.     fd : filedesc;
  1065.    BEGIN;
  1066.  
  1067.      (* read parameters *)
  1068.      Parms[1]:=ENDSTR;
  1069.      IF Exists(ParmFile)
  1070.       THEN
  1071.        BEGIN
  1072.          fd := Sopen(ParmFile,IOREAD);
  1073.          dummy := getline(Parms,fd,MAXSTR);
  1074.          Sclose(fd);
  1075.        END;
  1076.    END;
  1077.  
  1078.   PROCEDURE GetParm; (* get parameters from file *)
  1079.   VAR
  1080.     data:string;
  1081.    BEGIN;
  1082.      ReadParm(data);
  1083.      IF (length(data) > 0)
  1084.       THEN      (* get parameters *)
  1085.        BEGIN
  1086.          SizeRecv := UnChar(data[1]);
  1087.          MyTimeOut := UnChar(data[2]);   (* when I should time out *)
  1088.          MyPad := UnChar(data[3]);     (* padding characters to send  *)
  1089.          MyPadChar := Ctl(data[4]);       (* padding character *)
  1090.          MyEOL := UnChar(data[5]);        (* EOL to send *)
  1091.          MyQuote := data[6];              (* quote to send *)
  1092.        END;
  1093.    END;
  1094.  
  1095.   PROCEDURE SYSarguments;
  1096.     (* process special arguments for SYSTEM *)
  1097.    BEGIN
  1098.      (* nothing *)
  1099.    END;
  1100.  
  1101.   PROCEDURE StartRun; (* initialization as necessary *)
  1102.    BEGIN
  1103.      RunTime := 0;
  1104.    END;
  1105.  
  1106.   PROCEDURE Usage;  (* Print writeln & exit *)
  1107.    BEGIN
  1108.      writeln;
  1109.      writeln(
  1110.        'usage: KERMIT-H> [Help] [Connect] [Send/Receive/Print<filenames>]');
  1111.    END;
  1112.  
  1113.   PROCEDURE SetParameters;
  1114.     (* set new Parameter File Name *)
  1115.    BEGIN
  1116.      IF (length(aline) > 2)
  1117.       THEN
  1118.        BEGIN
  1119.          scopy(aline,3,ParmFile,1);
  1120.          GetParm; (* read new parameters *)
  1121.        END;
  1122.    END;
  1123.  
  1124.   PROCEDURE KermitInit;  (* initialize various parameters  & defaults *)
  1125.    BEGIN
  1126.      n := 0;
  1127.  
  1128.      NumSendPacks := 0;
  1129.      NumRecvPacks := 0;
  1130.      NumACK := 0;
  1131.      NumNAK := 0;
  1132.      NumACKrecv := 0;
  1133.      NumNAKrecv := 0;
  1134.      NumBADrecv := 0;
  1135.  
  1136.      ChInFile[Low] := 0;
  1137.      ChInFile[High] := 0;
  1138.      ChInPack := ChInFile;
  1139.  
  1140.      OneWayOnly := false;
  1141.      Verbosity := false;       (* default to false *)
  1142.      Trace := false;           (* default to no trace *)
  1143.      Debug := false;
  1144.      RunType := invalid;
  1145.      DiskFile := IOERROR;      (* to indicate not open yet *)
  1146.  
  1147.      ThisPacket := 1;
  1148.      LastPacket := 2;
  1149.      CurrentPacket := 3;
  1150.      NextPacket := 4;
  1151.      InputPacket := 5;
  1152.  
  1153.      WITH TOPacket DO
  1154.       BEGIN
  1155.         count := 3;
  1156.         seq := 0;
  1157.         ptype := TYPEN;
  1158.         data[1] := ENDSTR;
  1159.       END;
  1160.  
  1161.      NextArg := 1;          (* get first argument *)
  1162.      IF (NextArg<=nargs)
  1163.       THEN
  1164.       IF  NOT getarg(NextArg,aline,MAXSTR)
  1165.        THEN
  1166.        Usage;
  1167.  
  1168.      FROMCONSOLE:=NOTHING;
  1169.  
  1170.    END;
  1171.  
  1172.   PROCEDURE FinishUp; (* do any End of Program clean up *)
  1173.   VAR
  1174.     overhead ,effrate : integer;
  1175.    BEGIN
  1176.      Sclose(DiskFile);
  1177.      (* print info on number of packets etc *)
  1178.      IF ((RunType <> Invalid) AND Local )
  1179.       THEN
  1180.        BEGIN
  1181.          PutCon('Packets sent:       ',STDOUT);
  1182.          PutNum(NumSendPacks,STDOUT);
  1183.          PutCon('Packets received    ',STDOUT);
  1184.          PutNum(NumRecvPacks,STDOUT);
  1185.          (* Calculate overhead *)
  1186.          OverHd(ChInPack,ChInFile,overhead);
  1187.          IF (Overhead <>0)
  1188.           THEN
  1189.            BEGIN
  1190.              PutCon('Overhead (%):       ' ,STDOUT);
  1191.              PutNum(overhead,STDOUT);
  1192.            END;
  1193.          IF (RunTime <> 0)
  1194.           THEN
  1195.            BEGIN (* calculate effective rate *)
  1196.              CalRat(ChInFile,RunTime,effrate);
  1197.              PutCon('Effective Rate:     ',STDOUT);
  1198.              PutNum(effrate,STDOUT);
  1199.            END;
  1200.          IF (RunType = Transmit)
  1201.           THEN
  1202.            BEGIN
  1203.              PutCon('Number of ACK:      ',STDOUT);
  1204.              PutNum(NumACKrecv,STDOUT);
  1205.              PutCon('Number of NAK:      ',STDOUT);
  1206.              PutNum(NumNAKrecv,STDOUT);
  1207.              PutCon('Number of BAD:      ',STDOUT);
  1208.              PutNum(NumBADrecv,STDOUT);
  1209.            END
  1210.           ELSE
  1211.            BEGIN   (* for Receive *)
  1212.              PutCon('Number of ACK:      ',STDOUT);
  1213.              PutNum(NumACK,STDOUT);
  1214.              PutCon('Number of NAK:      ',STDOUT);
  1215.              PutNum(NumNAK,STDOUT);
  1216.            END;
  1217.          putcf(NEWLINE,STDOUT);
  1218.        END;
  1219.      State := Abort;
  1220.      Local := false;
  1221.    END;
  1222.  
  1223.   PROCEDURE DebugPacket((* Using *)    mes : cstring;
  1224.                         (* Using *)  VAR p : Ppack);
  1225.     (* Print Debugging Info *)
  1226.    BEGIN
  1227.      PutCon(mes,STDOUT);
  1228.      WITH Buf[p] DO
  1229.       BEGIN
  1230.         PutNum(Unchar(count),STDOUT);
  1231.         PutNum(Unchar(seq),STDOUT);
  1232.         putcf(BLANK,STDOUT);
  1233.         putcf(ptype,STDOUT);
  1234.         putcf(NEWLINE,STDOUT);
  1235.         putstr(data,STDOUT);
  1236.         putcf(NEWLINE,STDOUT);
  1237.       END;
  1238.    END;
  1239.  
  1240.   PROCEDURE ReSendPacket;
  1241.     (* re -sends previous packet *)
  1242.    BEGIN
  1243.      NumSendPacks := NumSendPacks+1;
  1244.      AddTo(ChInPack,Pad + UnChar(Buf[LastPacket].count) + 3);
  1245.      IF Debug
  1246.       THEN DebugPacket('Re-Sending ...      ',LastPacket);
  1247.      PutOut(LastPacket);
  1248.    END;
  1249.  
  1250.   PROCEDURE SendPacket;
  1251.  
  1252.     (* expects count as length of data portion *)
  1253.     (* and seq as number of packet *)
  1254.     (* builds & sends packet *)
  1255.   VAR
  1256.     i,len,chksum : integer;
  1257.     temp : Ppack;
  1258.    BEGIN
  1259.      IF (NumTry <> 1) AND (RunType = Transmit )
  1260.       THEN
  1261.       ReSendPacket
  1262.       ELSE
  1263.        BEGIN
  1264.          WITH Buf[ThisPacket] DO
  1265.           BEGIN
  1266.             mark :=SOH;               (* mark *)
  1267.             len := count;             (* save length *)
  1268.             count := MakeChar(len+3); (* count = 3+length of data *)
  1269.             seq := MakeChar(seq);     (* seq number *)
  1270.             chksum := count + seq + ptype;
  1271.             IF ( len > 0)
  1272.              THEN      (* is there data ? *)
  1273.              FOR i:= 1 TO len DO
  1274.              chksum := chksum + data[i];       (* loop for data *)
  1275.             chksum := CheckFunction(chksum);  (* calculate  checksum *)
  1276.             data[len+1] := MakeChar(chksum);  (* make printable & output *)
  1277.             data[len+2] := SendEOL;                    (* EOL *)
  1278.             data[len+3] := ENDSTR;
  1279.           END;
  1280.  
  1281.          NumSendPacks := NumSendPacks+1;
  1282.          IF Debug
  1283.           THEN DebugPacket('Sending ...         ',ThisPacket);
  1284.          PutOut(ThisPacket);
  1285.  
  1286.          IF RunType = Transmit
  1287.           THEN
  1288.            BEGIN
  1289.              AddTo(ChInPack,Pad + len + 6);
  1290.              temp := LastPacket;
  1291.              LastPacket := ThisPacket;
  1292.              ThisPacket := temp;
  1293.            END;
  1294.        END
  1295.  
  1296.    END;
  1297.  
  1298.   PROCEDURE SendACK((* Using *) n:integer); (* send ACK packet *)
  1299.    BEGIN
  1300.      WITH Buf[ThisPacket] DO
  1301.       BEGIN
  1302.         count := 0;
  1303.         seq := n;
  1304.         ptype := TYPEY;
  1305.       END;
  1306.      SendPacket;
  1307.      NumACK := NumACK+1;
  1308.    END;
  1309.  
  1310.   PROCEDURE SendNAK((* Using *) n:integer); (* send NAK packet *)
  1311.    BEGIN
  1312.      WITH Buf[ThisPacket] DO
  1313.       BEGIN
  1314.         count := 0;
  1315.         seq := n;
  1316.         ptype := TYPEN;
  1317.       END;
  1318.      SendPacket;
  1319.      NumNAK := NumNAK+1;
  1320.    END;
  1321.  
  1322.   PROCEDURE ErrorPack((* Using *) c:cstring);
  1323.     (* output Error packet if necessary -- then exit *)
  1324.    BEGIN
  1325.      IF (TTYmode = Cooked)
  1326.       THEN
  1327.       PutCon(c,STDOUT)
  1328.       ELSE
  1329.        BEGIN
  1330.          WITH Buf[ThisPacket] DO
  1331.           BEGIN
  1332.             seq := n;
  1333.             ptype := TYPEE;
  1334.             CtoS(c,data);
  1335.             count := length(data);
  1336.           END;
  1337.          SendPacket;
  1338.        END;
  1339.      FinishUp;
  1340.      State := Abort;
  1341.    END;
  1342.  
  1343.   PROCEDURE Verbose((* Using *) c:cstring);
  1344.     (* Print writeln if verbosity *)
  1345.    BEGIN
  1346.      IF Verbosity
  1347.       THEN
  1348.       PutCon(c,STDOUT);
  1349.    END;
  1350.  
  1351.   PROCEDURE PutErr((* Using *) c:cstring);
  1352.     (* Print error_messages *)
  1353.    BEGIN
  1354.      PutCon(c,STDOUT);
  1355.      IF (TtyMode = Raw) AND (NumKeptErrors < MAXERRORS)
  1356.       THEN
  1357.        BEGIN
  1358.          NumKeptErrors := NumKeptErrors + 1;
  1359.          KeptErrors[NumKeptErrors] := c;
  1360.        END;
  1361.    END;
  1362.  
  1363.   PROCEDURE Field1; (* Count *)
  1364.   VAR
  1365.     test: boolean;
  1366.    BEGIN
  1367.      WITH Buf[NextPacket] DO
  1368.       BEGIN
  1369.         WITH PackControl DO
  1370.          BEGIN
  1371.            Buf[InputPacket].count := t;
  1372.            count := UnChar(t);
  1373.            test := (count >= 3) OR (count <= SizeRecv-2);
  1374.            IF NOT test
  1375.             THEN
  1376.             Verbose('Bad count           ');
  1377.            good := good AND test;
  1378.          END;
  1379.       END;
  1380.    END;
  1381.  
  1382.   PROCEDURE Field2; (* Packet Number *)
  1383.   VAR
  1384.     test : boolean;
  1385.    BEGIN
  1386.      WITH Buf[NextPacket] DO
  1387.       BEGIN
  1388.         WITH PackControl DO
  1389.          BEGIN
  1390.            Buf[InputPacket].seq := t;
  1391.            seq := UnChar(t);
  1392.            test := (seq >= 0) OR (seq <= 63);
  1393.            IF NOT test
  1394.             THEN
  1395.             Verbose('Bad seq number      ');
  1396.            good := test AND good;
  1397.          END;
  1398.       END;
  1399.    END;
  1400.  
  1401.   PROCEDURE Field3; (* Packet Type *)
  1402.   VAR
  1403.     test : boolean;
  1404.    BEGIN
  1405.      WITH Buf[NextPacket] DO
  1406.       BEGIN
  1407.         WITH PackControl DO
  1408.          BEGIN
  1409.            ptype := t;
  1410.            Buf[InputPacket].ptype := t;
  1411.            test := IsValidPType(ptype);
  1412.            IF NOT test
  1413.             THEN
  1414.             Verbose('Bad Packet Type     ');
  1415.            good := test AND good;
  1416.          END;
  1417.       END;
  1418.    END;
  1419.  
  1420.   PROCEDURE Field4; (* Data *)
  1421.    BEGIN
  1422.      WITH PackControl DO
  1423.       BEGIN
  1424.         PacketPtr := PacketPtr+1;
  1425.         Buf[InputPacket].data[PacketPtr] := t;
  1426.         WITH Buf[NextPacket] DO
  1427.          BEGIN
  1428.            IF (t=MyQuote) AND (ptype <> TYPEY) AND (ptype <> TYPES)
  1429.             THEN    (* character is quote *)
  1430.              BEGIN
  1431.                IF control
  1432.                 THEN        (* quote ,quote  *)
  1433.                  BEGIN
  1434.                    data[i] := MyQuote;
  1435.                    i := i+1;
  1436.                    control := false;
  1437.                  END
  1438.                 ELSE      (* set control on *)
  1439.                 control := true
  1440.              END
  1441.             ELSE                 (* not quote *)
  1442.             IF control
  1443.              THEN      (* convert to control *)
  1444.               BEGIN
  1445.                 data[i] := ctl(t);
  1446.                 i := i+1;
  1447.                 control := false
  1448.               END
  1449.              ELSE      (* regular data *)
  1450.               BEGIN
  1451.                 data[i] := t;
  1452.                 i := i+1;
  1453.               END;
  1454.          END;
  1455.       END;
  1456.    END;
  1457.  
  1458.   PROCEDURE Field5; (* Check Sum *)
  1459.   VAR
  1460.     test : boolean;
  1461.    BEGIN
  1462.      WITH PackControl DO
  1463.       BEGIN
  1464.         PacketPtr := PacketPtr +1;
  1465.         Buf[InputPacket].data[PacketPtr] := t;
  1466.         Buf[InputPacket].data[PacketPtr + 1] := ENDSTR;
  1467.         check := CheckFunction(check);
  1468.         check := MakeChar(check);
  1469.         test := (t=check);
  1470.         IF NOT test
  1471.          THEN
  1472.          Verbose('Bad CheckSum        ');
  1473.         good := test AND good;
  1474.         Buf[NextPacket].data[i] := ENDSTR;
  1475.         finished := true;  (* set finished *)
  1476.       END;
  1477.    END;
  1478.  
  1479.   PROCEDURE BuildPacket;
  1480.     (* receive packet & validate checksum *)
  1481.   VAR
  1482.     temp : Ppack;
  1483.    BEGIN
  1484.      WITH PackControl DO
  1485.       BEGIN
  1486.         WITH Buf[NextPacket] DO
  1487.          BEGIN
  1488.            IF (t<>ENDSTR)
  1489.             THEN
  1490.             IF restart
  1491.              THEN
  1492.               BEGIN
  1493.                 (* read until get SOH marker *)
  1494.                 IF  (t = SOH)
  1495.                  THEN
  1496.                   BEGIN
  1497.                     finished := false;    (* set varibles *)
  1498.                     control := false;
  1499.                     good := true;
  1500.                     seq := -1;        (* set return values to bad packet *)
  1501.                     ptype := QUESTION;
  1502.                     data[1] := ENDSTR;
  1503.                     data[MAXSTR] := ENDSTR;
  1504.                     restart := false;
  1505.                     fld := 0;
  1506.                     i := 1;
  1507.                     PacketPtr := 0;
  1508.                     check := 0;
  1509.                   END;
  1510.               END
  1511.              ELSE                          (* have started packet *)
  1512.               BEGIN
  1513.                 IF (t=SOH)          (* check for restart or EOL *)
  1514.                  THEN
  1515.                  restart := true
  1516.                  ELSE
  1517.                  IF (t=myEOL)
  1518.                   THEN
  1519.                    BEGIN
  1520.                      finished := true;
  1521.                      good := false;
  1522.                    END
  1523.                   ELSE
  1524.                    BEGIN
  1525.                      CASE fld OF
  1526.                        (* increment field number *)
  1527.                        0:   fld := 1;
  1528.                        1:   fld := 2;
  1529.                        2:   fld := 3;
  1530.                        3:
  1531.                        IF (count=3)  (* no data *)
  1532.                         THEN
  1533.                         fld := 5
  1534.                         ELSE
  1535.                         fld := 4;
  1536.                        4:
  1537.                        IF (PacketPtr>=count-3) (* end of data *)
  1538.                         THEN
  1539.                         fld := 5;
  1540.                       END (* case *);
  1541.                      IF (fld<>5)
  1542.                       THEN
  1543.                       check := check+t; (* add into checksum *)
  1544.  
  1545.                      CASE fld OF
  1546.                        1:      Field1;
  1547.                        2:      Field2;
  1548.                        3:      Field3;
  1549.                        4:      Field4;
  1550.                        5:      Field5;
  1551.                       END;
  1552.                      (* case *)
  1553.                    END;
  1554.               END;
  1555.  
  1556.            IF finished
  1557.             THEN
  1558.              BEGIN
  1559.                IF (ptype=TYPEE)  AND good
  1560.                 THEN   (* error_packets *)
  1561.                  BEGIN
  1562.                    putstr(data,STDOUT);
  1563.                    FinishUp;
  1564.                    SendACK(n);          (* send ACK *)
  1565.                  END;
  1566.                NumRecvPacks := NumRecvPacks+1;
  1567.                IF Debug
  1568.                 THEN
  1569.                  BEGIN
  1570.                    DebugPacket('Received ...        ',InputPacket);
  1571.                    IF good
  1572.                     THEN
  1573.                     PutCon('Is Good             ',STDOUT);
  1574.                  END;
  1575.  
  1576.                temp := CurrentPacket;
  1577.                CurrentPacket := NextPacket;
  1578.                NextPacket := temp;
  1579.              END;
  1580.          END;
  1581.       END;
  1582.    END;
  1583.  
  1584.   FUNCTION ReceivePacket: boolean;
  1585.    BEGIN
  1586.      WITH PackControl DO
  1587.       BEGIN
  1588.         StartTimer;
  1589.         IF (Runtype = Receive) AND (State = Init) THEN
  1590.          TimeLeft := 10 * TimeLeft;    { Long wait for first message }
  1591.         finished := false;
  1592.         restart := true;
  1593.         good := false;
  1594.         FromConsole := nothing;  (* No Interupt *)
  1595.          REPEAT
  1596.           t := GetIn(TimeLeft,FromConsole);
  1597.           IF Local   (* check Interupt *)
  1598.            THEN BEGIN
  1599.            CASE FromConsole OF
  1600.              abortnow:
  1601.               BEGIN
  1602.                 FinishUp;
  1603.                 STIPHALT;
  1604.               END;
  1605.              nothing:        (* nothing *);
  1606.              CRin:
  1607.               BEGIN
  1608.                 t := MyEOL;
  1609.                 FromConsole := nothing;
  1610.               END;
  1611.             END;
  1612.            end;
  1613.            (* case *)
  1614.           BuildPacket;
  1615.          UNTIL finished  OR (TimeLeft = 0);
  1616.         IF (TimeLeft = 0)
  1617.          THEN
  1618.           BEGIN
  1619.             Buf[CurrentPacket] := TOPacket;
  1620.             restart := true;
  1621.             IF NOT ((RunType=Transmit) AND (State=Init))
  1622.              THEN
  1623.               BEGIN
  1624.                 PutCon('Timed Out           ',STDOUT);
  1625.               END;
  1626.           END;
  1627.         StopTimer;
  1628.         ReceivePacket := good;
  1629.       END;
  1630.    END;
  1631.  
  1632.   FUNCTION ReceiveACK : (* Returning *) boolean;
  1633.     (* receive ACK with correct number *)
  1634.   VAR
  1635.     Ok: boolean;
  1636.    BEGIN
  1637.      IF (NOT OneWayOnly )
  1638.       THEN
  1639.       Ok := ReceivePacket;
  1640.      WITH Buf[CurrentPacket] DO
  1641.       BEGIN
  1642.         IF (ptype=TYPEY)
  1643.          THEN
  1644.          NumACKrecv := NumACKrecv+1
  1645.          ELSE
  1646.          IF (ptype=TYPEN)
  1647.           THEN
  1648.           NumNAKrecv := NumNAKrecv+1
  1649.           ELSE
  1650.           IF NOT OneWayOnly
  1651.            THEN
  1652.            NumBadrecv := NumBadrecv +1;
  1653.            (* got right one ? *)
  1654.         ReceiveACK := ( Ok AND (ptype=TYPEY) AND (n=seq))
  1655.         OR  ( OneWayOnly)
  1656.       END;
  1657.    END;
  1658.  
  1659.   PROCEDURE GetData((* Returning *)   VAR newstate:KermitStates);
  1660.     (* get data from file into ThisPacket *)
  1661.   VAR
  1662.     (* and return next state - data &  EOF *)
  1663.     x,c : character;
  1664.     i: integer;
  1665.    BEGIN
  1666.      IF (NumTry=1)
  1667.       THEN
  1668.        BEGIN
  1669.          i := 1;
  1670.          x := ENDSTR;
  1671.          WITH Buf[ThisPacket] DO
  1672.           BEGIN
  1673.             WHILE (i< SizeSend - 8 ) AND (x <> ENDFILE)
  1674.             (* leave room for quote  & NEWLINE *)
  1675.             DO
  1676.              BEGIN
  1677.                x := getcf(c,DiskFile);
  1678.                IF (x<>ENDFILE)
  1679.                 THEN
  1680.                 IF (IsControl(x)) OR (x=SendQuote)
  1681.                  THEN
  1682.                   BEGIN           (* control char -- quote *)
  1683.                     IF (x=NEWLINE)
  1684.                      THEN      (* use proper EOL *)
  1685.                      CASE EOLforFile OF
  1686.                        LineFeed:   (* ok as is *);
  1687.                        CrLf:
  1688.                         BEGIN
  1689.                           data[i] := SendQuote;
  1690.                           i := i+1;
  1691.                           data[i] := Ctl(CR);
  1692.                           i := i+1;
  1693.                           (* LF will sent
  1694.                            below *)
  1695.                         END;
  1696.                        JustCR:     x := CR;
  1697.                       END (* case *);
  1698.                     data[i] := SendQuote;
  1699.                     i := i+1;
  1700.                     IF (x<>SendQuote)
  1701.                      THEN
  1702.                      data[i] := Ctl(x)
  1703.                      ELSE
  1704.                      data[i] := SendQuote;
  1705.                   END
  1706.                  ELSE               (* regular char *)
  1707.                  data[i] := x;
  1708.  
  1709.                IF (x<>ENDFILE)
  1710.                 THEN
  1711.                  BEGIN
  1712.                    i := i+1;    (* increase count for next char *)
  1713.                    AddTo(ChInFile,1);
  1714.                  END;
  1715.              END;
  1716.  
  1717.             data[i] := ENDSTR;   (* to terminate string *)
  1718.  
  1719.             count := i -1;       (* length *)
  1720.             seq := n;
  1721.             ptype := TYPED;
  1722.  
  1723.             IF (x=ENDFILE)
  1724.              THEN
  1725.               BEGIN
  1726.                 newstate := EOFile;
  1727.                 Sclose(DiskFile);
  1728.                 DiskFile := ioerror;
  1729.               END
  1730.              ELSE
  1731.              newstate := FileData;
  1732.             SaveState := newstate;        (* save state *)
  1733.           END
  1734.        END
  1735.       ELSE
  1736.       newstate := SaveState;        (* get old state *)
  1737.    END;
  1738.  
  1739.   FUNCTION GetNextFile: (* Returning *) boolean;
  1740.     (* get next file to send in ThisPacket *)
  1741.     (* returns true if no more *)
  1742.   VAR
  1743.     result: boolean;
  1744.    BEGIN
  1745.      result := true;
  1746.      IF (NumTry=1)
  1747.       THEN
  1748.       WITH Buf[ThisPacket] DO
  1749.        BEGIN
  1750.           REPEAT
  1751.            IF getarg(NextArg,data,MAXSTR)
  1752.             THEN
  1753.              BEGIN            (* open file  *)
  1754.                IF Exists(data)
  1755.                 THEN
  1756.                  BEGIN
  1757.                    DiskFile := Sopen(data,IOREAD);
  1758.                    count := length(data);
  1759.                    AddTo(ChInFile , count);
  1760.                    seq := n;
  1761.                    ptype := TYPEF;
  1762.                    PutCon(' SENDING...         ',STDOUT);
  1763.                    putstr(data,stdout);
  1764.                    IF DiskFile <= IOERROR
  1765.                     THEN
  1766.                     ErrorPack('Cannot open file    ');
  1767.                    result := false;
  1768.                    FIXNAME(data);
  1769.                  END;
  1770.              END;
  1771.            NextArg := NextArg+1;
  1772.           UNTIL ( NextArg > nargs ) OR ( NOT result )
  1773.        END
  1774.       ELSE
  1775.       result := false; (* for saved packet *)
  1776.      GetNextFile := result;
  1777.    END;
  1778.  
  1779.   PROCEDURE SendFile; (* send file name packet *)
  1780.    BEGIN
  1781.      Verbose( 'Sending ....        ');
  1782.      IF NumTry > MaxTry
  1783.       THEN
  1784.        BEGIN
  1785.          PutErr ('Send file - Too Many');
  1786.          State := Abort;      (* too many tries, abort *)
  1787.        END
  1788.       ELSE
  1789.        BEGIN
  1790.          NumTry := NumTry+1;
  1791.          IF GetNextFile
  1792.           THEN
  1793.            BEGIN
  1794.              State := Break;
  1795.              NumTry := 0;
  1796.            END
  1797.           ELSE
  1798.            BEGIN
  1799.              IF Verbosity
  1800.               THEN
  1801.               IF (NumTry = 1)
  1802.                THEN putstr(Buf[ThisPacket].data,STDOUT)
  1803.                ELSE putstr(Buf[LastPacket].data,STDOUT);
  1804.              SendPacket;     (* send this packet *)
  1805.              IF ReceiveACK
  1806.               THEN
  1807.                BEGIN
  1808.                  State := FileData;
  1809.                  NumTry := 0;
  1810.                  n := (n+1) MOD 64;
  1811.                END
  1812.            END;
  1813.        END;
  1814.    END;
  1815.  
  1816.   PROCEDURE SendData;  (* send file data packets *)
  1817.   VAR
  1818.     newstate: KermitStates;
  1819.    BEGIN
  1820.      IF Verbosity
  1821.       THEN
  1822.        BEGIN
  1823.          PutCon ( 'Sending data        ',STDOUT);
  1824.          PutNum(n,STDOUT);
  1825.        END;
  1826.      IF NumTry > MaxTry
  1827.       THEN
  1828.        BEGIN
  1829.          State := Abort;       (* too many tries, abort *)
  1830.          PutErr ('Send data - Too many');
  1831.        END
  1832.       ELSE
  1833.        BEGIN
  1834.          NumTry := NumTry+1;
  1835.          GetData(newstate);
  1836.          SendPacket;
  1837.          IF ReceiveACK
  1838.           THEN
  1839.            BEGIN
  1840.              State := newstate;
  1841.              NumTry := 0;
  1842.              n := (n+1) MOD 64;
  1843.            END
  1844.        END;
  1845.    END;
  1846.  
  1847.   PROCEDURE SendEOF;    (* send EOF  packet *)
  1848.    BEGIN
  1849.      Verbose ('Sending EOF         ');
  1850.      IF NumTry > MaxTry
  1851.       THEN
  1852.        BEGIN
  1853.          State := Abort;       (* too many tries, abort *)
  1854.          PutErr('Send EOF - Too Many ');
  1855.        END
  1856.       ELSE
  1857.        BEGIN
  1858.          NumTry := NumTry+1;
  1859.          IF (NumTry = 1)
  1860.           THEN
  1861.            BEGIN
  1862.              WITH Buf[ThisPacket] DO
  1863.               BEGIN
  1864.                 ptype := TYPEZ;
  1865.                 seq := n;
  1866.                 count := 0;
  1867.               END
  1868.            END;
  1869.          SendPacket;
  1870.          IF ReceiveACK
  1871.           THEN
  1872.            BEGIN
  1873.              State := FileHeader;
  1874.              NumTry := 0;
  1875.              n := (n+1) MOD 64;
  1876.            END
  1877.        END;
  1878.    END;
  1879.  
  1880.   PROCEDURE SendBreak; (* send break packet *)
  1881.    BEGIN
  1882.      Verbose ('Sending break       ');
  1883.      IF NumTry > MaxTry
  1884.       THEN
  1885.        BEGIN
  1886.          State := Abort;       (* too many tries, abort *)
  1887.          PutErr('Send break -Too Many');
  1888.        END
  1889.       ELSE
  1890.        BEGIN
  1891.          NumTry := NumTry+1;
  1892.          (* make up packet  *)
  1893.          IF NumTry = 1
  1894.           THEN
  1895.            BEGIN
  1896.              WITH Buf[ThisPacket] DO
  1897.               BEGIN
  1898.                 ptype := TYPEB;
  1899.                 seq := n;
  1900.                 count := 0;
  1901.               END
  1902.            END;
  1903.          SendPacket; (* send this packet *)
  1904.          IF ReceiveACK
  1905.           THEN
  1906.            BEGIN
  1907.              State := Complete;
  1908.            END
  1909.        END;
  1910.    END;
  1911.  
  1912.   PROCEDURE SendInit;  (* send init packet *)
  1913.    BEGIN
  1914.      Verbose ('Sending init        ');
  1915.      IF NumTry > MaxTry
  1916.       THEN
  1917.        BEGIN
  1918.          State := Abort;      (* too many tries, abort *)
  1919.          PutErr('Cannot Initialize   ');
  1920.        END
  1921.       ELSE
  1922.        BEGIN
  1923.          NumTry := NumTry+1;
  1924.          IF (NumTry = 1)
  1925.           THEN
  1926.            BEGIN
  1927.              WITH Buf[ThisPacket] DO
  1928.               BEGIN
  1929.                 EnCodeParm(data);
  1930.                 count := NUMPARAM;
  1931.                 seq := n;
  1932.                 ptype := TYPES;
  1933.               END
  1934.            END;
  1935.  
  1936.          SendPacket; (* send this packet *)
  1937.          IF ReceiveACK
  1938.           THEN
  1939.            BEGIN
  1940.              WITH Buf[CurrentPacket] DO
  1941.               BEGIN
  1942.                 IF OneWayOnly
  1943.                  THEN  (* use same data if test mode *)
  1944.                  data := Buf[LastPacket].data;
  1945.                 SizeSend := UnChar(data[1]);
  1946.                 TheirTimeOut := UnChar(data[2]);
  1947.                 Pad := UnChar(data[3]);
  1948.                 PadChar := Ctl(data[4]);
  1949.                 SendEOL := CR;  (* default to CR *)
  1950.                 IF (length(data) >= 5)
  1951.                  THEN
  1952.                  IF (data[5] <> 0)
  1953.                   THEN
  1954.                   SendEOL := UnChar(data[5]);
  1955.                 SendQuote := SHARP;  (* default # *)
  1956.                 IF (length(data) >= 6)
  1957.                  THEN
  1958.                  IF (data[6] <> 0)
  1959.                   THEN
  1960.                   SendQuote := data[6];
  1961.               END;
  1962.  
  1963.              State := FileHeader;
  1964.              NumTry := 0;
  1965.              n := (n+1) MOD 64;
  1966.            END;
  1967.        END;
  1968.    END;
  1969.  
  1970.   PROCEDURE SendSwitch;
  1971.     (* Send-switch is the state table switcher for sending files.
  1972.      * It loops until either it is finished or a fault is encountered.
  1973.      * Routines called by sendswitch are responsible for changing the state.
  1974.      *)
  1975.  
  1976.    BEGIN
  1977.      State := Init;              (* send initiate is the start state *)
  1978.      NumTry := 0;                (* say no tries yet *)
  1979.      IF NOT Local THEN
  1980.        BEGIN
  1981.          TTYRAW;                 (* if host--put tty in raw mode *)
  1982.          TtyMode := Raw;
  1983.        END;
  1984.      IF (NOT OneWayOnly )
  1985.       THEN
  1986.       Sleep(Delay);
  1987.      StartRun;
  1988.       REPEAT
  1989.        CASE State OF
  1990.          FileData:     SendData;         (* data-send state *)
  1991.          FileHeader:   SendFile;         (* send file name *)
  1992.          EOFile:       SendEOF;          (* send end-of-file *)
  1993.          Init:         SendInit;         (* send initialize *)
  1994.          Break:        SendBreak;        (* send break *)
  1995.          Complete:     (* nothing *);
  1996.          Abort:        (* nothing *);
  1997.         END (* case *);
  1998.       UNTIL ( (State = Abort) OR (State=Complete) );
  1999.      FLUSH;                      (* flush output buffer *)
  2000.      IF TtyMode = Raw THEN
  2001.        BEGIN
  2002.          TTYCOOKED;              (* if host--return tty to cooked mode *)
  2003.          TtyMode := Cooked;
  2004.        END;
  2005.    END;
  2006.  
  2007.   PROCEDURE GetFile((* Using *) data:string);
  2008.     (* create file from fileheader packet *)
  2009.   VAR
  2010.     strend: integer;
  2011.    BEGIN
  2012.      putstr(aline,stdout);
  2013.      IF (RUNTYPE=PRINT) THEN  DiskFile := Sopen(aline,IOWRITE) ELSE
  2014.      WITH Buf[CurrentPacket] DO
  2015.       BEGIN
  2016.         IF DiskFile = IOERROR      (* check if we already have a file *)
  2017.          THEN
  2018.           BEGIN
  2019.             IF Verbosity
  2020.              THEN
  2021.               BEGIN
  2022.                 PutCon ('Creating file ...   ',STDOUT);
  2023.                 putstr(data,STDOUT);
  2024.               END;
  2025.              (* check position of '.' -- truncate if bad *)
  2026.             IF (index(data,PERIOD) > FLEN1 )
  2027.              THEN
  2028.               BEGIN
  2029.                 data[FLEN1] := PERIOD;
  2030.                 data[FLEN1 + 1] := ENDSTR;
  2031.               END;
  2032.              (* check Max length *)
  2033.             IF length(data) > FLEN2
  2034.              THEN
  2035.              data[FLEN2 +1] := ENDSTR;
  2036.             IF Exists(data)
  2037.              THEN
  2038.               BEGIN
  2039.                 PutCon('File already exists ',STDOUT);
  2040.                 putstr(data,STDOUT);
  2041.                 PutCon('Creating  ...       ',STDOUT);
  2042.                 CtoS(TEMPFILE,data);
  2043.                 strend := 0;
  2044.                  REPEAT
  2045.                   strend := strend +1;
  2046.                  UNTIL (data[strend] = BLANK);
  2047.                 strend := itoc(n,data,strend);
  2048.                 putstr(data,STDOUT);
  2049.               END;
  2050.             DiskFile := Sopen(data,IOWRITE);
  2051.           END;
  2052.         IF (Diskfile <= IOERROR)
  2053.          THEN
  2054.          ErrorPack('Cannot create file  ');
  2055.       END;
  2056.    END;
  2057.  
  2058.   PROCEDURE ReceiveInit;
  2059.     (* receive init packet *)
  2060.     (* respond with ACK and  our parameters *)
  2061.    BEGIN
  2062.      IF NumTry > MaxTry
  2063.       THEN
  2064.        BEGIN
  2065.          State := Abort;
  2066.          PutErr('Cannot receive init ');
  2067.        END
  2068.       ELSE
  2069.        BEGIN
  2070.          Verbose ( 'Receiving Init      ');
  2071.          NumTry := NumTry+1;
  2072.          IF ReceivePacket
  2073.           AND (Buf[CurrentPacket].ptype = TYPES)
  2074.           THEN
  2075.            BEGIN
  2076.              WITH Buf[CurrentPacket] DO
  2077.               BEGIN
  2078.                 n := seq;
  2079.                 DeCodeParm(data);
  2080.               END;
  2081.  
  2082.              (* now send mine *)
  2083.              WITH Buf[ThisPacket] DO
  2084.               BEGIN
  2085.                 count := NUMPARAM;
  2086.                 seq := n;
  2087.                 Ptype := TYPEY;
  2088.                 EnCodeParm(data);
  2089.               END;
  2090.  
  2091.              SendPacket;
  2092.  
  2093.              NumACK := NumACK+1;
  2094.              State := FileHeader;
  2095.              OldTry := NumTry;
  2096.              NumTry := 0;
  2097.              n := (n+1) MOD 64
  2098.            END
  2099.           ELSE
  2100.            BEGIN
  2101.              IF Debug
  2102.               THEN
  2103.               PutCon('Received Bad init   ',STDOUT);
  2104.              SendNAK(n);
  2105.            END;
  2106.        END;
  2107.    END;
  2108.  
  2109.   PROCEDURE DataToFile; (* output to file *)
  2110.   VAR
  2111.     len,i : integer;
  2112.     temp : string;
  2113.    BEGIN
  2114.      WITH Buf[CurrentPacket] DO
  2115.       BEGIN
  2116.         len := length(data);
  2117.         AddTo(ChInFile ,len);
  2118.         CASE EOLforFile OF
  2119.           LineFeed:     putstr(data,DiskFile);
  2120.           CrLf:
  2121.            BEGIN  (* don't output  CR *)
  2122.              FOR i:=1 TO len DO
  2123.              IF data[i] <> CR
  2124.               THEN
  2125.               putcf(data[i],DiskFile);
  2126.            END;
  2127.           JustCR:
  2128.            BEGIN   (* change CR to NEWLINE *)
  2129.              FOR i:=1 TO len DO
  2130.              IF data[i]=CR
  2131.               THEN
  2132.               data[i]:=NEWLINE;
  2133.              putstr(data,DiskFile);
  2134.            END;
  2135.          END;
  2136.         (* case *)
  2137.       END;
  2138.    END;
  2139.  
  2140.   PROCEDURE Dodata;  (* Process Data packet *)
  2141.  
  2142.    BEGIN
  2143.      WITH Buf[CurrentPacket] DO
  2144.       BEGIN
  2145.         IF  seq = ((n + 63) MOD 64)
  2146.          THEN
  2147.           BEGIN                (* data last one *)
  2148.             IF OldTry>MaxTry
  2149.              (* number of tries? *)
  2150.              THEN
  2151.               BEGIN
  2152.                 State := Abort;
  2153.                 PutErr('Old data - Too many ');
  2154.               END
  2155.              ELSE
  2156.               BEGIN
  2157.                 SendACK(seq);
  2158.                 NumTry := 0;
  2159.               END;
  2160.           END
  2161.          ELSE
  2162.           BEGIN            (* data - this one *)
  2163.             IF (n<>seq)
  2164.              THEN
  2165.              SendNAK(n)
  2166.              ELSE
  2167.               BEGIN
  2168.                 SendACK(n); (* ACK *)
  2169.                 DataToFile;
  2170.                 OldTry := NumTry;
  2171.                 NumTry := 0;
  2172.                 n := (n+1) MOD 64;
  2173.               END;
  2174.           END;
  2175.       END;
  2176.    END;
  2177.  
  2178.   PROCEDURE DoFileLast;   (* Process File Packet *)
  2179.    BEGIN          (* File header - last one  *)
  2180.      IF OldTry > MaxTry (* tries ? *)
  2181.       THEN
  2182.        BEGIN
  2183.          State := Abort;
  2184.          PutErr('Old file - Too many ');
  2185.        END
  2186.       ELSE
  2187.        BEGIN
  2188.          OldTry := OldTry+1;
  2189.          WITH Buf[CurrentPacket] DO
  2190.           BEGIN
  2191.             IF seq = ((n + 63) MOD 64)
  2192.              (* packet number *)
  2193.              THEN
  2194.               BEGIN  (* send ACK *)
  2195.                 SendACK(seq);
  2196.                 NumTry := 0
  2197.               END
  2198.              ELSE
  2199.               BEGIN
  2200.                 SendNAK(n);   (* NAK *)
  2201.               END;
  2202.           END;
  2203.        END;
  2204.    END;
  2205.  
  2206.   PROCEDURE DoEOF;  (* Process EOF packet *)
  2207.    BEGIN                 (* EOF - this one *)
  2208.      IF Buf[CurrentPacket].seq<>n    (* packet number ? *)
  2209.       THEN
  2210.       SendNAK(n) (* NAK *)
  2211.       ELSE
  2212.        BEGIN               (* send ACK *)
  2213.          SendACK(n);
  2214.          Sclose(DiskFile);  (* close file *)
  2215.          DiskFile := IOERROR;
  2216.          OldTry := NumTry;
  2217.          NumTry := 0;
  2218.          n := (n+1) MOD 64; (* next packet  *)
  2219.          State := FileHeader;   (* change state *)
  2220.        END;
  2221.    END;
  2222.  
  2223.   PROCEDURE ReceiveData;  (* Receive data packets *)
  2224.   VAR
  2225.     strend: integer;
  2226.     packetnum: string;
  2227.     good : boolean;
  2228.  
  2229.    BEGIN
  2230.      IF NumTry > MaxTry          (* check number of tries *)
  2231.       THEN
  2232.        BEGIN
  2233.          State := Abort;
  2234.          CtoS('Recv data -Too many ',packetnum);
  2235.          strend := itoc(n,packetnum,CONLENGTH+1);
  2236.          putstr(packetnum,STDOUT);
  2237.        END
  2238.       ELSE
  2239.        BEGIN
  2240.          NumTry := NumTry+1;                (* increase number of tries *)
  2241.          good := ReceivePacket;        (* get packet *)
  2242.          WITH Buf[CurrentPacket] DO
  2243.           BEGIN
  2244.             IF Verbosity
  2245.              THEN
  2246.               BEGIN
  2247.                 PutCon('Receiving (Data)    ',STDOUT);
  2248.                 PutNum(Buf[CurrentPacket].seq,STDOUT);
  2249.               END;
  2250.             IF ((ptype = TYPED) OR (ptype=TYPEZ)
  2251.                 OR (ptype=TYPEF)) AND good           (* check type *)
  2252.              THEN
  2253.              CASE ptype OF
  2254.                TYPED:  DoData;
  2255.                TYPEF:  DoFileLast;
  2256.                TYPEZ:  DoEOF;
  2257.               END (* case *)
  2258.              ELSE
  2259.               BEGIN
  2260.                 Verbose('Expected data pack  ');
  2261.                 SendNAK(n);
  2262.               END;
  2263.           END;
  2264.        END;
  2265.    END;
  2266.  
  2267.   PROCEDURE DoBreak; (* Process Break packet *)
  2268.    BEGIN                    (* Break transmission *)
  2269.      IF Buf[CurrentPacket].seq<>n    (* packet number ? *)
  2270.       THEN
  2271.       SendNAK(n) (* NAK *)
  2272.       ELSE
  2273.        BEGIN            (* send  ACK *)
  2274.          SendACK(n) ;
  2275.          State := Complete  (* change state *)
  2276.        END
  2277.    END;
  2278.  
  2279.   PROCEDURE DoFile; (* Process file packet *)
  2280.    BEGIN                 (* File Header *)
  2281.      WITH Buf[CurrentPacket] DO
  2282.       BEGIN
  2283.         IF seq<>n           (* packet number ? *)
  2284.          THEN
  2285.          SendNAK(n)  (* NAK *)
  2286.          ELSE
  2287.           BEGIN               (* send ACK *)
  2288.             SendACK(n);
  2289.             AddTo(ChInFile, length(data));
  2290.             GetFile(data);   (* get file name *)
  2291.             OldTry := NumTry;
  2292.             NumTry := 0;
  2293.             n := (n+1) MOD 64; (* next packet  *)
  2294.             IF (State <> Abort) THEN State := FileData;   (* change state *)
  2295.           END;
  2296.       END;
  2297.    END;
  2298.  
  2299.   PROCEDURE DoEOFLast; (* Process EOF Packet *)
  2300.    BEGIN               (* End Of File Last One*)
  2301.      IF OldTry > MaxTry (* tries ? *)
  2302.       THEN
  2303.        BEGIN
  2304.          State := Abort;
  2305.          PutErr('Old EOF - Too many  ');
  2306.        END
  2307.       ELSE
  2308.        BEGIN
  2309.          OldTry := OldTry+1;
  2310.          WITH Buf[CurrentPacket] DO
  2311.           BEGIN
  2312.             IF seq =((n + 63 ) MOD 64)
  2313.              (* packet number *)
  2314.              THEN
  2315.               BEGIN  (* send ACK *)
  2316.                 SendACK(seq);
  2317.                 Numtry := 0
  2318.               END
  2319.              ELSE
  2320.               BEGIN
  2321.                 SendNAK(n);  (* NAK *)
  2322.               END
  2323.           END;
  2324.        END;
  2325.    END;
  2326.  
  2327.   PROCEDURE DoInitLast;
  2328.    BEGIN                (* Init Packet - last one *)
  2329.      IF OldTry>MaxTry   (* number of tries? *)
  2330.       THEN
  2331.        BEGIN
  2332.          State := Abort;
  2333.          PutErr('Old init - Too many ');
  2334.        END
  2335.       ELSE
  2336.        BEGIN
  2337.          OldTry := OldTry+1;
  2338.          IF Buf[CurrentPacket].seq = ((n + 63) MOD  64)
  2339.           (* packet number *)
  2340.           THEN
  2341.            BEGIN   (* send ACK *)
  2342.              WITH Buf[ThisPacket] DO
  2343.               BEGIN
  2344.                 count := NUMPARAM;
  2345.                 seq := Buf[CurrentPacket].seq;
  2346.                 ptype := TYPEY;
  2347.                 EnCodeParm(data);
  2348.               END;
  2349.              SendPacket;
  2350.              NumACK := NumACK+1;
  2351.              NumTry := 0;
  2352.            END
  2353.           ELSE
  2354.            BEGIN
  2355.              SendNAK(n);  (* NAK *)
  2356.            END;
  2357.        END;
  2358.    END;
  2359.  
  2360.   PROCEDURE ReceiveFile; (* receive file packet *)
  2361.   VAR
  2362.     good: boolean;
  2363.  
  2364.    BEGIN
  2365.      IF NumTry > MaxTry          (* check number of tries *)
  2366.       THEN
  2367.        BEGIN
  2368.          State := Abort;
  2369.          PutErr('Recv file - Too many');
  2370.        END
  2371.       ELSE
  2372.        BEGIN
  2373.          NumTry := NumTry+1;                (* increase number of tries *)
  2374.          good := ReceivePacket;             (* get packet *)
  2375.          WITH Buf[CurrentPacket] DO
  2376.           BEGIN
  2377.              IF VERBOSITY THEN BEGIN
  2378.                 PutCon('Receiving (File)    ',STDOUT);
  2379.         PutNum(seq,STDOUT);
  2380.              END;
  2381.                 PutCon(' RECEIVING...       ',STDOUT);
  2382.                 putstr(data,stdout);
  2383.             IF ((ptype = TYPES) OR (ptype=TYPEZ)
  2384.                 OR (ptype=TYPEF) OR (ptype=TYPEB)) (* check type *)
  2385.              AND good
  2386.              THEN
  2387.              CASE ptype OF
  2388.                TYPES:  DoInitLast;
  2389.                TYPEZ:  DoEOFLast;
  2390.                TYPEF:  DoFile;
  2391.                TYPEB:  DoBreak;
  2392.               END (* case *)
  2393.              ELSE
  2394.               BEGIN
  2395.                 IF Debug
  2396.                  THEN
  2397.                  PutCon('Expected File Pack  ',STDOUT);
  2398.                 SendNAK(n);
  2399.               END;
  2400.           END;
  2401.        END;
  2402.    END;
  2403.  
  2404.   PROCEDURE RecvSwitch; (* this procedure is the main receive routine *)
  2405.    BEGIN
  2406.      State := Init;
  2407.      NumTry := 0;
  2408.      IF NOT Local THEN
  2409.        BEGIN
  2410.          TTYRAW;                 (* if host--put tty in raw mode *)
  2411.          TtyMode := Raw;
  2412.        END;
  2413.      StartRun;
  2414.       REPEAT
  2415.        CASE State OF
  2416.          FileData:       ReceiveData;
  2417.          Init:           ReceiveInit;
  2418.          Break:          (* nothing *);
  2419.          FileHeader:     ReceiveFile;
  2420.          EOFile:         (* nothing *);
  2421.          Complete:       (* nothing *);
  2422.          Abort:          (* nothing *);
  2423.         END;
  2424.        (* case *)
  2425.       UNTIL (State = Abort ) OR ( State = Complete );
  2426.      FLUSH;                     (* flush output buffer *)
  2427.      IF TtyMode = Raw THEN
  2428.        BEGIN
  2429.          TTYCOOKED;              (* if host--return tty to cooked mode *)
  2430.          TtyMode := Cooked;
  2431.        END;
  2432.    END;
  2433.  
  2434.  BEGIN
  2435.    SYSinit;             (*  system dependent  *)
  2436.    initio;
  2437.    done:=false;
  2438.    NumTry:=0;
  2439.    NumKeptErrors := 0;
  2440.    Pad := DEFPAD;               (* set defaults *)
  2441.    MyPad := DEFPAD;
  2442.    PadChar := DEFPADCHAR;
  2443.    MyPadChar := DEFPADCHAR;
  2444.    TheirTimeOut := DEFTIMEOUT;
  2445.    MyTimeOut := DEFTIMEOUT;
  2446.    Delay := DEFDELAY;
  2447.    SizeRecv := MAXPACK;
  2448.    SizeSend := MAXPACK;
  2449.    SendEOL := DEFEOL;
  2450.    MyEOL := DEFEOL;
  2451.    SendQuote := DEFQUOTE;
  2452.    MyQuote := DEFQUOTE;
  2453.    MaxTry := DEFTRY;
  2454.    Halfduplex := DEFDUPLEX;
  2455.    CASE DEFEOLTYPE OF
  2456.      1:      EOLforFile := LineFeed;
  2457.      2:      EOLforFile := CrLf;
  2458.      3:      EOLforFile := JustCR;
  2459.     END (* case *);
  2460.    CtoS(PFILE,ParmFile);
  2461.    GetParm;
  2462.    Local := false;      (* default to remote *)
  2463.    TtyMode := Cooked;
  2464.  
  2465.  
  2466. repeat
  2467.    initcmd;
  2468.  
  2469.      KermitInit;       (* initialize *)
  2470.  
  2471.      WHILE ( NextArg <= nargs ) AND (RUNTYPE<>transmit) and
  2472.         (RUNTYPE<>receive) and (RUNTYPE<>print) and (not done)
  2473.     DO
  2474.       BEGIN
  2475.         (* check for valid commands *)
  2476.         (* r s c M x u z *)
  2477.         IF
  2478.         (aline[1]=LETS) OR
  2479.         (aline[1]=LETR) OR
  2480.         (aline[1]=LETP) OR
  2481.         (aline[1]=LETC) OR
  2482.         (aline[1]=LETM) OR
  2483.         (aline[1]=LETX) OR
  2484.         (aline[1]=LETU) OR
  2485.         (aline[1]=LETZ) OR
  2486.         (aline[1]=LETH) OR
  2487.         (aline[1]=LETQ) OR
  2488.         (aline[1]=LETT) OR
  2489.         (aline[1]=LETE)
  2490.        THEN
  2491.          CASE aline[1] OF
  2492.            LETS:   RunType := Transmit;
  2493.            LETR:   RunType := Receive;
  2494.            LETP:   RunType := PRINT;
  2495.            LETE,LETQ:   done:=true;
  2496.            LETC:
  2497.             BEGIN               (* look for -lvd *)
  2498.               FOR j := length(aline) DOWNTO 1 DO
  2499.                BEGIN
  2500.                  IF (aline[j]=LETC)
  2501.                   THEN
  2502.                    BEGIN
  2503.                      Local := true;
  2504.                      IF NOT OneWayOnly
  2505.                       THEN
  2506.                        BEGIN
  2507.                         Local := connect(Halfduplex);
  2508.                         IF NOT Local THEN
  2509.                          PutErr('Cannot connect      ');
  2510.                        END;
  2511.                    END;
  2512.                  IF (aline[j]=LETV)
  2513.                   THEN
  2514.                   Verbosity := true;
  2515.                  IF (aline[j]=LETD)
  2516.                   THEN
  2517.                   Debug := true;
  2518.                  IF (aline[j]=LETH)
  2519.                   THEN
  2520.                   Halfduplex := true;
  2521.                  IF (aline[j]=LETF)
  2522.                   THEN
  2523.                   Halfduplex := false;
  2524.                END;
  2525.             END;
  2526.            LETH:   BEGIN WRITELN;
  2527.                          WRITELN('KERMIT-H Comands:');
  2528.                          WRITELN;
  2529. (*
  2530. WRITELN('C [H/F/D/V]               - Connect [Half/Full duplex,Debug,Verbose]');
  2531. *)
  2532. Writeln('S <filename> {<filename>} - Send files');
  2533. Writeln('R {<filename>}            - Receive files');
  2534. (*
  2535. Writeln('P {<filename>]            - Print files');
  2536. *)
  2537. Writeln('H                         - Help {this message}');
  2538. Writeln('E                         - Exit');
  2539. Writeln('Q                         - Quit');
  2540.                    END;
  2541.            LETX:   OneWayOnly := true;
  2542.            LETM:   SetParameters;
  2543.            LETU:   SYSarguments;   (* do special for SYSTEM *)
  2544.            LETZ:
  2545.             BEGIN
  2546.               IF (aline[2]=LETL) OR (aline[2]=LETC)
  2547.                OR (aline[2]=LETR)
  2548.                THEN
  2549.                CASE aline[2] OF
  2550.                  LETL:   EOLforFile := LineFeed;
  2551.                  LETC:   EOLforFile := CrLf;
  2552.                  LETR:   EOLforFile := JustCR;
  2553.                 END (* case *);
  2554.             END;
  2555.            LETT:
  2556.             BEGIN
  2557.               FILECREATE(TRACEFILE);
  2558.               bind(filet,TRACEFILE,BindStatus);
  2559.               IF BindStatus = 0 THEN Trace := true;
  2560.               Verbosity := true;
  2561.               Debug := true;
  2562.               TtyMode := RAW;
  2563.               PutCon('Kermit Trace Output ',STDOUT);
  2564.               PutCon('                    ',STDOUT);
  2565.               TtyMode := COOKED;
  2566.             END;
  2567.           END (* case *)
  2568.          ELSE
  2569.          Usage;
  2570.          (* get next argument *)
  2571.         NextArg := NextArg+1;
  2572.         IF (NextArg <= nargs )
  2573.          THEN
  2574.          IF NOT getarg(NextArg,aline,MAXSTR)
  2575.           THEN
  2576.           Usage;
  2577.       END;
  2578.  
  2579.      CASE RunType OF
  2580.        Receive:
  2581.         BEGIN (* filename is optional here *)
  2582.           IF getarg(NextArg,aline,MAXSTR)
  2583.            THEN
  2584.             BEGIN
  2585.               IF Exists(aline)
  2586.                THEN
  2587.                 BEGIN
  2588.                   PutErr('Overwriting         ');
  2589.                   putstr(aline,STDOUT);
  2590.                 END;
  2591.               DiskFile := Sopen(aline,IOWRITE);
  2592.               IF DiskFile <= IOERROR
  2593.                THEN
  2594.                ErrorPack('Cannot Open File    ');
  2595.             END;
  2596.           RecvSwitch;
  2597.         END;
  2598.  
  2599.        PRINT:
  2600.         BEGIN
  2601.               CtoS(LP,aline);
  2602.               DiskFile := Sopen(aline,IOWRITE);
  2603.               IF DiskFile <= IOERROR
  2604.                THEN
  2605.                ErrorPack('Cannot Open File    ');
  2606.           RecvSwitch;
  2607.         END;
  2608.  
  2609.        Transmit:
  2610.         BEGIN (* must give filename *)
  2611.           FOR j:= NextArg TO nargs DO
  2612.            BEGIN
  2613.              IF NOT getarg(NextArg,aline,MAXSTR)
  2614.               THEN
  2615.               Usage;
  2616.              IF NOT Exists(aline)
  2617.               THEN
  2618.               ErrorPack('File not found      ');
  2619.            END;
  2620.           IF getarg(NextArg,aline,MAXSTR)
  2621.            THEN SendSwitch;
  2622.         END;
  2623.        Invalid:        (* nothing *);
  2624.        SetParm:        (* nothing *);
  2625.       END;
  2626.      (* case *)
  2627.  
  2628. until done;
  2629.  
  2630.      FinishUp; (* End of Program *)
  2631.  
  2632.      IF (NumKeptErrors > 0)     (* Print any message we couldn't before *)
  2633.       THEN
  2634.        BEGIN
  2635.          PutCon('   Delayed Messages:',STDOUT);
  2636.          FOR J := 1 TO NumKeptErrors DO PutCon(KeptErrors[J],STDOUT);
  2637.        END;
  2638.  
  2639. 9999:
  2640.      SYSFINISH;  (* do System dependent *)
  2641. END.
  2642.