PROGRAM Kermit(input,output); LABEL 9999; { used only to simulate a "halt" instruction } CONST { standard file descriptors. subscripts in open, etc. } STDIN = 1; { these are not to be changed } STDOUT = 2; STDERR = 3; DL11LINE = 4; BINARYFILE = 5; { other io-related stuff } IOERROR = 0; { status values for open files } IOAVAIL = 1; IOREAD = 2; IOWRITE = 3; IOLINE = 4; MAXOPEN = 7; { maximum number of open files } MAXCMD = 10; { maximun number of arguments } { universal manifest constants } ENDFILE = MaxInt; { Cannot be -1 } ENDSTR = 256; { Cannot be 0 } MAXSTR = 100; { longest possible string } CONLENGTH = 20; { length of constant string } BLKSIZE = 512; { Block Size for files } { ascii character set in decimal } { used by KERMIT } NULLCHAR = 0; SOH = 1; { SOH } BACKSPACE = 8; TAB = 9; NEWLINE = 10; { LF } CR = 13; { CR } BLANK = 32; SHARP = 35; { # } AMPER = 38; { & } PERIOD = 46; { . } COLON = 58; { : } LESS = 60; { < } GREATER = 62; { > } QUESTION = 63; { ? } DEL = 127; { rubout } { Constants for KERMIT } DEFTRY = 5; { default for number of retries } DEFITRY = 15; { default for number of retries on init } DEFTIMEOUT = 12; { default time out } MAXPACK = 94; { max is 94 ~ - ' ' } DEFDELAY = 5; { delay before sending first init } NUMPARAM = 7; { number of parameters in init packet } DEFQUOTE = SHARP; { default quote character } DEFPAD = 0; { default number OF padding chars } DEFPADCHAR = 0; { default padding character } DEF8CHAR = AMPER; { default 8 Bit Quote Character } { packet types } TYPEB = 66; { ord('B') } TYPED = 68; { ord('D') } TYPEE = 69; { ord('E') } TYPEF = 70; { ord('F') } TYPEN = 78; { ord('N') } TYPES = 83; { ord('S') } TYPET = 84; { ord('T') } TYPEY = 89; { ord('Y') } TYPEZ = 90; { ord('Z') } { Command parser constants } SMALLSIZE = 13; LARGESIZE = 80; MINPACKETSIZE = 10; MAXPACKETSIZE = 94; oON = 21; oOFF = 22; oEVEN = 31; oODD = 32; oNONE = 33; TYPE character = -128..MaxInt; { byte-sized. ascii + other stuff } string = array [1..MAXSTR] of character; string100 = PACKED ARRAY[1..MAXSTR] of char; cstring = PACKED ARRAY [1..CONLENGTH] OF char; filedesc = IOERROR..MAXOPEN; ioblock = record { to keep track of open files } filevar : text; mode : -IOWRITE..IOLINE; end; block = array[1..BLKSIZE] of char; binfile = file of block; { Data Types for Kermit } Packet = RECORD mark : character; { SOH character } count: character; { # of bytes following this field } seq : character; { sequence number modulo 64 } ptype: character; { d,y,n,s,b,f,z,e,t packet type } data : string; { the actual data } { chksum is last validchar in data array } { eol is added, not considered part of packet proper } END; Command = (Transmit,Receive,SetParm,Connect,Invalid,Alldone); KermitStates = (FileData,Init,Break,FileHeader,EOFile,Complete,Abort); EOLtype = (LineFeed,CrLf,JustCr); Stats = real; Ppack = ^Packet; InType = (nothing,CRin,abortnow); TypeOfBinary = (NotSupported,FullBinary,Quoted); { Parser defined types } string13 = packed array [1..SMALLSIZE] of char; string80 = packed array [1..LARGESIZE] of char; VAR { for system } openlist : ARRAY [1..MAXOPEN] OF ioblock; { open files } redirect : ARRAY [STDIN..STDOUT] OF filedesc; cmdargs : 0..MAXCMD; cmdlin : string; cmdidx : ARRAY [1..MAXCMD] OF 1..MAXSTR; bfile : binfile; binbuffer : block; bptr : integer; { Varibles for Kermit } DiskFile : filedesc; { File being read/written } SaveState : kermitstates; NextArg : integer; { next argument to process } local : boolean; { local/remote flag } MaxTry : integer; n : integer; { packet number } NumTry : integer; { times this packet retried } OldTry : integer; Pad : integer; { padding to send } MyPad : integer; { number of padding characters I need } PadChar : character; MyPadChar: character; RunType : command; State : kermitstates; { current state of the automaton } MyTimeOut: integer; { when i want to be timed out } TheirTimeOut : integer; Delay : integer; LineIN,LineOUT : filedesc; { Line to other KERMIT } SizeRecv, SizeSend : integer; SendEOL, SendQuote : character; myEOL,myQuote: character; QuoteForBinary : character; BinaryMode : TypeOfBinary; Def8QuoteMode : character; { default 8 Bit Mode is Y or AMPER this the one we send when starting transmit } EOLforFile : EOLtype; NumSendPacks : integer; NumRecvPacks : integer; NumACK : integer; NumNAK : integer; NumACKrecv : integer; NumNAKrecv : integer; NumBADrecv : integer; RunTime: integer; ChInFileSend, ChInPackSend, ChInFileRecv, ChInPackRecv : Stats; Verbosity: boolean; { true to print verbose messages } OneWayOnly : boolean; { used for testing } Debug : boolean; ThisPacket : Ppack; { current packet being sent } LastPacket : Ppack; { last packet sent } CurrentPacket : Ppack; { current packet received } NextPacket : Ppack; { next packet being received } InputPacket : Ppack; { save input to do debug } TimeLeft : integer; { until Time_Out } { these are used for the Receive Packet Procedures } FromConsole : InType; { input from Console during receive } check: integer; { Checksum } PacketPtr : integer; { pointer to InputPacket } dataptr : integer; { pointer to data of Packet } fld : 0..5; { current fld number } t : character; { input character } finished : boolean; { finished packet ? } restart : boolean; { restart packet ? } control : boolean; { quoted ? } ishigh : integer; { shift to put high bit on } isgood : boolean; { packet is good ? } invalidConnection : boolean; { Parser defined variables } commandLine, fileSpec : string80; exitProgram,fileWarning : boolean; localEcho, sFileSpec, rFileSpec, fileWarn, lSpeed : integer; debugging, commandLen, fileEol, parity, eightBitQuoting : integer; oldRunType : command; {$E+} PROCEDURE stiphalt; { used by external procedures for halt } BEGIN GOTO 9999; END; {$E-} { initio (RT-11) -- initialize open file list } PROCEDURE initio; EXTERNAL; { open (RT-11) -- open a file for reading or writing } FUNCTION Sopen (VAR name : string; omode : integer) : filedesc; EXTERNAL; { close all files on exit } PROCEDURE closeall; EXTERNAL; FUNCTION Exists({ Using } VAR s:string): { Returning } boolean; EXTERNAL; { getarg (RT-11) -- copy n-th command line argument into s } FUNCTION getarg (n : integer; VAR s : string; maxs : integer) : boolean; EXTERNAL; PROCEDURE PutCS({ Using } x:cstring; { Using } s : string; { Using } fd:filedesc); EXTERNAL; PROCEDURE OpenPort; EXTERNAL; PROCEDURE BadVTerminalConnect; EXTERNAL; PROCEDURE MakeConnection; EXTERNAL; PROCEDURE KermitInit; { initialize various parameters & defaults } EXTERNAL; PROCEDURE FinishUp(ok : boolean); { do any End of Program clean up } EXTERNAL; PROCEDURE ErrorPack({ Using } c:cstring); { output Error packet if necessary -- then exit } EXTERNAL; PROCEDURE PutErr({ Using } c:cstring); { Print error_messages } EXTERNAL; PROCEDURE Verbose({ Using } c:cstring); EXTERNAL; PROCEDURE SendSwitch; EXTERNAL; PROCEDURE RecvSwitch; EXTERNAL; PROCEDURE KermitMain; { Main KERMIT procedure } VAR aline : string; j : integer; errorOccurred : boolean; dummy : boolean; BEGIN Verbose('KermitMain... '); errorOccurred := false; CASE Runtype OF Receive: BEGIN { filename is optional here } IF (rFileSpec = oON) THEN BEGIN dummy := getarg(1,aline,MAXSTR); IF ((Exists(aline)) AND (local)) THEN PutCS('Overwriting ',aline,STDERR); DiskFile := Sopen(aline, -IOWRITE); IF (DiskFile <= IOERROR) THEN BEGIN PutErr('Cannot Open File '); errorOccurred := true; END ELSE IF (local) THEN PutCS('Receiving File... ', aline, STDERR); rFileSpec := oOFF; END; IF NOT(errorOccurred) THEN RecvSwitch; END; Transmit: SendSwitch; Invalid, SetParm, Alldone: { nothing }; END; { case } FinishUp(errorOccurred); { end of program } END { main KERMIT }; PROCEDURE PromptAndParseUser(VAR exitProgram : boolean; VAR RunType : command); EXTERNAL; BEGIN { of main } initio; KermitInit; { initialize } 9999: { Goto for an error_packet } RunType := Invalid; WHILE NOT(exitProgram) DO BEGIN PromptAndParseUser(exitProgram, RunType); IF NOT(exitProgram) THEN BEGIN CASE RunType OF Receive, Transmit : IF (NOT local) THEN KermitMain ELSE IF NOT(invalidConnection) THEN KermitMain ELSE BadVTerminalConnect; Connect : BEGIN local := true; OpenPort; IF NOT(invalidConnection) THEN MakeConnection ELSE BadVTerminalConnect; END; END; END; RunType := Invalid; END; Closeall; END.