home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / pibsoft / terminal / source / receivk2.mod < prev    next >
Encoding:
Text File  |  1988-03-06  |  52.9 KB  |  1,528 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.  
  381. BEGIN (* Handle_End_Pack *)
  382.                                    (* Write any remaining characters *)
  383.                                    (* in file buffer to file and     *)
  384.                                    (* close it.                      *)
  385.    Err := 0;
  386.  
  387.    IF File_Open THEN
  388.       BEGIN
  389.                                    (* Add a Ctrl-Z to file if in     *)
  390.                                    (* text mode to mark end of file. *)
  391.  
  392.          Ctrl_Z_Written := FALSE;
  393.  
  394.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) THEN
  395.             IF ( Write_Buffer^[Buffer_Pos] <> ORD( ^Z ) ) THEN
  396.                IF ( Buffer_Pos < Buffer_Size ) THEN
  397.                   BEGIN
  398.                      INC( Buffer_Pos );
  399.                      Write_Buffer^[Buffer_Pos] := ORD( ^Z );
  400.                      Ctrl_Z_Written            := TRUE;
  401.                      Buffer_Num                := Buffer_Num + 1;
  402.                   END;
  403.                                    (* Write any remaining characters in *)
  404.                                    (* buffer.                           *)
  405.  
  406.  
  407.          BlockWrite( XFile, Write_Buffer^, Buffer_Pos, Write_Count );
  408.  
  409.          Err := Int24Result;
  410.  
  411.          IF ( Write_Count <> Buffer_Pos ) THEN
  412.             Err := 1;
  413.                                    (* Write a Ctrl-Z to file if in     *)
  414.                                    (* text mode and no room in buffer. *)
  415.  
  416.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) AND
  417.             ( NOT Ctrl_Z_Written ) THEN
  418.             BEGIN
  419.                Write_Buffer^[1] := ORD( ^Z );
  420.                BlockWrite( XFile, Write_Buffer^, 1, Write_Count );
  421.                Err              := Err + Int24Result;
  422.                IF ( Write_Count <> 1 ) THEN
  423.                   Err := 1;
  424.                Buffer_Num       := Buffer_Num + 1;
  425.             END;
  426.                                    (* Set file date and time *)
  427.  
  428.          IF ( Kermit_Do_File_Date OR Kermit_Do_File_Time ) AND
  429.             Use_Time_Sent THEN
  430.                Kermit_Set_File_Date_And_Time;
  431.  
  432.                                    (* Close the file *)
  433.          CLOSE( XFile );
  434.          Err := Int24Result;
  435.                                    (* Mark file as closed. *)
  436.          File_Open   := FALSE;
  437.                                    (* Add char count this file *)
  438.                                    (* to running total         *)
  439.  
  440.          Buffer_Total := Buffer_Total + Buffer_Num;
  441.  
  442.       END;
  443.  
  444.                                    (* Acknowledge last record  *)
  445.    IF ( Err = 0 ) THEN
  446.       Send_ACK
  447.    ELSE
  448.       BEGIN
  449.          Kermit_Abort       := TRUE;
  450.          Kermit_Abort_Level := One_File;
  451.          Send_Abort_Packet;
  452.                                    (* Allow reception of further packets *)
  453.  
  454.          Kermit_Abort       := FALSE;
  455.          Kermit_Abort_Level := No_Abort;
  456.       END;
  457.                                    (* And go back to waiting for *)
  458.                                    (* start of next file.        *)
  459.    Kermit_State := Receive_Header;
  460.  
  461.                                    (* Toss this file if necessary *)
  462.  
  463.    IF ( Toss_File AND Evict_Partial_Trans ) THEN
  464.       BEGIN
  465.          ASSIGN( F , Full_Name );
  466.          ERASE ( F );
  467.          Err := INT24Result;
  468.       END;
  469.  
  470. END   (* Handle_End_Pack *);
  471.  
  472. (*----------------------------------------------------------------------*)
  473. (*             Handle_Break_Packet --- Handle break packet              *)
  474. (*----------------------------------------------------------------------*)
  475.  
  476. PROCEDURE Handle_Break_Pack;
  477.  
  478. VAR
  479.    Write_Count   : INTEGER;
  480.    Err           : INTEGER;
  481.    Ctrl_Z_Written: BOOLEAN;
  482.    F             : FILE;
  483.  
  484. BEGIN (* Handle_Break_Pack *)
  485.                                    (* Write any remaining characters *)
  486.                                    (* in file buffer to file and     *)
  487.                                    (* close it.                      *)
  488.    Err := 0;
  489.  
  490.    IF File_Open THEN
  491.       BEGIN
  492.                                    (* Add a Ctrl-Z to file if in     *)
  493.                                    (* text mode to mark end of file. *)
  494.  
  495.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) THEN
  496.             IF ( Buffer_Pos < Buffer_Size ) THEN
  497.                BEGIN
  498.                   INC( Buffer_Num );
  499.                   INC( Buffer_Pos );
  500.                   Write_Buffer^[Buffer_Pos] := ORD( ^Z );
  501.                   Ctrl_Z_Written            := TRUE;
  502.                END
  503.             ELSE
  504.                Ctrl_Z_Written := FALSE;
  505.  
  506.                                    (* Write any remaining characters in *)
  507.                                    (* buffer.                           *)
  508.  
  509.          BlockWrite( XFile, Write_Buffer^, Buffer_Pos, Write_Count );
  510.  
  511.          Err         := Int24Result;
  512.  
  513.          IF ( Write_Count <> Buffer_Pos ) THEN
  514.             Err := 1;
  515.                                    (* Write a Ctrl-Z to file if in     *)
  516.                                    (* text mode and no room in buffer. *)
  517.  
  518.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) AND
  519.             ( NOT Ctrl_Z_Written ) THEN
  520.             BEGIN
  521.                Buffer_Num       := Buffer_Num + 1;
  522.                Write_Buffer^[1] := ORD( ^Z );
  523.                BlockWrite( XFile, Write_Buffer^, 1, Write_Count );
  524.                Err := Int24Result;
  525.                IF ( Write_Count <> 1 ) THEN
  526.                   Err := 1;
  527.             END;
  528.                                    (* Set file date and time *)
  529.  
  530.          IF ( Kermit_Do_File_Date OR Kermit_Do_File_Time ) AND
  531.             Use_Time_Sent THEN
  532.                Kermit_Set_File_Date_And_Time;
  533.  
  534.                                    (* Close the file *)
  535.          CLOSE( XFile );
  536.          Err := Int24Result;
  537.                                    (* Mark file as closed. *)
  538.          File_Open   := FALSE;
  539.                                    (* Add char count this file *)
  540.                                    (* to running total         *)
  541.  
  542.          Buffer_Total := Buffer_Total + Buffer_Num;
  543.  
  544.       END;
  545.                                    (* Acknowledge this packet *)
  546.    IF ( Err = 0 ) THEN
  547.       Send_ACK
  548.    ELSE
  549.       BEGIN
  550.          Kermit_Abort       := TRUE;
  551.          Kermit_Abort_Level := One_File;
  552.          Send_Abort_Packet;
  553.                                    (* Allow reception of further packets *)
  554.          Kermit_Abort       := FALSE;
  555.          Kermit_Abort_Level := No_Abort;
  556.       END;
  557.                                    (* We're done with this batch of files. *)
  558.    Receive_Done := TRUE;
  559.                                    (* Toss this file if necessary *)
  560.  
  561.    IF ( Toss_File AND Evict_Partial_Trans ) THEN
  562.       BEGIN
  563.          ASSIGN( F , Full_Name );
  564.          ERASE ( F );
  565.          Err := INT24Result;
  566.       END;
  567.  
  568. END   (* Handle_Break_Pack *);
  569.  
  570. (*----------------------------------------------------------------------*)
  571. (*           Expand_Bottom_Packet --- Expand bottom packet in table     *)
  572. (*----------------------------------------------------------------------*)
  573.  
  574. PROCEDURE Expand_Bottom_Packet;
  575.  
  576. VAR
  577.    Data_Ptr : Kermit_Packet_Ptr;
  578.    Data_Len : INTEGER;
  579.  
  580. BEGIN (* Expand_Bottom_Packet *)
  581.  
  582.    IF Kermit_Queue[Kermit_Window_Bottom].ACK_Flag THEN
  583.       BEGIN
  584.                                    (* Expand the bottom packet in the *)
  585.                                    (* window and write it to disk.    *)
  586.  
  587.          WITH Kermit_Queue[Kermit_Window_Bottom] DO
  588.             BEGIN
  589.                Data_Ptr := ADDR( Sector_Data[ Data_Slot ] );
  590.                Data_Len := Data_Length;
  591. {
  592.                IF Kermit_Debug THEN
  593.                   BEGIN
  594.                      Write_Log( 'Expand packet = ' + IToS( Kermit_Window_Bottom ) , FALSE, FALSE );
  595.                      Write_Log( 'Data_Slot = ' + IToS( Data_Slot          ) , FALSE, FALSE );
  596.                      Write_Log( 'Data_Len  = ' + IToS( Data_Len           ) , FALSE, FALSE );
  597.                   END;
  598. }
  599.             END;
  600.  
  601.  
  602.          IF ( NOT Expand_Packet( Data_Ptr , Data_Len ) ) THEN
  603.             BEGIN
  604.                Kermit_Abort       := TRUE;
  605.                Kermit_Abort_Level := One_File;
  606.             END;
  607.                                    (* Move up bottom of the table. *)
  608.  
  609.          Kermit_Window_Bottom := SUCC( Kermit_Window_Bottom ) MOD 64;
  610.          DEC( Kermit_Window_Used );
  611.  
  612.       END
  613.    ELSE
  614.       BEGIN
  615.                                    (* If there's no room in the table for *)
  616.                                    (* the new packet, abort the transfer. *)
  617.  
  618.          Kermit_Abort       := TRUE;
  619.          Kermit_Abort_Level := One_File;
  620.  
  621.          Display_Kermit_Message_2('Apparent deadlock, transfer cancelled.');
  622.  
  623.       END;
  624.  
  625. END   (* Expand_Bottom_Packet *);
  626.  
  627. (*----------------------------------------------------------------------*)
  628. (* Handle_Windowed_Data_Pack --- Handle data packet in windowed transfer*)
  629. (*----------------------------------------------------------------------*)
  630.  
  631. PROCEDURE Handle_Windowed_Data_Pack;
  632.  
  633. VAR
  634.    Data_Ptr : Kermit_Packet_Ptr;
  635.    Data_Len : INTEGER;
  636.    Pack_Num : INTEGER;
  637.    Last_Num : INTEGER;
  638.    Do_Insert: BOOLEAN;
  639.  
  640. (*----------------------------------------------------------------------*)
  641. (*     Insert_Packet_In_Table --- Insert received packet into table     *)
  642. (*----------------------------------------------------------------------*)
  643.  
  644. PROCEDURE Insert_Packet_In_Table;
  645.  
  646. BEGIN (* Insert_Packet_In_Table *)
  647.  
  648.                                    (* Get offset to store data. *)
  649.  
  650.    Data_Place           := Data_Place + 96;
  651.  
  652.    IF ( ( Data_Place + 96 ) > MaxSectorLength ) THEN
  653.       Data_Place := Receive_Offset;
  654.  
  655.                                    (* Insert received packet data into table. *)
  656.  
  657.    WITH Kermit_Queue[Rec_Packet_Num] DO
  658.       BEGIN
  659.          Data_Slot       := Data_Place;
  660. {
  661.          IF Kermit_Debug THEN
  662.             BEGIN
  663.                Write_Log( '---Insert packet --- = ' + IToS( Rec_Packet_Num ) , FALSE, FALSE );
  664.                Write_Log( 'Data_Slot = ' + IToS( Data_Slot          ) , TRUE, FALSE );
  665.                Write_Log( 'Length    = ' + IToS( Rec_Packet_Length  ) , TRUE, FALSE );
  666.                Write_Log( '---End Insert    --- ' , TRUE, FALSE );
  667.             END;
  668. }
  669.          ACK_Flag        := TRUE;
  670.          Retry_Count     := 0;
  671.          Data_Length     := Rec_Packet_Length;
  672.          MOVE( Rec_Packet_Ptr^[1], Sector_Data[Data_Slot],
  673.                Rec_Packet_Length );
  674.       END;
  675.  
  676. END   (* Insert_Packet_In_Table *);
  677.  
  678. (*----------------------------------------------------------------------*)
  679. (*     PacketBeyondWindow  --- Test if packet beyond current window     *)
  680. (*----------------------------------------------------------------------*)
  681.  
  682. FUNCTION PacketBeyondWindow : BOOLEAN;
  683.  
  684. VAR
  685.    Low : INTEGER;
  686.    High: INTEGER;
  687.  
  688. BEGIN (* PacketBeyondWindow *)
  689.  
  690.    Low  := ( Kermit_Window_Top + 2           ) MOD 64;
  691.    High := ( Kermit_Window_Top + Window_Size_Used ) MOD 64;
  692.  
  693.    WHILE ( Low <> High ) AND ( Rec_Packet_Num <> Low ) DO
  694.       Low := SUCC( Low ) MOD 64;
  695.  
  696.    PacketBeyondWindow := ( Low = Rec_Packet_Num );
  697.  
  698. END   (* PacketBeyondWindow *);
  699.  
  700. (*----------------------------------------------------------------------*)
  701.  
  702. BEGIN (* Handle_Windowed_Data_Pack *)
  703.  
  704.                                    (* Indicate windowing has started   *)
  705.  
  706.    IF ( NOT Windowing_Started ) THEN
  707.       BEGIN
  708.          Windowing_Started     := TRUE;
  709.          Kermit_Window_Top     := PRED( Packet_Num ) MOD 64;
  710.          Kermit_Window_Bottom  := Packet_Num;
  711.          Kermit_Doing_Transfer := TRUE;
  712.       END;
  713.                                    (* ACKnowledge the received packet. *)
  714.    Send_ACK;
  715.                                    (* Assume we'll be inserting packet *)
  716.                                    (* into table.                      *)
  717.    Do_Insert := TRUE;
  718.                                    (* Check the sequence number of the *)
  719.                                    (* received data packet against the *)
  720.                                    (* current table bounds.            *)
  721.  
  722.    IF ( Rec_Packet_Num = ( SUCC( Kermit_Window_Top ) MOD 64 ) ) THEN
  723.       BEGIN (* Next packet in sequence *)
  724. {
  725.          IF Kermit_Debug THEN
  726.             Write_Log( '--- Next packet in sequence --- = ' + IToS( Rec_Packet_Num ) , FALSE, FALSE );
  727. }
  728.                                    (* We got the next packet in sequence. *)
  729.                                    (* See if we have to rotate the table  *)
  730.                                    (* to insert this entry.               *)
  731.  
  732.          IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  733.             Expand_Bottom_Packet;
  734.  
  735.                                    (* If we didn't abort, put the new packet *)
  736.                                    (* in the top window slot.                *)
  737.  
  738.          Kermit_Window_Top := SUCC( Kermit_Window_Top  ) MOD 64;
  739.          INC( Kermit_Window_Used );
  740.  
  741.       END (* Next packet in sequence *)
  742.  
  743.                                    (* Handle packet which fits into body of *)
  744.                                    (* table as simple insert.               *)
  745.    ELSE IF PacketInWindow THEN
  746.       (* Nothing to do here *)
  747. {
  748.       BEGIN
  749.          IF Kermit_Debug THEN
  750.             Write_Log('--- Packet was in window --- ', FALSE, FALSE);
  751.       END
  752. }
  753.                                    (* Packet is beyond current window. *)
  754.                                    (* Some packets were lost.          *)
  755.    ELSE IF PacketBeyondWindow THEN
  756.  
  757.                                    (* Packet is beyond current window. *)
  758.                                    (* Some packets were lost.          *)
  759.       BEGIN
  760.                                    (* NAK the missing packets.  Also,  *)
  761.                                    (* rotate the table up to fit in    *)
  762.                                    (* this new packet.  If we can't,   *)
  763.                                    (* abort the transfer.              *)
  764. {
  765.          IF Kermit_Debug THEN
  766.             Write_Log('--- Packet beyond window --- ', FALSE, FALSE);
  767. }
  768.          Pack_Num := SUCC( Kermit_Window_Top ) MOD 64;
  769.  
  770.          REPEAT
  771. {
  772.             IF Kermit_Debug THEN
  773.                Write_Log('---    Pack_Num = ' + IToS( Pack_Num ), FALSE, FALSE);
  774. }
  775.             Packet_Num := Pack_Num;
  776.             Send_NAK;
  777.  
  778.             IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  779.                Expand_Bottom_Packet;
  780.  
  781.             Kermit_Queue[Pack_Num].ACK_Flag := FALSE;
  782.  
  783.                                    (* Set up to insert the packet at the *)
  784.                                    (* new top of the rotated table.      *)
  785.  
  786.             Pack_Num             := SUCC( Pack_Num ) MOD 64;
  787.             Kermit_Window_Top    := SUCC( Kermit_Window_Top  ) MOD 64;
  788.  
  789.             INC( Kermit_Window_Used );
  790.  
  791.          UNTIL ( ( Pack_Num = Rec_Packet_Num ) OR Kermit_Abort );
  792.  
  793.                                    (* We may still need one more rotation *)
  794.  
  795.          IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  796.             Expand_Bottom_Packet;
  797.  
  798.                                    (* If we didn't abort, put the new packet *)
  799.                                    (* in the top window slot.                *)
  800.  
  801.          Kermit_Window_Top := SUCC( Kermit_Window_Top  ) MOD 64;
  802.          INC( Kermit_Window_Used );
  803. {
  804.          IF Kermit_Debug THEN
  805.             BEGIN
  806.                Write_Log('      New Window_Top    = ' + IToS( Kermit_Window_Top ),
  807.                          FALSE, FALSE );
  808.                Write_Log('      New Window_Bottom = ' + IToS( Kermit_Window_Bottom ),
  809.                          FALSE, FALSE );
  810.             END;
  811. }
  812.       END
  813.                                    (* Packet is completely bogus -- ignore it. *)
  814.    ELSE
  815.       Do_Insert := FALSE;
  816.  
  817.                                    (* Insert packet into table.       *)
  818.    IF ( NOT Kermit_Abort ) THEN
  819.       BEGIN
  820.          IF Do_Insert THEN
  821.             Insert_Packet_In_Table;
  822.       END
  823.    ELSE                            (* Send abort packet if necessary. *)
  824.       Send_Abort_Packet;
  825.  
  826. END   (* Handle_Windowed_Data_Pack *);
  827.  
  828. (*----------------------------------------------------------------------*)
  829. (*              Receive_Normal --- Receive file without windowing       *)
  830. (*----------------------------------------------------------------------*)
  831.  
  832. PROCEDURE Receive_Normal;
  833.  
  834. BEGIN (* Receive_Normal *)
  835.                                    (* Indicate transfer has started.  *)
  836.    Kermit_Doing_Transfer := TRUE;
  837.  
  838.                                    (* Loop over packets in file being *)
  839.                                    (* received.                       *)
  840.    REPEAT
  841.                                    (* Number of tries for a good packet *)
  842.       Try := 0;
  843.  
  844.       REPEAT
  845.                                    (* Get next packet *)
  846.          Receive_Packet;
  847.  
  848.          CASE Packet_OK OF
  849.                                    (* If packet bad *)
  850.  
  851.             FALSE : IF ( NOT Kermit_Abort ) THEN
  852.                        BEGIN
  853.                           INC( Try );
  854.                           IF ( Try = Kermit_MaxTry ) THEN
  855.                              BEGIN
  856.                                 Kermit_Abort       := TRUE;
  857.                                 Kermit_Abort_Level := One_File;
  858.                                 Kermit_Construct_Message( 'EToo many retries.' );
  859.                              END
  860.                           ELSE
  861.                              Send_NAK;
  862.                        END
  863.                     ELSE
  864.                        BEGIN
  865.                           Packet_Num           := SUCC( Packet_Num ) MOD 64;
  866.                           Kermit_Window_Top    := Rec_Packet_Num;
  867.                           Kermit_Window_Bottom := Rec_Packet_Num;
  868.                           Send_Abort_Packet;
  869.                        END;
  870.  
  871.                                    (* If packet OK *)
  872.              TRUE : BEGIN
  873.                                    (* Duplicate packet -- just ACK and *)
  874.                                    (* continue.                        *)
  875.  
  876.                        IF ( Packet_Num = Rec_Packet_Num ) THEN
  877.                           Send_ACK
  878.                        ELSE
  879.                           BEGIN
  880.  
  881.                              Packet_Num           := Rec_Packet_Num;
  882.                              Kermit_Window_Top    := Rec_Packet_Num;
  883.                              Kermit_Window_Bottom := Rec_Packet_Num;
  884.  
  885.                              CASE Kermit_Packet_Type OF
  886.                                 Data_Pack  : Handle_Data_Pack;
  887.                                 End_Pack   : Handle_End_Pack;
  888.                                 Break_Pack : Handle_Break_Pack;
  889.                                 Attrib_Pack: Handle_Attrib_Pack;
  890.                                 Header_Pack: ;
  891.                                 ELSE         Send_NAK;
  892.                              END  (* CASE *);
  893.  
  894.                           END;
  895.                     END;
  896.  
  897.          END (* CASE *);
  898.  
  899.       UNTIL ( Packet_OK OR Kermit_Abort );
  900.  
  901.    UNTIL ( Receive_Done OR Kermit_Abort OR
  902.            ( Kermit_Packet_Type = Header_Pack ) );
  903.  
  904. END (* Receive_Normal *);
  905.  
  906. (*----------------------------------------------------------------------*)
  907. (*              Receive_Windowing --- Receive file with windowing       *)
  908. (*----------------------------------------------------------------------*)
  909.  
  910. PROCEDURE Receive_Windowing;
  911.  
  912. (*----------------------------------------------------------------------*)
  913. (*   Send_NAK_For_Most_Desired --- Send NAK for most desired packet     *)
  914. (*----------------------------------------------------------------------*)
  915.  
  916. PROCEDURE Send_NAK_For_Most_Desired;
  917.  
  918. VAR
  919.    L: INTEGER;
  920.  
  921. BEGIN (* Send_NAK_For_Most_Desired *)
  922.  
  923.                                    (* If windowing started -- i.e.,  *)
  924.                                    (* a data packet has appeared --  *)
  925.                                    (* then send NAK for most desired *)
  926.                                    (* packet.  Else, send ordinary   *)
  927.                                    (* NAK.                           *)
  928.    IF Windowing_Started THEN
  929.       BEGIN
  930.                                    (* Send NAK for most wanted packet. *)
  931.                                    (* This is the first unACKd packet  *)
  932.                                    (* in the table, or, if all are     *)
  933.                                    (* ACKd, the first packet beyond    *)
  934.                                    (* the table.                       *)
  935.  
  936.          IF ( Kermit_Window_Used > 0 ) THEN
  937.             BEGIN
  938.                Packet_Num := Kermit_Window_Bottom;
  939.                WHILE ( ( Packet_Num <> Kermit_Window_Top   ) AND
  940.                        ( Kermit_Queue[Packet_Num].ACK_Flag ) ) DO
  941.                   Packet_Num := SUCC( Packet_Num ) MOD 64;
  942.                IF Kermit_Queue[Packet_Num].ACK_Flag THEN
  943.                   Packet_Num := SUCC( Packet_Num ) MOD 64;
  944.             END
  945.          ELSE
  946.             Packet_Num := SUCC( Kermit_Window_Top ) MOD 64;
  947.  
  948.                                    (* Clear possible bogus XOFF received *)
  949.                                    (* by remote system.                  *)
  950.  
  951.          IF Async_Do_XonXoff THEN
  952.             IF ( NOT Async_XOFF_Sent ) THEN
  953.                Async_Send( CHR( XON ) );
  954.  
  955.                                    (* If we timed out, send NAK, else    *)
  956.                                    (* ignore the bad packet.             *)
  957.  
  958.          IF Kermit_Retry THEN
  959.             Send_NAK;
  960.  
  961.       END
  962.    ELSE                            (* Send ordinary NAK if no windowing yet *)
  963.       BEGIN
  964.          Send_NAK;
  965.       END;
  966. {
  967.    IF Kermit_Debug THEN
  968.       BEGIN
  969.          Write_Log( 'Send_NAK_For_Most_Desired = ' + IToS( Packet_Num ), FALSE,
  970.                     FALSE );
  971.          Write_Log('   Window_Top    = ' + IToS( Kermit_Window_Top ),
  972.                    FALSE, FALSE );
  973.          Write_Log('   Window_Bottom = ' + IToS( Kermit_Window_Bottom ),
  974.                    FALSE, FALSE );
  975.          IF Kermit_Retry THEN
  976.             Write_Log('   Timed out', FALSE, FALSE )
  977.          ELSE
  978.             Write_Log('   Checksum bad', FALSE, FALSE );
  979.          L := PRED( Kermit_Window_Bottom ) MOD 64;
  980.          REPEAT
  981.             L := SUCC( L ) MOD 64;
  982.             IF Kermit_Queue[L].ACK_Flag THEN
  983.                Write_Log('      Block ' + IToS( L ) + ' ACKED', FALSE, FALSE )
  984.             ELSE
  985.                Write_Log('      Block ' + IToS( L ) + ' NOT ACKED', FALSE, FALSE );
  986.          UNTIL ( L = Kermit_Window_Top );
  987.       END;
  988. }
  989.  
  990. END   (* Send_NAK_For_Most_Desired *);
  991.  
  992. (*----------------------------------------------------------------------*)
  993. (*          OK_Packet_Received --- Handle reception of good packet      *)
  994. (*----------------------------------------------------------------------*)
  995.  
  996. PROCEDURE OK_Packet_Received;
  997.  
  998. BEGIN (* OK_Packet_Received *)
  999.  
  1000.    Packet_Num := Rec_Packet_Num;
  1001.  
  1002.    CASE Kermit_Packet_Type OF
  1003.  
  1004.       Data_Pack  : Handle_Windowed_Data_Pack;
  1005.  
  1006.       End_Pack,
  1007.       Break_Pack : BEGIN
  1008.                                    (* Write any remaining packets to disk *)
  1009.  
  1010.                       IF ( NOT Kermit_Abort ) THEN
  1011.                          WHILE ( ( Kermit_Window_Used > 0 ) AND
  1012.                                  ( NOT Kermit_Abort       )     ) DO
  1013.                             BEGIN
  1014.                                Expand_Bottom_Packet;
  1015.                                Update_Kermit_Display;
  1016.                             END;
  1017.  
  1018.                       IF ( Kermit_Packet_Type = Break_Pack ) THEN
  1019.                          Handle_Break_Pack
  1020.                       ELSE
  1021.                          Handle_End_Pack;
  1022.  
  1023.                    END;
  1024.  
  1025.       Attrib_Pack: IF Kermit_Attributes THEN
  1026.                       Handle_Attrib_Pack
  1027.                    ELSE
  1028.                       Send_NAK_For_Most_Desired;
  1029.  
  1030.       Header_Pack: ;
  1031.  
  1032.       ELSE         Send_NAK_For_Most_Desired;
  1033.  
  1034.    END  (* CASE *);
  1035.  
  1036. END   (* OK_Packet_Received *);
  1037.  
  1038. (*----------------------------------------------------------------------*)
  1039. (*          Bad_Packet_Received --- Handle reception of bad packet      *)
  1040. (*----------------------------------------------------------------------*)
  1041.  
  1042. PROCEDURE Bad_Packet_Received;
  1043.  
  1044. BEGIN (* Bad_Packet_Received *)
  1045.  
  1046.    IF ( NOT Kermit_Abort ) THEN
  1047.       BEGIN
  1048.                                    (* Increment tries to get good packet *)
  1049.          INC( Try );
  1050.                                    (* Abort transfer if too many *)
  1051.  
  1052.          IF ( Try = Kermit_MaxTry ) THEN
  1053.             BEGIN
  1054.                Kermit_Abort       := TRUE;
  1055.                Kermit_Abort_Level := One_File;
  1056.                Kermit_Construct_Message( 'EToo many retries.' );
  1057.             END
  1058.          ELSE
  1059.             BEGIN
  1060.                                    (* If we're in a retry mode, and an    *)
  1061.                                    (* XOFF was received, the XOFF may be  *)
  1062.                                    (* spurious, so clear it before trying *)
  1063.                                    (* again.  We also need to flush the   *)
  1064.                                    (* comm output buffer at this point    *)
  1065.                                    (* as well.                            *)
  1066.                                    (*                                     *)
  1067.                                    (* If an XOFF wasn't received, perhaps *)
  1068.                                    (* the remote system got a spurious    *)
  1069.                                    (* XOFF, so we send an XON.            *)
  1070.                                    (*                                     *)
  1071.  
  1072.                IF ( Try > 2 ) THEN
  1073.                   IF Async_XOff_Received THEN
  1074.                      BEGIN
  1075.                         Async_Flush_Output_Buffer;
  1076.                         Clear_XOFF_Received;
  1077.                      END
  1078.                   ELSE
  1079.                      IF Async_Do_XonXoff THEN
  1080.                         IF ( NOT Async_XOFF_Sent ) THEN
  1081.                            Async_Send_Now( CHR( XON ) );
  1082.  
  1083.                                    (* Not too many retries yet --      *)
  1084.                                    (* send NAK for most wanted packet. *)
  1085.  
  1086.                Send_NAK_For_Most_Desired;
  1087.  
  1088.             END;
  1089.  
  1090.       END
  1091.    ELSE
  1092.       BEGIN (* Abort found *)
  1093.  
  1094.          Packet_Num := SUCC( Kermit_Window_Top ) MOD 64;
  1095.  
  1096.          Send_Abort_Packet;
  1097.  
  1098.       END   (* Abort found *);
  1099.  
  1100. END   (* Bad_Packet_Received *);
  1101.  
  1102. (*----------------------------------------------------------------------*)
  1103.  
  1104. BEGIN (* Receive_Windowing *)
  1105.                                    (* Set window size                 *)
  1106.  
  1107.    Window_Size_Used := MAX( His_Kermit_Window_Size , 1 );
  1108.  
  1109.                                    (* Allow more retries when windowing *)
  1110.  
  1111.    Save_Retry       := Kermit_MaxTry;
  1112.    Kermit_MaxTry    := Kermit_MaxTry + Window_Size_Used;
  1113.  
  1114.                                    (* Reset send packet address to free *)
  1115.                                    (* up remainder for packets of table *)
  1116.                                    (* entries.                          *)
  1117.  
  1118.    Send_Packet_Ptr  := ADDR( Sector_Data[100] );
  1119.  
  1120.                                    (* Empty window at this point       *)
  1121.  
  1122.    Kermit_Window_Used   := 0;
  1123.    Kermit_Window_Top    := 0;
  1124.    Kermit_Window_Bottom := 0;
  1125.    Data_Place           := Receive_Offset;
  1126.    Windowing_Started    := FALSE;
  1127. {
  1128.    IF Kermit_Debug THEN
  1129.       BEGIN
  1130.          Write_Log( 'Window_Size   = ' + IToS( Window_Size_Used ) , FALSE, FALSE );
  1131.          Write_Log( 'Window_Used   = ' + IToS( Kermit_Window_Used ) , FALSE, FALSE );
  1132.          Write_Log( 'Window_Top    = ' + IToS( Kermit_Window_Top  ) , FALSE, FALSE );
  1133.          Write_Log( 'Window_Bottom = ' + IToS( Kermit_Window_Bottom ) , FALSE, FALSE );
  1134.          Write_Log( 'Data_Place    = ' + IToS( Data_Place         ) , FALSE, FALSE );
  1135.       END;
  1136. }
  1137.                                    (* Loop over packets in file being *)
  1138.                                    (* received.                       *)
  1139.    REPEAT
  1140.                                    (* Number of tries for a good packet *)
  1141.       Try := 0;
  1142.  
  1143.       REPEAT
  1144.                                    (* Get next packet *)
  1145.          Receive_Packet;
  1146. {
  1147.          IF Kermit_Debug THEN
  1148.             IF Packet_OK THEN
  1149.                Write_Log( 'Receive packet done OK  = ' + IToS( Rec_Packet_Num ),
  1150.                           FALSE, FALSE)
  1151.             ELSE
  1152.                Write_Log( 'Receive packet done BAD = ' + IToS( Rec_Packet_Num ),
  1153.                           FALSE, FALSE);
  1154. }
  1155.                                    (* Handle received packet *)
  1156.  
  1157.          IF Packet_OK THEN
  1158.             OK_Packet_Received
  1159.          ELSE
  1160.             Bad_Packet_Received;
  1161.  
  1162.       UNTIL ( Packet_OK OR Kermit_Abort );
  1163.  
  1164.    UNTIL ( Receive_Done OR Kermit_Abort OR
  1165.            ( Kermit_Packet_Type = Header_Pack ) );
  1166.  
  1167.                                    (* Reset retry counter *)
  1168.    Kermit_MaxTry    := Save_Retry;
  1169.  
  1170.                                    (* Reset send packet pointer address *)
  1171.  
  1172.    Send_Packet_Ptr  := ADDR( Sector_Data[Send_Offset] );
  1173.  
  1174.                                    (* Reset packet number *)
  1175.  
  1176.    Packet_Num       := Rec_Packet_Num;
  1177.  
  1178. END (* Receive_Windowing *);
  1179.  
  1180. (*----------------------------------------------------------------------*)
  1181.  
  1182. BEGIN (* Kermit_Receive_File *)
  1183.                                    (* Assume date/time not received   *)
  1184.    Kermit_Do_File_Date := FALSE;
  1185.    Kermit_Do_File_Time := FALSE;
  1186.                                    (* Remember start time             *)
  1187.  
  1188.    Kermit_Transfer_Start := TimeOfDay;
  1189.  
  1190.                                    (* Perform actual transfer.        *)
  1191.    IF Kermit_Do_Sliding_Win THEN
  1192.       Receive_Windowing
  1193.    ELSE
  1194.       Receive_Normal;
  1195.                                    (* Calculate transfer time *)
  1196.  
  1197.    Kermit_Transfer_End  := TimeOfDay;
  1198.    Total_Time           := Total_Time +
  1199.                            TimeDiff( Kermit_Transfer_Start ,
  1200.                                      Kermit_Transfer_End );
  1201.  
  1202.                                    (* Indicate we're through with transfer *)
  1203.    Kermit_Doing_Transfer := FALSE;
  1204.  
  1205.                                    (* Clear message lines *)
  1206.    IF ( NOT Kermit_Abort ) THEN
  1207.       Kermit_Clear_Message_Lines;
  1208.  
  1209. END    (* Kermit_Receive_File *);
  1210.  
  1211. (*----------------------------------------------------------------------*)
  1212.  
  1213. PROCEDURE Do_Kermit_Receive;
  1214.  
  1215. VAR
  1216.    C_Trans_Rate_E : ShortStr;
  1217.    C_Trans_Rate_A : ShortStr;
  1218.    Rec_Str        : AnyStr;
  1219.    W_Str          : STRING[3];
  1220.    Err            : INTEGER;
  1221.    D_Path         : AnyStr;
  1222.    Save_Close     : BOOLEAN;
  1223.    Get_String     : AnyStr;
  1224.    I              : INTEGER;
  1225.  
  1226. BEGIN  (* Do_Kermit_Receive *)
  1227.                                    (* Hide cursor *)
  1228.    CursorOff;
  1229.                                    (* Save screen *)
  1230.    Save_Screen( Kermit_Local_Save );
  1231.  
  1232.                                    (* Initialize status display information *)
  1233.    Packets_Received   := 0;
  1234.    Packets_Sent       := 0;
  1235.    Packets_Bad        := 0;
  1236.    Buffer_Num         := 0;
  1237.    Buffer_Num_Actual  := 0;
  1238.    Buffer_Total       := 0;
  1239.    Receive_Done       := FALSE;
  1240.    Kermit_MaxTry      := 5;
  1241.    Kermit_Abort       := FALSE;
  1242.    Kermit_Retry       := FALSE;
  1243.    Quoting            := FALSE;
  1244.    Kermit_Abort_Level := No_Abort;
  1245.    Total_Time         := 0;
  1246.  
  1247.                                    (* Get title   *)
  1248.    IF FileName <> '' THEN
  1249.       Kermit_Menu_Title := 'Receive file ' + FileName + ' using Kermit'
  1250.    ELSE
  1251.       Kermit_Menu_Title := 'Receive file using Kermit';
  1252.  
  1253.                                    (* Initialize status display              *)
  1254.    Initialize_Display;
  1255.  
  1256.    Write_Log( Kermit_Menu_Title, FALSE, FALSE );
  1257.  
  1258.                                    (* Allocate buffer for file data  *)
  1259.  
  1260.    Buffer_Length  := Max_Write_Buffer;
  1261.    Buffer_Size    := Buffer_Length;
  1262.  
  1263.    GetMem( Write_Buffer , Buffer_Length );
  1264.  
  1265.    IF ( Write_Buffer = NIL ) THEN
  1266.       BEGIN
  1267.          Display_Kermit_Message('  Not enough memory to perform receive.');
  1268.          Press_Any;
  1269.          Restore_Screen_And_Colors( Kermit_Local_Save );
  1270.          CursorOn;
  1271.          EXIT;
  1272.       END;
  1273.                                    (* Choose reception method depending upon *)
  1274.                                    (* whether remote system in server mode   *)
  1275.                                    (* or not.                                *)
  1276.  
  1277.    IF Kermit_Remote_Server THEN
  1278.       Kermit_State := Get_File
  1279.    ELSE
  1280.       Kermit_State := Receive_Init;
  1281.  
  1282.                                    (* Transfer not aborted yet               *)
  1283.    Abort_Done := FALSE;
  1284.                                    (* Loop over received packets             *)
  1285.    REPEAT
  1286.                                    (* Take action depending upon current *)
  1287.                                    (* Kermit state.                      *)
  1288.       CASE Kermit_State OF
  1289.  
  1290.          Get_File        : Kermit_Get;
  1291.          Receive_Init    : Kermit_Receive_Init;
  1292.          Receive_Header  : Kermit_Receive_Header;
  1293.          Receive_File    : Kermit_Receive_File;
  1294.  
  1295.       END (* CASE *);
  1296.  
  1297.    UNTIL ( Kermit_Abort OR Receive_Done );
  1298.  
  1299.                                    (* Display transfer rate *)
  1300.  
  1301.    IF ( Receive_Done AND ( NOT Abort_Done ) ) THEN
  1302.       BEGIN
  1303.  
  1304.          Display_Kermit_Message('Receive completed.');
  1305.  
  1306.          IF ( Total_Time = 0 ) THEN
  1307.             Total_Time := 1;
  1308.  
  1309.          Kermit_Transfer_Rate := Buffer_Total / ( Total_Time * 1.0 );
  1310.  
  1311.          STR( Kermit_Transfer_Rate:10:0 , C_Trans_Rate_E );
  1312.  
  1313.          Display_Kermit_Message_2('Effective transfer rate was ' +
  1314.                                   LTrim( C_Trans_Rate_E ) + ' CPS.');
  1315.  
  1316.          Kermit_Transfer_Rate := Buffer_Num_Actual / ( Total_Time * 1.0 );
  1317.  
  1318.          STR( Kermit_Transfer_Rate:10:0 , C_Trans_Rate_A );
  1319.  
  1320.          Display_Kermit_Message_3('Actual transfer rate was ' +
  1321.                                   LTrim( C_Trans_Rate_A ) + ' CPS.');
  1322.  
  1323.       END;
  1324.  
  1325.    IF Abort_Done THEN
  1326.       Write_Log('Receive cancelled.' , TRUE , FALSE );
  1327.  
  1328.                                    (* Ensure entire protocol aborted   *)
  1329.                                    (* if requested.                    *)
  1330.    Kermit_Done := Abort_Done;
  1331.  
  1332.    Window_Delay;
  1333.                                    (* Remove download buffer           *)
  1334.    MyFreeMem( Write_Buffer , Buffer_Length );
  1335.  
  1336.                                    (* Remove Kermit window             *)
  1337.  
  1338.    IF ( Kermit_Local_Save <> NIL ) THEN
  1339.       Restore_Screen_And_Colors( Kermit_Local_Save );
  1340.  
  1341.                                    (* Display cursor again *)
  1342.    CursorOn;
  1343.                                    (* Signal transfer done *)
  1344.    IF ( NOT Silent_Mode ) THEN
  1345.       FOR I := 1 TO Transfer_Bells DO
  1346.          Menu_Beep;
  1347.  
  1348. END    (* Do_Kermit_Receive *);
  1349.  
  1350. (*----------------------------------------------------------------------*)
  1351.  
  1352. PROCEDURE Get_File_Pattern;
  1353.  
  1354. BEGIN (* Get_File_Pattern *)
  1355.                                    (* Get file name from kbd/screen *)
  1356.  
  1357.    IF ( LENGTH( FileName ) = 0 ) THEN
  1358.       IF Auto_Find_FileNames THEN
  1359.          Get_Auto_File_Name( Saved_Kbd_File_Name , FileName );
  1360.  
  1361.    Draw_Titled_Box( Local_Save, 10, 5, 78, 8, '' );
  1362.  
  1363.    PibTerm_Window( 11, 6, 77, 7 );
  1364.  
  1365.    GoToXY( 2 , 1 );
  1366.  
  1367.    WRITE('File to receive: ');
  1368.  
  1369.    IF ( ( NOT ( Host_Mode OR Script_Transfer ) ) OR ( LENGTH( FileName ) = 0 ) ) THEN
  1370.       BEGIN
  1371.          FileName := FileName;
  1372.          Read_Edited_String( FileName );
  1373.          IF ( FileName = CHR( ESC ) ) THEN
  1374.             FileName := '';
  1375.          WRITELN;
  1376.       END
  1377.    ELSE
  1378.       WRITELN( FileName );
  1379.  
  1380.    Restore_Screen_And_Colors( Local_Save );
  1381.  
  1382. END   (* Get_File_Pattern *);
  1383.  
  1384. (*----------------------------------------------------------------------*)
  1385.  
  1386. BEGIN (* Receive_Kermit_File *)
  1387.                                    (* Get Kermit menu *)
  1388.  
  1389.    Make_A_Menu( Kermit_Menu, Receive_Quit_Item, 6, 20, 40, 9, Receive_Quit_Item,
  1390.                 'Choose Kermit function: ',
  1391.                 'a) GET Text File;b) GET Binary file;c) RECEIVE Text File;' +
  1392.                 'd) RECEIVE Binary File;' +
  1393.                 'f) Finish Remote Server;l) Logout Remote Server;' +
  1394.                 'r) Remote Server Commands;t) Transfer to Send File Menu;' +
  1395.                 'q) Quit Kermit',
  1396.                 FALSE );
  1397.  
  1398.    Kermit_Done            := FALSE;
  1399.    Sending_File           := FALSE;
  1400.    Host_Count             := 0;
  1401.    Send_Packet_Ptr        := ADDR( Sector_Data[Send_Offset] );
  1402.    Send_Packet_Ptr^[2]    := CHR( 0 );
  1403.    Send_Packet_Ptr^[3]    := CHR( 0 );
  1404.    Send_Packet_Ptr^[4]    := CHR( 0 );
  1405.    Initial_SOH_Received   := Doing_Kermit_Autodown;
  1406.  
  1407.    REPEAT
  1408.                                    (* Reinitialize Kermit variables *)
  1409.       Kermit_Init;
  1410.                                    (* No remote command yet         *)
  1411.       Remote_Comm := '';
  1412.                                    (* Display Kermit receive menu   *)
  1413.  
  1414.       IF ( NOT ( Host_Mode OR Script_Transfer OR Doing_Kermit_Autodown ) ) THEN
  1415.          BEGIN
  1416.             Menu_Display_Choices( Kermit_Menu );
  1417.             Menu_Choice := Menu_Get_Choice( Kermit_Menu , Erase_Menu );
  1418.          END
  1419.       ELSE
  1420.          BEGIN
  1421.  
  1422.             INC( Host_Count );
  1423.  
  1424.             IF ( Host_Count = 1 ) THEN
  1425.                IF ( Doing_Kermit_Autodown ) THEN
  1426.                   Menu_Choice := 4
  1427.                ELSE
  1428.                   BEGIN
  1429.  
  1430.                      IF ( Kermit_File_Type_Var <> Kermit_Binary ) THEN
  1431.                         IF ( LENGTH( FileName ) > 0 ) THEN
  1432.                            Menu_Choice := 1
  1433.                         ELSE
  1434.                            Menu_Choice := 3
  1435.                      ELSE
  1436.                         IF ( LENGTH( FileName ) > 0 ) THEN
  1437.                            Menu_Choice := 2
  1438.                         ELSE
  1439.                            Menu_Choice := 4;
  1440.  
  1441.                      IF ( LENGTH( FileName ) > 0 ) THEN
  1442.                         IF ( FileName[1] = '/' ) THEN
  1443.                            BEGIN
  1444.                               Menu_Choice := 7;
  1445.                               Remote_Comm := FileName;
  1446.                            END;
  1447.  
  1448.                   END
  1449.             ELSE
  1450.                Menu_Choice := Receive_Quit_Item;
  1451.  
  1452.          END;
  1453.                                    (* Perform desired Kermit function *)
  1454.       CASE Menu_Choice OF
  1455.  
  1456.          1: BEGIN
  1457.                Kermit_File_Type_Var := Kermit_Ascii;
  1458.                Get_File_Pattern;
  1459.                Kermit_Remote_Server := TRUE;
  1460.                IF ( LENGTH( FileName ) > 0 ) THEN
  1461.                   Do_Kermit_Receive;
  1462.             END;
  1463.  
  1464.          2: BEGIN
  1465.                Kermit_File_Type_Var := Kermit_Binary;
  1466.                Get_File_Pattern;
  1467.                Kermit_Remote_Server := TRUE;
  1468.                IF ( LENGTH( FileName ) > 0 ) THEN
  1469.                   Do_Kermit_Receive;
  1470.             END;
  1471.  
  1472.          3: BEGIN
  1473.                Kermit_File_Type_Var := Kermit_Ascii;
  1474.                FileName := '';
  1475.                Kermit_Remote_Server := FALSE;
  1476.                Do_Kermit_Receive;
  1477.             END;
  1478.  
  1479.          4: BEGIN
  1480.                Kermit_File_Type_Var := Kermit_Binary;
  1481.                FileName := '';
  1482.                Kermit_Remote_Server := FALSE;
  1483.                Do_Kermit_Receive;
  1484.             END;
  1485.  
  1486.          5: BEGIN
  1487.                Kermit_Finish_Server( 'F' );
  1488.             END;
  1489.  
  1490.          6: BEGIN
  1491.                Kermit_Finish_Server( 'L' );
  1492.             END;
  1493.  
  1494.          7: BEGIN
  1495.                Kermit_Remote_Commands( Remote_Comm , Do_A_Receive );
  1496.                FileName := '';
  1497.                Kermit_Remote_Server := FALSE;
  1498.                IF Do_A_Receive THEN
  1499.                   Do_Kermit_Receive;
  1500.             END;
  1501.  
  1502.          8: BEGIN
  1503.                Kermit_Done  := TRUE;
  1504.                Sending_File := TRUE;
  1505.             END;
  1506.  
  1507.          ELSE
  1508.             BEGIN
  1509.                Kermit_Done := TRUE;
  1510.             END;
  1511.  
  1512.       END (* CASE *);
  1513.  
  1514.    UNTIL Kermit_Done;
  1515.                                    (* Ensure status window restored        *)
  1516.    IF Do_Status_Line THEN
  1517.       PibTerm_Window( 1, 1, Max_Screen_Col, Max_Screen_Line - 1 );
  1518.  
  1519.                                    (* Ensure switch to send code if needed *)
  1520.  
  1521.    Kermit_Really_Done := ( NOT Sending_File );
  1522.    FileName           := '';
  1523.  
  1524.                                    (* Turn off autodownload in progress *)
  1525.    Doing_Kermit_Autodown := FALSE;
  1526.  
  1527. END   (* Receive_Kermit_File *);
  1528.