home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / pibterm / pibt41s4.arc / RECEIVK2.MOD < prev    next >
Text File  |  1988-03-23  |  55KB  |  1,538 lines

  1. (*----------------------------------------------------------------------*)
  2. (*     Kermit_Receive_File --- get file data from remote Kermit         *)
  3. (*----------------------------------------------------------------------*)
  4.  
  5. PROCEDURE Kermit_Receive_File;
  6.  
  7. (*----------------------------------------------------------------------*)
  8. (*                                                                      *)
  9. (*     Procedure:  Kermit_Receive_File                                  *)
  10. (*                                                                      *)
  11. (*     Purpose:    Gets file data from remote Kermit                    *)
  12. (*                                                                      *)
  13. (*     Calling Sequence:                                                *)
  14. (*                                                                      *)
  15. (*        Kermit_Receive_File;                                          *)
  16. (*                                                                      *)
  17. (*     Remarks:                                                         *)
  18. (*                                                                      *)
  19. (*        This procedure receives file data from the remote Kermit      *)
  20. (*        until a Break packet, and End packet, or an Unknown packet    *)
  21. (*        is received.  It will also abort if there are too many        *)
  22. (*        retries.                                                      *)
  23. (*                                                                      *)
  24. (*----------------------------------------------------------------------*)
  25.  
  26. VAR
  27.    Try               : INTEGER;
  28.    Save_Retry        : INTEGER;
  29.    Data_Place        : INTEGER;
  30.    Windowing_Started : BOOLEAN;
  31.  
  32. (*----------------------------------------------------------------------*)
  33. (*             Send_Abort_Packet --- Send abort transfer request        *)
  34. (*----------------------------------------------------------------------*)
  35.  
  36. PROCEDURE Send_Abort_Packet;
  37.  
  38. BEGIN (* Send_Abort_Packet *)
  39.                                    (* Send appropriate abort packet *)
  40.    CASE Kermit_Abort_Level OF
  41.  
  42.       One_File:         BEGIN
  43.                            Send_Packet_Ptr^[4] := 'Y';
  44.                            Send_Packet_Ptr^[5] := 'X';
  45.                            Send_Packet_Length  := 5;
  46.                            Display_Kermit_Message_2('Cancelling transfer of current file.');
  47.                         END;
  48.  
  49.       Entire_Protocol:  BEGIN
  50.                            Receive_Done       := TRUE;
  51.                            Abort_Done         := TRUE;
  52.                            Display_Kermit_Message_2('Cancelling entire protocol.');
  53.                         END;
  54.  
  55.       All_Files:        BEGIN
  56.                            Send_Packet_Ptr^[4] := 'Y';
  57.                            Send_Packet_Ptr^[5] := 'Z';
  58.                            Send_Packet_Length  := 5;
  59.                            Display_Kermit_Message_2('Cancelling transfer of all files.');
  60.                         END;
  61.       ELSE
  62.                         BEGIN
  63.                            Send_Packet_Ptr^[4] := 'N';
  64.                            Send_Packet_Length  := 4;
  65.                         END;
  66.    END (* CASE *);
  67.                                    (* Construct and send abort packet *)
  68.  
  69.    IF ( Kermit_Abort_Level <> Entire_Protocol ) THEN
  70.       BEGIN
  71.          Build_Packet;
  72.          Send_Packet;
  73.       END;
  74.                                    (* Ensure file tossed out *)
  75.    Toss_File := TRUE;
  76.  
  77. END   (* Send_Abort_Packet *);
  78.  
  79. (*----------------------------------------------------------------------*)
  80. (*   Kermit_Set_File_Date_And_Time  -- Set date and time on Kermit file *)
  81. (*----------------------------------------------------------------------*)
  82.  
  83. PROCEDURE Kermit_Set_File_Date_And_Time;
  84.  
  85. VAR
  86.    KDate : LONGINT;
  87.    KDateW: ARRAY[1..2] OF WORD ABSOLUTE KDate;
  88.  
  89. BEGIN (* Kermit_Set_File_Date_And_Time *)
  90.  
  91.    KDateW[1] := Kermit_File_Time;
  92.    KDateW[2] := Kermit_File_Date;
  93.  
  94.    SetFTime( XFile , KDate );
  95.  
  96. END   (* Kermit_Set_File_Date_And_Time *);
  97.  
  98. (*----------------------------------------------------------------------*)
  99. (*           Handle_Attrib_Pack --- handle one attribute packet         *)
  100. (*----------------------------------------------------------------------*)
  101.  
  102. PROCEDURE Handle_Attrib_Pack;
  103.  
  104. VAR
  105.    InPos            : INTEGER;
  106.    I                : INTEGER;
  107.    J                : INTEGER;
  108.    Len_Packet       : INTEGER;
  109.    Rejected_Attribs : FileStr;
  110.    L_Attrib         : INTEGER;
  111.    L_Attrib_Last    : INTEGER;
  112.    Attrib           : CHAR;
  113.    Date_String      : STRING[10];
  114.    Time_String      : STRING[10];
  115.    Year             : INTEGER;
  116.    Month            : INTEGER;
  117.    Day              : INTEGER;
  118.    Hour             : INTEGER;
  119.    Mins             : INTEGER;
  120.    Secs             : INTEGER;
  121.    Size_String      : STRING[10];
  122.  
  123. (*----------------------------------------------------------------------*)
  124.  
  125. FUNCTION Get_Number( S: AnyStr ) : INTEGER;
  126.  
  127. VAR
  128.    J   : INTEGER;
  129.    Sum : INTEGER;
  130.  
  131. BEGIN (* Get_Number *)
  132.  
  133.    Sum := 0;
  134.  
  135.    FOR J := 1 TO LENGTH( S ) DO
  136.       Sum := Sum * 10 + ORD( S[J] ) - ORD('0');
  137.  
  138.    Get_Number := Sum;
  139.  
  140. END   (* Get_Number *);
  141.  
  142. (*----------------------------------------------------------------------*)
  143.  
  144. PROCEDURE Extract_File_Date;
  145.  
  146. BEGIN (* Extract_File_Date *)
  147.  
  148.    Date_String      := '';
  149.    Kermit_File_Date := 0;
  150.                                    (* Extract date string *)
  151.  
  152.    WHILE ( ( I <= L_Attrib_Last ) AND ( Rec_Packet_Ptr^[I] <> ' ' ) ) DO
  153.       BEGIN
  154.          Date_String := Date_String + Rec_Packet_Ptr^[I];
  155.          INC( I );
  156.       END;
  157.                                    (* Pull apart date string.          *)
  158.                                    (* Note:  year may be 2 or 4 digits *)
  159.  
  160.    IF ( LENGTH( Date_String ) = 6 ) THEN
  161.       BEGIN
  162.          Year  := Get_Number( Date_String[1] + Date_String[2] ) + 1900;
  163.          Month := Get_Number( Date_String[3] + Date_String[4] );
  164.          Day   := Get_Number( Date_String[5] + Date_String[6] );
  165.       END
  166.    ELSE IF ( LENGTH( Date_String ) = 8 ) THEN
  167.       BEGIN
  168.          Year  := Get_Number( COPY( Date_String, 1, 4 ) );
  169.          Month := Get_Number( Date_String[5] + Date_String[6] );
  170.          Day   := Get_Number( Date_String[7] + Date_String[8] );
  171.       END
  172.    ELSE
  173.       BEGIN
  174.          Year  := 0;
  175.          Month := 0;
  176.          Day   := 0;
  177.       END;
  178.                                    (* Convert date to DOS form *)
  179.  
  180.    Kermit_File_Date := MAX( Year - 1980 , 0 ) SHL 9 + Month SHL 5 + Day;
  181.  
  182.    Kermit_Do_File_Date := ( Kermit_File_Date <> 0 );
  183. {
  184.    IF Kermit_Debug THEN
  185.       BEGIN
  186.          Write_Log('Date_String = <' + Date_String + '>', FALSE, FALSE );
  187.          IF Kermit_Do_File_Date THEN
  188.             Write_Log( 'Do_Date = YES', FALSE, FALSE )
  189.          ELSE
  190.             Write_Log( 'Do_Date = NO', FALSE, FALSE );
  191.          Write_Log('   I        = ' + IToS( I ), FALSE, FALSE );
  192.          Write_Log('   L_Attrib_Last = ' + IToS( L_Attrib_Last ), FALSE, FALSE );
  193.       END;
  194. }
  195. END   (* Extract_File_Date *);
  196.  
  197. (*----------------------------------------------------------------------*)
  198.  
  199. PROCEDURE Extract_File_Time;
  200.  
  201. BEGIN (* Extract_File_Time *)
  202.  
  203.    Time_String      := '';
  204.    Kermit_File_Time := 0;
  205. {
  206.    IF Kermit_Debug THEN
  207.       BEGIN
  208.          Write_Log('Extract_File_Time', FALSE, FALSE );
  209.          Write_Log('   I        = ' + IToS( I ), FALSE, FALSE );
  210.          Write_Log('   L_Attrib_Last = ' + IToS( L_Attrib_Last ), FALSE, FALSE );
  211.       END;
  212. }
  213.    IF ( I < L_Attrib_Last ) THEN
  214.       BEGIN
  215.          IF ( Rec_Packet_Ptr^[I] = ' ' ) THEN
  216.             INC( I );
  217.          WHILE ( I <= L_Attrib_Last ) DO
  218.             BEGIN
  219.                Time_String := Time_String + Rec_Packet_Ptr^[I];
  220.                INC( I );
  221.             END;
  222.       END;
  223.                                    (* Pull apart time string.  *)
  224.    IF ( Time_String <> '' ) THEN
  225.       BEGIN
  226.  
  227.          Hour  := Get_Number( Time_String[1] + Time_String[2] );
  228.          Mins  := Get_Number( Time_String[4] + Time_String[5] );
  229.  
  230.          IF ( LENGTH( Time_String ) > 5 ) THEN
  231.             Secs  := Get_Number( Time_String[7] + Time_String[8] )
  232.          ELSE
  233.             Secs  := 0;
  234.                                    (* Convert time to DOS form *)
  235.  
  236.          Kermit_File_Time := Hour SHL 11 OR Mins SHL 5 OR ( Secs DIV 2 );
  237.  
  238.          Kermit_Do_File_Time := TRUE;
  239.  
  240.       END;
  241. {
  242.    IF Kermit_Debug THEN
  243.       BEGIN
  244.          Write_Log('Time_String = <' + Time_String + '>', FALSE, FALSE );
  245.          IF Kermit_Do_File_Time THEN
  246.             Write_Log( 'Do_Time = YES', FALSE, FALSE )
  247.          ELSE
  248.             Write_Log( 'Do_Time = NO', FALSE, FALSE );
  249.       END;
  250. }
  251. END   (* Extract_File_Time *);
  252.  
  253. (*----------------------------------------------------------------------*)
  254.  
  255. BEGIN (* Handle_Attrib_Pack *)
  256.                                    (* Start of received packet     *)
  257.    InPos            := 1;
  258.    Len_Packet       := Rec_Packet_Length;
  259.    Rejected_Attribs := '';
  260. {
  261.    IF Kermit_Debug THEN
  262.       Write_Log('Attribute packet = <' +
  263.                 COPY( Rec_Packet_Ptr^, 1, Rec_Packet_Length ) +
  264.                 '>', FALSE, FALSE );
  265. }
  266.                                    (* Pick up attributes           *)
  267.    WHILE ( InPos < Len_Packet ) DO
  268.       BEGIN
  269.  
  270.          Attrib        := Rec_Packet_Ptr^[InPos];
  271.          L_Attrib      := ORD( Rec_Packet_Ptr^[InPos+1] ) - 32;
  272.          I             := InPos + 2;
  273.          L_Attrib_Last := L_Attrib + PRED( I );
  274. {
  275.          IF Kermit_Debug THEN
  276.             BEGIN
  277.                Write_Log('   Attribute = <' + Attrib + '>', FALSE, FALSE );
  278.             END;
  279. }
  280.          IF Kermit_Attributes THEN
  281.  
  282.             CASE Attrib OF
  283.  
  284.                '!': BEGIN (* Get approximate file size *)
  285.  
  286.                        Kermit_File_Size := Get_Number( COPY( Rec_Packet_Ptr^, I, L_Attrib ) );
  287.  
  288.                        IF Display_Status THEN
  289.                           BEGIN
  290.                              GoToXY( 25 , 4 );
  291.                              STR( Kermit_File_Size , Size_String );
  292.                              WRITE( Size_String , 'K' );
  293.                              ClrEol;
  294.                           END;
  295.  
  296.                     END   (* Get approximate file size *);
  297.  
  298.                '#': BEGIN (* Get date/time of file creation *)
  299.                        Extract_File_Date;
  300.                        Extract_File_Time;
  301.                     END;
  302.  
  303.                '1': BEGIN (* Get exact file size *)
  304.  
  305.                        Kermit_File_Size := 0;
  306.  
  307.                        FOR J := I TO ( I + L_Attrib - 1 ) DO
  308.                           IF Rec_Packet_Ptr^[J] IN ['0'..'9'] THEN
  309.                              Kermit_File_Size := Kermit_File_Size * 10 +
  310.                                                  ( ORD( Rec_Packet_Ptr^[J] ) - ORD('0') );
  311.  
  312.                        IF Display_Status THEN
  313.                           BEGIN
  314.                              GoToXY( 25 , 4 );
  315.                              STR( Kermit_File_Size , Size_String );
  316.                              WRITE( Size_String );
  317.                              ClrEol;
  318.                           END;
  319.  
  320.                     END   (* Get exact file size *);
  321.  
  322.                ELSE
  323.                   Rejected_Attribs := Rejected_Attribs + Attrib;
  324.  
  325.             END (* CASE *)
  326.  
  327.          ELSE
  328.             Rejected_Attribs := Rejected_Attribs + Attrib;
  329.  
  330.          InPos := InPos + L_Attrib + 2;
  331.  
  332.       END;
  333.                                    (* Acknowledge this packet *)
  334.    IF Kermit_Abort THEN
  335.       Send_Abort_Packet
  336.    ELSE
  337.       Send_ACK;
  338.  
  339. END   (* Handle_Attrib_Pack *);
  340.  
  341. (*----------------------------------------------------------------------*)
  342. (*             Handle_Data_Pack --- handle one data packet              *)
  343. (*----------------------------------------------------------------------*)
  344.  
  345. PROCEDURE Handle_Data_Pack;
  346.  
  347. BEGIN (* Handle_Data_Pack *)
  348.                                    (* If abort pending, send abort  *)
  349.                                    (* packet and don't expand data. *)
  350.    IF Kermit_Abort THEN
  351.       Send_Abort_Packet
  352.    ELSE
  353.       BEGIN
  354.                                    (* Else, send ACK for the data *)
  355.                                    (* packet ... *)
  356.          Send_ACK;
  357.                                    (* ... and expand data packet. *)
  358.  
  359.          IF ( NOT Expand_Packet( Rec_Packet_Ptr , Rec_Packet_Length ) ) THEN
  360.             BEGIN
  361.                Kermit_Abort       := TRUE;
  362.                Kermit_Abort_Level := One_File;
  363.             END;
  364.  
  365.       END;
  366.  
  367. END   (* Handle_Data_Pack *);
  368.  
  369. (*----------------------------------------------------------------------*)
  370. (*             Handle_End_Pack --- handle end of file packet            *)
  371. (*----------------------------------------------------------------------*)
  372.  
  373. PROCEDURE Handle_End_Pack;
  374.  
  375. VAR
  376.    Write_Count   : INTEGER;
  377.    Err           : INTEGER;
  378.    Ctrl_Z_Written: BOOLEAN;
  379.    F             : FILE;
  380.    SSize         : STRING[20];
  381.  
  382. BEGIN (* Handle_End_Pack *)
  383.                                    (* Write any remaining characters *)
  384.                                    (* in file buffer to file and     *)
  385.                                    (* close it.                      *)
  386.    Err := 0;
  387.  
  388.    IF File_Open THEN
  389.       BEGIN
  390.                                    (* Add a Ctrl-Z to file if in     *)
  391.                                    (* text mode to mark end of file. *)
  392.  
  393.          Ctrl_Z_Written := FALSE;
  394.  
  395.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) THEN
  396.             IF ( Write_Buffer^[Buffer_Pos] <> ORD( ^Z ) ) THEN
  397.                IF ( Buffer_Pos < Buffer_Size ) THEN
  398.                   BEGIN
  399.                      INC( Buffer_Pos );
  400.                      Write_Buffer^[Buffer_Pos] := ORD( ^Z );
  401.                      Ctrl_Z_Written            := TRUE;
  402.                      Buffer_Num                := Buffer_Num + 1;
  403.                   END;
  404.                                    (* Write any remaining characters in *)
  405.                                    (* buffer.                           *)
  406.  
  407.  
  408.          BlockWrite( XFile, Write_Buffer^, Buffer_Pos, Write_Count );
  409.  
  410.          Err := Int24Result;
  411.  
  412.          IF ( Write_Count <> Buffer_Pos ) THEN
  413.             Err := 1;
  414.                                    (* Write a Ctrl-Z to file if in     *)
  415.                                    (* text mode and no room in buffer. *)
  416.  
  417.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) AND
  418.             ( NOT Ctrl_Z_Written ) THEN
  419.             BEGIN
  420.                Write_Buffer^[1] := ORD( ^Z );
  421.                BlockWrite( XFile, Write_Buffer^, 1, Write_Count );
  422.                Err              := Err + Int24Result;
  423.                IF ( Write_Count <> 1 ) THEN
  424.                   Err := 1;
  425.                Buffer_Num       := Buffer_Num + 1;
  426.             END;
  427.                                    (* Set file date and time *)
  428.  
  429.          IF ( Kermit_Do_File_Date OR Kermit_Do_File_Time ) AND
  430.             Use_Time_Sent THEN
  431.                Kermit_Set_File_Date_And_Time;
  432.  
  433.                                    (* Close the file *)
  434.          CLOSE( XFile );
  435.          Err := Int24Result;
  436.                                    (* Mark file as closed. *)
  437.          File_Open   := FALSE;
  438.                                    (* Add char count this file *)
  439.                                    (* to running total         *)
  440.  
  441.          Buffer_Total := Buffer_Total + Buffer_Num;
  442.  
  443.                                    (* Display count received in log *)
  444.          STR( Buffer_Num , SSize );
  445.          Write_Log('Size of file received was ' + SSize + ' bytes' , TRUE, FALSE );
  446.  
  447.       END;
  448.  
  449.                                    (* Acknowledge last record  *)
  450.    IF ( Err = 0 ) THEN
  451.       Send_ACK
  452.    ELSE
  453.       BEGIN
  454.          Kermit_Abort       := TRUE;
  455.          Kermit_Abort_Level := One_File;
  456.          Send_Abort_Packet;
  457.                                    (* Allow reception of further packets *)
  458.  
  459.          Kermit_Abort       := FALSE;
  460.          Kermit_Abort_Level := No_Abort;
  461.       END;
  462.                                    (* And go back to waiting for *)
  463.                                    (* start of next file.        *)
  464.    Kermit_State := Receive_Header;
  465.  
  466.                                    (* Toss this file if necessary *)
  467.  
  468.    IF ( Toss_File AND Evict_Partial_Trans ) THEN
  469.       BEGIN
  470.          ASSIGN( F , Full_Name );
  471.          ERASE ( F );
  472.          Err := INT24Result;
  473.       END;
  474.  
  475. END   (* Handle_End_Pack *);
  476.  
  477. (*----------------------------------------------------------------------*)
  478. (*             Handle_Break_Packet --- Handle break packet              *)
  479. (*----------------------------------------------------------------------*)
  480.  
  481. PROCEDURE Handle_Break_Pack;
  482.  
  483. VAR
  484.    Write_Count   : INTEGER;
  485.    Err           : INTEGER;
  486.    Ctrl_Z_Written: BOOLEAN;
  487.    F             : FILE;
  488.    SSize         : STRING[20];
  489.  
  490. BEGIN (* Handle_Break_Pack *)
  491.                                    (* Write any remaining characters *)
  492.                                    (* in file buffer to file and     *)
  493.                                    (* close it.                      *)
  494.    Err := 0;
  495.  
  496.    IF File_Open THEN
  497.       BEGIN
  498.                                    (* Add a Ctrl-Z to file if in     *)
  499.                                    (* text mode to mark end of file. *)
  500.  
  501.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) THEN
  502.             IF ( Buffer_Pos < Buffer_Size ) THEN
  503.                BEGIN
  504.                   INC( Buffer_Num );
  505.                   INC( Buffer_Pos );
  506.                   Write_Buffer^[Buffer_Pos] := ORD( ^Z );
  507.                   Ctrl_Z_Written            := TRUE;
  508.                END
  509.             ELSE
  510.                Ctrl_Z_Written := FALSE;
  511.  
  512.                                    (* Write any remaining characters in *)
  513.                                    (* buffer.                           *)
  514.  
  515.          BlockWrite( XFile, Write_Buffer^, Buffer_Pos, Write_Count );
  516.  
  517.          Err         := Int24Result;
  518.  
  519.          IF ( Write_Count <> Buffer_Pos ) THEN
  520.             Err := 1;
  521.                                    (* Write a Ctrl-Z to file if in     *)
  522.                                    (* text mode and no room in buffer. *)
  523.  
  524.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) AND
  525.             ( NOT Ctrl_Z_Written ) THEN
  526.             BEGIN
  527.                Buffer_Num       := Buffer_Num + 1;
  528.                Write_Buffer^[1] := ORD( ^Z );
  529.                BlockWrite( XFile, Write_Buffer^, 1, Write_Count );
  530.                Err := Int24Result;
  531.                IF ( Write_Count <> 1 ) THEN
  532.                   Err := 1;
  533.             END;
  534.                                    (* Set file date and time *)
  535.  
  536.          IF ( Kermit_Do_File_Date OR Kermit_Do_File_Time ) AND
  537.             Use_Time_Sent THEN
  538.                Kermit_Set_File_Date_And_Time;
  539.  
  540.                                    (* Close the file *)
  541.          CLOSE( XFile );
  542.          Err := Int24Result;
  543.                                    (* Mark file as closed. *)
  544.          File_Open   := FALSE;
  545.                                    (* Add char count this file *)
  546.                                    (* to running total         *)
  547.  
  548.          Buffer_Total := Buffer_Total + Buffer_Num;
  549.  
  550.                                    (* Display count received in log *)
  551.          STR( Buffer_Num , SSize );
  552.          Write_Log('Size of file received was ' + SSize + ' bytes' , TRUE, FALSE );
  553.  
  554.       END;
  555.                                    (* Acknowledge this packet *)
  556.    IF ( Err = 0 ) THEN
  557.       Send_ACK
  558.    ELSE
  559.       BEGIN
  560.          Kermit_Abort       := TRUE;
  561.          Kermit_Abort_Level := One_File;
  562.          Send_Abort_Packet;
  563.                                    (* Allow reception of further packets *)
  564.          Kermit_Abort       := FALSE;
  565.          Kermit_Abort_Level := No_Abort;
  566.       END;
  567.                                    (* We're done with this batch of files. *)
  568.    Receive_Done := TRUE;
  569.                                    (* Toss this file if necessary *)
  570.  
  571.    IF ( Toss_File AND Evict_Partial_Trans ) THEN
  572.       BEGIN
  573.          ASSIGN( F , Full_Name );
  574.          ERASE ( F );
  575.          Err := INT24Result;
  576.       END;
  577.  
  578. END   (* Handle_Break_Pack *);
  579.  
  580. (*----------------------------------------------------------------------*)
  581. (*           Expand_Bottom_Packet --- Expand bottom packet in table     *)
  582. (*----------------------------------------------------------------------*)
  583.  
  584. PROCEDURE Expand_Bottom_Packet;
  585.  
  586. VAR
  587.    Data_Ptr : Kermit_Packet_Ptr;
  588.    Data_Len : INTEGER;
  589.  
  590. BEGIN (* Expand_Bottom_Packet *)
  591.  
  592.    IF Kermit_Queue[Kermit_Window_Bottom].ACK_Flag THEN
  593.       BEGIN
  594.                                    (* Expand the bottom packet in the *)
  595.                                    (* window and write it to disk.    *)
  596.  
  597.          WITH Kermit_Queue[Kermit_Window_Bottom] DO
  598.             BEGIN
  599.                Data_Ptr := ADDR( Sector_Data[ Data_Slot ] );
  600.                Data_Len := Data_Length;
  601. {
  602.                IF Kermit_Debug THEN
  603.                   BEGIN
  604.                      Write_Log( 'Expand packet = ' + IToS( Kermit_Window_Bottom ) , FALSE, FALSE );
  605.                      Write_Log( 'Data_Slot = ' + IToS( Data_Slot          ) , FALSE, FALSE );
  606.                      Write_Log( 'Data_Len  = ' + IToS( Data_Len           ) , FALSE, FALSE );
  607.                   END;
  608. }
  609.             END;
  610.  
  611.  
  612.          IF ( NOT Expand_Packet( Data_Ptr , Data_Len ) ) THEN
  613.             BEGIN
  614.                Kermit_Abort       := TRUE;
  615.                Kermit_Abort_Level := One_File;
  616.             END;
  617.                                    (* Move up bottom of the table. *)
  618.  
  619.          Kermit_Window_Bottom := SUCC( Kermit_Window_Bottom ) MOD 64;
  620.          DEC( Kermit_Window_Used );
  621.  
  622.       END
  623.    ELSE
  624.       BEGIN
  625.                                    (* If there's no room in the table for *)
  626.                                    (* the new packet, abort the transfer. *)
  627.  
  628.          Kermit_Abort       := TRUE;
  629.          Kermit_Abort_Level := One_File;
  630.  
  631.          Display_Kermit_Message_2('Apparent deadlock, transfer cancelled.');
  632.  
  633.       END;
  634.  
  635. END   (* Expand_Bottom_Packet *);
  636.  
  637. (*----------------------------------------------------------------------*)
  638. (* Handle_Windowed_Data_Pack --- Handle data packet in windowed transfer*)
  639. (*----------------------------------------------------------------------*)
  640.  
  641. PROCEDURE Handle_Windowed_Data_Pack;
  642.  
  643. VAR
  644.    Data_Ptr : Kermit_Packet_Ptr;
  645.    Data_Len : INTEGER;
  646.    Pack_Num : INTEGER;
  647.    Last_Num : INTEGER;
  648.    Do_Insert: BOOLEAN;
  649.  
  650. (*----------------------------------------------------------------------*)
  651. (*     Insert_Packet_In_Table --- Insert received packet into table     *)
  652. (*----------------------------------------------------------------------*)
  653.  
  654. PROCEDURE Insert_Packet_In_Table;
  655.  
  656. BEGIN (* Insert_Packet_In_Table *)
  657.  
  658.                                    (* Get offset to store data. *)
  659.  
  660.    Data_Place           := Data_Place + 96;
  661.  
  662.    IF ( ( Data_Place + 96 ) > MaxSectorLength ) THEN
  663.       Data_Place := Receive_Offset;
  664.  
  665.                                    (* Insert received packet data into table. *)
  666.  
  667.    WITH Kermit_Queue[Rec_Packet_Num] DO
  668.       BEGIN
  669.          Data_Slot       := Data_Place;
  670. {
  671.          IF Kermit_Debug THEN
  672.             BEGIN
  673.                Write_Log( '---Insert packet --- = ' + IToS( Rec_Packet_Num ) , FALSE, FALSE );
  674.                Write_Log( 'Data_Slot = ' + IToS( Data_Slot          ) , TRUE, FALSE );
  675.                Write_Log( 'Length    = ' + IToS( Rec_Packet_Length  ) , TRUE, FALSE );
  676.                Write_Log( '---End Insert    --- ' , TRUE, FALSE );
  677.             END;
  678. }
  679.          ACK_Flag        := TRUE;
  680.          Retry_Count     := 0;
  681.          Data_Length     := Rec_Packet_Length;
  682.          MOVE( Rec_Packet_Ptr^[1], Sector_Data[Data_Slot],
  683.                Rec_Packet_Length );
  684.       END;
  685.  
  686. END   (* Insert_Packet_In_Table *);
  687.  
  688. (*----------------------------------------------------------------------*)
  689. (*     PacketBeyondWindow  --- Test if packet beyond current window     *)
  690. (*----------------------------------------------------------------------*)
  691.  
  692. FUNCTION PacketBeyondWindow : BOOLEAN;
  693.  
  694. VAR
  695.    Low : INTEGER;
  696.    High: INTEGER;
  697.  
  698. BEGIN (* PacketBeyondWindow *)
  699.  
  700.    Low  := ( Kermit_Window_Top + 2           ) MOD 64;
  701.    High := ( Kermit_Window_Top + Window_Size_Used ) MOD 64;
  702.  
  703.    WHILE ( Low <> High ) AND ( Rec_Packet_Num <> Low ) DO
  704.       Low := SUCC( Low ) MOD 64;
  705.  
  706.    PacketBeyondWindow := ( Low = Rec_Packet_Num );
  707.  
  708. END   (* PacketBeyondWindow *);
  709.  
  710. (*----------------------------------------------------------------------*)
  711.  
  712. BEGIN (* Handle_Windowed_Data_Pack *)
  713.  
  714.                                    (* Indicate windowing has started   *)
  715.  
  716.    IF ( NOT Windowing_Started ) THEN
  717.       BEGIN
  718.          Windowing_Started     := TRUE;
  719.          Kermit_Window_Top     := PRED( Packet_Num ) MOD 64;
  720.          Kermit_Window_Bottom  := Packet_Num;
  721.          Kermit_Doing_Transfer := TRUE;
  722.       END;
  723.                                    (* ACKnowledge the received packet. *)
  724.    Send_ACK;
  725.                                    (* Assume we'll be inserting packet *)
  726.                                    (* into table.                      *)
  727.    Do_Insert := TRUE;
  728.                                    (* Check the sequence number of the *)
  729.                                    (* received data packet against the *)
  730.                                    (* current table bounds.            *)
  731.  
  732.    IF ( Rec_Packet_Num = ( SUCC( Kermit_Window_Top ) MOD 64 ) ) THEN
  733.       BEGIN (* Next packet in sequence *)
  734. {
  735.          IF Kermit_Debug THEN
  736.             Write_Log( '--- Next packet in sequence --- = ' + IToS( Rec_Packet_Num ) , FALSE, FALSE );
  737. }
  738.                                    (* We got the next packet in sequence. *)
  739.                                    (* See if we have to rotate the table  *)
  740.                                    (* to insert this entry.               *)
  741.  
  742.          IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  743.             Expand_Bottom_Packet;
  744.  
  745.                                    (* If we didn't abort, put the new packet *)
  746.                                    (* in the top window slot.                *)
  747.  
  748.          Kermit_Window_Top := SUCC( Kermit_Window_Top  ) MOD 64;
  749.          INC( Kermit_Window_Used );
  750.  
  751.       END (* Next packet in sequence *)
  752.  
  753.                                    (* Handle packet which fits into body of *)
  754.                                    (* table as simple insert.               *)
  755.    ELSE IF PacketInWindow THEN
  756.       (* Nothing to do here *)
  757. {
  758.       BEGIN
  759.          IF Kermit_Debug THEN
  760.             Write_Log('--- Packet was in window --- ', FALSE, FALSE);
  761.       END
  762. }
  763.                                    (* Packet is beyond current window. *)
  764.                                    (* Some packets were lost.          *)
  765.    ELSE IF PacketBeyondWindow THEN
  766.  
  767.                                    (* Packet is beyond current window. *)
  768.                                    (* Some packets were lost.          *)
  769.       BEGIN
  770.                                    (* NAK the missing packets.  Also,  *)
  771.                                    (* rotate the table up to fit in    *)
  772.                                    (* this new packet.  If we can't,   *)
  773.                                    (* abort the transfer.              *)
  774. {
  775.          IF Kermit_Debug THEN
  776.             Write_Log('--- Packet beyond window --- ', FALSE, FALSE);
  777. }
  778.          Pack_Num := SUCC( Kermit_Window_Top ) MOD 64;
  779.  
  780.          REPEAT
  781. {
  782.             IF Kermit_Debug THEN
  783.                Write_Log('---    Pack_Num = ' + IToS( Pack_Num ), FALSE, FALSE);
  784. }
  785.             Packet_Num := Pack_Num;
  786.             Send_NAK;
  787.  
  788.             IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  789.                Expand_Bottom_Packet;
  790.  
  791.             Kermit_Queue[Pack_Num].ACK_Flag := FALSE;
  792.  
  793.                                    (* Set up to insert the packet at the *)
  794.                                    (* new top of the rotated table.      *)
  795.  
  796.             Pack_Num             := SUCC( Pack_Num ) MOD 64;
  797.             Kermit_Window_Top    := SUCC( Kermit_Window_Top  ) MOD 64;
  798.  
  799.             INC( Kermit_Window_Used );
  800.  
  801.          UNTIL ( ( Pack_Num = Rec_Packet_Num ) OR Kermit_Abort );
  802.  
  803.                                    (* We may still need one more rotation *)
  804.  
  805.          IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  806.             Expand_Bottom_Packet;
  807.  
  808.                                    (* If we didn't abort, put the new packet *)
  809.                                    (* in the top window slot.                *)
  810.  
  811.          Kermit_Window_Top := SUCC( Kermit_Window_Top  ) MOD 64;
  812.          INC( Kermit_Window_Used );
  813. {
  814.          IF Kermit_Debug THEN
  815.             BEGIN
  816.                Write_Log('      New Window_Top    = ' + IToS( Kermit_Window_Top ),
  817.                          FALSE, FALSE );
  818.                Write_Log('      New Window_Bottom = ' + IToS( Kermit_Window_Bottom ),
  819.                          FALSE, FALSE );
  820.             END;
  821. }
  822.       END
  823.                                    (* Packet is completely bogus -- ignore it. *)
  824.    ELSE
  825.       Do_Insert := FALSE;
  826.  
  827.                                    (* Insert packet into table.       *)
  828.    IF ( NOT Kermit_Abort ) THEN
  829.       BEGIN
  830.          IF Do_Insert THEN
  831.             Insert_Packet_In_Table;
  832.       END
  833.    ELSE                            (* Send abort packet if necessary. *)
  834.       Send_Abort_Packet;
  835.  
  836. END   (* Handle_Windowed_Data_Pack *);
  837.  
  838. (*----------------------------------------------------------------------*)
  839. (*              Receive_Normal --- Receive file without windowing       *)
  840. (*----------------------------------------------------------------------*)
  841.  
  842. PROCEDURE Receive_Normal;
  843.  
  844. BEGIN (* Receive_Normal *)
  845.                                    (* Indicate transfer has started.  *)
  846.    Kermit_Doing_Transfer := TRUE;
  847.  
  848.                                    (* Loop over packets in file being *)
  849.                                    (* received.                       *)
  850.    REPEAT
  851.                                    (* Number of tries for a good packet *)
  852.       Try := 0;
  853.  
  854.       REPEAT
  855.                                    (* Get next packet *)
  856.          Receive_Packet;
  857.  
  858.          CASE Packet_OK OF
  859.                                    (* If packet bad *)
  860.  
  861.             FALSE : IF ( NOT Kermit_Abort ) THEN
  862.                        BEGIN
  863.                           INC( Try );
  864.                           IF ( Try = Kermit_MaxTry ) THEN
  865.                              BEGIN
  866.                                 Kermit_Abort       := TRUE;
  867.                                 Kermit_Abort_Level := One_File;
  868.                                 Kermit_Construct_Message( 'EToo many retries.' );
  869.                              END
  870.                           ELSE
  871.                              Send_NAK;
  872.                        END
  873.                     ELSE
  874.                        BEGIN
  875.                           Packet_Num           := SUCC( Packet_Num ) MOD 64;
  876.                           Kermit_Window_Top    := Rec_Packet_Num;
  877.                           Kermit_Window_Bottom := Rec_Packet_Num;
  878.                           Send_Abort_Packet;
  879.                        END;
  880.  
  881.                                    (* If packet OK *)
  882.              TRUE : BEGIN
  883.                                    (* Duplicate packet -- just ACK and *)
  884.                                    (* continue.                        *)
  885.  
  886.                        IF ( Packet_Num = Rec_Packet_Num ) THEN
  887.                           Send_ACK
  888.                        ELSE
  889.                           BEGIN
  890.  
  891.                              Packet_Num           := Rec_Packet_Num;
  892.                              Kermit_Window_Top    := Rec_Packet_Num;
  893.                              Kermit_Window_Bottom := Rec_Packet_Num;
  894.  
  895.                              CASE Kermit_Packet_Type OF
  896.                                 Data_Pack  : Handle_Data_Pack;
  897.                                 End_Pack   : Handle_End_Pack;
  898.                                 Break_Pack : Handle_Break_Pack;
  899.                                 Attrib_Pack: Handle_Attrib_Pack;
  900.                                 Header_Pack: ;
  901.                                 ELSE         Send_NAK;
  902.                              END  (* CASE *);
  903.  
  904.                           END;
  905.                     END;
  906.  
  907.          END (* CASE *);
  908.  
  909.       UNTIL ( Packet_OK OR Kermit_Abort );
  910.  
  911.    UNTIL ( Receive_Done OR Kermit_Abort OR
  912.            ( Kermit_Packet_Type = Header_Pack ) );
  913.  
  914. END (* Receive_Normal *);
  915.  
  916. (*----------------------------------------------------------------------*)
  917. (*              Receive_Windowing --- Receive file with windowing       *)
  918. (*----------------------------------------------------------------------*)
  919.  
  920. PROCEDURE Receive_Windowing;
  921.  
  922. (*----------------------------------------------------------------------*)
  923. (*   Send_NAK_For_Most_Desired --- Send NAK for most desired packet     *)
  924. (*----------------------------------------------------------------------*)
  925.  
  926. PROCEDURE Send_NAK_For_Most_Desired;
  927.  
  928. VAR
  929.    L: INTEGER;
  930.  
  931. BEGIN (* Send_NAK_For_Most_Desired *)
  932.  
  933.                                    (* If windowing started -- i.e.,  *)
  934.                                    (* a data packet has appeared --  *)
  935.                                    (* then send NAK for most desired *)
  936.                                    (* packet.  Else, send ordinary   *)
  937.                                    (* NAK.                           *)
  938.    IF Windowing_Started THEN
  939.       BEGIN
  940.                                    (* Send NAK for most wanted packet. *)
  941.                                    (* This is the first unACKd packet  *)
  942.                                    (* in the table, or, if all are     *)
  943.                                    (* ACKd, the first packet beyond    *)
  944.                                    (* the table.                       *)
  945.  
  946.          IF ( Kermit_Window_Used > 0 ) THEN
  947.             BEGIN
  948.                Packet_Num := Kermit_Window_Bottom;
  949.                WHILE ( ( Packet_Num <> Kermit_Window_Top   ) AND
  950.                        ( Kermit_Queue[Packet_Num].ACK_Flag ) ) DO
  951.                   Packet_Num := SUCC( Packet_Num ) MOD 64;
  952.                IF Kermit_Queue[Packet_Num].ACK_Flag THEN
  953.                   Packet_Num := SUCC( Packet_Num ) MOD 64;
  954.             END
  955.          ELSE
  956.             Packet_Num := SUCC( Kermit_Window_Top ) MOD 64;
  957.  
  958.                                    (* Clear possible bogus XOFF received *)
  959.                                    (* by remote system.                  *)
  960.  
  961.          IF Async_Do_XonXoff THEN
  962.             IF ( NOT Async_XOFF_Sent ) THEN
  963.                Async_Send( CHR( XON ) );
  964.  
  965.                                    (* If we timed out, send NAK, else    *)
  966.                                    (* ignore the bad packet.             *)
  967.  
  968.          IF Kermit_Retry THEN
  969.             Send_NAK;
  970.  
  971.       END
  972.    ELSE                            (* Send ordinary NAK if no windowing yet *)
  973.       BEGIN
  974.          Send_NAK;
  975.       END;
  976. {
  977.    IF Kermit_Debug THEN
  978.       BEGIN
  979.          Write_Log( 'Send_NAK_For_Most_Desired = ' + IToS( Packet_Num ), FALSE,
  980.                     FALSE );
  981.          Write_Log('   Window_Top    = ' + IToS( Kermit_Window_Top ),
  982.                    FALSE, FALSE );
  983.          Write_Log('   Window_Bottom = ' + IToS( Kermit_Window_Bottom ),
  984.                    FALSE, FALSE );
  985.          IF Kermit_Retry THEN
  986.             Write_Log('   Timed out', FALSE, FALSE )
  987.          ELSE
  988.             Write_Log('   Checksum bad', FALSE, FALSE );
  989.          L := PRED( Kermit_Window_Bottom ) MOD 64;
  990.          REPEAT
  991.             L := SUCC( L ) MOD 64;
  992.             IF Kermit_Queue[L].ACK_Flag THEN
  993.                Write_Log('      Block ' + IToS( L ) + ' ACKED', FALSE, FALSE )
  994.             ELSE
  995.                Write_Log('      Block ' + IToS( L ) + ' NOT ACKED', FALSE, FALSE );
  996.          UNTIL ( L = Kermit_Window_Top );
  997.       END;
  998. }
  999.  
  1000. END   (* Send_NAK_For_Most_Desired *);
  1001.  
  1002. (*----------------------------------------------------------------------*)
  1003. (*          OK_Packet_Received --- Handle reception of good packet      *)
  1004. (*----------------------------------------------------------------------*)
  1005.  
  1006. PROCEDURE OK_Packet_Received;
  1007.  
  1008. BEGIN (* OK_Packet_Received *)
  1009.  
  1010.    Packet_Num := Rec_Packet_Num;
  1011.  
  1012.    CASE Kermit_Packet_Type OF
  1013.  
  1014.       Data_Pack  : Handle_Windowed_Data_Pack;
  1015.  
  1016.       End_Pack,
  1017.       Break_Pack : BEGIN
  1018.                                    (* Write any remaining packets to disk *)
  1019.  
  1020.                       IF ( NOT Kermit_Abort ) THEN
  1021.                          WHILE ( ( Kermit_Window_Used > 0 ) AND
  1022.                                  ( NOT Kermit_Abort       )     ) DO
  1023.                             BEGIN
  1024.                                Expand_Bottom_Packet;
  1025.                                Update_Kermit_Display;
  1026.                             END;
  1027.  
  1028.                       IF ( Kermit_Packet_Type = Break_Pack ) THEN
  1029.                          Handle_Break_Pack
  1030.                       ELSE
  1031.                          Handle_End_Pack;
  1032.  
  1033.                    END;
  1034.  
  1035.       Attrib_Pack: IF Kermit_Attributes THEN
  1036.                       Handle_Attrib_Pack
  1037.                    ELSE
  1038.                       Send_NAK_For_Most_Desired;
  1039.  
  1040.       Header_Pack: ;
  1041.  
  1042.       ELSE         Send_NAK_For_Most_Desired;
  1043.  
  1044.    END  (* CASE *);
  1045.  
  1046. END   (* OK_Packet_Received *);
  1047.  
  1048. (*----------------------------------------------------------------------*)
  1049. (*          Bad_Packet_Received --- Handle reception of bad packet      *)
  1050. (*----------------------------------------------------------------------*)
  1051.  
  1052. PROCEDURE Bad_Packet_Received;
  1053.  
  1054. BEGIN (* Bad_Packet_Received *)
  1055.  
  1056.    IF ( NOT Kermit_Abort ) THEN
  1057.       BEGIN
  1058.                                    (* Increment tries to get good packet *)
  1059.          INC( Try );
  1060.                                    (* Abort transfer if too many *)
  1061.  
  1062.          IF ( Try = Kermit_MaxTry ) THEN
  1063.             BEGIN
  1064.                Kermit_Abort       := TRUE;
  1065.                Kermit_Abort_Level := One_File;
  1066.                Kermit_Construct_Message( 'EToo many retries.' );
  1067.             END
  1068.          ELSE
  1069.             BEGIN
  1070.                                    (* If we're in a retry mode, and an    *)
  1071.                                    (* XOFF was received, the XOFF may be  *)
  1072.                                    (* spurious, so clear it before trying *)
  1073.                                    (* again.  We also need to flush the   *)
  1074.                                    (* comm output buffer at this point    *)
  1075.                                    (* as well.                            *)
  1076.                                    (*                                     *)
  1077.                                    (* If an XOFF wasn't received, perhaps *)
  1078.                                    (* the remote system got a spurious    *)
  1079.                                    (* XOFF, so we send an XON.            *)
  1080.                                    (*                                     *)
  1081.  
  1082.                IF ( Try > 2 ) THEN
  1083.                   IF Async_XOff_Received THEN
  1084.                      BEGIN
  1085.                         Async_Flush_Output_Buffer;
  1086.                         Clear_XOFF_Received;
  1087.                      END
  1088.                   ELSE
  1089.                      IF Async_Do_XonXoff THEN
  1090.                         IF ( NOT Async_XOFF_Sent ) THEN
  1091.                            Async_Send_Now( CHR( XON ) );
  1092.  
  1093.                                    (* Not too many retries yet --      *)
  1094.                                    (* send NAK for most wanted packet. *)
  1095.  
  1096.                Send_NAK_For_Most_Desired;
  1097.  
  1098.             END;
  1099.  
  1100.       END
  1101.    ELSE
  1102.       BEGIN (* Abort found *)
  1103.  
  1104.          Packet_Num := SUCC( Kermit_Window_Top ) MOD 64;
  1105.  
  1106.          Send_Abort_Packet;
  1107.  
  1108.       END   (* Abort found *);
  1109.  
  1110. END   (* Bad_Packet_Received *);
  1111.  
  1112. (*----------------------------------------------------------------------*)
  1113.  
  1114. BEGIN (* Receive_Windowing *)
  1115.                                    (* Set window size                 *)
  1116.  
  1117.    Window_Size_Used := MAX( His_Kermit_Window_Size , 1 );
  1118.  
  1119.                                    (* Allow more retries when windowing *)
  1120.  
  1121.    Save_Retry       := Kermit_MaxTry;
  1122.    Kermit_MaxTry    := Kermit_MaxTry + Window_Size_Used;
  1123.  
  1124.                                    (* Reset send packet address to free *)
  1125.                                    (* up remainder for packets of table *)
  1126.                                    (* entries.                          *)
  1127.  
  1128.    Send_Packet_Ptr  := ADDR( Sector_Data[100] );
  1129.  
  1130.                                    (* Empty window at this point       *)
  1131.  
  1132.    Kermit_Window_Used   := 0;
  1133.    Kermit_Window_Top    := 0;
  1134.    Kermit_Window_Bottom := 0;
  1135.    Data_Place           := Receive_Offset;
  1136.    Windowing_Started    := FALSE;
  1137. {
  1138.    IF Kermit_Debug THEN
  1139.       BEGIN
  1140.          Write_Log( 'Window_Size   = ' + IToS( Window_Size_Used ) , FALSE, FALSE );
  1141.          Write_Log( 'Window_Used   = ' + IToS( Kermit_Window_Used ) , FALSE, FALSE );
  1142.          Write_Log( 'Window_Top    = ' + IToS( Kermit_Window_Top  ) , FALSE, FALSE );
  1143.          Write_Log( 'Window_Bottom = ' + IToS( Kermit_Window_Bottom ) , FALSE, FALSE );
  1144.          Write_Log( 'Data_Place    = ' + IToS( Data_Place         ) , FALSE, FALSE );
  1145.       END;
  1146. }
  1147.                                    (* Loop over packets in file being *)
  1148.                                    (* received.                       *)
  1149.    REPEAT
  1150.                                    (* Number of tries for a good packet *)
  1151.       Try := 0;
  1152.  
  1153.       REPEAT
  1154.                                    (* Get next packet *)
  1155.          Receive_Packet;
  1156. {
  1157.          IF Kermit_Debug THEN
  1158.             IF Packet_OK THEN
  1159.                Write_Log( 'Receive packet done OK  = ' + IToS( Rec_Packet_Num ),
  1160.                           FALSE, FALSE)
  1161.             ELSE
  1162.                Write_Log( 'Receive packet done BAD = ' + IToS( Rec_Packet_Num ),
  1163.                           FALSE, FALSE);
  1164. }
  1165.                                    (* Handle received packet *)
  1166.  
  1167.          IF Packet_OK THEN
  1168.             OK_Packet_Received
  1169.          ELSE
  1170.             Bad_Packet_Received;
  1171.  
  1172.       UNTIL ( Packet_OK OR Kermit_Abort );
  1173.  
  1174.    UNTIL ( Receive_Done OR Kermit_Abort OR
  1175.            ( Kermit_Packet_Type = Header_Pack ) );
  1176.  
  1177.                                    (* Reset retry counter *)
  1178.    Kermit_MaxTry    := Save_Retry;
  1179.  
  1180.                                    (* Reset send packet pointer address *)
  1181.  
  1182.    Send_Packet_Ptr  := ADDR( Sector_Data[Send_Offset] );
  1183.  
  1184.                                    (* Reset packet number *)
  1185.  
  1186.    Packet_Num       := Rec_Packet_Num;
  1187.  
  1188. END (* Receive_Windowing *);
  1189.  
  1190. (*----------------------------------------------------------------------*)
  1191.  
  1192. BEGIN (* Kermit_Receive_File *)
  1193.                                    (* Assume date/time not received   *)
  1194.    Kermit_Do_File_Date := FALSE;
  1195.    Kermit_Do_File_Time := FALSE;
  1196.                                    (* Remember start time             *)
  1197.  
  1198.    Kermit_Transfer_Start := TimeOfDay;
  1199.  
  1200.                                    (* Perform actual transfer.        *)
  1201.    IF Kermit_Do_Sliding_Win THEN
  1202.       Receive_Windowing
  1203.    ELSE
  1204.       Receive_Normal;
  1205.                                    (* Calculate transfer time *)
  1206.  
  1207.    Kermit_Transfer_End  := TimeOfDay;
  1208.    Total_Time           := Total_Time +
  1209.                            TimeDiff( Kermit_Transfer_Start ,
  1210.                                      Kermit_Transfer_End );
  1211.  
  1212.                                    (* Indicate we're through with transfer *)
  1213.    Kermit_Doing_Transfer := FALSE;
  1214.  
  1215.                                    (* Clear message lines *)
  1216.    IF ( NOT Kermit_Abort ) THEN
  1217.       Kermit_Clear_Message_Lines;
  1218.  
  1219. END    (* Kermit_Receive_File *);
  1220.  
  1221. (*----------------------------------------------------------------------*)
  1222.  
  1223. PROCEDURE Do_Kermit_Receive;
  1224.  
  1225. VAR
  1226.    C_Trans_Rate_E : ShortStr;
  1227.    C_Trans_Rate_A : ShortStr;
  1228.    Rec_Str        : AnyStr;
  1229.    W_Str          : STRING[3];
  1230.    Err            : INTEGER;
  1231.    D_Path         : AnyStr;
  1232.    Save_Close     : BOOLEAN;
  1233.    Get_String     : AnyStr;
  1234.    I              : INTEGER;
  1235.  
  1236. BEGIN  (* Do_Kermit_Receive *)
  1237.                                    (* Hide cursor *)
  1238.    CursorOff;
  1239.                                    (* Save screen *)
  1240.    Save_Screen( Kermit_Local_Save );
  1241.  
  1242.                                    (* Initialize status display information *)
  1243.    Packets_Received   := 0;
  1244.    Packets_Sent       := 0;
  1245.    Packets_Bad        := 0;
  1246.    Buffer_Num         := 0;
  1247.    Buffer_Num_Actual  := 0;
  1248.    Buffer_Total       := 0;
  1249.    Receive_Done       := FALSE;
  1250.    Kermit_MaxTry      := 5;
  1251.    Kermit_Abort       := FALSE;
  1252.    Kermit_Retry       := FALSE;
  1253.    Quoting            := FALSE;
  1254.    Kermit_Abort_Level := No_Abort;
  1255.    Total_Time         := 0;
  1256.  
  1257.                                    (* Get title   *)
  1258.    IF FileName <> '' THEN
  1259.       Kermit_Menu_Title := 'Receive file ' + FileName + ' using Kermit'
  1260.    ELSE
  1261.       Kermit_Menu_Title := 'Receive file using Kermit';
  1262.  
  1263.                                    (* Initialize status display              *)
  1264.    Initialize_Display;
  1265.  
  1266.    Write_Log( Kermit_Menu_Title, FALSE, FALSE );
  1267.  
  1268.                                    (* Allocate buffer for file data  *)
  1269.  
  1270.    Buffer_Length  := Max_Write_Buffer;
  1271.    Buffer_Size    := Buffer_Length;
  1272.  
  1273.    GetMem( Write_Buffer , Buffer_Length );
  1274.  
  1275.    IF ( Write_Buffer = NIL ) THEN
  1276.       BEGIN
  1277.          Display_Kermit_Message('  Not enough memory to perform receive.');
  1278.          Press_Any;
  1279.          Restore_Screen_And_Colors( Kermit_Local_Save );
  1280.          CursorOn;
  1281.          EXIT;
  1282.       END;
  1283.                                    (* Choose reception method depending upon *)
  1284.                                    (* whether remote system in server mode   *)
  1285.                                    (* or not.                                *)
  1286.  
  1287.    IF Kermit_Remote_Server THEN
  1288.       Kermit_State := Get_File
  1289.    ELSE
  1290.       Kermit_State := Receive_Init;
  1291.  
  1292.                                    (* Transfer not aborted yet               *)
  1293.    Abort_Done := FALSE;
  1294.                                    (* Loop over received packets             *)
  1295.    REPEAT
  1296.                                    (* Take action depending upon current *)
  1297.                                    (* Kermit state.                      *)
  1298.       CASE Kermit_State OF
  1299.  
  1300.          Get_File        : Kermit_Get;
  1301.          Receive_Init    : Kermit_Receive_Init;
  1302.          Receive_Header  : Kermit_Receive_Header;
  1303.          Receive_File    : Kermit_Receive_File;
  1304.  
  1305.       END (* CASE *);
  1306.  
  1307.    UNTIL ( Kermit_Abort OR Receive_Done );
  1308.  
  1309.                                    (* Display transfer rate *)
  1310.  
  1311.    IF ( Receive_Done AND ( NOT Abort_Done ) ) THEN
  1312.       BEGIN
  1313.  
  1314.          Display_Kermit_Message('Receive completed.');
  1315.  
  1316.          IF ( Total_Time = 0 ) THEN
  1317.             Total_Time := 1;
  1318.  
  1319.          Kermit_Transfer_Rate := Buffer_Total / ( Total_Time * 1.0 );
  1320.  
  1321.          STR( Kermit_Transfer_Rate:10:0 , C_Trans_Rate_E );
  1322.  
  1323.          Display_Kermit_Message_2('Effective transfer rate was ' +
  1324.                                   LTrim( C_Trans_Rate_E ) + ' CPS.');
  1325.  
  1326.          Kermit_Transfer_Rate := Buffer_Num_Actual / ( Total_Time * 1.0 );
  1327.  
  1328.          STR( Kermit_Transfer_Rate:10:0 , C_Trans_Rate_A );
  1329.  
  1330.          Display_Kermit_Message_3('Actual transfer rate was ' +
  1331.                                   LTrim( C_Trans_Rate_A ) + ' CPS.');
  1332.  
  1333.       END;
  1334.  
  1335.    IF Abort_Done THEN
  1336.       Write_Log('Receive cancelled.' , TRUE , FALSE );
  1337.  
  1338.                                    (* Ensure entire protocol aborted   *)
  1339.                                    (* if requested.                    *)
  1340.    Kermit_Done := Abort_Done;
  1341.  
  1342.    Window_Delay;
  1343.                                    (* Remove download buffer           *)
  1344.    MyFreeMem( Write_Buffer , Buffer_Length );
  1345.  
  1346.                                    (* Remove Kermit window             *)
  1347.  
  1348.    IF ( Kermit_Local_Save <> NIL ) THEN
  1349.       Restore_Screen_And_Colors( Kermit_Local_Save );
  1350.  
  1351.                                    (* Display cursor again *)
  1352.    CursorOn;
  1353.                                    (* Signal transfer done *)
  1354.    IF ( NOT Silent_Mode ) THEN
  1355.       FOR I := 1 TO Transfer_Bells DO
  1356.          Menu_Beep;
  1357.  
  1358. END    (* Do_Kermit_Receive *);
  1359.  
  1360. (*----------------------------------------------------------------------*)
  1361.  
  1362. PROCEDURE Get_File_Pattern;
  1363.  
  1364. BEGIN (* Get_File_Pattern *)
  1365.                                    (* Get file name from kbd/screen *)
  1366.  
  1367.    IF ( LENGTH( FileName ) = 0 ) THEN
  1368.       IF Auto_Find_FileNames THEN
  1369.          Get_Auto_File_Name( Saved_Kbd_File_Name , FileName );
  1370.  
  1371.    Draw_Titled_Box( Local_Save, 10, 5, 78, 8, '' );
  1372.  
  1373.    PibTerm_Window( 11, 6, 77, 7 );
  1374.  
  1375.    GoToXY( 2 , 1 );
  1376.  
  1377.    WRITE('File to receive: ');
  1378.  
  1379.    IF ( ( NOT ( Host_Mode OR Script_Transfer ) ) OR ( LENGTH( FileName ) = 0 ) ) THEN
  1380.       BEGIN
  1381.          FileName := FileName;
  1382.          Read_Edited_String( FileName );
  1383.          IF ( FileName = CHR( ESC ) ) THEN
  1384.             FileName := '';
  1385.          WRITELN;
  1386.       END
  1387.    ELSE
  1388.       WRITELN( FileName );
  1389.  
  1390.    Restore_Screen_And_Colors( Local_Save );
  1391.  
  1392. END   (* Get_File_Pattern *);
  1393.  
  1394. (*----------------------------------------------------------------------*)
  1395.  
  1396. BEGIN (* Receive_Kermit_File *)
  1397.                                    (* Get Kermit menu *)
  1398.  
  1399.    Make_A_Menu( Kermit_Menu, Receive_Quit_Item, 6, 20, 40, 9, Receive_Quit_Item,
  1400.                 'Choose Kermit function: ',
  1401.                 'a) GET Text File;b) GET Binary file;c) RECEIVE Text File;' +
  1402.                 'd) RECEIVE Binary File;' +
  1403.                 'f) Finish Remote Server;l) Logout Remote Server;' +
  1404.                 'r) Remote Server Commands;t) Transfer to Send File Menu;' +
  1405.                 'q) Quit Kermit',
  1406.                 FALSE );
  1407.  
  1408.    Kermit_Done            := FALSE;
  1409.    Sending_File           := FALSE;
  1410.    Host_Count             := 0;
  1411.    Send_Packet_Ptr        := ADDR( Sector_Data[Send_Offset] );
  1412.    Send_Packet_Ptr^[2]    := CHR( 0 );
  1413.    Send_Packet_Ptr^[3]    := CHR( 0 );
  1414.    Send_Packet_Ptr^[4]    := CHR( 0 );
  1415.    Initial_SOH_Received   := Doing_Kermit_Autodown;
  1416.  
  1417.    REPEAT
  1418.                                    (* Reinitialize Kermit variables *)
  1419.       Kermit_Init;
  1420.                                    (* No remote command yet         *)
  1421.       Remote_Comm := '';
  1422.                                    (* Display Kermit receive menu   *)
  1423.  
  1424.       IF ( NOT ( Host_Mode OR Script_Transfer OR Doing_Kermit_Autodown ) ) THEN
  1425.          BEGIN
  1426.             Menu_Display_Choices( Kermit_Menu );
  1427.             Menu_Choice := Menu_Get_Choice( Kermit_Menu , Erase_Menu );
  1428.          END
  1429.       ELSE
  1430.          BEGIN
  1431.  
  1432.             INC( Host_Count );
  1433.  
  1434.             IF ( Host_Count = 1 ) THEN
  1435.                IF ( Doing_Kermit_Autodown ) THEN
  1436.                   Menu_Choice := 4
  1437.                ELSE
  1438.                   BEGIN
  1439.  
  1440.                      IF ( Kermit_File_Type_Var <> Kermit_Binary ) THEN
  1441.                         IF ( LENGTH( FileName ) > 0 ) THEN
  1442.                            Menu_Choice := 1
  1443.                         ELSE
  1444.                            Menu_Choice := 3
  1445.                      ELSE
  1446.                         IF ( LENGTH( FileName ) > 0 ) THEN
  1447.                            Menu_Choice := 2
  1448.                         ELSE
  1449.                            Menu_Choice := 4;
  1450.  
  1451.                      IF ( LENGTH( FileName ) > 0 ) THEN
  1452.                         IF ( FileName[1] = '/' ) THEN
  1453.                            BEGIN
  1454.                               Menu_Choice := 7;
  1455.                               Remote_Comm := FileName;
  1456.                            END;
  1457.  
  1458.                   END
  1459.             ELSE
  1460.                Menu_Choice := Receive_Quit_Item;
  1461.  
  1462.          END;
  1463.                                    (* Perform desired Kermit function *)
  1464.       CASE Menu_Choice OF
  1465.  
  1466.          1: BEGIN
  1467.                Kermit_File_Type_Var := Kermit_Ascii;
  1468.                Get_File_Pattern;
  1469.                Kermit_Remote_Server := TRUE;
  1470.                IF ( LENGTH( FileName ) > 0 ) THEN
  1471.                   Do_Kermit_Receive;
  1472.             END;
  1473.  
  1474.          2: BEGIN
  1475.                Kermit_File_Type_Var := Kermit_Binary;
  1476.                Get_File_Pattern;
  1477.                Kermit_Remote_Server := TRUE;
  1478.                IF ( LENGTH( FileName ) > 0 ) THEN
  1479.                   Do_Kermit_Receive;
  1480.             END;
  1481.  
  1482.          3: BEGIN
  1483.                Kermit_File_Type_Var := Kermit_Ascii;
  1484.                FileName := '';
  1485.                Kermit_Remote_Server := FALSE;
  1486.                Do_Kermit_Receive;
  1487.             END;
  1488.  
  1489.          4: BEGIN
  1490.                Kermit_File_Type_Var := Kermit_Binary;
  1491.                FileName := '';
  1492.                Kermit_Remote_Server := FALSE;
  1493.                Do_Kermit_Receive;
  1494.             END;
  1495.  
  1496.          5: BEGIN
  1497.                Kermit_Finish_Server( 'F' );
  1498.             END;
  1499.  
  1500.          6: BEGIN
  1501.                Kermit_Finish_Server( 'L' );
  1502.             END;
  1503.  
  1504.          7: BEGIN
  1505.                Kermit_Remote_Commands( Remote_Comm , Do_A_Receive );
  1506.                FileName := '';
  1507.                Kermit_Remote_Server := FALSE;
  1508.                IF Do_A_Receive THEN
  1509.                   Do_Kermit_Receive;
  1510.             END;
  1511.  
  1512.          8: BEGIN
  1513.                Kermit_Done  := TRUE;
  1514.                Sending_File := TRUE;
  1515.             END;
  1516.  
  1517.          ELSE
  1518.             BEGIN
  1519.                Kermit_Done := TRUE;
  1520.             END;
  1521.  
  1522.       END (* CASE *);
  1523.  
  1524.    UNTIL Kermit_Done;
  1525.                                    (* Ensure status window restored        *)
  1526.    IF Do_Status_Line THEN
  1527.       PibTerm_Window( 1, 1, Max_Screen_Col, Max_Screen_Line - 1 );
  1528.  
  1529.                                    (* Ensure switch to send code if needed *)
  1530.  
  1531.    Kermit_Really_Done := ( NOT Sending_File );
  1532.    FileName           := '';
  1533.  
  1534.                                    (* Turn off autodownload in progress *)
  1535.    Doing_Kermit_Autodown := FALSE;
  1536.  
  1537. END   (* Receive_Kermit_File *);
  1538.