home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / lilith / m2recv.mod < prev    next >
Text File  |  2020-01-01  |  20KB  |  691 lines

  1. IMPLEMENTATION MODULE KermRecv;
  2. (************************************************************************)
  3. (*  Receive one or more files from remote Kermit                        *)
  4. (*  written:            15.10.85     Matthias Aebi                      *)
  5. (*  last modification:  18.03.86     Matthias Aebi                      *)
  6. (************************************************************************)
  7.  
  8. FROM Terminal    IMPORT WriteString, WriteLn, Write;
  9. FROM FileSystem  IMPORT File, Create, Close, WriteChar, Response, Rename,
  10.                         Lookup;
  11. FROM KermMisc    IMPORT RecvChar, BitAND, UnChar, ToChar, Ctl, ReadChar,
  12.                         PrtErrPacket, IncPackNum, DecPackNum,
  13.                         DispInit, DispFile, DispPack, DispTry, DispMsg,
  14.                         CardToString;
  15. FROM KermParam   IMPORT LPackSize, LTimeOut, LNumOfPad, LPadChar, LDebug,
  16.                         LEOLChar, LQuoteChar, LStartChar, LFileType,
  17.                         LCurrPort, LTimer, LMaxRetries, LFilNamConv,
  18.                         LWarning,
  19.                         RPackSize, RTimeOut, RNumOfPad, RPadChar,
  20.                         REOLChar, RQuoteChar, FileTyp, ParityTyp, Packet;
  21. FROM KermSend    IMPORT SendPacket;
  22. FROM OutTerminal IMPORT WriteC;
  23. FROM FileMessage IMPORT WriteResponse;
  24. FROM TextScreen  IMPORT SetPos, ClearLines;
  25. FROM String      IMPORT Length, Insert;
  26. FROM M2Kermit    IMPORT Param1;
  27.  
  28.  
  29. CONST
  30.     ESC = 33C;
  31.     EOL = 36C;
  32.     CR  = 15C;
  33.  
  34. VAR
  35.     sendPack   : Packet; (* globally defined local variables *)
  36.     recvPack   : Packet;
  37.     num        : CARDINAL;
  38.     len        : CARDINAL;
  39.     typ        : CHAR;
  40.     theFile    : File;
  41.     msgNum     : CARDINAL;  (* Packet number *)
  42.     numTry     : CARDINAL;  (* Number of retries *)
  43.     oldTry     : CARDINAL;  (* save Number of retries *)
  44.     numOfPacks : CARDINAL;  (* Total number of packets *)
  45.     numOfTries : CARDINAL;  (* Total number of retries *)
  46.  
  47. (************************************************************************)
  48.         PROCEDURE RecvPacket(VAR typ: CHAR; VAR num, len: CARDINAL;
  49.                              VAR Data: ARRAY OF CHAR);
  50. (************************************************************************)
  51. VAR
  52.     i       : CARDINAL;
  53.     ch      : CHAR;
  54.     cState  : CHAR;
  55.     cChkSum : CARDINAL;
  56.     rChkSum : CARDINAL;
  57.  
  58.     (*------------------------------------------------------------------*)
  59.                         PROCEDURE GetChar(VAR ch: CHAR): CHAR;
  60.     (*------------------------------------------------------------------*)
  61.     CONST
  62.         Factor = 3300; (* 3300 retries equal 1 second *)
  63.  
  64.     VAR
  65.         counter : CARDINAL;
  66.  
  67.     BEGIN
  68.         counter := 0;
  69.         LOOP
  70.             IF RecvChar(ch, LCurrPort)
  71.             THEN
  72.                 IF LFileType = text
  73.                 THEN    (* strip parity bit *)
  74.                     ch := CHAR(BitAND(CARDINAL(ch),7FH));
  75.                 END;
  76.  
  77.                 IF ch <> LStartChar
  78.                 THEN
  79.                     RETURN "C";
  80.                 ELSE
  81.                     RETURN "L";
  82.                 END;
  83.             END;
  84.  
  85.             IF LTimer
  86.             THEN
  87.                 IF (counter DIV Factor) > LTimeOut
  88.                 THEN
  89.                     DispMsg("Timer Timeout (M2-Kermit)");
  90.                     RETURN "T";  (* Time Out interrupt *)
  91.                 ELSE
  92.                     INC(counter);
  93.                 END;
  94.             END;
  95.  
  96.             IF ReadChar(ch)
  97.             THEN
  98.                 IF ch = EOL
  99.                 THEN
  100.                     DispMsg("User Timeout (M2-Kermit)");
  101.                     RETURN "T"; (* User interrupt *)
  102.                 ELSIF ch = ESC
  103.                 THEN
  104.                     RETURN "A"; (* User abort *)
  105.                 END;
  106.             END;
  107.         END;
  108.     END GetChar;
  109.  
  110.  
  111. BEGIN (* RecvPacket *)
  112.     cState := "S";
  113.     LOOP
  114.         CASE cState OF
  115.         "S": (* wait for SOH *)
  116.             cState := GetChar(ch);
  117.             IF cState = "C"
  118.             THEN
  119.                 cState := "S";
  120.             END; |
  121.  
  122.         "L": (* get packet length *)
  123.             cState := GetChar(ch);
  124.             IF cState = "C"
  125.             THEN
  126.                 cChkSum := ORD(ch);
  127.                 len := UnChar(ch) - 3;
  128.                 cState := "N";
  129.             END; |
  130.  
  131.         "N": (* get packet number *)
  132.             cState := GetChar(ch);
  133.             IF cState = "C"
  134.             THEN
  135.                 cChkSum := cChkSum + ORD(ch);
  136.                 num := UnChar(ch);
  137.                 cState := "Y";
  138.             END; |
  139.  
  140.         "Y": (* get packet type *)
  141.             cState := GetChar(ch);
  142.             IF cState = "C"
  143.             THEN
  144.                 cChkSum := cChkSum + ORD(ch);
  145.                 typ := ch;
  146.                 i := 0;
  147.             END; |
  148.  
  149.         "C": (* get packet body character *)
  150.             cState := GetChar(ch);
  151.             IF cState = "C"
  152.             THEN
  153.                 IF i < len
  154.                 THEN
  155.                     cChkSum := cChkSum + ORD(ch);
  156.                     Data[i] := ch;
  157.                     INC(i);
  158.                 ELSE
  159.                     rChkSum := UnChar(ch);
  160.                     cState := "E";
  161.                 END;
  162.             END; |
  163.  
  164.         "E":
  165.             cState := GetChar(ch);
  166.             IF cState = "C"
  167.             THEN
  168.                 cChkSum := BitAND(((BitAND(cChkSum,192) DIV 64)+cChkSum),63);
  169.                 IF LDebug   (* if debugging on *)
  170.                 THEN
  171.                     SetPos(13,0);
  172.                     ClearLines(5);
  173.  
  174.                     WriteString("Length: ");
  175.                     WriteC(len,2); WriteLn;
  176.  
  177.                     WriteString("Number: ");
  178.                     WriteC(num,2); WriteLn;
  179.  
  180.                     WriteString("Type: ");
  181.                     Write(typ); WriteLn;
  182.  
  183.                     WriteString("Packet: ");
  184.                     FOR i := 1 TO len DO
  185.                         Write(Data[i-1]);
  186.                     END;
  187.                 END;
  188.  
  189.                 IF cChkSum <> rChkSum
  190.                 THEN
  191.                     DispMsg("Checksum Error (M2-Kermit)");
  192.                 END;
  193.  
  194.                 EXIT;
  195.             END; |
  196.  
  197.         "A","T": (* user abort / timeout *)
  198.             typ := cState;
  199.             EXIT;
  200.  
  201.         END;
  202.     END;
  203. END RecvPacket;
  204.  
  205.  
  206. (************************************************************************)
  207.                  PROCEDURE BufEmp(data: Packet; len: CARDINAL);
  208. (************************************************************************)
  209. VAR
  210.     i  : CARDINAL;
  211.     ch : CHAR;
  212.  
  213. BEGIN
  214.     i := 0;
  215.     WHILE i < len DO
  216.         ch := data[i]; INC(i);
  217.         IF ch = LQuoteChar
  218.         THEN
  219.             ch := data[i]; INC(i);
  220.             IF CHAR(BitAND(CARDINAL(ch),7FH)) <> LQuoteChar
  221.             THEN
  222.                 ch := Ctl(ch);
  223.             END;
  224.         END;
  225.  
  226.         IF (ch = CHR(10)) AND (LFileType = text)
  227.         THEN
  228.             ch := EOL;
  229.         END;
  230.  
  231.         IF (ch <> CR) OR (LFileType <> text)
  232.         THEN
  233.             WriteChar(theFile, ch);
  234.         END;
  235.     END;
  236. END BufEmp;
  237.  
  238.  
  239. (************************************************************************)
  240.            PROCEDURE SwitchRecv(saveName: ARRAY OF CHAR): BOOLEAN;
  241. (************************************************************************)
  242. (*   SwitchRecv calls the different routines depending on the current   *)
  243. (*   receive state. For a description of all states see Kermit protocol *)
  244. (*   manual. Returns TRUE if receive was successful.                    *)
  245.  
  246. VAR
  247.     state    : CHAR; (* current receive state *)
  248.     fileName : ARRAY [0..63] OF CHAR; (* received filename *)
  249.  
  250.  
  251.     (*------------------------------------------------------------------*)
  252.                   PROCEDURE ErrorExit(errMessage: ARRAY OF CHAR);
  253.     (*------------------------------------------------------------------*)
  254.     (* close file, display error message, send error packet             *)
  255.     BEGIN
  256.         Close(theFile);
  257.         DispMsg(errMessage);
  258.         SendPacket("E",0,Length(errMessage), errMessage);
  259.     END ErrorExit;
  260.  
  261.  
  262.     (*------------------------------------------------------------------*)
  263.                       PROCEDURE RecvInit(VAR state: CHAR);
  264.     (*------------------------------------------------------------------*)
  265.     BEGIN
  266.         INC(numTry);
  267.         IF numTry > LMaxRetries
  268.         THEN
  269.             state := "T";
  270.             RETURN;
  271.         END;
  272.  
  273.         RecvPacket(typ, num, len, recvPack);
  274.         CASE typ OF
  275.         "S":
  276.             RPackSize   := UnChar(recvPack[0]);
  277.             RTimeOut    := UnChar(recvPack[1]);
  278.             RNumOfPad   := UnChar(recvPack[2]);
  279.             RPadChar    := Ctl(recvPack[3]);
  280.             REOLChar    := CHR(UnChar(recvPack[4]));
  281.             RQuoteChar  := recvPack[5];
  282.  
  283.             sendPack[0] := ToChar(LPackSize);    (* Maximum packet lemgth   *)
  284.             sendPack[1] := ToChar(LTimeOut);     (* seconds before timeot   *)
  285.             sendPack[2] := ToChar(LNumOfPad);    (* number of padding chars *)
  286.             sendPack[3] := Ctl(LPadChar);        (* padding character       *)
  287.             sendPack[4] := ToChar(ORD(LEOLChar));(* end of line/packet char *)
  288.             sendPack[5] := LQuoteChar;           (* control character quote *)
  289.  
  290.             oldTry := numTry;
  291.             numTry := 0;
  292.             DispPack;
  293.             state := "F";
  294.  
  295.             SendPacket("Y",msgNum,0,"");
  296.             msgNum := IncPackNum(msgNum); |
  297.  
  298.         "E": (* got error packet *)
  299.             PrtErrPacket(recvPack, len);
  300.             state := "E"; |
  301.  
  302.         "T": (* timeout *)
  303.             DispTry;
  304.             SendPacket("N",msgNum,0,""); |
  305.  
  306.         "A": (* user abort *)
  307.             state := "A";
  308.  
  309.         ELSE (* undefined packet type *)
  310.             state := "U";
  311.  
  312.         END;
  313.     END RecvInit;
  314.  
  315.  
  316.     (*------------------------------------------------------------------*)
  317.                      PROCEDURE RecvFile(VAR state: CHAR);
  318.     (*------------------------------------------------------------------*)
  319.     VAR
  320.         i        : CARDINAL;
  321.         j        : CARDINAL;
  322.         ch       : CHAR;
  323.  
  324.     BEGIN
  325.         INC(numTry);
  326.         IF numTry > LMaxRetries
  327.         THEN
  328.             state := "T";
  329.             RETURN;
  330.         END;
  331.  
  332.         RecvPacket(typ, num, len, recvPack);
  333.         CASE typ OF
  334.         "S":
  335.             INC(oldTry);
  336.             IF (oldTry > LMaxRetries)
  337.             THEN
  338.                 state := "T";
  339.                 RETURN;
  340.             END;
  341.  
  342.             IF num = DecPackNum(msgNum)
  343.             THEN
  344.  
  345.                 sendPack[0] := ToChar(LPackSize);(* Maximum packet lemgth   *)
  346.                 sendPack[1] := ToChar(LTimeOut); (* seconds before timeot   *)
  347.                 sendPack[2] := ToChar(LNumOfPad);(* number of padding chars *)
  348.                 sendPack[3] := Ctl(LPadChar);    (* padding character       *)
  349.                 sendPack[4] := ToChar(ORD(LEOLChar)); (* end of line/packet char *)
  350.                 sendPack[5] := LQuoteChar;       (* control character quote *)
  351.  
  352.                 numTry := 0;
  353.                 DispPack;
  354.                 SendPacket("Y",msgNum,6,sendPack);
  355.             ELSE
  356.                 state := "P";
  357.             END; |
  358.  
  359.         "Z":
  360.             INC(oldTry);
  361.             IF oldTry > LMaxRetries
  362.             THEN
  363.                 state := "T";
  364.                 RETURN;
  365.             END;
  366.  
  367.             IF num = DecPackNum(msgNum)
  368.             THEN
  369.                 numTry := 0;
  370.                 DispPack;
  371.                 SendPacket("Y",num,0,"");
  372.             ELSE
  373.                 state := "P";
  374.             END; |
  375.  
  376.         "F":
  377.             IF num <> msgNum
  378.             THEN
  379.                 state := "P";
  380.                 RETURN;
  381.             END;
  382.  
  383.             j := 0;
  384.             FOR i:=0 TO len-1 DO
  385.                 ch := recvPack[i];
  386.                 IF LFilNamConv
  387.                 THEN
  388.                     IF j = 0
  389.                     THEN
  390.                         fileName[0] := "D";
  391.                         fileName[1] := "K";
  392.                         fileName[2] := ".";
  393.                         IF (ch>="0") AND (ch<="9")
  394.                         THEN
  395.                             fileName[3] := "X";
  396.                             j := 4;
  397.                         ELSE
  398.                             j := 3;
  399.                         END;
  400.                     END;
  401.  
  402.                     IF (ch>="a") AND (ch<="z")
  403.                     THEN
  404.                         ch := CAP(ch);
  405.                     END;
  406.  
  407.                     IF ((ch>="A") AND (ch<="Z")) OR
  408.                        ((ch>="0") AND (ch<="9")) OR
  409.                         (ch=".")
  410.                     THEN
  411.                         fileName[j] := ch;
  412.                     ELSE
  413.                         fileName[j] := "X";
  414.                     END;
  415.                     INC(j);
  416.                 ELSE
  417.                     fileName[j] := ch;
  418.                     INC(j);
  419.                 END;
  420.             END;
  421.             IF fileName[j-1] = "."
  422.             THEN
  423.                 DEC(j);
  424.             END;
  425.             fileName[j] := 0C;
  426.  
  427.             Create(theFile, "DK."); (* create a temporary file *)
  428.             IF theFile.res # done
  429.             THEN
  430.                 DispMsg("Could not create temporary file");
  431.                 WriteResponse(theFile.res);
  432.  
  433.                 Close(theFile);
  434.                 state := "E";
  435.             ELSE
  436.                 DispFile(fileName);
  437.                 oldTry := numTry;
  438.                 numTry := 0;
  439.                 IF saveName[0] # 0C
  440.                 THEN
  441.                     DispMsg("Receiving as ");
  442.                     WriteString(saveName);
  443.                 END;
  444.                 DispPack;
  445.                 state := "D";
  446.  
  447.                 SendPacket("Y",msgNum,0,"");
  448.                 msgNum := IncPackNum(msgNum);
  449.            END; |
  450.  
  451.         "B":
  452.             IF num <> msgNum
  453.             THEN
  454.                 state := "P";
  455.                 RETURN;
  456.             END;
  457.  
  458.             DispPack;
  459.             state := "C";
  460.             SendPacket("Y",msgNum,0,""); |
  461.  
  462.         "E": (* got error packet *)
  463.             PrtErrPacket(recvPack, len);
  464.             state := "E"; |
  465.  
  466.         "T": (* timeout *)
  467.             DispTry;
  468.             SendPacket("N",msgNum,0,""); |
  469.  
  470.         "A": (* user abort *)
  471.             state := "A";
  472.  
  473.         ELSE (* undefined packet type *)
  474.             state := "U";
  475.  
  476.         END;
  477.     END RecvFile;
  478.  
  479.  
  480.     (*------------------------------------------------------------------*)
  481.                     PROCEDURE RecvData(VAR state: CHAR);
  482.     (*------------------------------------------------------------------*)
  483.     VAR
  484.         fNameStr : ARRAY [0..63] OF CHAR;
  485.         numStr   : ARRAY [0..15] OF CHAR;
  486.         pos      : CARDINAL;
  487.         fCounter : CARDINAL;
  488.         delFile  : File;
  489.  
  490.     BEGIN
  491.         INC(numTry);
  492.         IF numTry > LMaxRetries
  493.         THEN
  494.             state := "T";
  495.             RETURN;
  496.         END;
  497.  
  498.         RecvPacket(typ, num, len, recvPack);
  499.         CASE typ OF
  500.         "D":
  501.             IF num <>msgNum
  502.             THEN
  503.                 INC(oldTry);
  504.                 IF (oldTry > LMaxRetries)
  505.                 THEN
  506.                     state := "T";
  507.                     RETURN;
  508.                 END;
  509.  
  510.                 IF num = DecPackNum(msgNum)
  511.                 THEN
  512.                     numTry := 0;
  513.                     SendPacket("Y",msgNum,0,"");
  514.                 ELSE
  515.                     state := "P";
  516.                 END;
  517.             ELSE
  518.                 BufEmp(recvPack, len);
  519.                 oldTry := numTry;
  520.                 numTry := 0;
  521.                 DispPack;
  522.  
  523.                 SendPacket("Y",msgNum,0,"");
  524.                 msgNum := IncPackNum(msgNum);
  525.             END; |
  526.  
  527.         "F":
  528.             INC(oldTry);
  529.             IF oldTry > LMaxRetries
  530.             THEN
  531.                 state := "T";
  532.                 RETURN;
  533.             END;
  534.  
  535.             IF num = DecPackNum(msgNum)
  536.             THEN
  537.                 numTry := 0;
  538.                 DispPack;
  539.                 SendPacket("Y",num,0,"");
  540.            ELSE
  541.                 state := "P";
  542.            END; |
  543.  
  544.         "Z":
  545.             IF (num <> msgNum)
  546.             THEN
  547.                 state := "P";
  548.             ELSE
  549.                 fCounter := 1;
  550.                 REPEAT
  551.                     fNameStr[0] := 0C;
  552.                     IF saveName[0] # 0C
  553.                     THEN
  554.                         Insert(fNameStr, 0, saveName);
  555.                     ELSE
  556.                         Insert(fNameStr, 0, fileName);
  557.                     END;
  558.  
  559.                     Rename(theFile, fNameStr);
  560.                     IF theFile.res = notdone
  561.                     THEN
  562.                         IF LWarning
  563.                         THEN
  564.                             pos := Length(fNameStr);
  565.                             Insert(fNameStr, pos, ".V");
  566.                             CardToString(fCounter, numStr);
  567.                             Insert(fNameStr, pos+2, numStr);
  568.                             INC(fCounter);
  569.                             Rename(theFile, fNameStr);
  570.                             IF theFile.res = done
  571.                             THEN
  572.                                 DispMsg("File saved as ");
  573.                                 WriteString(fNameStr);
  574.                             END;
  575.                         ELSE
  576.                             (* delete the old file *)
  577.                             Lookup(delFile, fNameStr, FALSE);
  578.                             Rename(delFile, "DK.");
  579.                             Close(delFile);
  580.                             Rename(theFile, fNameStr);
  581.                             IF theFile.res = done
  582.                             THEN
  583.                                 DispMsg("Old file replaced");
  584.                             END;
  585.                         END;
  586.                     END; (* THEN *)
  587.  
  588.                 UNTIL theFile.res <> notdone;
  589.  
  590.                 IF saveName[0] <> 0C
  591.                 THEN
  592.                     saveName[0] := 0C;
  593.                 END;
  594.  
  595.                 IF theFile.res <> done
  596.                 THEN
  597.                     DispMsg("Could not save the file ");
  598.                     WriteString(fNameStr);
  599.                     WriteResponse(theFile.res);
  600.                     state := "E";
  601.                     RETURN;
  602.                 END;
  603.  
  604.                 Close(theFile);
  605.                 DispPack;
  606.                 state := "F";
  607.  
  608.                 SendPacket("Y",msgNum,0,"");
  609.                 DispInit;  (* reinitialize Status display *)
  610.                 msgNum := IncPackNum(msgNum);
  611.             END; |
  612.  
  613.         "E": (* got error packet *)
  614.             PrtErrPacket(recvPack, len);
  615.             state := "E"; |
  616.  
  617.         "T": (* timeout *)
  618.             DispTry;
  619.             SendPacket("N",msgNum,0,""); |
  620.  
  621.         "A": (* user abort *)
  622.             state := "A";
  623.  
  624.         ELSE (* undefined packet type *)
  625.             state := "U";
  626.  
  627.         END;
  628.     END RecvData;
  629.  
  630.  
  631. BEGIN (* SwitchRecv *)
  632.     msgNum := 0;     (* First packet has # 0 *)
  633.     numTry := 0;     (* No retries so far *)
  634.     DispInit;        (* Initialize Status display *)
  635.     state := "R";    (* First state is receive init pack *)
  636.  
  637.     LOOP
  638.         CASE state OF
  639.         "R":
  640.             RecvInit(state); |
  641.  
  642.         "F":
  643.             RecvFile(state); |
  644.  
  645.         "D":
  646.             RecvData(state); |
  647.  
  648.         "C":
  649.             RETURN TRUE; |
  650.  
  651.         "P":
  652.             ErrorExit("Packet sequence error (M2-Kermit)");
  653.             RETURN FALSE; |
  654.  
  655.         "U":
  656.             ErrorExit("Undefined packet type (M2-Kermit)");
  657.             RETURN FALSE; |
  658.  
  659.         "T":
  660.             ErrorExit("Too many retries (M2-Kermit)");
  661.             RETURN FALSE; |
  662.  
  663.         "A":
  664.             ErrorExit("User aborted transmission (M2-Kermit)");
  665.             RETURN FALSE; |
  666.  
  667.         "E":  (* Any other Problem *);
  668.             Close(theFile);
  669.             RETURN FALSE;
  670.  
  671.         ELSE
  672.             ErrorExit("Undefined State (M2-Kermit)");
  673.             RETURN FALSE;
  674.  
  675.         END;
  676.     END;
  677. END SwitchRecv;
  678.  
  679. (************************************************************************)
  680.                             PROCEDURE Receive;
  681. (************************************************************************)
  682. BEGIN
  683.     IF SwitchRecv(Param1)
  684.     THEN
  685.         DispMsg("Receive successful");
  686.     END;
  687.     SetPos(27,0);
  688. END Receive;
  689.  
  690. END KermRecv.
  691.