(*===========================================================================*)
(*                             Virus Check                                   *)
(*===========================================================================*)
(*                                                                           *)
(*              Original : Writen by David Siebert                           *)
(*                         08-feb-88                                         *)
(*===========================================================================*)
(*                                                                           *)
(*             Modified  : 02-may-88 David Siebert                           *)
(*                         converted a program to module                     *)
(*                         03-may-88 David Siebert                           *)
(*                         found the bug in the program                      *)
(*                                                                           *)
(*===========================================================================*)
IMPLEMENTATION MODULE VK;
FROM CharCheck IMPORT IsPrintable,IsVowel;
FROM SYSTEM IMPORT TSIZE,ADDRESS;
FROM IO IMPORT DoIO,IOStdReq,IORequest,IORequestPtr;
FROM TrackDiskDevice IMPORT IOExtTD,TDSector,NrSecs,TDMotor,ETDRead,
TrackDiskName,TDChangeNum;
FROM PortUtils IMPORT CreatePort,CreateExtIO,DeletePort,DeleteExtIO;
FROM Ports IMPORT MsgPortPtr;
FROM Memory IMPORT MemChip,AllocMem,FreeMem,MemReqSet;
FROM Devices IMPORT OpenDevice,CloseDevice;


(* $S-,$T-,$A+ *)
PROCEDURE VCheck (Drive:LONGCARD;VAR MySec:TDD):BOOLEAN;
TYPE
   LookString = ARRAY[1..4] OF CHAR;

CONST
  ON       = 1;
 OFF       = 0;
 NumOfCyl  = 80;
 NumOfHead = 2;
 
VAR 
  DTA       : ADDRESS;
  DumbGymnastics : IORequestPtr;
  reqsize   : IOExtTD;
  diskreq   : POINTER TO IOExtTD;
  DiskCount,
  Error,
  cyl,
  sec,
  hd       : LONGCARD;
  DiskPort : MsgPortPtr;
  Data     : POINTER TO LookString;
  Virus,
  Lcount   : INTEGER;
  ByteBand ,
  RetVal   : BOOLEAN;

PROCEDURE ReadCylSec(DTA:ADDRESS;cyl,sec,hd:LONGCARD):LONGCARD;
  VAR
    offset ,
    err    : LONGCARD;
  BEGIN
    diskreq := ADDRESS(DumbGymnastics);
    diskreq^.iotdReq.ioLength:=TDSector;
    diskreq^.iotdReq.ioData:=DTA;
    (* Show where data goes *)
    diskreq^.iotdReq.ioReq.ioCommand:=ETDRead;
    (* Calculate Offset *)
    diskreq^.iotdCount:=DiskCount;
    offset:=TDSector *(sec+NrSecs*hd+NrSecs*NumOfHead*cyl);
    diskreq^.iotdReq.ioOffset:=offset;
  DumbGymnastics:=ADDRESS(diskreq);
  err:=DoIO(DumbGymnastics^);
  RETURN(err);
END ReadCylSec;

PROCEDURE Motor(OnOff:LONGCARD):LONGCARD;
(* Turn On Disk Motor *)
VAR
  err : LONGCARD;

BEGIN
  diskreq := ADDRESS(DumbGymnastics);
  diskreq^.iotdReq.ioLength:=OnOff;
  diskreq^.iotdReq.ioReq.ioCommand:=TDMotor;
  DumbGymnastics:=ADDRESS(diskreq);
  err:=DoIO(DumbGymnastics^);
RETURN(err);
  (* Return the error code to the calling program*)
END Motor;

PROCEDURE Check():BOOLEAN;
VAR 
  vowel:BOOLEAN;
  i,
  j:INTEGER;
  q:POINTER TO CHAR;
BEGIN
  Lcount:=0;
  i:=284;
  WHILE (Lcount<4) AND (i<408) DO
    Data:=DTA+ADDRESS(i);
    vowel:=FALSE;
    Lcount:=0;
    FOR j:=1 TO 4 DO
      IF IsPrintable(Data^[j]) THEN
        IF NOT vowel THEN
           vowel:=IsVowel(Data^[j]);
        END;(* End If*)
        Lcount :=Lcount +1
      ELSE
        Lcount:=0
      END; (*end if *);
    END; (* end for*);
    i:= i+1
  END; (*While *)
  IF (Lcount=4)AND vowel THEN
    FOR i:=1 TO TDSector DO
      q:=DTA+ADDRESS(i);
      MySec[i]:=q^;
    END ; (* end for *)
    RETURN (TRUE);
  ELSE 
    RETURN(FALSE);
  END; (*END IF*);
END Check;

PROCEDURE ByteCheck():BOOLEAN;
VAR 
  i,
  j:INTEGER;
  z:CHAR;
  q:POINTER TO CHAR;

BEGIN

  Lcount:=0;
  i:=16;
  q:=DTA+ADDRESS(i);
  IF q^="V" THEN
    FOR i:=1 TO TDSector DO
      q:=DTA+ADDRESS(i);
      MySec[i]:=q^;
    END ; (* end for *)
    RETURN (TRUE);
  ELSE 
    RETURN(FALSE);
  END; (*END IF*);
END ByteCheck;

BEGIN
  DTA:=AllocMem(TDSector,MemReqSet{MemChip});
  DiskPort := CreatePort("",0);
  DumbGymnastics := CreateExtIO(DiskPort,TSIZE(IOExtTD));
  Error := OpenDevice(TrackDiskName,Drive,DumbGymnastics,0);
  IF Error=0 THEN
     diskreq:=ADDRESS(DumbGymnastics);
     diskreq^.iotdReq.ioReq.ioCommand:=TDChangeNum;
     Error:=DoIO(DumbGymnastics^);
     DiskCount:=diskreq^.iotdReq.ioActual;
     Error:=Motor(ON);
     Error:=ReadCylSec(DTA,0,0,0);
     Error:=Motor(OFF);
     ByteBand:=ByteCheck();
     Error:=Motor(ON);
     Error:=ReadCylSec(DTA,0,1,0);
     Error:=Motor(OFF);
     CloseDevice(DumbGymnastics);
     IF (Check() OR ByteBand ) THEN
        RetVal:= TRUE;
     (* Virus *)
     ELSE
        RetVal:= FALSE;
     (* no Virus  *)
     END; (* end if *)
  ELSE
   (* if error opeing drive *)
  RetVal:=FALSE; 
  END; (* End IF *)
  DeleteExtIO (DumbGymnastics,TSIZE(IOExtTD));
  DeletePort(DiskPort);
  FreeMem(DTA,TDSector);
  RETURN RetVal;
END VCheck;
END VK.
