#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/filehandler.h>
#include <intuition/intuitionbase.h>
#include <devices/hardblocks.h>
#include <devices/input.h>
#include <devices/conunit.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>

#include <MyStartup.h>
#include <MyLib.h>

/***********************************************/

LONG DoPkt1(struct MsgPort *, LONG, LONG);
#pragma libcall DOSBase DoPkt1 F0 32103

/***********************************************/

#define BLOCK_SIZE 512

#define NoBlock 0xffffffff

#define BLOCKS_NEEDED 4

#define PASSWORD_SIZE 40

/***********************************************/

char __chip Hardblock[BLOCK_SIZE];

struct RDArgs *RDArgs;

struct IntuitionBase *IntuitionBase;

struct IOStdReq IORequest;
struct IOStdReq InputRequest;

struct Window *MyWindow;
struct Task *MyTask;

struct
   {
      char *Drive;
   } Arguments;

char VersionString[]="$VER: Password 1.1 (26.04.93)";

ULONG PasswordBlock;
int PasswordIndex;

char PasswordBuffer[PASSWORD_SIZE];
int BufferIndex;
BOOL Locked;

ULONG RDBBlock;

/***********************************************/

void CloseAll(int RC)

{
   if (InputRequest.io_Command==IND_ADDHANDLER)
      {
         InputRequest.io_Command=IND_REMHANDLER;
         DoIO(&InputRequest);
         CloseDevice(&InputRequest);
      }
   CloseDevice(&IORequest);
   CloseLibrary(IntuitionBase);
   FreeArgs(RDArgs);
   exit(RC);
}

/***********************************************/

void LoadBlock(int BufferSize, ULONG BlockNumber, ULONG BlockID)

{
   int i;
   ULONG SummedLongs;
   LONG CheckSum;
   ULONG *Temp;

   if (CheckSignal(SIGBREAKF_CTRL_C))
      {
         PrintFault(ERROR_BREAK,"RemovePassword");
         CloseAll(RETURN_WARN);
      }
   IORequest.io_Command=CMD_READ;
   IORequest.io_Length=BLOCK_SIZE;
   IORequest.io_Data=Hardblock;
   IORequest.io_Offset=BlockNumber*BLOCK_SIZE;
   if (DoIO(&IORequest))
      {
         printf("Error reading block %ld\n",BlockNumber);
         CloseAll(RETURN_FAIL);
      }
   if (BlockID)
      {
         if (BlockID!=((struct RigidDiskBlock *)Hardblock)->rdb_ID)
            {
               printf("Block %ld: exspected type 0x%lx got type 0x%lx\n",BlockNumber,BlockID,((struct RigidDiskBlock *)Hardblock)->rdb_ID);
               CloseAll(RETURN_FAIL);
            }
         SummedLongs=((struct RigidDiskBlock *)Hardblock)->rdb_SummedLongs;
         CheckSum=0;
         Temp=(ULONG *)Hardblock;
         for (i=0; i<SummedLongs; i++)
            {
               CheckSum=CheckSum+(*Temp++);
            }
         if (CheckSum)
            {
               printf("Checksum of block %ld is invalid.\n",BlockNumber);
               CloseAll(RETURN_FAIL);
            }
      }
}

/***********************************************/

void SearchPassword(void)

{
   BOOL FoundRDB;

   FoundRDB=FALSE;
   for (RDBBlock=0; RDBBlock<RDB_LOCATION_LIMIT && !FoundRDB; )
      {
         LoadBlock(sizeof(struct RigidDiskBlock),RDBBlock,0);
         if (*(ULONG *)Hardblock==IDNAME_RIGIDDISK)
            {
               FoundRDB=TRUE;
            }
         else
            {
               RDBBlock++;
            }
      }
   if (!FoundRDB)
      {
         printf("Sorry, I couldn't locate the RigidDiskBlock on this unit!\n");
         CloseAll(RETURN_FAIL);
      }
   printf("Found RigidDiskBlock on block %ld\n",RDBBlock);
   LoadBlock(sizeof(struct RigidDiskBlock),RDBBlock,IDNAME_RIGIDDISK);
   PasswordBlock=((struct RigidDiskBlock *)Hardblock)->rdb_DriveInit;
   while (PasswordBlock!=NoBlock)
      {
         LoadBlock(sizeof(struct LoadSegBlock),PasswordBlock,IDNAME_LOADSEG);
         for (PasswordIndex=20; PasswordIndex<BLOCK_SIZE; PasswordIndex++)
            {
               if (!__builtin_strcmp(Hardblock+PasswordIndex,VersionString))
                  {
                     PasswordIndex+=__builtin_strlen(VersionString)+1;
                     return;
                  }
            }
         PasswordBlock=((struct LoadSegBlock *)Hardblock)->lsb_Next;
      }
   printf("Sorry, there is no password on this unit!\n");
   CloseAll(RETURN_WARN);
}

/***********************************************/

void OpenDriveDevice(void)

{
   struct DosList *DosList;
   struct FileSysStartupMsg *StartupMsg;
   char *Device;
   ULONG Unit;
   int RC;

   RC=0;
   DosList=LockDosList(LDF_READ | LDF_DEVICES);
   if (DosList=FindDosEntry(DosList,Arguments.Drive,LDF_DEVICES))
      {
         StartupMsg=(struct FileSysStartupMsg *)BADDR(DosList->dol_misc.dol_handler.dol_Startup);
         IORequest.io_Message.mn_ReplyPort=&((struct Process *)SysBase->ThisTask)->pr_MsgPort;
         Device=((char *)BADDR(StartupMsg->fssm_Device))+1;
         Unit=StartupMsg->fssm_Unit;
         if (OpenDevice(Device,Unit,&IORequest,0))
            {
               printf("Unable to open %s unit %lu\n",Device,Unit);
               RC=RETURN_FAIL;
            }
         else
            {
               printf("Locating password on %s unit %ld\n",Device,Unit);
            }
      }
   else
      {
         printf("\x22%s:\x22 not found.\n",Arguments.Drive);
         RC=RETURN_FAIL;
      }
   UnLockDosList(LDF_READ | LDF_DEVICES);
   if (RC) CloseAll(RC);
}

/***********************************************/

struct InputEvent * __asm __saveds InputHandler(register __a0 struct InputEvent *InputEvent)

{
   struct InputEvent *InputEvents;
   ULONG IntuiLock;
   struct Window *ActiveWindow;

   InputEvents=InputEvent;
   while (InputEvent)
      {
         IntuiLock=LockIBase(0);
         ActiveWindow=IntuitionBase->ActiveWindow;
         UnlockIBase(IntuiLock);
         if (ActiveWindow==MyWindow)
            {
               if (InputEvent->ie_Class==IECLASS_RAWKEY)
                  {
                     if (!(InputEvent->ie_Code&IECODE_UP_PREFIX))
                        {
                           if (InputEvent->ie_Code<0x60 && !Locked)
                              {
                                 switch(InputEvent->ie_Code)
                                    {
                                       case 0x44:
                                       case 0x50: PasswordBuffer[BufferIndex]=0xfe;
                                                  Locked=TRUE;
                                                  Signal(MyTask,SIGBREAKF_CTRL_E);
                                                  break;
                                       case 0x41: if (BufferIndex)
                                                     {
                                                        BufferIndex--;
                                                     }
                                                  break;
                                       default:   if (BufferIndex<PASSWORD_SIZE-2)
                                                     {
                                                        if (InputEvent->ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
                                                           {
                                                              InputEvent->ie_Code|=0x80;
                                                           }
                                                        PasswordBuffer[BufferIndex++]=InputEvent->ie_Code;
                                                     }
                                                  break;
                                    }
                              }
                        }
                     InputEvent->ie_Class=IECLASS_NULL;
                  }
            }
         InputEvent=InputEvent->ie_NextEvent;
      }
   return(InputEvents);
}

/***********************************************/

void InstallInputHandler(void)

{
   static struct Interrupt Interrupt=
      {
         NULL,NULL,
         NT_INTERRUPT,
         127,
         "RemovePassword",
         NULL,
         (void (*)())InputHandler
      };

   struct InfoData __aligned InfoData;

   MyTask=SysBase->ThisTask;
   Locked=TRUE;
   InputRequest.io_Message.mn_ReplyPort=IORequest.io_Message.mn_ReplyPort;
   DoPkt1(((struct FileHandle *)BADDR(Input()))->fh_Type,ACTION_DISK_INFO,MKBADDR(&InfoData));
   MyWindow=((struct ConUnit *)(((struct IOStdReq *)(InfoData.id_InUse))->io_Unit))->cu_Window;
   if (!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0)) ||
       OpenDevice("input.device",0,&InputRequest,0))
      {
         CloseAll(RETURN_FAIL);
      }
   InputRequest.io_Command=IND_ADDHANDLER;
   InputRequest.io_Data=&Interrupt;
   DoIO(&InputRequest);
}

/***********************************************/

void EnterOldPassword(void)

{
   int Try;

   for (Try=0; Try<3; Try++)
      {
         printf("Please enter the current password: ");
         Flush(Output());
         BufferIndex=0;
         Locked=FALSE;
         Wait(SIGBREAKF_CTRL_E);
         printf("\n");
         while (BufferIndex>=0)
            {
               if (PasswordBuffer[BufferIndex]!=Hardblock[PasswordIndex+BufferIndex])
                  {
                     printf("Wrong password!\n");
                     break;
                  }
               BufferIndex--;
            }
         if (BufferIndex<0)
            {
               return;
            }
      }
   CloseAll(RETURN_ERROR);
}

/***********************************************/

void RemovePassword(void)

{
   int i;
   long CheckSum;

   LoadBlock(sizeof(struct RigidDiskBlock),RDBBlock,IDNAME_RIGIDDISK);
   ((struct RigidDiskBlock *)Hardblock)->rdb_DriveInit=NoBlock;
   ((struct RigidDiskBlock *)Hardblock)->rdb_ChkSum=0;
   CheckSum=0;
   for (i=0; i<((struct RigidDiskBlock *)Hardblock)->rdb_SummedLongs; i++)
      {
         CheckSum+=((long *)Hardblock)[i];
      }
   ((struct RigidDiskBlock *)Hardblock)->rdb_ChkSum=0-CheckSum;
   printf("Writing block %ld\n",RDBBlock);
   IORequest.io_Command=CMD_WRITE;
   IORequest.io_Length=BLOCK_SIZE;
   IORequest.io_Data=Hardblock;
   IORequest.io_Offset=RDBBlock*BLOCK_SIZE;
   if (DoIO(&IORequest))
      {
         printf("Error writing block %ld\n",RDBBlock);
         CloseAll(RETURN_FAIL);
      }
}

/***********************************************/

void main(void)

{
   if (CommandLineLength)
      {
         if (RDArgs=ReadArgs("DRIVE/A",(long *)&Arguments,NULL))
            {
               OpenDriveDevice();
               SearchPassword();
               InstallInputHandler();
               EnterOldPassword();
               RemovePassword();
               CloseAll(RETURN_OK);
            }
         PrintFault(IoErr(),"RemovePassword");
      }
   CloseAll(RETURN_FAIL);
}
