home *** CD-ROM | disk | FTP | other *** search
- Module KermitGlobals;
-
- { This module contains global protocol definitions (packet types, generic
- { command codes, protocol states), character conversion functions,
- { error handling and some other global definitions. }
-
- {===============================} Exports {===================================}
-
- Imports Perq_String from Perq_String;
-
- CONST
-
- KermitMessage = 'NTH Kermit for 3RC/ICL Perq - V2.2';
- AbortedByCtlC = 'Transfer aborted by control C';
-
- GCLogin = 'I'; { Generic commands }
- GCConnect = 'C';
- GCLogout = 'L';
- GCFinish = 'F';
- GCDirectory = 'D';
- GCDiskUsage = 'U';
- GCErase = 'E';
- GCTypeFile = 'T';
- GCSubmit = 'S';
- GCPrint = 'P';
- GCWhoIsOn = 'W';
- GCSendMess = 'M';
- GCHelp = 'H';
- GCStatusQ = 'Q';
-
- OldFile = FALSE;
- NewFile = TRUE;
-
- NULL = chr(0);
- CR = chr(13);
- LF = chr(10);
- FF = chr(12);
- BS = chr(8);
- CtlZ = chr( ord('Z') mod #40 );
- ESC = chr( ord('[') mod #40 );
- Xon = chr( ord('Q') mod #40 );
- Xoff = chr( ord('S') mod #40 );
- BreakKey = chr(255);
-
- MaxString = 100;
-
- ProgressLines=5;
-
- TYPE
- KermitStates= ( FileData,
- Init,
- Break,
- FileHeader,
- RemoteReply,
- EOFile,
- Complete,
- Abort1,
- AbortCtlC,
- AbortAll );
-
- StringType = array [ 1 .. MaxString ] of char;
-
- FNameType = PString;
-
- PacketType = ( DataPack,
- ACKPack,
- NAKPack,
- SinitPack,
- BrkPack,
- FHeadPack,
- EOFPack,
- ErrPack,
- RinitPack,
- CommPack,
- GCommPack,
- THeadPack,
- NoChangePack, { for internal use }
- TimOutPack, { - " - }
- IllPack, { - " - }
- ChkIllPack); { - " - }
-
- Packet = record
- mark : char; { SOH character }
- count : char; { # bytes following this field }
- seq : char; { sequence number mod 64 }
- ptype : char; { packet-type }
- data : String[MaxString]; { the data }
- { checksum is last of data }
- end;
-
- VAR
-
- { Protocol state variables }
-
- N,NN : Integer; { Current packet seq. number }
- OldTry,NumTry,TotTry : Integer; { Packet retry counts }
- CurrState : KermitStates; { the current state of Kermit }
-
- LastNAK : Integer; { if previous packet was NAK:
- Seq.no of last NAK, else -1 }
-
- function ToChar ( ch : char ): char;
- function UnChar ( ch : char ): char;
- function Ctl ( ch : char ): char;
- function MakeCheck ( chksum : integer ): char;
- function Prev ( n : integer ):integer;
-
- function PackToCh ( pType : PacketType ): char;
-
- function ChToPack( ch : char ): PacketType;
-
- procedure Succeeded;
- procedure SendACK ( num : integer );
- procedure SendBrk;
- procedure SendNAK ( num : integer );
- procedure SendErrPack( Mess : String );
- procedure TreatErrPack( VAR EPack : Packet; Num : integer );
-
- procedure LocalError( EMess : PString );
-
- function SendGComm( Cmd : char; CmdParam : String ) : boolean;
-
- procedure DbgNL;
- procedure DbgInt ( n : integer );
- procedure DbgChar ( ch : char );
- procedure DbgWrite ( Str : String );
- procedure DbgState ( S : KermitStates );
- procedure DbgPacket ( Pack : Packet );
- procedure DbgShowPacket ( VAR Pack : Packet);
- procedure DbgFileName ( VAR FileN : FNameType );
-
- Imports KermitScreen from KermitScreen;
-
- {==========================} private {=======================================}
-
- Imports Perq_String from Perq_String;
- imports KermitLineIO from KermitLineIO;
- imports KermitParameters from KermitParameters;
- imports KermitRead from KermitRead;
-
- {-----------------------------------------------------------------------------}
- {==================== Kermit basic operations ================================}
- {-----------------------------------------------------------------------------}
-
- function ToChar ( ch : char ): char;
- begin
- { make sure not a control character }
- ToChar := chr( ord ( ch ) + ord ( ' ' ) );
- end;
-
- {-----------------------------------------------------------------------------}
-
- function UnChar ( ch : char ): char;
- begin
- { undoes ToChar }
- UnChar := chr ( ord ( ch ) - ord ( ' ' ) );
- end;
-
- {-----------------------------------------------------------------------------}
-
- function Ctl ( ch : char ): char;
- begin
- { toggle control bit }
- Ctl := chr( lxor ( ord( ch ), 64 ) );
- end;
-
- {-----------------------------------------------------------------------------}
-
- function MakeCheck ( chksum : integer ): char;
- begin
- MakeCheck := ToChar (
- chr (
- ( chksum +
- Land ( chksum , 192 ) div 64 )
- mod 64
- )
- );
- end;
-
- {-----------------------------------------------------------------------------}
-
-
- function Prev ( n : integer ):integer;
- begin
- if n = 0 then
- Prev := 63
- else
- Prev := n - 1;
- end;
-
- {-----------------------------------------------------------------------------}
-
-
- function PackToCh ( pType : PacketType ): char;
- var RetVal : char;
- begin
- case pType of
- DataPack : RetVal := 'D';
- ACKPack : RetVal := 'Y';
- NAKPack : RetVal := 'N';
- SInitPack : RetVal := 'S';
- BrkPack : RetVal := 'B';
- FHeadPack : RetVal := 'F';
- EOFPack : RetVal := 'Z';
- ErrPack : RetVal := 'E';
- RinitPack : RetVal := 'R';
- CommPack : RetVal := 'C';
- GCommPack : RetVal := 'G';
- THeadPack : RetVal := 'X';
- NoChangePack,
- TimOutPack,
- IllPack,
- ChkIllPack : RetVal := ' ';
- end;
- PackToCh := RetVal;
- end;
-
- {-----------------------------------------------------------------------------}
-
- function ChToPack( ch : char ): PacketType;
- begin
- if not ( ch in LegalPackets ) then
- begin
- if Debug then begin
- DbgWrite ( 'Illegal packet type : ' );
- DbgChar ( ch );
- DbgNL;
- end;
- ChToPack := IllPack;
- end
- else
- begin
- case ch of
- 'D' : ChToPack := DataPack;
- 'Y' : ChToPack := AckPack;
- 'N' : ChToPack := NakPack;
- 'S' : ChToPack := SinitPack;
- 'B' : ChToPack := BrkPack;
- 'F' : ChToPack := FHeadPack;
- 'Z' : ChToPack := EOFPack;
- 'E' : ChToPack := ErrPack;
- 'R' : ChToPack := RinitPack;
- 'C' : ChToPack := CommPack;
- 'G' : ChToPack := GCommPack;
- 'X' : ChToPack := THeadPack;
- end;
- end;
- end;
-
-
- {-----------------------------------------------------------------------------}
- {===================== Debugging output routines =============================}
- {-----------------------------------------------------------------------------}
-
-
- { Perq Kermit is always Local, so use standard output for debug info }
- procedure DbgNL;
- { Globals : Debug ( read )
- SideEffects : Finishes current line on debug-file
- }
- begin
- if Debug then writeln;
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure DbgInt( n : integer );
- { Globals : Debug ( read )
- SideEffects : Writes an integer on DbgOut with default field width
- }
- begin
- if Debug then write( n );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure PrintChar( ch : char );
- begin
- if ch IN [' '..'~'] then
- write( ch )
- else
- if ch='/' then
- write( '//' )
- else
- write( '/', ord( ch ):3:-8, '/' );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure DbgChar( ch : char );
- { Globals : Debug ( read )
- SideEffects : Outputs a character on DbgOut.
- }
- begin
- if Debug then
- PrintChar(ch);
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure DbgWrite( Str : String );
- { Abstract : Outputs a string to Debug-file.
- Globals : Debug ( read )
- SideEffects : Writes a string on DbgOut
- Input Params: Str - String to be written
- }
- var i : integer;
- begin
- if Debug then
- for i := 1 to Length( Str ) do
- PrintChar( Str[i] );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure DbgState( S : KermitStates );
- begin
- if Debug then
- case S of
- FileData : Write( 'FileData ');
- Init : Write( 'Init ');
- Break : Write( 'Break ');
- FileHeader : Write( 'FileHeader ');
- RemoteReply : Write( 'RemoteReply');
- EOFile : Write( 'EOFile ');
- Complete : Write( 'Complete ');
- Abort1 : Write( 'Abort1 ');
- AbortCtlC : Write( 'AbortCtlC ');
- AbortAll : Write( 'AbortAll ');
- end;
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure DbgPacket ( Pack : Packet );
- { Abstract : Outputs a packet on debug-file.
- Does a Writeln on debug-file.
- Globals : Debug ( read )
- InputParams : Pack - Packet to be written on DbgOut.
- SideEffects : Outputs packet and "NewLine" to DbgOut.
- Uses : UnChar
- }
- var i : integer;
- begin
- if Debug then
- begin
- with Pack do
- if PType IN LegalPackets then
- begin
- write( 'Packet: ' );
- PrintChar( count );
- PrintChar( seq );
- PrintChar( pType );
- if count < ' ' then
- write( '/////// Bad count field in packet! //////' )
- else
- for i := 1 to ord( UnChar ( count ) ) - 2 do
- PrintChar( Data[i] );
- end else
- begin
- write( ' DbgPacket: Invalid packet type ');
- end;
- writeln;
- end;
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure DbgFileName(VAR FileN:FNameType );
- begin
- if Debug then
- write( FileN );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure DbgShowPacket(VAR Pack:Packet);
- { Abstract : Writes a packet to the Debug file
- as DbgPacket, but in greater detail }
-
- var i,packlen : integer;
- begin
- if Debug then
- with Pack do begin
- write( 'DbgShowPacket: ' );
- if not ( Mark in [ SendSOH, RecSOH ] ) then begin
- writeln( ' *** Bad StartOfHeader character: / ',
- ord(Mark):3:-8,'/' );
- end;
- write( ' Seq =' );
- if seq<' ' then
- write( ' BAD' )
- else
- write( ord(UnChar(seq)):4:8 );
- if count<' ' then
- writeln( ' *** Bad Packet Lenght *** ')
- else begin
- PackLen := ord( UnChar(count) );
- write( ' Count = ',PackLen:3 );
- write( ' PType = ');
- PrintChar( PType );
- Writeln;
- if PackLen>MaxString - 2 then PackLen := MaxString - 2;
- for i:=1 to PackLen-2 do
- PrintChar( data[i] );
- writeln;
- end;
- end { with };
- end;
-
- {-----------------------------------------------------------------------------}
- {======================= Packet utilities ====================================}
- {-----------------------------------------------------------------------------}
-
- procedure SendACK( num : integer );
- VAR dummy : Packet;
- begin
- SendPacket( ACKPack,
- num,
- 0,
- dummy );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure SendNAK( num : integer );
- VAR dummy : Packet;
- begin
- SendPacket( NAKPack,
- num,
- 0,
- dummy );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure SendBrk;
- VAR dummy : Packet;
- begin
- SendPacket( BrkPack,
- 0,
- 0,
- dummy );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure Succeeded;
- { -- Update sequence number, a packet has been received OK }
- begin
- OldTry := NumTry; { Number of retries for previous packet }
- NumTry := 0; { Number of retries for next packet }
- n := ( n + 1 ) mod 64; { Update packet sequence number (mod 64) }
- nn := nn + 1; { Total packet count }
- end;
-
- {-----------------------------------------------------------------------------}
- {======================== Error handling =====================================}
- {-----------------------------------------------------------------------------}
-
- procedure LocalError( EMess : PString );
- var OldWin : WinType;
- { For use when fatal error:
- { Write an error message to the screen, and send an error packet to remote }
- begin
- CurrentWindow( OldWin );
- SwitchWindow( MainWindow );
- SendErrPack( EMess );
- writeln( EMess );
- SwitchWindow( OldWin );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure TreatErrPack( VAR Epack : Packet; Num : integer );
- VAR EMess : PString;
- OldWin : WinType;
- begin
- SendAck( Num ); { Ack the error packet anyway }
- CurrentWindow( OldWin );
- SwitchWindow( TermWindow ); { Or main window ? }
- writeln;
- { Error packet should step packet seq. numbers forward?? }
- if (( (N+1) MOD 64 )<>Num ) and Debug then
- writeln( 'Bad number field in error packet!' );
-
- EMess := Substr( Epack.data, 1, length( Epack.data )-1 );
- writeln( EMess );
- SwitchWindow( OldWin );
- end;
-
- {-----------------------------------------------------------------------------}
-
- procedure SendErrPack( Mess : String );
- Var EPack : Packet;
- begin
- EPack.Data := Mess;
- SendPacket( ErrPack, N, Length( Mess ), EPack );
- { Should one wait for ACK or not?? }
- end;
-
- {-----------------------------------------------------------------------------}
- {===================== Generic and host commands =============================}
- {-----------------------------------------------------------------------------}
-
- function SendGComm( Cmd : char; CmdParam : String ) : boolean;
-
- VAR LPack, RPack : Packet;
- Num, Len, Size : integer;
- PackType : PacketType;
- CmdS : String[1];
- begin
- FlushBuffer( Idev ); { don't let us be led astray by pending ACK's }
- Adjust( CmdS, 1 );
- CmdS[1] := Cmd;
- LPack.data := Concat( CmdS, CmdParam );
- Size := Length( CmdParam ) + 1;
-
- NumTry := 0;
- SendPacket( GCommPack, 0, Size, LPack ); { Send command }
- CurrState := RemoteReply;
- SendGComm := Complete = ReadSwitch; { Read reply }
-
- end.
-