#include <exec/types.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <dos/dos.h>

#include <libraries/gadtools.h>
#include <libraries/reqtools.h>

#include <proto/exec.h>
#include <proto/dlg.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/reqtools.h>

#include <gengui.h>

#include <dlg/crypt.h>

#include <pragmas/dlg.h>

#include "XHandler_def.h"
#include "XHandler.h"

static char yyy_version[]="$VER: DLG_XHandler 1.6  "__AMIGADATE__"";

char     HName[120] = "L:TPT-Handler";

struct   Library       *DLGBase = NULL;
struct   ReqToolsBase  *ReqToolsBase = NULL;

struct   Screen        *scr = NULL;
struct   Window        *win = NULL;

/// Base requester
struct   EasyStruct    req =
{
   sizeof(struct EasyStruct),
   NULL,
   "Notice!!",
   "%s",
   "OK",
};
//-

struct   IntuiMessage  *imsg = NULL;

struct   TextAttr   TxtAttr  = { "topaz.font", 11, 0, 0 };

struct   rtFileRequester   *freq = NULL;

UBYTE CRC;

int decryptowner(char *, ULONG);
int Decrypt(char *, char *);
void ProcHandler(char *);
void ShutDown(int);
int OldDecrypt(char *, char *);

/// Main
void main(void)
{
   int      PortBit;
   int      UserSigBit = SIGBREAKF_CTRL_C;

   struct   NewWindow        *WinData  = NULL;

   ReqToolsBase = (struct ReqToolsBase *)OpenLibrary("reqtools.library",38L);

   if(!ReqToolsBase) ShutDown(10);

   DLGBase = OpenLibrary("dlg.library",2L);

   if(!DLGBase) ShutDown(10);

   freq = rtAllocRequestA(RT_FILEREQ,NULL);

   if(!freq) ShutDown(10);

   scr = LockPubScreen(NULL);

   if(!scr)
   {
      ShutDown(10);
   }

   WinData = calloc(1,sizeof(struct NewWindow));

   if(!WinData)
   {
      printf("Cannot allocate mem for window data!\n");
      ShutDown(10);
   }

   WinData->LeftEdge = scr->MouseX - 100;
   WinData->TopEdge = scr->MouseY - 25;
   WinData->Width = 200;
   WinData->Height = 50;
   WinData->Screen = scr;
   WinData->MaxWidth = 6000;
   WinData->MaxHeight = 6000;
   WinData->Title = "DLG Handler Detective";
   WinData->Type = PUBLICSCREEN;
   WinData->Flags =        WFLG_DRAGBAR      |  WFLG_DEPTHGADGET     |
                           WFLG_CLOSEGADGET  |  WFLG_SMART_REFRESH   |
                           WFLG_ACTIVATE     |  WFLG_SIZEGADGET      |
                           WFLG_SIZEBRIGHT;
   WinData->IDCMPFlags =   IDCMP_REQVERIFY   |  IDCMP_MENUVERIFY     |
                           IDCMP_NEWSIZE     |  IDCMP_REFRESHWINDOW  |
                           IDCMP_GADGETUP    |  IDCMP_CLOSEWINDOW    |
                           IDCMP_VANILLAKEY;

   win = OpenWindow(WinData);

   if(!win)
   {
      printf("Could not open window!\n");
      free(WinData);
      UnlockPubScreen(NULL,scr);
      scr = NULL;
      ShutDown(10);
   }

   free(WinData);
   UnlockPubScreen(NULL,scr);
   scr = NULL;

   if(GG_SmartRenderGui(win,&XH,NULL))
   {
      printf("Cannot open GUI!\n");
      ShutDown(10);
   }


/// Main loop, wait for events
   while(1)
   {
      PortBit = Wait(UserSigBit | 1<<win->UserPort->mp_SigBit);

///   Main Window messages
      if(1<<win->UserPort->mp_SigBit | PortBit)
      {
         BOOL Terminated = FALSE;

         while(!Terminated && (imsg = GG_GetIMsg(win->UserPort)))
         {
            char *NewStr = NULL;

            switch(imsg->Class)
            {
///            REFRESHWINDOW
               case IDCMP_REFRESHWINDOW:
                  GG_BeginRefresh(&XH);
                  GG_RefreshGui(&XH);
                  GG_EndRefresh(&XH,TRUE);
                  break;
//-

///            CLOSEWINDOW
               case IDCMP_CLOSEWINDOW:
                  Terminated = TRUE;
                  break;
//-

///            GADGETUP
               case IDCMP_GADGETUP:

                  switch(GetGadget(imsg)->GadgetID)
                  {
                     char FName[120];

///                  NAMESTR
                     case NAMESTR:
                        NewStr = GetString(XH_Gadgets[XH_NAMESTR]);

                        if(!Exists(NewStr))
                        {
                           char t[1000];

                           sprintf(t,"File %s does not exist!",NewStr);
                           EasyRequest(win,&req,NULL,t);
                        }
                        else
                        {
                           strcpy(HName,NewStr);
                        }

                        break;
//-

///                  NAMEBUT
                     case NAMEBUT:
                        if(rtFileRequest(freq,FName,"Choose a file to examine",
                                          RT_Window,           win,
                                          RT_ReqPos,           REQPOS_POINTER,
                                          RT_LockWindow,       TRUE,
                                          RTFI_OkText,         "Select",
                                          TAG_END))
                        {
                           NewStr = strdup(FName);
                           strcpy(FName,freq->Dir);
                           AddPart(FName,NewStr,120);
                           strcpy(HName,FName);
                           GG_SetGadgetAttrs(XH_Gadgets[XH_NAMESTR],win,NULL,GTST_String,HName,TAG_END);
                        }


                        break;
//-

///                  GO!
                     case GOBUT:
                        ProcHandler(HName);
                        break;
//-

///                  Quit
                     case QBUT:
                        Terminated = TRUE;
                        break;
//-

                  }
                  break; // close out IDCMP_GADGETUP
//-

///            NEWSIZE
               case IDCMP_NEWSIZE:
               {
                  GG_ResizeGui(&XH);
                  break;
               }
//-

///            Untrapped IDCMP
               case IDCMP_REQVERIFY:
               case IDCMP_MENUVERIFY:
               case IDCMP_VANILLAKEY:
                  printf("Untrapped IDCMP\n");
                  break;
//-

            }

            GG_ReplyIMsg(imsg);
         }

         if(Terminated) break;
      }
//-

   }
//-

   ShutDown(0);
}
//-

/// ShutDown
void ShutDown(int code)
{
   if(freq) rtFreeRequest(freq);
   GG_FreeGui(&XH);
   if(scr)  UnlockPubScreen(NULL,scr);
   if(win)  CloseWindow(win);
   if(DLGBase) CloseLibrary(DLGBase);
   exit(code);
}
//-

/// ProcHandler
void ProcHandler(char *File)
{
   BOOL     found = FALSE;
   BOOL     NFound = FALSE;

   BPTR     fh = NULL;

   char     t[1000];
   char     serno[50] = "";
   char     owner[100] = "";

   int      counter = 0;
   int      a = 0;

   UBYTE   *buf = NULL;
   UBYTE   *oldbuf = NULL;

   ULONG    serialnumber = 0;


   if (!(buf=(UBYTE *)malloc(5000)))
   {
      sprintf(t,"Can't allocate buffer\n");
      EasyRequest(win,&req,NULL,t);
      return;
   }

   if (!(oldbuf=(UBYTE *)malloc(5000)))
   {
      sprintf(t,"Can't allocate second buffer\n");
      EasyRequest(win,&req,NULL,t);
      free(buf);
      return;
   }

   fh = Open(File,MODE_OLDFILE);

   if (!fh)
   {
      sprintf(t,"Can't open handler!\n");
      EasyRequest(win,&req,NULL,t);
      free(buf);
      free(oldbuf);
      return;
   }


   /* read in the last part of tpt-handler */
   Seek(fh, -5000, OFFSET_END);

   if (Read(fh, buf, 5000) != 5000)
   {
      sprintf(t,"Can't read in data from handler!\n");
      EasyRequest(win,&req,NULL,t);
      Close(fh);
      free(buf);
      free(oldbuf);
      return;
   }

   found = FALSE;

   for(counter=4999;counter;counter--)
   {
      if (buf[counter]==')')
      {
         counter--;
         if (buf[counter]=='-')
         {
            counter--;
            if (buf[counter]==':')
            {
               found=TRUE;
               break;
            }
         }
      }
   }

   if (!found)
   {
      sprintf(t,"Can't find offset marker!\n");
      EasyRequest(win,&req,NULL,t);
      Close(fh);
      free(buf);
      free(oldbuf);
      return;
   }

   /* We have found the smiley on tpt-handler */
   Seek(fh, 134 - (5000 - (long)counter), OFFSET_END);

   Read(fh, buf, 21);
   Close(fh);
   memcpy(oldbuf,buf,21);
   Decrypt(buf, buf);

   for(a=0; a<21; a++)
   {
      if (buf[a]=='#')
      {
         NFound = TRUE;
         break;
      }
   }

   if(!NFound)
   {
      memcpy(buf,oldbuf,21);
      OldDecrypt(buf,buf);

      for(a=0; a<21; a++)
      {
         if(buf[a]=='#')
         {
            NFound = TRUE;
            break;
         }
      }

      if(!NFound)
      {
         sprintf(t,"Decryption Error!\n");
         EasyRequest(win,&req,NULL,t);
         free(buf);
         free(oldbuf);
         return;
      }
   }

   free(oldbuf);
   a++;

   buf[a+6] = 0;

   sprintf(serno,"%s",buf);

   if (strncmp(buf+a,"PR",2)  &&
       strncmp(buf+a,"DV",2)  &&
       strncmp(buf+a,"BT",2)  &&
       strncmp(buf+a,"RE",2) )
   {
      sprintf(t,"Can't find prefix, found %s!\n",buf);
      EasyRequest(win,&req,NULL,t);
      return;
   }

   if ((!isdigit(buf[a+2])) ||
      (!isdigit(buf[a+3])) ||
      (!isdigit(buf[a+4])) ||
      (!isdigit(buf[a+5])))
   {
      sprintf(t,"Non-numeric data after prefix!\n");
      EasyRequest(win,&req,NULL,t);
      return;
   }

   // new steve stuff
   serialnumber    = atol(buf+a+2);
   strcpy(owner,"");

   if (!decryptowner(owner, serialnumber))
   {
      sprintf(t,"Can't decrypt owner info!\n");
      EasyRequest(win,&req,NULL,t);
      return;
   }
   // end new steve stuff

   sprintf(t,"%s\n\n%s\n",serno,owner);
   EasyRequest(win,&req,NULL,t);

   free(buf);
   return;
}
//-

/// Decrypt
// this routine has been modified to update 1.0 handlers only
int Decrypt(char *inbuf,char *outbuf)
{
   UBYTE numchars, shift, i;

   Forbid();
   numchars = inbuf[0];
   shift    = numchars;

   for(i=0;i<numchars;i++)
   {
      outbuf[i] = inbuf[i+1] - shift;
      shift     = inbuf[i+1] - CRYPTOFFSET;
   }

   Permit();
   return((int)numchars);
}
//-

/// OldDecrypt
// This routine retains backwards compatability
OldDecrypt(char *inbuf, char *outbuf)
{
  UBYTE numchars, shift, i;

  numchars=inbuf[0];
  shift=numchars;

  for(i=0;i<numchars;i++)
  {
    outbuf[i] = inbuf[i+1]-shift;
    shift = inbuf[i+1]-shift;
  }

  return(numchars);
}
//-
