/*@P************************************************************************
 * File           : TSTCHK.C
 * Project        : EVERLOCK EVCHK3.OBJ Test Application
 * Author         : M. Brendan Van Horn
 * Compiler       : Borland C++ v4.02
 * Description    :
 *
 * Copyright (c) 1994-95 Az-Tech Software, Inc.
 * ALL RIGHTS RESERVED
 ************************************************************************P@*/

// This was written and tested on a system using SMALL FONTS.  If you are
// using large fonts the display will not be as pleasing.

#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <dos.h>
#include "azmemory.h"
#include "sb.h"

// disable Microsoft warning for unknown pragmas
#pragma warning (disable: 4068)

/* Get state of access flag x in byte array a. */
#define ISFLAGSET(a,x) ((a)[((x)-1)>>3]&(1<<(((x)-1)&7)))

/***************************************************************************
 * DPMI Registers
 ***************************************************************************/
typedef struct tagDPMI_REGS
{
   unsigned long  edi, esi, ebp, reserved, ebx, edx, ecx, eax;
   unsigned short flags, es, ds, fs, gs, ip, cs, sp, ss;
} DPMI_REGS;

/***************************************************************************
 * Function Prototypes.
 ***************************************************************************/
#define Evchk3Test_DefProc DefWindowProc
int NormalizeStatus( int status );
int DoCheck( HINSTANCE hInstance );
LRESULT CALLBACK _export WndProc( HWND hWnd, UINT iMessage,
                                 WPARAM wParam, LPARAM lParam );
void Evchk3Test_OnDestroy(HWND hWnd);
void Evchk3Test_OnPaint(HWND hWnd);

int evchk3( SB __far *lpSB );
BOOL RealAlloc( DWORD size );
void RealFree( void );

/***************************************************************************
 * Global Variables.
 ***************************************************************************/
char szAppName[] = "Evchk3Test";
char szAppTitle[] = "EVERLOCK EVCHK3.OBJ Test Application";
UINT errFlags = MB_ICONSTOP | MB_OK;
UINT okFlags = MB_ICONINFORMATION | MB_OK;
SB sb;
char szText[255];

BOOL fDriver = FALSE;                  /* did we get the memory from AzMemory? */
LRESULT drvrStatus = 0;                /* status of last driver call. */
DPMI_REGS dpmiRegs;                    /* DPMI register structure. */
HDRVR hDriver = NULL;                  /* handle to the AzMemory driver. */
ALLOCINFO stAllocInfo;                 /* driver allocation information. */
const char szDriverName[] = "azmemory.drv";
extern char __far __pascal EVCHK3[];
extern char __far __pascal EVCHK3Z[];

#pragma argsused
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine,
                    int nCmdShow )
{
   int nCompStatus;
   WNDCLASS w;
   HWND hWnd;
   MSG msg;

   // if we are a second instance, just quit
   if ( hPrevInst )
      return 0;

   nCompStatus = DoCheck(hInstance);

   if(nCompStatus)
      return nCompStatus;

   // register window class
   w.style = CS_HREDRAW | CS_VREDRAW;
   w.lpfnWndProc = WndProc;
   w.cbClsExtra = 0;
   w.cbWndExtra = 0;
   w.hInstance = hInstance;
   w.hIcon = LoadIcon(NULL, IDI_APPLICATION);
   w.hCursor = LoadCursor(NULL, IDC_ARROW);
   w.hbrBackground = GetStockBrush(WHITE_BRUSH);
   w.lpszMenuName = NULL;
   w.lpszClassName = szAppName;

   if(!RegisterClass(&w))
      return 0;

   hWnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT, CW_USEDEFAULT,
                       CW_USEDEFAULT, CW_USEDEFAULT,
                       NULL, NULL, hInstance, NULL);

   if(hWnd == NULL)
      return 0;

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   while(GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }

   // return to the OS
   return nCompStatus;
}

int DoCheck(HINSTANCE hInstance)
{
   int nCompStatus;
   HCURSOR hSaveCursor, hWaitCursor;

   // INITIALIZE THE CONTENTS OF THE SB STRUCTURE TO ZERO's
   memset( &sb, 0, sizeof( SB ) );

   // INITIALIZE THE STRUCTURE FIELDS NECESSARY FOR FUNCTION USED
   strncpy( sb.id, "AZSB", 4 );  // initialize ID field
   sb.func = 1;                  // initialize function to perform
   sb.pin = 1804054920;          // update with PIN from EV3 file 

   // get the module filename for this instance of the application
   GetModuleFileName( hInstance, sb.source, 63 );

   // change from our application name to the dummy application name
   strcpy( strrchr( sb.source, '\\' ) + 1, "WCHECK.EXE" );

   // get the handle of the hourglass (waiting) cursor
   hWaitCursor = LoadCursor( NULL, IDC_WAIT );

   // turn on the waiting cursor
   hSaveCursor = SetCursor( hWaitCursor );

   // PERFORM THE PROTECTION CHECK USING EVCHK3.OBJ
   nCompStatus = evchk3( &sb );

   // restore the original cursor
   SetCursor( hSaveCursor );

   // display the results of the check
   if ( nCompStatus )
   {
      sb.stat1 = nCompStatus;
      // format the error message
      wsprintf( szText, "EVCHK3.OBJ Error %04X!", sb.stat1 );

      // display the error message
      MessageBox( NULL, szText, szAppName, errFlags );

      return NormalizeStatus( sb.stat1 );
   }
   else if ( sb.stat1 )
   {
      // format the error message
      wsprintf( szText, "Security Error %04X-%04X-%04X!", sb.stat1,
                sb.stat2, sb.stat3 );

      // display the error message
      MessageBox( NULL, szText, szAppName, errFlags );

      // return to the OS
      return NormalizeStatus( sb.stat1 );
   }

   return 0;
}

int evchk3( SB __far *lpUserSB )
{
   DWORD dwTotalSize;
   WORD wCodeSize;
   WORD nCompStatus;
   WORD segSB;
   DPMI_REGS __far *lpdpmiRegs;
   char __far *lpRealSB;

   /* sanity check!  make sure we have the proper SB signature before continuing */
   if ( 0 != _fstrncmp( lpUserSB->id, "AZSB", 4 ) )

      /* invalid signature, abort back to our caller */
      return 0x7240;

   /* calculate the size of the real-mode code */
   wCodeSize = (WORD) ( EVCHK3Z - EVCHK3 );

   /* calculate the amount of real-mode memory we require */
   dwTotalSize = wCodeSize + sizeof( SB );

   /* allocate the real-mode memory we require */
   if ( FALSE == RealAlloc( dwTotalSize ) )
   {
      /* set the return codes for this failure */
      lpUserSB->stat1 = 0x7002;
      lpUserSB->stat2 = (short) drvrStatus;
      lpUserSB->stat3 = (short) dwTotalSize;

      /* return to our caller with simulated error code */
      return 0;
   }

   /* create the pointer to the real-mode SB area */
   lpRealSB = stAllocInfo.lpProtBuff + wCodeSize;

   /* setup invalid return code in the SB structure */
   lpUserSB->stat1 = -1;
   lpUserSB->stat2 = 0;
   lpUserSB->stat3 = 0;

   /* copy the protected mode SB to the real mode SB */
   _fmemcpy( lpRealSB, lpUserSB, sizeof( SB ) );

   /* copy the code from the data segment to the real mode buffer */
   _fmemcpy( stAllocInfo.lpProtBuff, EVCHK3, (size_t) wCodeSize );

   /* clear out the DPMI register block */
   _fmemset( &dpmiRegs, 0, sizeof( DPMI_REGS ) );

   /* CS:IP of call is SEG:0 of DOS memory */
   dpmiRegs.cs = stAllocInfo.wBuffSeg;

   /* setup pointer to DPMI registers */
   lpdpmiRegs = (DPMI_REGS __far *) &dpmiRegs;

   /* get the segment of the SB buffer */
   segSB = stAllocInfo.wBuffSeg;

   /* default to no error conditions */
   nCompStatus = 0;

   __asm mov   bh,0             /* flags = 0                               */
   __asm mov   cx,2             /* two words to copy to real mode stack    */
   __asm les   di,lpdpmiRegs    /* pointer to regs struct                  */
   __asm mov   ax,0301h         /* call real mode procedure                */
   __asm push  segSB            /* SEGMENT of the Real SB                  */
   __asm push  wCodeSize        /* OFFSET of the Real SB                   */
                                /* DPMI will xfer this to real mode stack  */
   __asm int   31h
   __asm add   sp,4             /* clean up what we pushed                 */
   __asm jnc   NOERROR          /* if no error code, skip getting status   */
   __asm mov   nCompStatus,ax   /* get error code from DPMI server         */
   __asm jmp   CONT             /* skip getting error code from the module */

NOERROR:

   /* get any error codes from the module */
   nCompStatus = LOWORD( dpmiRegs.eax );

CONT:

   /* copy the results to the protected mode SB */
   _fmemcpy( lpUserSB, lpRealSB, sizeof( SB ) );

   /* release the real memory buffer */
   RealFree();

   /* return our results */
   return nCompStatus;
}

int NormalizeStatus( int status )
{
   int temp;

   /* get the hundreds digit from the error code */
   temp = ( ( status & 0x0F00 ) >> 8 ) * 100;

   /* add in the tens digit from the error code */
   temp += ( ( status & 0x00F0 ) >> 4 ) * 10;

   /* finally, add in the ones digit */
   temp += status & 0x000F;

   /* return the normalized status value to our caller */
   return temp;
}

BOOL RealAlloc( DWORD size )
{
   DWORD dwBuffer;
   HGLOBAL hBuffer;

   /* mark that the driver is not available until we know otherwise */
   drvrStatus = -1;

   /* setup the default contents of the allocation information struct */
   memset( &stAllocInfo, 0, sizeof( ALLOCINFO ) );
   stAllocInfo.wStructSize = sizeof( ALLOCINFO );

   /* attempt to open the AzMemory driver for our use */
   hDriver = OpenDriver( szDriverName, NULL, NULL );

   /* verify that the driver has been opened */
   if ( NULL != hDriver )
   {
      /* mark that the driver has been opened by us */
      fDriver = TRUE;

      /* try to allocate the buffer from the driver */
      drvrStatus = SendDriverMessage( hDriver, DRV_ALLOCBUFFER, size,
                                      (LPARAM) (LPALLOCINFO) &stAllocInfo );

      /* if we allocated the memory, return that everything's hunky-dorey */
      if ( ERR_OK == drvrStatus )
         return TRUE;
   } else
      fDriver = FALSE;

   /* attempt to allocate the memory */
   dwBuffer = GlobalDosAlloc( size );

   /* if we got the buffer */
   if ( 0 != dwBuffer )
   {
      /* save the values in the allocation information structure */
      stAllocInfo.dwBuffSize = size;
      stAllocInfo.wBuffSel   = LOWORD( dwBuffer );
      stAllocInfo.wBuffSeg   = HIWORD( dwBuffer );
      stAllocInfo.lpProtBuff = MK_FP( stAllocInfo.wBuffSel, 0 );
      stAllocInfo.lpRealBuff = MK_FP( stAllocInfo.wBuffSeg, 0 );

      /* set the real-mode buffer to a known state */
      _fmemset( stAllocInfo.lpProtBuff, 0xAA, (size_t) stAllocInfo.dwBuffSize );

      /* return success to our caller */
      return TRUE;
   }

   /* if we get here there is no driver and no memory available */
   return FALSE;
}

void RealFree( void )
{
   /* was the driver used to allocate the memory buffer? */
   if ( NULL != hDriver )
   {
      /* yes, was a buffer allocated from the driver? */
      if ( ERR_OK == drvrStatus )
      {
         /* clear the contents of the real-mode buffer */
         _fmemset( stAllocInfo.lpProtBuff, 0xBB, (size_t) stAllocInfo.dwBuffSize );

         /* yes, so free the buffer from the driver */
         drvrStatus = SendDriverMessage( hDriver, DRV_FREEBUFFER, 0, 0 );

         /* clear the contents of the memory allocation info structure */
         _fmemset( &stAllocInfo, 0, sizeof( ALLOCINFO ) );
      }

      /* close the driver since we are done with it */
      CloseDriver( hDriver, 0, 0 );
   }

   /* is there still an allocated buffer? */
   if ( 0 != stAllocInfo.wBuffSel )
   {
      /* clear the contents of the real-mode buffer */
      _fmemset( stAllocInfo.lpProtBuff, 0xBB, (size_t) stAllocInfo.dwBuffSize );

      /* yes, so we allocated the buffer with GlobalDosAlloc, free it now */
      GlobalDosFree( stAllocInfo.wBuffSel );

      /* clear the contents of the memory allocation info structure */
      _fmemset( &stAllocInfo, 0, sizeof( ALLOCINFO ) );
   }
}

LRESULT CALLBACK _export WndProc( HWND hWnd, UINT iMessage,
                                 WPARAM wParam, LPARAM lParam )
{
   switch(iMessage)
   {
      HANDLE_MSG(hWnd, WM_DESTROY, Evchk3Test_OnDestroy);
      HANDLE_MSG(hWnd, WM_PAINT, Evchk3Test_OnPaint);
      default:
         return Evchk3Test_DefProc(hWnd, iMessage, wParam, lParam);
   }
}

#pragma argsused
void Evchk3Test_OnDestroy(HWND hWnd)
{
   PostQuitMessage(0);
}

void Evchk3Test_OnPaint(HWND hWnd)
{
   char szBuffer[81];
   char szTemp1[81];
   char szTemp2[81];
   char szTemp3[4];
   int i = 0;
   int j, k, done;
   PAINTSTRUCT PaintStruct;
   HDC PaintDC;
   char *p, *q;

   PaintDC = BeginPaint(hWnd, &PaintStruct);
   SetBkMode(PaintDC, TRANSPARENT);

   // output Return Code fields
   sprintf(szBuffer, "Return Code: %04X-%04X-%04X", sb.stat1,
               sb.stat2, sb.stat3);
   TextOut(PaintDC, 92, 8, szBuffer, lstrlen(szBuffer));

   // output Function field
   sprintf(szBuffer, "Function Code: %d", sb.func);
   TextOut(PaintDC, 80, 20, szBuffer, lstrlen(szBuffer));

   // output Drive, Path and Program checked
   sprintf(szBuffer, "Drive and Path Checked: %s", sb.source);
   TextOut(PaintDC, 17, 32, szBuffer, lstrlen(szBuffer));

   // output Protection Type field
   if(sb.ptype == 'P')
      sprintf(szBuffer, "Protection Type: Original Product");
   else if(sb.ptype == 'C')
      sprintf(szBuffer, "Protection Type: CPU-Lock Product");
   else if(sb.ptype == 'E')
      sprintf(szBuffer, "Protection Type: Encrypt Only Product");
   else
      sprintf(szBuffer, "Protection Type: Installed Copy");
   TextOut(PaintDC, 71, 44, szBuffer, lstrlen(szBuffer));

   // output the Product Name
   sprintf(szBuffer, "Product Name: %s", sb.prod);
   TextOut(PaintDC, 81, 56, szBuffer, lstrlen(szBuffer));

   // output the Product Serial Number
   sprintf(szBuffer, "Product Serial#: %lu", sb.snp);
   TextOut(PaintDC, 73, 68, szBuffer, lstrlen(szBuffer));

   // output the NET User Handle
   sprintf(szBuffer, "NET-Users Handle: %u", sb.hnuc);
   TextOut(PaintDC, 52, 80, szBuffer, lstrlen(szBuffer));

   // output the Authorization Version
   sprintf(szBuffer, "Authorization Version: %u", sb.avers);
   TextOut(PaintDC, 34, 92, szBuffer, lstrlen(szBuffer));

   // output the Exec-Counts found
   if(sb.ecl == 0xFFFF)
      sprintf(szBuffer, "Exec-Count Limit: Unlimited");
   else
      sprintf(szBuffer, "Exec-Count Limit: %d", sb.ecl);
   TextOut(PaintDC, 63, 104, szBuffer, lstrlen(szBuffer));

   // output Expire-Days found
   if(sb.edl == 0xFFFF)
   {
      sprintf(szBuffer, "Expire-Days Limit: Unlimited");
      TextOut(PaintDC, 55, 116, szBuffer, lstrlen(szBuffer));
   }
   else
   {
      sprintf(szBuffer, "Expire-Days Left: %d", sb.edl);
      TextOut(PaintDC, 64, 116, szBuffer, lstrlen(szBuffer));
      i += 1;
      sprintf(szBuffer, "Expire-Date: %s", sb.ed);
      TextOut(PaintDC, 96, (116 + (i * 12)), szBuffer, lstrlen(szBuffer));
   }

   // output Network-Users Limit and Count
   if(sb.nul == 0xFFFF)
   {
      sprintf(szBuffer, "Net-Users Limit: Unlimited");
      TextOut(PaintDC, 71, (128 + (i * 12)), szBuffer, lstrlen(szBuffer));
   }
   else
   {
      sprintf(szBuffer, "Net-Users Count: %d", sb.nuc);
      TextOut(PaintDC, 66, (128 + (i * 12)), szBuffer, lstrlen(szBuffer));
      i += 1;
      sprintf(szBuffer, "Net-Users Limit: %d", sb.nul);
      TextOut(PaintDC, 71, (128 + (i * 12)), szBuffer, lstrlen(szBuffer));
   }

   // output the Install Counts if on Original diskette
   if(sb.ptype == 'P')
   {
      i += 1;
      sprintf(szBuffer, "Install Counts Left: %d", sb.icr);
      TextOut(PaintDC, 56, (128 + (i * 12)), szBuffer, lstrlen(szBuffer));
   }

   // output User-Data
   sprintf(szBuffer, "User-Data: %02X %02X %02X %02X %02X %02X %02X %02X",
                        sb.usrdat[0], sb.usrdat[1], sb.usrdat[2], sb.usrdat[3],
                        sb.usrdat[4], sb.usrdat[5], sb.usrdat[6], sb.usrdat[7]);
   TextOut(PaintDC, 108, (140 + (i * 12)), szBuffer, lstrlen(szBuffer));

   // output Access Flags
   k=0;
   memset(szTemp1, '\0', 81);
   for(j=0; j<64; j++)
   {
      if(sb.accflg[j >> 3] & (1 << (j & 7)))
         szTemp1[k++] = j+1;
   }
   
   if(szTemp1[0] == '\0')
   {
      sprintf(szBuffer, "Access Flags Set: None");
      TextOut(PaintDC,  62, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
   }
   else
   {
      memset(szTemp2, '\0', 81);
      strcpy(szBuffer, "Access Flags Set: ");
      p = szTemp1;
      for(j=0; j<64; j++)
      {
         if(*p != '\0')
         {
            sprintf(szTemp3, "%02d ", *p);
            p++;
            strcat(szTemp2, szTemp3);
         }
         else
            break;

         if(lstrlen(szTemp2) == 60)
         {
            if(szBuffer[0] == '\0')
            {
               strcpy(szBuffer, szTemp2);
               i+=1;
               TextOut(PaintDC, 182, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
               szBuffer[0] = '\0';
               szTemp2[0] = '\0';
            }
            else
            {
               strcat(szBuffer, szTemp2);
               TextOut(PaintDC,  62, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
               szBuffer[0] = '\0';
               szTemp2[0] = '\0';
            }
         }
      }

      if(szTemp2[0] != '\0')
      {
         if(strncmp(szBuffer, "Access Flags", 12) == 0)
         {
            strcat(szBuffer, szTemp2);
            TextOut(PaintDC,  62, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
         }
         else
         {
            strcpy(szBuffer, szTemp2);
            i+=1;
            TextOut(PaintDC, 182, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
         }
      }
   }

   // output Registration Info
   if(sb.rtype == 'N')
   {
      i+=1;
      sprintf(szBuffer, "Registered to Name: %s", sb.rname);
      TextOut(PaintDC,  62, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
      i+=1;
      sprintf(szBuffer, "Registered to Company: %s", sb.rcomp);
      TextOut(PaintDC,  62, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
      i+=1;
      sprintf(szBuffer, "Registered to Location: %s", sb.rloc);
      TextOut(PaintDC,  62, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
      i+=1;
      sprintf(szBuffer, "Date Registered: %s", sb.rdate);
      TextOut(PaintDC,  62, (152 + (i * 12)), szBuffer, lstrlen(szBuffer));
   }

   // output Current Date
   sprintf(szBuffer, "Today's Date: %s", sb.cdate);
   TextOut(PaintDC,  87, (164 + (i * 12)), szBuffer, lstrlen(szBuffer));

   // output Secure String
   strcpy(szBuffer, "Secure String:");
   TextOut(PaintDC,  87, (188 + (i * 12)), szBuffer, lstrlen(szBuffer));
   p = sb.secstr;
   q = p;

   if(lstrlen(p))
   {
      done = FALSE;
      while(!done)
      {
         while(*q != '\0' && *q != '\r' && *q != '\n')
            q++;

         if(q != '\0')
         {
            *q = '\0';
            q++;
            while(*q == '\r' || *q == '\n')
               q++;

            if(lstrlen(p) < 81)
            {
               strcpy(szBuffer, p);
               TextOut(PaintDC,  182, (188 + (i * 12)), szBuffer, lstrlen(szBuffer));
               i += 1;
            }
            else
            {
               memset(szBuffer, '\0', 81);
               strncpy(szBuffer, p, 80);
               TextOut(PaintDC,  182, (188 + (i * 12)), szBuffer, lstrlen(szBuffer));
               i += 1;
            }

            if(*q != '\0')
            {
               p = q;
            }
            else
               done = TRUE;
         }
         else
         {
            strcpy(szBuffer, p);
            TextOut(PaintDC,  182, (188 + (i * 12)), szBuffer, lstrlen(szBuffer));
            i += 1;
            done = TRUE;
         }
      }
   }

   EndPaint(hWnd, &PaintStruct);
}
