Module KermitRead; { This module exports routines for receiving files from a remote machine } {========================} exports {=========================================} imports KermitFile from KermitFile; imports KermitGlobals from KermitGlobals; function ReadSwitch : KermitStates; function ReceiveInit( VAR RFile : FNameType ) : KermitStates; {========================} private {=========================================} const SenderAborted = 'Transfer was aborted by sender error packet'; imports KermitParameters from KermitParameters; imports KermitLineIO from KermitLineIO; imports System from System; imports UtilProgress from UtilProgress; VAR Mess : String; { Last file error message } {----------------------------------------------------------------------------} function ReceiveInit( VAR RFile : FNameType ) : KermitStates; { Prod the server to make it send us a file } VAR Pack : Packet; begin PutFileName( RFile, Pack ); SendPacket( RinitPack, 0, -1, Pack ); ReceiveInit := Init; end; {----------------------------------------------------------------------------} function ReadData : KermitStates; const DataExp = '?Illegal packet type received - expected data packet'; var Len, Num, Dummy : integer; RetVal : KermitStates; Pack : Packet; ErrCode : FileErrs; handler CtlC; begin CtrlCPending := false; ReadData := AbortCtlC; exit( ReadData ); end; begin if Debug then begin DbgWrite( ' Entering ReadData ..... ' ); DbgNL; end; NumTry := NumTry + 1; if NumTry>1 then TotTry := TotTry + 1; if NumTry > MaxTryPack then begin Mess := '?Unable to receive data'; writeln( Mess ); RetVal := Abort1; end else begin case ReadPacket ( Num , Len , Pack ) of DataPack : begin if Num <> n then begin OldTry := OldTry + 1; if OldTry > MaxTryPack then begin Mess := '?Unable to acknowledge data packet'; writeln( Mess ); SendErrPack( Mess ); RetVal := AbortAll; end else begin if Num = Prev ( n ) then begin SendAck( Num ); NumTry := 0; RetVal := CurrState; end else begin Mess := '?Data packet out of sequence'; writeln( Mess ); SendErrPack( Mess ); RetVal := AbortAll; end; end; end else begin ErrCode := EmptyBuffer ( Pack ); if ErrCode >=FNoError then begin SendACK( n ); Succeeded; RetVal := CurrState; end else begin FileError( '', ErrCode, Mess ); writeln( Mess ); RetVal := Abort1; end end; end; FHeadPack : begin OldTry := OldTry + 1; if OldTry > MaxTryPack then begin LocalError ( '?Unable to acknowledge file header packet' ); RetVal := AbortAll; end else if Num = Prev ( n ) then begin SendACK( num ); NumTry := 0; RetVal := CurrState; end else begin LocalError( DataExp ); RetVal := Abort1; end; end; EOFPack : begin if Num <> n then begin LocalError( '?EOF packet out of sequence' ); RetVal := Abort1; end else begin if (Len > 0) and (Pack.Data[1] = 'D') then ErrCode := DiscardFile else ErrCode := KeepFile; if ErrCode>=FNoError then begin SendAck( n ); Succeeded; RetVal := FileHeader; end else begin FileError( '', ErrCode, Mess ); SendErrPack( Mess ); writeln( Mess ); RetVal := AbortAll; end; end; end; ErrPack: begin TreatErrPack( Pack, Num ); RetVal := AbortAll; end; NAKPack : begin SendNAK( n ); RetVal := CurrState; end; ACKPack, SInitPack, IllPack : begin writeln( DataExp ); RetVal := Abort1; end; ChkIllPack : begin if Debug then begin DbgWrite ( 'Illegal CheckSum - Sending NAK' ); DbgNL; end; SendNAK ( n ); RetVal := CurrState; end; TimOutPack : begin if Debug then begin DbgWrite ( 'Timed out waiting for pack. number:' ); DbgInt ( n ); DbgNL; end; SendAck ( Prev(n) ); { SendNAK ( n ); } RetVal := CurrState; end; end; { case } end; ReadData := RetVal; end; {----------------------------------------------------------------------------} Const OnlyFile = False; TextReply = True; function ReadFile( ReplyExpected : Boolean ) : KermitStates; const FHeadExp = '?Illegal packet type received - expected file header packet'; var num : integer; len : integer; Status : integer; Pack : Packet; RetVal : KermitStates; FileName : FNameType; FE : FileErrs; handler CtlC; begin CtrlCPending := false; ReadFile := AbortCtlC; exit( ReadFile ); end; begin if Debug then begin DbgWrite( 'Entering ReadFile ...... '); DbgNL; end; NumTry := NumTry + 1; if NumTry>1 then TotTry := TotTry + 1; if NumTry > MaxTryPack then begin LocalError( '?Unable to receive file header' ); RetVal := AbortAll; end else begin case ReadPacket ( Num , len , Pack ) of SInitPack : { May be our ACK lost } if ReplyExpected then begin Mess := '?Illegal packet type received'; writeln( Mess ); SendErrPack( Mess ); RetVal := AbortAll; end else begin OldTry := OldTry + 1; if OldTry > MaxTryPack then begin writeln ( '?Unable to acknowledge send initiate packet'); RetVal := AbortAll; { abort on too many errors } end else begin if num = Prev ( n ) then { Previous packet? } begin ReadPars ( Pack ); { yes - re-ACK } SendPacket( NoChangePack, num, -1, Pack ); NumTry := 0; RetVal := CurrState; end; end; end; EOFPack : if ReplyExpected then begin writeln( '?Illegal packet type received' ); RetVal := Abort1; end else begin OldTry := OldTry + 1; if OldTry > MaxTryPack then begin writeln( '?Unable to acknowledge EOF packet' ); RetVal := Abort1; end else begin if num = Prev ( n ) then begin SendACK( num ); NumTry := 0; RetVal := CurrState; end else begin writeln( FHeadExp ); RetVal := Abort1; end; end; end; THeadPack : begin if num<> n then RetVal := Abort1 else begin WriteScreen; RetVal := FileData; end; end; FHeadPack : { which is what we really want } begin if num <> n then RetVal := Abort1 else begin GetFilename ( Filename, Pack ); FE := NextWriteFile( FileName ); repeat case FE of FNoError, FRenamed: begin SendACK( n ); if Debug then begin DbgWrite( 'Receiving : ' ); DbgFilename( FileName ); DbgNL; end; Succeeded; RetVal := FileData; FE := FNoError; end; otherwise: { Retry - error closing prev. file } begin FileError( '', FE, Mess ); writeln( Mess ); FE := NextWriteFile( FileName ); end; end; until FE=FNoError; end; end; BrkPack : begin if num <> n then begin writeln ( '?Break packet received out of sequence' ); RetVal := Abort1; end else begin SendACK( n ); RetVal := Complete; end; end; ErrPack: begin TreatErrPack( Pack, Num ); writeln( SenderAborted ); RetVal := AbortAll; end; AckPack : if ReplyExpected then begin if N <> Num then begin RetVal := AbortAll; end else begin WriteScreen; Pack.PType := PackToCh( DataPack ); FE := EmptyBuffer( Pack ); FE := FileIdle; RetVal := Complete; end; end else begin RetVal := Abort1; writeln( FHeadExp ); end; DataPack, NAKPack, IllPack : begin RetVal := Abort1; writeln( FHeadExp ); end; ChkIllPack : begin if Debug then begin DbgWrite('Wrong checksum - sending NAK'); DbgNL; end; SendNAK( n ); RetVal := CurrState; end; TimOutPack : begin if Debug then begin DbgWrite('Timed out waiting for FHeadPacket'); DbgNL; end; SendNAK( n ); RetVal := CurrState; end; end; end; ReadFile := RetVal; end; {----------------------------------------------------------------------------} function ReadInit : KermitStates; const SInitExp = '?Illegal packet type received - expected send initiate packet'; var num : integer; len : integer; Pack : Packet; RetVal : KermitStates; Answer : PacketType; handler CtlC; begin CtrlCPending := false; ReadInit := AbortCtlC; exit( ReadInit ); end; begin if Debug then begin DbgWrite( 'Entering ReadInit ...... '); DbgNL; end; NumTry := NumTry + 1; if NumTry>1 then TotTry := TotTry + 1; if NumTry > MaxTryInit then begin LocalError( '?Unable to receive initiate' ); RetVal := AbortAll; end else begin Answer := ReadPacket( Num, len, Pack ); if Answer = SInitPack then begin ReadPars( Pack ); SendPacket( NoChangePack, n, -1, Pack ); Succeeded; RetVal := FileHeader; end else if Answer = TimOutPack then begin if Debug then begin DbgWrite('Timed out waiting for Send-init - Retrying'); DbgNL; end; SendNAK ( n ); RetVal := CurrState; end else if Answer = ChkIllPack then begin if Debug then begin DbgWrite('Illegal checksum - retrying'); DbgNL; end; SendNAK ( n ); RetVal := CurrState; end else if Answer = ErrPack then begin TreatErrPack( Pack, Num ); writeln( SenderAborted ); RetVal := AbortAll; end else begin if Debug then begin DbgWrite('Unable to receive send-init-packet'); DbgNL; DbgPacket( Pack ); end; writeln( SInitExp ); SendErrPack( SInitExp ); RetVal := AbortAll; end; end; ReadInit := RetVal; end; {----------------------------------------------------------------------------} function ReadSwitch : KermitStates; var Dummy : FileErrs; handler CtlCAbort; begin CtrlCPending := false; end; { This is the state table switcher for the receive file function } begin if (CurrState <> RemoteReply) then CurrState := Init; n := 0; nn := 0; NumTry := 0; OldTry := 0; TotTry := 0; InitProgress; LoadBusy; { From UtilProgress - load Busy bee } ShowPackNum; while (CurrState <> AbortAll) and (CurrState <> Complete) and (CurrState <> AbortCtlC) do begin ShowPackNum; case CurrState of FileData : CurrState := ReadData; FileHeader : CurrState := ReadFile( OnlyFile ); RemoteReply : CurrState := ReadFile( TextReply ); Init : CurrState := ReadInit; EOFile, Break : begin LocalError ('?Unexpected packet read - EOFile or Break'); CurrState := Abort1; end; Abort1 : begin FileAbort; CurrState := FileHeader; end; end; ShowProgress( ProgressLines ); if Debug then begin DbgWrite ( 'ReadSwitch : State transition to --> ' ); DbgState ( CurrState ); DbgNL; end; end; if CurrState = AbortCtlC then begin writeln( AbortedByCtlC ); SendErrPack( AbortedByCtlC ); end; ReadSwitch := CurrState; Dummy := FileIdle; QuitProgress; end.