/************************************************************************/
/*                                                                      */
/*                                                                      */
/*                                VirusX                                */
/*                                                                      */
/*                           by Steve Tibbett                           */
/*                            and Dan James                             */
/*                                                                      */
/*              Please - if you find a new virus, Send me a copy!       */
/*              (And warn me it's on the disk!).  I want to keep        */
/*              this program current.  (Feel free to put something      */
/*              neat on the disk also!)                                 */
/*                                                                      */
/*  The Makefile included in the "source.zoo" file you should have      */
/*  gotten in the VirusX.Zoo file this came from, is set up for the     */
/*  MANX Make Utility.  Switching to Lattice's LMK should be easy,      */
/*  but I've had no reason to.  The important thing is the command      */
/*  line switches and the BLINK command line.                           */
/*                                                                      */
/*  Thanks to John Toebes for a lot of help getting it going, and       */
/*  thanks to Dan James for providing KV, and providing most of the     */
/*  code that deals with the non-Bootblock viruses.                     */
/*                                                                      */
/************************************************************************/
/*                                                                      */
/*  History:                                                            */
/*  --------                                                            */
/*      April '88 or so:  V1.0 written and released.                    */
/*     A few days later:  V1.01 released.  V1.0 wrote garbage to the    */
/*                        disk if it was write protected then fixed.    */
/*          27-March-88:  V1.2 released.  V1.2's purpose in life was    */
/*                        to deal with the Byte Bandit virus.           */
/*                        (Actually, it's well after midnight - make    */
/*                        that March 28th. :)                           */
/*          28-March-88:  Oops, V1.2 was 3K or so bigger than it needed */
/*                        to be.  Fix it, release v1.21.                */
/*           15-June-88:  V1.3, V1.2 cleaned up and made smaller.       */
/*            8-July-88:  V1.4.  Revenge virus checking, Viewbooting,   */
/*                        check for SCA in RAM, more cleaning up.       */
/*           24-July-88:  V1.5, only change was the addition of the     */
/*                        Byte Warrior virus.                           */
/*             1-Aug-88:  V1.6 (busy week), Dan Mosedale sent me the    */
/*                        Northstar Virus.  Nuked it.                   */
/*            18-Aug-88:  V1.7 - after 2 weeks off, got the Obelisk     */
/*                        Softworks crew virus.                         */
/*     a few days later:  V1.71, can't remember why.                    */
/*   September Sometime:  Biggest mistake of my life, released V2.0.    */
/*         3 days later:  Bigger mistake:  Released V2.01 - which was   */
/*                        2.0 with another bug added.  Argh.            */
/*             6-Nov-88:  Finally got some time to clean things up,     */
/*                        check out the startup code bugs, clean up the */
/*                        docs and source, and release V2.1.  There     */
/*                        haven't been any new viruses in about a month */
/*                        now, but I hear one or two are on the way.    */
/*            31-Dec-88:  Got the IRQ virus yesterday.  Neat one!       */
/*                        Releasing V3.0 tonite or tomorrow to handle   */
/*                        it.  See description below.                   */
/*            04-Jan-89:  Got 2 new viruses, released 3.1.              */
/*            18-Feb-89:  And boy, am I tired.  8 (count 'em) 8 new     */
/*                        viruses in this version.  Ack!  DOUBLE        */
/*                        the last version.  New option: CHECK, good    */
/*                        for including VirusX with a commercial        */
/*                        program.  V3.20                               */
/*                                                                      */
/*            26-Nov-89:  Has it been this long?  Anyways... I'm        */
/*                        calling this one V4.0.  See the real docs     */
/*                        for more information.                         */
/*                                                                      */
/************************************************************************/
/*                                                                      */
/*  Viruses Dealt With:                                                 */
/*  -------------------                                                 */
/*                                                                      */
/*      SCA             - The SCA is the simplest virus to deal with,   */
/*                        as it's not actually DOING anything except    */
/*                        hiding in memory, until you reboot.           */
/*                        We just look at CoolCapture and fix it to get */
/*                        it out of RAM.                                */
/*                                                                      */
/*      Byte Bandit     - The Byte Bandit virus takes the DoIO() vector */
/*                        and redirects it through itself.  Thus, any   */
/*                        attempt to read or write the boot block (ie,  */
/*                        AmigaDOS trying to figure out what kind of    */
/*                        disk it is) results in the BB writing itself  */
/*                        onto that disk.  VirusX couldn't just rewrite */
/*                        the boot block, we have to get him out of RAM */
/*                        first.  This virus also has an interrupt that */
/*                        crashes the machine every 5 minutes or so     */
/*                        after it's infected a few of your disks.  Ow. */
/*                        It stays in memory not via the Capture        */
/*                        vectors, but by a Resident module.            */
/*                                                                      */
/*      Revenge         - Basically, a Byte Bandit clone except it will */
/*                        bring up an obscene pointer a few minutes     */
/*                        after you reboot.  We treat it much like the  */
/*                        byte bandit.                                  */
/*                                                                      */
/*      Byte Warrior    - Jumps right into 1.2 Kickstart.  Won't work   */
/*                        under 1.3.  Hangs around via Resident struct, */
/*                        doesn't do any damage.                        */
/*                                                                      */
/*      North Star      - Like SCA, hangs around via CoolCapture,       */
/*                        killing CoolCapture kills the North Star.     */
/*                                                                      */
/*      Obelisk Softworks Crew                                          */
/*                      - Hangs around via CoolCapture, also            */
/*                        watches reads of DoIO() (but doesn't          */
/*                        infect EVERY disk - onlyt ones you boot       */
/*                        off of)                                       */
/*                                                                      */
/*       IRQ            - This is the FIRST Non-Bootblock Virus.        */
/*                        It copies itself from place to place via the  */
/*                        first executable program found in your        */
/*                        startup-sequence.  It SetFunction's           */
/*                        OldOpenLibrary(), has a KickTagPtr,           */
/*                        and lives in the first hunk of an             */
/*                        infected program.                             */
/*                        THANKS! to Gary Duncan and Henrik Clausen for */
/*                        being the first to send this one to me!       */
/*                                                                      */
/*  Pentagon Circle     - This one looks at the DoIO vector, and has    */
/*                        a CoolCapture vector.  It will write itself   */
/*                        over any virus inserted, but not onto         */
/*                        anything else.  (Neat idea!).  No danger,     */
/*                        easy to eliminate.  Holding left button       */
/*                        while booting with this one shows different   */
/*                        screen colour, but doesn't get rid of it.     */
/*                        Thanks to Bill at CMI (CMI*BILL on Plink)     */
/*                        for sending me this one!                      */
/*                                                                      */
/*  SystemZ Virus Protector                                             */
/*                      - I took this one out.  It's not really a       */
/*                        'Virus' in that it won't overwrite a disk     */
/*                        without asking you first.  Besides, it seems  */
/*                        a lot of people LIKE the SystemZ Virus        */
/*                        Protector (though it isn't perfect).          */
/*                                                                      */
/*   Lamer Exterminator - THIS one was a bugger.  Yet another virus     */
/*                        aimed at hurting people.  Y'see, a Lamer      */
/*                        is apparently the worst kind of pirate -      */
/*                        one who doesn't crack software, doesn't       */
/*                        write software, just collects names and       */
/*                        addresses and collects and spreads software.  */
/*                        Lamers don't do anybody any good - and the    */
/*                        guy behind this Virus took it upon himself    */
/*                        to make their (and our) lives miserabler.     */
/*                        Anyway, this virus loads into RAM into a      */
/*                        different location every time (using a        */
/*                        random location).  It is encrypted on the     */
/*                        disk so you can't SEE the name of it, and     */
/*                        it never actually SHOWS the name (but it's    */
/*                        definately there).  It changes the            */
/*                        encryption key used each time it is written   */
/*                        back to disk.  It has a counter and will      */
/*                        wait until the machine has been reset 2 times */
/*                        OR until 3 disks have been infected, and will */
/*                        then pick a DATA block (Only a DATA block -   */
/*                        FFS disks are safe, I guess), randomly, and   */
/*                        will write the word 'LAMER!' all through it.  */
/*                        This is obviously not good, and will cause    */
/*                        random disk errors.  This is the worst kind   */
/*                        of havoc to wreak on the new user - and this  */
/*                        virus is EVERYWHERE!  I've gotten it from 5   */
/*                        people in the last week alone (all from       */
/*                        different countries!  Ack!).  Anyways, credit */
/*                        for being the first with this one is          */
/*                        Christian Schneider.  Thanks, Christian!      */
/*  Might as well break the margin convention here, eh?  Anyways,       */
/*  something else I thought of about this virus:  It introduces a NEW  */
/*  way for a Virus to stay in RAM.  Y'see, if ExecBase is okay at      */
/*  reboot time (Exec keeps a checksum, among other things, and checks  */
/*  to see if anything has been corrupted quite carefully).  Anyways,   */
/*  if Exec thinks ExecBase is okay, it doesn't bother rebuilding it.   */
/*  Sooo, this virus sets the SumKickData() vector to point at itself.  */
/*  Then at Reboot when this vector gets called after reset, the virus  */
/*  ReInstalls himself.  At least this is what I think is happening.    */
/*  This virus sets up a Resident structure, but never sets the Match   */
/*  Word - either this means we don't need the MatchWord or it means    */
/*  his SumKickData() is doing the recovery job - either way, it's      */
/*  new!  3 points for originality.                                     */
/*                                                                      */
/*  Graffiti - The first virus to come with rotating 3-d graphics!      */
/*             It's neat - you might want to trigger it (I'm not sure   */
/*             how) before nuking it.  Anyway, this one just sets       */
/*             CoolCapture(), does something with DoIO() during the     */
/*             reboot but sets it back to normal before anybody gets    */
/*             to look at it.  Lots of code is taken by the graphics    */
/*             stuff.  I just clear the CoolCapture vector.  [yawn]     */
/*                                                                      */
/*  Old Northstar - Poof.						*/
/*                                                                      */
/*  16 Bit Crew - Well, I didn't actually have to DO anything to get    */
/*		 VirusX to recognize it... because it seems to operate  */
/*               like the Graffiti Virus.  If the 16 bit crew is in     */
/*               RAM, VirusX will say it removed the Graffiti virus.    */
/*               Oh well.  8-)                                          */
/*                                                                      */
/*  DiskDoktor - I spent more time on this one than on any other.       */
/*               Y'see, this virus does lots of things.  The first one  */
/*               for some reason was quite funny to me.  heh            */
/*               What it would do is after you have rebooted 5 times,   */
/*               each time you reboot after that, the virus would eat   */
/*               10K times the total number of reboots - so after       */
/*               rebooting 10 times, you would be short about 100K.     */
/*               This virus also starts up another TASK.  I'm not       */
/*               exactly sure when it happens, but another task named   */
/*               'clipboard.device' will appear at a priority of -120,  */
/*               and will continually bash the Virus' vectors into the  */
/*               Coldcapture, Coolcapture, Warmcapture (which it sets   */
/*               to $ff000000 just to annoy), and the DoIO() vector.    */
/*               When I was working on this one, I figured I just had   */
/*               to restore the old values to the DoIO() vector, but as */
/*               soon as I did so, the Virus restored them - and since  */
/*               I didn't disassemble the entire thing, I didn't realize*/
/*               this until I wasted time looking for other faults.     */
/*               This one also allocates some memory, copies some code  */
/*               out of Exec into this memory, and executes it.  I      */
/*               never bothered to figure out why - Once it's gone, it's*/
/*               gone.                                                  */
/*                                                                      */
/*  Australian Parasite:  Hey - I like this one.  It says it will       */
/*   not destroy game bootsectors or corrupt disks - but it's still a   */
/*   Virus.  What makes this one unique is the way it lets itself       */
/*   be known.  Get this - after so many disk accesses (something like  */
/*   600 blocks read off of a floppy), it turns your screen Upside Down!*/
/*   Nifty.  You can still USE the screen upside down - it just looks,  */
/*   well, a bit weird.  Anyway, it uses the DoIO() vector, the TD      */
/*   Read vector, starts at SysStkLower, and that's about it.  Stays    */
/*   around via CoolCapture.  Thanks to Martyn at 17Bit Software        */
/*   in England for being the first to send this to me.                 */
/*                                                                     */
/*   VKill:  This one doesn't think it's a virus, and depending on    */
/*   your point of view, it might not be.  It won't write itself to   */
/*  a nonstandard boot block - so it won't hurt games.  But it will   */
/*     still load into your system, vector your PutMsg() routine      */
/*   through itself, sit on your supervisor stack, without telling    */
/*    you.  Not good.  I have had this one for a while, trying to     */
/*    decide what to do with it - I guess what convinced me is the    */
/*   fact that the text message which identifies itself is actually   */
/*   ENCRYPTED - for a virus killer, this is a pretty questionable    */
/*                            thing to do.                            */
/*                                                                     */
/************************************************************************/
/*                                                                      */
/*  Thanks also to Robb Walton for being the first to send one of the   */
/*  other ones, (but I can't remember which one anymore... 8-(  )       */
/*                                                                      */
/************************************************************************/

#include "virusx.h"
#include "virusx.i"

void MemCleanup() {}
extern struct DOSBase *DOSBase;

void 
chkabort(void) {}

int ReadBlock(int block, APTR loc);

#define BREAK (SetSignal(0,0) & SIGBREAKF_CTRL_C)

/******************************************************************/
/* These string constants are used in multiple places, and thus   */
/* save bytes by having only one copy of them.                    */
/******************************************************************/
char TITLETEXT[]        = "VirusX 4.00 by Steve Tibbett";
char CHECKINGTEXT[]	= "VirusX: Checking Device DF0:";
char TDName[]           =  "trackdisk.device";
char ITBodyText[80];
char text[]             = "DF?: Boot Sectors";

char BGSCheck[]		= { 'D','E','V','S','/',0xa0,0xa0,0xa0,0x20,0x20,0x20,0xa0,0x20,0x20,0x20,0xa0,0x00 };

/**********************************************************************/
/*                            The Big One                             */
/**********************************************************************/
extern struct VirusInfo VI[];

/************************************************************************/
/*  Miscellaneous variables.                                            */
/************************************************************************/
long    ChangeCount[4];                 /* TD_CHANGECOUNT for 4 drives  */
long    LastSum;                        /* Used in the checksumming     */
long    error;                          /* sort of a temporary variable */
char    WindowBig = FALSE;              /* TRUE if the window is big    */
int 	VirusesInBigWindow;		/* For setting big window size  */
struct  Port *diskport;                 /* trackdisk's port.            */
struct  IOStdReq *diskreq;              /* trackdisk's IOStdReq         */
long    DisksChecked, DisksInstalled;   /* for title bar info           */
struct 	Process *Me;			/* for setting the WindowPtr	*/
int 	WindowYDelta;			/* Big Window Y Size Change	*/


char 	CaptureCheck = TRUE;
char 	KickTagCheck = FALSE;
char	CheckAndQuit = FALSE;
char	SetPatchFlag = FALSE;

struct IntuitionBase    *IntuitionBase; 	/* For Library Bindings */
struct GfxBase          *GfxBase;
struct Window           *Window;
struct IntuiMessage     *Message;
struct ExecBase         *ExecBase;
struct Screen		*Screen;

char Keepgoing;         /* A flag.  It's false when we want out.        */
long x, y, i;           /* Left over from my using Basic                */
char flag;              /* Another flag.  Lets start our own country.   */

void RenderItem(char *Item, int Value);

struct NewWindow NewWindow =
        {
        128,0,  309,10,  0,1,
        DISKINSERTED | CLOSEWINDOW | VANILLAKEY | NEWSIZE | MOUSEBUTTONS, /* IDCMP Flagz */
        WINDOWDRAG | WINDOWDEPTH | RMBTRAP | WINDOWCLOSE | NOCAREREFRESH, /* Windo Flagz */
        NULL, NULL,TITLETEXT,
        NULL,NULL,0,0,0,0,WBENCHSCREEN,
        };

struct RastPort *RP;
unsigned char *diskbuffer;

/************************************************************************/
/* Warning messages.  These messages get modified before being          */
/* displayed (Unless you DO have a DF9:)                                */
/************************************************************************/
char TEXTPTR[] = "Danger:  The disk in DF?: is";
char NBCTEXT[] = "Danger:  The disk in DF?: has";

/*************************************************************************/
/*   This is a byte by byte copy of working boot block code.  Check it   */
/*   out if you like.  This is what gets written back to the disk when   */
/*   you ask VirusX to fix a disk.                                       */
/*************************************************************************/
unsigned char bootblock[] = { 'D', 'O', 'S', 0,
0xc0, 0x20, 0x0f, 0x19, 0x00, 0x00, 0x03, 0x70, 0x43, 0xfa, 0x00, 0x18,
0x4e, 0xae, 0xff, 0xa0, 0x4a, 0x80, 0x67, 0x0a, 0x20, 0x40, 0x20, 0x68,
0x00, 0x16, 0x70, 0x00, 0x4e, 0x75, 0x70, 0xff, 0x60, 0xfa, 0x64, 0x6f,
0x73, 0x2e, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x00, 0x00, 0x00,
0x00, 0x00};

/**********************************************************************/
/*                         It all starts here                         */
/**********************************************************************/
int
main(int argc, char **argv)
{
x=1;

while (argv[x] != 0)
	{
	if (argv[x][0] == '-')
		{
		switch (toupper(argv[x][1]))
			{
			case 'A':
				NewWindow.Flags |= ACTIVATE;
				break;
			case 'C':
				CaptureCheck = FALSE;
				break;
			case 'K':
				KickTagCheck = TRUE;
				break;
			case 'Q':
				CheckAndQuit = TRUE;
				break;
			case 'R':
				SetPatchFlag = TRUE;
				break;
			case 'X':
				NewWindow.LeftEdge = atoi(&argv[x][2]);
				break;
			case 'Y':
				NewWindow.TopEdge = atoi(&argv[x][2]);
				break;
			};
		};
	x++;
	};

if  ((diskbuffer = AllocMem((long)1024, (long)MEMF_CHIP|MEMF_CLEAR)) == 0) 
	goto OuttaHere;

/* These had better not ever fail.  If they do, something's Very wrong. */
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L);
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L);
ExecBase = (struct ExecBase *)OpenLibrary("exec.library", 0L);

Me = (struct Process *)FindTask(0L);
Me->pr_WindowPtr = 0;

/*  We use the same port/request through the whole program.  Works OK. */
diskport = CreatePort(0L,0L);
diskreq = CreateStdIO(diskport);

if ((Window = OpenWindow(&NewWindow)) == NULL)
	goto Quitter;

RP = Window->RPort;
Screen = Window->WScreen;

/* Set the ChangeCount for the Trackdisk devices */
SetUp();

/* Check RAM out... */
CheckMemoryForViruses();
CheckMemoryForLinkViruses();

CheckBlock();

if (!CheckAndQuit)
	DoLittle();

Quitter:
if (Window != 0) CloseWindow(Window);
if (diskport != 0) DeletePort(diskport);
if (diskreq != 0) DeleteStdIO(diskreq);
FreeMem(diskbuffer, (long)1024 );
OuttaHere:
CloseLibrary(GfxBase);
CloseLibrary(IntuitionBase);
CloseLibrary((struct Library *)ExecBase);
return(0);
}

/**********************************************************************/
/*                   This is the main VirusX loop.                    */
/**********************************************************************/
void
DoLittle(void)
{
long Code, Class;     /* for storing our IntuiMessage stuff */
char KG2;      		/* KeepGoing 2.  Another boolleean. */
int phase;

KG2 = TRUE;

SetAPen(RP, 1L);
SetBPen(RP, 0L);
SetDrMd(RP, (long)JAM2);

phase = 0;

while (KG2 == TRUE)
        {
	if (BREAK) break;

	Message = (struct IntuiMessage *)GetMsg(Window->UserPort);
        if (Message == 0)
       	        {
               	WaitTOF();
                WaitTOF();
               	WaitTOF();	/* I don't trust Delay() anymore */
                WaitTOF();
       	        WaitTOF();
               	WaitTOF();

		if (++phase > 20) 
			{
			phase = 0;
			CheckMemoryForLinkViruses();
			};
                continue;
                };

        Class = Message->Class;
        Code = Message->Code;
        ReplyMsg((struct Message *)Message);

        switch (Class)
		{
		case CLOSEWINDOW:
	                KG2 = FALSE;
        		break;
		
		case MOUSEBUTTONS:
			if (Code == MENUDOWN)
				ToggleBigWindow();
			break;

		case VANILLAKEY:
			switch (toupper(Code))
	                        {
	                        case 'I':
        	                        ToggleBigWindow();
        	                        break;
				case 'C':
	                                for (x=0; x<4; x++) ChangeCount[x] = 10000;
        	                        CheckBlock();
					break;
				case 27:
					KG2 = FALSE;
					break;
				default:
	                                flag = ShowAscii(Code);
        	                        if (flag == 1) CheckBlock();
                	        };
                	break;

		case DISKINSERTED:
	                CheckBlock();
        		break;

	        };

        if (WindowBig) RenderInfo();
        };
}


/************************************************/
/* Opens trackdisk, finds out who's out there,  */
/* and sets Changecount up accordioningly.      */
/************************************************/
void
SetUp(void)
{
long x;

for (x = 0; x < 4; x++) /* go thru all 4 possible drives */
        {
        ChangeCount[x] = 1000;
        error = OpenDevice(TDName,(long)x,diskreq,0L);
        if (error > 0)
                ChangeCount[x] = -1;
		else CloseDevice(diskreq);
        };
}

/*********************************************************/
/* This routine returns which drive changed disks lately */
/*********************************************************/
int
WhoChanged(void)
{
int RetVal = -1;       /* The value we'll return */

for (x = 0; x < 4; x++)
        {
        if (ChangeCount[x] == -1)
                continue;       /* no drive here */

        error = OpenDevice(TDName,(long)x,diskreq,(long)0);
        if (error > 0)
                continue;       /* no drive here */

        diskreq->io_Command = TD_CHANGESTATE;
        DoIO(diskreq);
        if (diskreq->io_Actual != 0)
                {
                CloseDevice(diskreq);
                continue;
                };

        diskreq->io_Command = TD_CHANGENUM;
        DoIO(diskreq);
        if (diskreq->io_Actual != ChangeCount[x])
                {
                RetVal = x;
                ChangeCount[x] = diskreq->io_Actual;
                CloseDevice(diskreq);
                break;
                };

        CloseDevice(diskreq);
        };

return(RetVal);
}

/****************************************************************/
/*  Figures out which drive changed disks (using WhoChanged(),  */
/*  And checks it.  Calling this after every DISKINSERTED is OK.*/
/****************************************************************/
void
CheckBlock(void)
{
long Sum, a, Unit;
unsigned long *iptr, *ptr;
char drivename[10];

while ((Unit = WhoChanged()) != -1)
        {
	short VirusFound = -1, x = 0, Virus = FALSE;

 	CHECKINGTEXT[26] = '0'+Unit;
	SetWindowTitles(Window, CHECKINGTEXT, (STRPTR)-1);
        strcpy(drivename, "DF0:");
        drivename[2] = '0'+Unit;

        /* Unit # to open is returned by "WhoChanged()" up above. */
        if (Unit == -1) continue;

        error = OpenDevice(TDName,(long)Unit,diskreq,0L);
        if (error > 0) continue;
	error = ReadBootBlock();
        DisksChecked++;
        CloseDevice(diskreq);
        if (error == FALSE) continue;

        ptr = (long *)diskbuffer;
        iptr = (long *)diskbuffer;

        if (iptr[0] != ID_DOS_DISK) 
		continue;
	
        Sum = 0;
        for (a=0; a<256; a++)
                {
                LastSum = Sum;
                Sum = Sum + ptr[a];
                if (LastSum > Sum) Sum++;  /* took me a while to figger this out */
                }

        if (Sum != 0)
                {
		CheckDriveForLinkViruses(drivename);
                continue; /* if it's not bootable, we DONT want it! */
                };

	while (VI[x].Name != 0)
		{
		if (Virus == TRUE) break;

		if (iptr[VI[x].LongWordOffsets[0]] == VI[x].WhatToExpect[0])
			if (iptr[VI[x].LongWordOffsets[1]] == VI[x].WhatToExpect[1])
				{
				VI[x].NumFound++;
				VirusFound = x;
				Virus = TRUE;
				break;
				};
		x++;
		};

        /* compare boot block with real boot block.  If it's not, notify */
        if (Virus == FALSE)
	        for (x = 0; x < 39; x++) /* num of bytes in bootblock */
                	if (diskbuffer[8+x] != bootblock[8+x])
	                        Virus = TRUE;

	/* Oh no, a Virus! */
        if (Virus == TRUE)
                {
                NBCTEXT[23] = '0'+Unit; /* change DF9: to real drive in text */
                TEXTPTR[23] = '0'+Unit;
                error = FALSE;

                /* Should check Copy Count flag sometime... */
		if (VirusFound != -1)
			error = MyRequest(VI[VirusFound].Name, 1);
			else
                        {
                        /* Probably just a custom boot block (or a new virus...) */
			char buf[200];
			strcpy(buf, NBCTEXT);
			strcat(buf, "|Nonstandard Boot Code!");
			WBenchToFront();
			error = SimpleRequest(buf, "Ignore It|Repair It", Window, 0);
                        }

                if (error != 0) 
			DoInstall(Unit); /* user wants it neutered. */
                };

        CheckDriveForLinkViruses(drivename);
        };  /* End of While Whochanged */

SetWindowTitles(Window, TITLETEXT, (STRPTR)-1);
}

/********************************************/
/* This is where the boot code gets changed */
/********************************************/
void  
DoInstall(int un)
{
int x;

/* Rewrite disk?  Really?  */
error = SimpleRequest("Install New Bootblock?|Are you sure?", "No, Cancel|Yes, Do It", Window, 0);

if (error == 0) return;      /* user changed his brain. */

DisksInstalled++;

error = OpenDevice(TDName, (long)un,diskreq,0L);
if (error > 0) return;

while (ProtStatus() == TRUE)
        {
	error = SimpleRequest("The disk is write protected.", "Forget It|Try Again", Window, 0);
        if (error != 0) /* error is true or false, depending on user */
		continue;
        CloseDevice((struct IOStdReq *)diskreq);
        return; /* unrecoverable write protect error!! Panic!!!!!!! */
	};

for (x = 0; x < 1024; x++)
        diskbuffer[x] = 0;      /* clear diskbuffer to zero.  clean. */

CopyMem(bootblock, diskbuffer, 50L); /* Copy it over */

/* Write it ! */

        error = 0;
        diskreq->io_Length = 1024; /* here we go! */
        diskreq->io_Data = (APTR)diskbuffer;
        diskreq->io_Command = CMD_WRITE;
        diskreq->io_Offset = 0L;
        DoIO((struct IOStdReq *)diskreq);
        error = diskreq->io_Error;

if (error < 19 && error != 29)
        {
        diskreq->io_Command = CMD_UPDATE;       /* flush buffer to disk */
        DoIO((struct IOStdReq *)diskreq);
        error = diskreq->io_Error;
        };

MotorOff();

if (error > 19 && error != 29)
	SetWindowTitles(Window, "Disk Error!", (STRPTR)-1);
	else SetWindowTitles(Window, "Disk Healed.", (STRPTR)-1);

Delay(75L);
SetWindowTitles(Window, TITLETEXT, (STRPTR)-1);

CloseDevice((struct IOStdReq *)diskreq);
}


/**********************************************************************/
/*                      Turn off the Disk Motor                       */
/**********************************************************************/
void
MotorOff(void)
{
	diskreq->io_Length = 0;
	diskreq->io_Command = TD_MOTOR;/* Motor Off */
	DoIO(diskreq);
}

/* This has to be global */
unsigned long *TD;

/**********************************************************************/
/*             Check RAM for Known Viruses from Database              */
/**********************************************************************/
void
CheckMemoryForViruses(void)
{
short x = 0, y;
short LookFlags;
char AlertFlag;
unsigned long *EB;

EB = (unsigned long *)ExecBase;
TD = (unsigned long *)FindName(&ExecBase->DeviceList, "trackdisk.device");

while (VI[x].Name != 0)
	{
	AlertFlag = FALSE;
	
/* * * Check First * * */

	if (VI[x].Handler != 0)
		AlertFlag = ((VI[x].Handler)());
	else
	for (y=0; y<2; y++)
		{
		LookFlags = VI[x].HowToLook[y]; 
		if (LookFlags == 0) continue;
	
		if (LookFlags & HTL_TDM1C)
			{
			unsigned long *TTD = TD;
			
			TTD = TTD - (0x1c / 4);

			if (LookFlags & HTL_LOOKINDIRECT) TTD = (unsigned long *)*TTD;

			TTD = (char *)(((unsigned long)TTD)+VI[x].LookOffset[y]);

			if (*TTD == VI[x].WhatToLookFor[y]) 
				{ AlertFlag = TRUE; }
				else AlertFlag = FALSE;
			};

		if (LookFlags & HTL_DOIO)
			{
			unsigned long *TEB;

			TEB = (char *)(((unsigned long)EB)-0x1c6);
	
			if (LookFlags & HTL_LOOKINDIRECT) TEB = (unsigned long *)*TEB;

			TEB = (char *)(((unsigned long)TEB)+VI[x].LookOffset[y]);
		
			if (*TEB == VI[x].WhatToLookFor[y]) 
				{ AlertFlag = TRUE; }
				else AlertFlag = FALSE;
			};

		if (LookFlags & HTL_ABSOLUTE)
			{
			unsigned short *S;

			S = VI[x].WhatToLookFor[y];
			if (*S == VI[x].LookOffset[y])
				AlertFlag = TRUE;
			};


/* * * DONE CHECKING, NOW FIX * * */

		if (AlertFlag == TRUE)
			{
			for (y=0; y<2; y++)
				{
				unsigned long *Dest;

				LookFlags = VI[x].DoToThis[y]; 
				if (LookFlags == 0) continue;

				if (LookFlags & HTL_CLEARKICKTAGS)
					ExecBase->KickTagPtr = 0;

				if (LookFlags & HTL_SETLONG)
					{
					unsigned long *ptr;
					ptr = VI[x].WhatToLookFor[0];
					*ptr = VI[x].WhatToLookFor[1];
					};
	
				if (LookFlags & HTL_TDM1C)
					{
					unsigned char *t;
					unsigned long *TEB;
		
					t = (unsigned char *)TD;
					t = t - 0x1c;
					TEB = (unsigned long *)t;

					Dest = TEB;

					TEB = (unsigned long *)*TEB;

					t = (char *)TEB;
					t = t + VI[x].AtOffset[y];
					TEB = (unsigned long *)t;
		
					Forbid();
					if (LookFlags & HTL_SETTO)
						{
						*TEB = VI[x].WithThis[y];
						}
						else Dest[0] = *TEB;
					Permit();
					};


				if (LookFlags & HTL_DOIO)
					{
					unsigned char *t;
					unsigned long *TEB;

					t = (unsigned char *)EB;
					t = t - 0x1c6;
					TEB = (unsigned long *)t;

					Dest = TEB;

					TEB = (unsigned long *)*TEB;

					t = (char *)TEB;
					t = t + VI[x].AtOffset[y];
					TEB = (unsigned long *)t;

					Forbid();
					if (LookFlags & HTL_SETTO)
						*TEB = VI[x].WithThis[y];
						else
						{
						Dest[0] = *TEB;
						};
						
					Permit();
					};
				};
			};
		};

	/* Do this AFTER processing the REAL removal. */

	if (VI[x].CoolCapture != 0)
		{
		if ((long *)ExecBase->CoolCapture == (long *)VI[x].CoolCapture)
			{
			ExecBase->CoolCapture = 0;
			AlertFlag = TRUE;
			};
		};

        if (AlertFlag == TRUE) 
		{
		MyRequest(VI[x].Name, 2);
		};
	x++;
	}

if ((ExecBase->CoolCapture != NULL) && CaptureCheck)
	{
	if (SetPatchFlag)
		if ((ExecBase->CoolCapture>(APTR)0x80000) && (ExecBase->CoolCapture<(APTR)0x100000))
			goto SkipCoolCapCheck;
	x = SimpleRequest("The system's CoolCapture Vector|is not Zero.  This could mean a new|Virus is in RAM, or that some other program|is using this vector.  See the|VirusX Documentation for more info.|Clear it?", " Yes | No ", Window, 0);
	if (x == 0) ExecBase->CoolCapture = NULL;
	};

if ((ExecBase->ColdCapture != NULL) && CaptureCheck)
	{
	if (SetPatchFlag)
		if ((ExecBase->ColdCapture>(APTR)0x80000) && (ExecBase->ColdCapture<(APTR)0x100000))
			goto SkipCoolCapCheck;
	x = SimpleRequest("The system's ColdCapture Vector|is not Zero.  This could mean a new|Virus is in RAM, or that some other program|is using this vector.  See the|VirusX Documentation for more info.|Clear it?", " Yes | No ", Window, 0);
	if (x == 0) ExecBase->ColdCapture = NULL;
	};

SkipCoolCapCheck:
if ((ExecBase->KickTagPtr != NULL) && (KickTagCheck == TRUE))
	{
	x = SimpleRequest("The system's KickTagPtr Vector|is not Zero.  This could mean a new|Virus is in RAM, or that some other program|is using this vector.  See the|VirusX Documentation for more info.|Clear it?", " Yes | No ", Window, 0);
	if (x == 0) ExecBase->KickTagPtr = NULL;
	};

}

/**************************************************************/
/*  This is the routine that displauys a block as ASCII text. */
/**************************************************************/
int 
ShowAscii(long key)
{
int drive, x, y, deltax, deltay;
long a;
int FLAG=0;

drive = key - '0';

if ((drive < 0) || (drive > 3) || (ChangeCount[drive] == -1)) return(0);

if ((error = OpenDevice(TDName,(long)drive,diskreq,0L)) > 0) return(0);
error = ReadBootBlock();
CloseDevice(diskreq);
if (error == FALSE) return(0);

/* save the amount we moved the window */
deltax = Window->LeftEdge;
deltay = Window->TopEdge;

WindowToFront(Window);
MoveWindow(Window, -deltax, -deltay);
SizeWindow(Window, 278L, 160-WindowYDelta);
WaitForNewSize();


SetAPen(RP, 0L);
RectFill(RP, 2, 12, 278, 167);

SetAPen(RP, 3L);
Move(RP, (long)(14+(12*8)), 165L);
Text(RP, "Block 0", 7L);
Move(RP, (long)(324+(12*8)), 165L);
Text(RP, "Block 1", 7L);
SetAPen(RP, 1L);

text[2] = key;
SetWindowTitles(Window, text, (STRPTR)-1);

x=0; y=0;

SetAPen(RP, 1L);
SetDrMd(RP, JAM2);

for (a=0; a<512; a=a+32)
        {
        Move(RP, (long)(10+(x*8)), (long)20+(y*9));
        Text(RP, &diskbuffer[a], 32L);

        Move(RP, (long)(320+(x*8)), (long)20+(y*9));
        Text(RP, &diskbuffer[a+512], 32L);
        y++;
        };

Wait(1<<Window->UserPort->mp_SigBit);
Message = (struct IntuiMessage *)GetMsg(Window->UserPort);

/*  If a disk was inserted, we want CheckBlock() to happen later on some time */
if (Message->Class == DISKINSERTED) FLAG=1;
ReplyMsg((struct Message *)Message);

SetAPen(RP, 0L);
RectFill(RP, 2, 12, 278, 167);

SetWindowTitles(Window, TITLETEXT, (STRPTR)-1);

SizeWindow(Window, -278L, -160+WindowYDelta);
WaitForNewSize();
if (WindowBig) RenderInfo();

/* deltas plus current position, in case dude moved the window */
MoveWindow(Window, deltax+(-Window->LeftEdge), deltay+(-Window->TopEdge));
Delay(10L);

return(FLAG);
}


/**********************************************************************/
/* When you do a SizeWindow() command, you have to wait for a NEWSIZE */
/* IntuiMessage before drawing in it.  That's all this routine does.  */
/**********************************************************************/
void
WaitForNewSize(void)
{
int Class;

while (TRUE)
	{
	WaitPort(Window->UserPort);
	Message = (struct IntuiMessage *)GetMsg(Window->UserPort);
	Class = Message->Class;
	ReplyMsg((struct Message *)Message);
	if (Class != MOUSEBUTTONS) break;
	};
}


/**********************************************************************/
/*                        Make an AutoRequest.                        */
/*                                                                    */
/*                               Types:                               */
/*                                                                    */
/*                1: "is infected with the xxx VIRUS!"                */
/*            2: "NOTICE:  The `blah' VIRUS was found..."             */
/*                      3: Cold/capture warning.                      */
/**********************************************************************/
int
MyRequest(char *string, int type)
{
char buf[255];

switch (type)
        {
        case 1:
                strcpy(ITBodyText, "infected with the `");
                strcat(ITBodyText, string);
                strcat(ITBodyText, "' VIRUS!");
                break;
        case 2:
                strcpy(ITBodyText, "NOTICE:  The `");
                strcat(ITBodyText, string);
                strcat(ITBodyText, "' VIRUS was found");
                break;
        };


WBenchToFront();
switch (type)
	{
	case 1:
		strcpy(buf, TEXTPTR);
		strcat(buf, "|");
		strcat(buf, ITBodyText);
		return(SimpleRequest(buf, "Ignore It|Repair It", Window, 0));
	case 2:
		strcpy(buf, "NOTICE:|The ");
		strcat(buf, string);
		strcat(buf, " VIRUS was found|in memory, and is now Disabled.|Please see the VirusX Documentation|for more information.");
		return(SimpleRequest(buf, " Will Do. ", Window, SR_ANYKEYQUIT));
	};
}



/**********************************************************************/
/*          Reads the first 1024 bytes into the 'diskbuffer'          */
/**********************************************************************/
int
ReadBootBlock(void)
{
	if (ReadBlock(0, (APTR)diskbuffer) == FALSE) return(FALSE);
	/* If we got block 0, Block 1 cannot possibly fail. */
	ReadBlock(1, (APTR)&diskbuffer[512]);
	return(TRUE);
}

/**********************************************************************/
/*             Read a sector to the given memory location             */
/**********************************************************************/
int
ReadBlock(int block, APTR loc)
{
	diskreq->io_Command = CMD_READ;
	diskreq->io_Data = loc;
	diskreq->io_Length = 512;
	diskreq->io_Offset = block*512;
	DoIO((struct IOStdReq *)diskreq);

	if (diskreq->io_Error > 0) 
		return(FALSE);

	Delay(5);
	MotorOff();

	return(TRUE);
}

/**********************************************************************/
/*                     Shove diskbuffer to disk.                      */
/**********************************************************************/
 int
WriteBlock(long block)
{
	diskreq->io_Length  = 512;
	diskreq->io_Data    = (APTR)diskbuffer;
	diskreq->io_Command = CMD_WRITE;
	diskreq->io_Offset  = block*512;

	DoIO(diskreq);

	if(diskreq->io_Error > 19)
		return(FALSE);

	diskreq->io_Command = ETD_UPDATE;
	DoIO(diskreq);

	MotorOff();
}

/**********************************************************************/
/*                Return TRUE if disk is not writable.                */
/**********************************************************************/
int
ProtStatus(void)
{
	diskreq->io_Flags   = 0;
	diskreq->io_Command = TD_PROTSTATUS;

	DoIO(diskreq);

	if(diskreq->io_Error == TDERR_DiskChanged)
		return TRUE;

	if(diskreq->io_Actual)
		return TRUE;

	return FALSE;
}


/**********************************************************************/
/*    Look for any virus that might appear other than at boot time    */
/**********************************************************************/
void
CheckMemoryForLinkViruses(void)
{
if (CheckRAMForIRQ() == 1)
        MyRequest("IRQ", 2);

if (CheckRAMForXeno() == 1)
	SimpleRequest("A program you ran contained the Xeno virus.|It has been removed from RAM, but VirusX will not|extensively search for it on disk.|Use the KV Utility to check recently executed files.", " Thanks ", Window, SR_ANYKEYQUIT);

CheckRamForLamer();
}


/**********************************************************************/
/*            Check the disk for any non-bootblock Viruses            */
/**********************************************************************/
void
CheckDriveForLinkViruses(char *drivename)
{
int err;
char buffer[200];
char dirbuffer[80];
char filebuffer[100];
char fnamebuffer[100];
char ssbuffer[80];
char sscommand[80];
char pass;
BPTR fp = 0;

/** Check for RLamer Virus **/
CheckDiskForRLamer(drivename[2]-'0');

/** GET FIRST COMMAND IN S.S. FOR USE IN CHECKING FOR ANY VIRUS **/
ssbuffer[0] = 0;
strcpy(buffer, drivename);
strcat(buffer, "S/Startup-Sequence");
fp = Open(buffer, MODE_OLDFILE);
if (fp != 0) 
	{
	/* It's faster to do a single read and find the end of the 
	   string myself, than it is to read the S-S character by character */

	Read(fp, sscommand, 80);	
	
	for (x=0; x<80; x++)
		{
		if (sscommand[x] == 32 || sscommand[x] == 10 || sscommand[x] == ';')
			{
			sscommand[x] = 0;
			break;
			};
		};
	}

Close(fp);
fp = 0;

/** Check for BGS9 Virus **/
strcpy(buffer, drivename);
strcat(buffer, BGSCheck);
fp = Lock(buffer, ACCESS_READ);
if (fp != 0)
	{
	BPTR vfp;
	long VL;

	vfp = 0;

	strcpy(buffer, drivename);
	strcat(buffer, sscommand);
	vfp = Open(buffer, MODE_OLDFILE);
	if (vfp == 0)
		{
		strcpy(buffer, drivename);
		strcat(buffer, "C/");
		strcat(buffer, sscommand);
		vfp = Open(buffer, MODE_OLDFILE);
		if (vfp == 0)
			{
			strcpy(buffer, "The disk in ");
			strcat(buffer, drivename);
			strcat(buffer, "apparently has been|affected by the BGS9 Virus, but|I cannot find the Virus itself.|See the Documentation for more info.");
			SimpleRequest(buffer, " Okay ", Window, SR_ANYKEYQUIT);
			goto OuttaHereNow;
			}
		};

	/** Now vfp is the virus's file pointer **/
	Seek(vfp, 0, OFFSET_END);
	VL = Seek(vfp, 0, OFFSET_BEGINNING);
	if (VL != 2608)
		{
		char buff[255];
		strcpy(buff, "A virus that looks like BGS9 was found,|on the file ");
		strcat(buff, buffer);
		strcat(buff, ",|but it's Not the BGS9 virus.  You should examine|this file, and the 'Devs' directory on that disk.");
		SimpleRequest(buff, "Oh No!", Window, 0);
		} else
		{
		char nbuff[80];
		int err;

		Close(vfp);
		vfp = 0;
		err = DeleteFile(buffer);
		if (err != 0)
			{
			strcpy(nbuff, drivename);
			strcat(nbuff, BGSCheck);
			err = Rename(nbuff, buffer);
			if (err != 0)
				{
				strcpy(buffer, "BGS9 Virus removed from ");
				strcat(buffer, drivename);
				SimpleRequest(buffer, "  Thank you  ", Window, 0);
				goto OuttaHereNow;
				};
			};

		strcpy(buffer, "Error removing BGS9 virus from|device ");
		strcat(buffer, drivename);
		strcat(buffer, ", file ");
		strcat(buffer, sscommand);
		strcat(buffer, ".|Check your startup sequence (the first command in it),|and look in the DEVS directory.");
		SimpleRequest(buffer, "  Thank you  ", Window, 0);
		};

	if (vfp != 0) Close(vfp);
	};
OuttaHereNow:

/** Check for IRQ **/
pass = 0;
while (TRUE)
	{
	if (pass == 3) break;
	if (pass > 1 && sscommand[0] == 0) break;

	switch (pass)
		{
		case 0:		/* Check DF0:C/DIR 	*/
			strcpy(dirbuffer, drivename);
			strcat(dirbuffer, "C/");
			strcpy(filebuffer, "DIR");
			break;
		case 1:		/* Check Startup-Sequence */
			strcpy(dirbuffer, drivename);
			strcat(dirbuffer, "C/");
			strcpy(filebuffer, sscommand);
			break;
		case 2:		/* Check the drive for the ssname */
			strcpy(dirbuffer, drivename);
			strcpy(filebuffer, sscommand);
			break;
		};

	pass++;

	strcpy(fnamebuffer, dirbuffer);
	strcat(fnamebuffer, filebuffer);

	/* if return is 1, we go it. */
	err = CheckFileForIRQ(fnamebuffer, 0);
	
	if (err == 1)
		{
		strcpy(buffer, "NOTICE:  The IRQ Virus was found|on the file '");
		strcat(buffer, fnamebuffer);
		strcat(buffer, "'.|Okay to remove?");

		WBenchToFront();
		err = SimpleRequest(buffer, "Leave it|Remove it", Window, 0);
		if (err == 0)
			continue;

		while (TRUE)
			{
			err = CheckFileForIRQ(fnamebuffer, 1);
			if (err == 1)
			        {
				SetWindowTitles(Window, "Disk Healed.", (STRPTR)-1);
				Delay(75);
				SetWindowTitles(Window, TITLETEXT, (STRPTR)-1);
				break;
				} else
				{
				err = SimpleRequest("Error removing.|Disk may be write protected.|Try Again?", "Cancel|Retry", Window, 0);
				if (err == 0) break;
				}
			};
		};
	};
}


/**********************************************************************/
/*  Switches between the big, rendered-in window, and the small one.  */
/**********************************************************************/
void
ToggleBigWindow(void)
{
if (Window == 0) return;

VirusesInBigWindow = 0;

if (WindowBig == FALSE)
	{
	/* Make window big: Step 1, Figure Y Height Needed */
	WindowYDelta = 24;   /* Start at 24: DisksChecked, DisksInstalled */
	x=0;
	while (VI[x].Name != 0)
		{
		if (VI[x].NumFound != 0)
			{
			VirusesInBigWindow++;
			WindowYDelta += 9;
			};
		x++;
		};

	if ((Window->TopEdge+Window->Height+WindowYDelta) > Screen->Height)
		MoveWindow(Window, 0, -Window->TopEdge);

	SizeWindow(Window, 0, WindowYDelta);
	WaitForNewSize();
	WindowBig = TRUE;
	RenderInfo();
	}
	else 
	{
	/** Make Window Small **/
	SizeWindow(Window, 0, -WindowYDelta);
	WaitForNewSize();
	WindowYDelta = 0;
	WindowBig = FALSE;
	}
}


/**********************************************************************/
/*                       Render the Info Window                       */
/**********************************************************************/
int ItemY;

void
RenderInfo(void)
{
int Num = 0, x = 0, Delta;
char buff[80];

while (VI[x].Name != 0)
	{
	if (VI[x].NumFound != 0) 
		Num++;
	x++;
	};

Delta = (Num-VirusesInBigWindow)*9;
if (Delta != 0)
	{
	if ((Window->TopEdge+Window->Height+Delta) > Screen->Height)
		MoveWindow(Window, 0, -Window->TopEdge);
	SizeWindow(Window, 0, Delta);
	WindowYDelta += Delta;
	WaitForNewSize();
	};

VirusesInBigWindow = Num;

ItemY = 17;
SetAPen(RP, 1);
SetDrMd(RP, JAM2);

RenderItem("Disks Checked:", DisksChecked);
RenderItem("Disks Installed:", DisksInstalled);
ItemY += 3;
x=0;
while (VI[x].Name != 0)
	{
	if (VI[x].NumFound != 0)
		{
		strcpy(buff, VI[x].Name);
		strcat(buff, " Found:");
		RenderItem(buff, VI[x].NumFound);
		};
	x++;
	};
}


/**********************************************************************/
/*                  Draw an item into the Big Window                  */
/**********************************************************************/
 void
RenderItem(char *Item, int Value)
{
char buff[10];
int Len = strlen(Item);

SetAPen(RP, 0);
RectFill(RP, 2, ItemY-7, Window->Width-3, ItemY+2);
SetAPen(RP, 1);

Move(RP, 214-(Len*8), ItemY);
Text(RP, Item, Len);
Move(RP, 220, ItemY);
Len = itoa(buff, Value);
while (strlen(buff) < 6) strcat(buff, " ");
Text(RP, buff, 5);
ItemY += 9;
}


/**********************************************************************/
/*                      Convert integer to ASCII                      */
/**********************************************************************/
 int
itoa(char *buff, int value)
{
char buf2[11];
int len = 0;
int i = 0;

do	{
	buf2[len++] = '0'+(value%10);
	value = value / 10;
	} while (value > 0);

len--;

while (len != -1) 
	{
	buff[i++] = buf2[len--];
	};

buff[i] = 0;
return(i);
}



/**********************************************************************/
/*                        Do some IRQ Hunting                         */
/**********************************************************************/

#define VTAG     0x00000109L
#define SLONG    ((long)sizeof(long))

#define OK        1                     /* no error */
#define GOTHIM   OK                     /* removed virus from file */

#define VTAG     0x00000109L            /* virus hunk length */
#define VSIG1    0x0000FFFEL            /* part of virus signature */
#define VSIG2    0x61000000L            /* part of virus signature */


long inp, *buff, size;

int
cleanup(int val)
{
        if(inp)         Close(inp);
        if(buff)        FreeMem(buff,size);
        return val;
}

/**********************************************************************/
/*              Check the passed filename for IRQ Virus.              */
/*        If flag is FALSE, then just determine, don't remove.        */
/**********************************************************************/
int
CheckFileForIRQ(char *fname, int flag)
{

	BPTR flock;
        int   i = 0;
        long  nhunk;
        long tbuff[488/4];

        buff = 0L;

	if ((inp = Open(fname, MODE_OLDFILE)) == FALSE)
		return(FALSE);

        Read(inp, (char *)&tbuff[0], 487);     /* get the first long word   */
        if(tbuff[0] != 0x000003F3)            /* check for executable file */
                return cleanup(FALSE);

        if(tbuff[5] != VTAG)
                return cleanup(FALSE);

        Seek(inp,0L,OFFSET_END);               /* seek to end of file         */
        size = Seek(inp,0L,OFFSET_BEGINNING); /* rewind the file to get size */
        if(size <= 0L)
                return cleanup(FALSE);

        if((buff = AllocMem(size,0L)) == 0)     /* mem buffer for file */
                return cleanup(FALSE);

        if(Read(inp,(char *)&buff[0],size) != size) /* read entire file into buffer */
                return cleanup(FALSE);

        nhunk = buff[ 2 ];              /* number of hunks in file */

        while(buff[ i++ ] != 0x000003E9)
                ;

        if( ((buff[ i+1 ] & 0x0000FFFF) != VSIG1)
      || ((buff[ i+2 ] & 0xFFFF0000) != VSIG2) )
                return cleanup(FALSE);

        if (!flag)
                return cleanup(1);

        Close(inp);
        if((inp = Open(fname,MODE_NEWFILE)) == 0)
                return cleanup(FALSE);

        buff[2] -= 1;   buff[4] -= 1;   /* readjust program header info */

        if(Write(inp,(char *)&buff[0],5L*SLONG) != 5L*SLONG)
                return cleanup(FALSE);

        if(Write(inp,(char *)&buff[6],nhunk*SLONG) != nhunk*SLONG)
                return cleanup(FALSE);

        i = i + 8L + VTAG;
        size = (size/SLONG - i)*SLONG;

        if(Write(inp,(char *)&buff[i],size) != size)
                return cleanup(FALSE);

        return cleanup(1);
}
