module KermitConnect; { { Module for simulating a terminal. { { The correct communications parameters must have { been set up before this routine is used. { } {===========================} exports {====================================} imports FileDefs from FileDefs; procedure Terminal( EscChar : Char ); procedure SetSaveFile( NewSaveFile : PathName ); {===========================} private {====================================} imports MenuUtils from MenuUtils; imports system from system; imports FileSystem from FileSystem; imports IO_Unit from IO_Unit; imports IOErrors from IOErrors; imports IOUtils from IOUtils; { own modules: } imports KermitScreen from KermitScreen; imports KermitLineIO from KermitLineIO; imports KermitParameters from KermitParameters; {----------------------------------------------------------------------------} const BBuffSize = 512; { number of bytes in FS-block } {----------------------------------------------------------------------------} var BuffPtr : PDirBlk; BufferIndex : -1..BBuffSize; BlockNumber : FirstBlk..LastBlk; Id : FileID; GetC,SendC : char; LineIndex : integer; TermMenu, SpeedMenu, ParityMenu, StopMenu : pNameDesc; {----------------------------------------------------------------------------} { procedure FlushBuffer; var i : integer; begin for i:=MinBuffIndex to BufferIndex do write(SaveFile,Buffer[i]); BufferIndex:=MinBuffIndex - 1; end; } {----------------------------------------------------------------------------} procedure SaveInBuffer(ch:char); begin if BufferIndex = BBuffSize - 1 then begin FSBlkWrite(Id,BlockNumber,BuffPtr); BlockNumber := BlockNumber + 1; BufferIndex:=-1; { if XonXoff then RSPutChar(XOn); } end; BufferIndex:=BufferIndex+1; BuffPtr^.ByteBuffer[BufferIndex]:=ord(ch); end; {----------------------------------------------------------------------------} procedure OpenSave; begin Id := FSEnter( SaveFile ); if Id = 0 then begin PutMessage('*** Illegal Log File name ***'); SaveFile := ''; end else begin BlockNumber := FirstBlk; BufferIndex:= - 1; end; SwitchWindow( MainWindow ); end; { OpenSave } {----------------------------------------------------------------------------} procedure CloseSave; begin if BufferIndex >= 0 then begin { The last block is partially full } FSBlkWrite(Id,BlockNumber,BuffPtr); FSClose(Id,BlockNumber,(BufferIndex+1)*8); { last parameter is number of bits in last block } end else { The last block is FULL } FSClose(Id,BlockNumber-1,BBuffSize*8); end; { CloseSave } {----------------------------------------------------------------------------} procedure SetSaveFile( NewSaveFile : PathName ); begin if SaveFile<>'' then CloseSave; SaveFile := NewSaveFile; if SaveFile<>'' then OpenSave; end; {----------------------------------------------------------------------------} procedure ChangeSaveFile; var NewSaveFile : PathName; CurrWin : WinType; begin CurrentWindow( CurrWin ); SwitchWindow( MessageWindow ); write( 'Enter name of new log file : ' ); readln( NewSaveFile ); SetSaveFile( NewSaveFile ); SwitchWindow( CurrWin ); end; {----------------------------------------------------------------------------} procedure TreatIncoming(ch:char); begin case ch of BS : if LineIndex >= 1 then BackSpace(' ') else write(''); CR : begin LineIndex := 0; if FileSave and not (SaveFile='') then SaveInBuffer(ch); PutChr(chr( LAnd( ord(ch), 127 ))); end; NULL : ; otherwise : begin LineIndex := LineIndex + 1; if FileSave and not (SaveFile='') then SaveInBuffer(ch); PutChr(chr( LAnd( ord(ch), 127 ))); end; end; end; {----------------------------------------------------------------------------} function Xlat(ch:char): char; var Res : char; begin if ( LAnd(ord(ch),#200) <> 0 ) then { control-character } Res := chr(LAnd(ord(ch),#37)) else Res := ch; Xlat := Res; end; {----------------------------------------------------------------------------} procedure EscHelp; begin SwitchWindow( MainWindow ); writeln; writeln(' ? - This message' ); writeln(' C - Close connection, return to Perq' ); writeln(' B - Send break' ); writeln(' 0 - Send a NUL' ); writeln(' Q - Quit (turn off) logging to a file' ); writeln(' R - Resume (turn on) logging to a file' ); writeln; writeln('Typing the escape character will send it to the remote computer'); write ('Command>'); end; {----------------------------------------------------------------------------} function MakeUpper(ch:char): char; var Res : char; begin Res := Ch; if ( LAnd(ord(ch),#200) <> 0 ) then { control-character } Res := chr(LAnd(ord(ch),#177)); if ch in ['a'..'z'] then Res := chr( ord(ch) - (ord('a') - ord('A')) ); MakeUpper := Res; end; {----------------------------------------------------------------------------} procedure DoSetBaud; function GetBaud:SpeedType; begin { GetBaud } GetBaud := recast(GetMenuAnswer(SpeedMenu,200),SpeedType); end; { GetBaud } begin Baud := GetBaud; RefreshBaud; end; {----------------------------------------------------------------------------} procedure DoSetParity; function GetKerParity:ParityType; begin GetKerParity := recast(GetMenuAnswer(ParityMenu,150),ParityType); end; begin Parity := GetKerParity; RefreshParity; end; {----------------------------------------------------------------------------} procedure DoSetStop; function GetStop:StopType; begin GetStop := recast(GetMenuAnswer(StopMenu,150),StopType); end; begin StopBits := GetStop; RefreshStopBits; end; {----------------------------------------------------------------------------} procedure InitTMenu; var SetMenu : pMenuEntry; begin AllocNameDesc( NTermComm, 0, TermMenu ); {$range-} with TermMenu^ do begin Header := 'Terminal commands'; Commands[ord(TermHelp) ] := '?'; Commands[ord(TermQuit) ] := 'QUIT terminal mode'; Commands[ord(TermSetBaud) ] := 'set BAUD'; Commands[ord(TermSetStop) ] := 'set STOP-BITS'; Commands[ord(TermSetParity) ] := 'set PARITY'; Commands[ord(TermSaveFile) ] := 'set LOG-FILE'; Commands[ord(TermOnSave) ] := 'set LOG ON'; Commands[ord(TermOffSave) ] := 'set LOG OFF'; Commands[ord(TermOnXonXoff) ] := 'set XON-XOFF ON'; Commands[ord(TermOffXonXoff)] := 'set XON-XOFF OFF'; end; SetMenu := RootMenu^.NextLevel[ ord( MainSet ) ]; with SetMenu^ do begin SpeedMenu := NextLevel[ ord( SetBaud ) ]^.MPtr; ParityMenu := NextLevel[ ord( SetParity ) ]^.MPtr; StopMenu := NextLevel[ ord( SetStop ) ]^.MPtr; end; {$range=} end; {----------------------------------------------------------------------------} procedure GiveHelp; begin SwitchWindow( MainWindow ); writeln; writeln(' Terminal commands: '); writeln; writeln('QUIT - return to Kermit-Perq main command level'); writeln('SET BAUD/STOP/PARITY - set line parameters'); writeln('SET LOG-FILE - enter name of file to log terminal session to'); writeln('SET LOG ON/OFF - turn log output on/off'); writeln('SET XON-XOFF ON/OFF - use/respect XON/XOFF handshake'); writeln; SwitchWindow( TermWindow ); end; {----------------------------------------------------------------------------} procedure Terminal( EscChar : char ); var GetC, SendC : char; done, HelpPrompt : boolean; TComm : TermCommType; function GetTermComm : TermCommType; begin GetTermComm:=recast(GetMenuAnswer(TermMenu,150),TermCommType); end; procedure DoTermComm( TComm : TermCommType ); begin case TComm of TermHelp : GiveHelp; TermSetBaud : DoSetBaud; TermSetParity : DoSetParity; TermSetStop : DoSetStop; TermQuit : ; TermOnSave : FileSave := true; TermOffSave : FileSave := false; TermSaveFile : ChangeSaveFile; TermOnXonXoff : XonXoff := true; TermOffXonXoff : XonXoff := false; end; end; handler IOWrErr( IOStatus : integer ); begin PutMessage('Write error on line (possibly unplugged RS232 connector)'); end; handler IORdErr( IOStatus : integer ); begin PutMessage('Read error on line (possibly wrong speed or parity)'); end; handler CtlC; begin ctrlcpending := false; end; begin XonXoff := true; { enable handshake } BlockNumber := FirstBlk; new(BuffPtr); { Set up pointer to buffer } InitTermScreen; InitTMenu; LineIndex := 0; done:=false; repeat if GetChar( Idev, GetC ) then { IO Complete on RS232-line } TreatIncoming(GetC); if IOCRead(KeyBoard,SendC) = IOEIOC then { IO Complete on keyboard } begin if SendC <> EscChar then begin { Must handle conversion to ctrl-chars myself. ^DEL = BREAK } SendC:=Xlat(SendC); { Send character on RS232-line } if SendC <> BreakKey then { not a break? } Outbt( Odev, SendC) else SendBreak( 500 { milliseconds }); end else begin HelpPrompt := false; repeat while IOCRead( KeyBoard, SendC ) <> IOEIOC do ; if HelpPrompt then begin writeln; ChangeWindow( TermWindow ); end; if SendC=EscChar then begin SendC := Xlat( SendC ); Outbt( Odev, SendC ); end else begin SendC := MakeUpper( SendC ); case SendC of '0': OutBt( Odev, chr(0) ); 'B': SendBreak( 500 ); 'C': TComm := TermQuit; 'Q': FileSave := FALSE; 'R': FileSave := TRUE; '?': begin EscHelp; HelpPrompt := true; end; otherwise: write(Chr(7)); end; end; until SendC<>'?'; end; end; if TabSwitch then begin TComm:= GetTermComm; DoTermComm( TComm ); end; until TComm = TermQuit; CleanupTermScreen; DestroyNameDescr( TermMenu); end.