/*@P************************************************************************
 * File           : TSTRESET.C
 * Project        : EVERLOCK EVMOV3.OBJ Reset 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@*/

#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"
#include "tstreset.h"

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

/***************************************************************************
 * 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.
 ***************************************************************************/
void CenterDialog( HWND hDlg );
void GlobalDialogBox( HINSTANCE hInstance, FARPROC dlgProc, UINT resId );
int NormalizeStatus( int status );
void ParseCommand( SB *pSB, LPSTR lpCmdLine );
LRESULT CALLBACK ResetDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
void ResetOnCommand( HWND, int, HWND, UINT );
BOOL ResetOnInitDialog( HWND, HWND, LPARAM );

int evmov3( SB __far *lpUserSB );
BOOL RealAlloc( DWORD size );
void RealFree( void );

/***************************************************************************
 * Global Variables.
 ***************************************************************************/
char szAppName[] = "EVERLOCK EVMOV3.OBJ Reset Test Application";
UINT errFlags = MB_ICONSTOP | MB_OK;
UINT okFlags = MB_ICONINFORMATION | MB_OK;
UINT confFlags = MB_ICONQUESTION | MB_OKCANCEL;
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 EVMOV3[];
extern char __far __pascal EVMOV3Z[];

#pragma argsused
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine,
                    int nCmdShow )
{
   int comp_status;
   HCURSOR hSaveCursor, hWaitCursor;

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

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

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

   /* zero out the contents of the SB structure */
   memset( &sb, 0, sizeof( SB ) );

   /* initialize the contents of the SB buffer */
   strncpy( sb.id, "AZSB", 4 );

   /* parse out the command line parameters */
   ParseCommand( &sb, lpCmdLine );

   /* get the reset use-count and product serial numbers */
   sb.func = 0;
   comp_status = evmov3( &sb );

   /* restore the original cursor */
   SetCursor( hSaveCursor );

   /* verify the success of the information gathering */
   if ( comp_status )
   {
      /* format the error message */
      sprintf( szText, "EVMOV3.OBJ Error %04X!", comp_status );

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

      /* return to the OS */
      return NormalizeStatus( comp_status );

   } else if ( sb.stat1 ) {

      /* format the error message */
      sprintf( 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 );
   }

   /* get the reset information? */
   GlobalDialogBox( hInstance, (FARPROC) ResetDlgProc, IDD_RESET );

   /* if the user aborted, return to our caller to handle error */
   if ( sb.stat1 )
   {
      /* inform the user why we are ending */
      MessageBox( NULL, "TSTRESET ending at user's request.", szAppName,
                  errFlags );

      /* return to the operating system */
      return NormalizeStatus( sb.stat1 );
   }

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

   /* perform the actual reset operation */
   sb.func = 2;
   comp_status = evmov3( &sb );

   /* restore the original cursor */
   SetCursor( hSaveCursor );

   /* verify the reset operation */
   if ( comp_status )
   {
      /* format the error message */
      sprintf( szText, "EVMOV3.OBJ Error %04X!", comp_status );

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

      /* return to the OS */
      return NormalizeStatus( comp_status );

   } else if ( sb.stat1 ) {

      /* format the error message */
      sprintf( 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 );
   }

   /* let the user know we were successfull */
   MessageBox( NULL, "Reset Successfull!", szAppName, okFlags );

   /* return to the OS */
   return 0;
}

void GlobalDialogBox( HINSTANCE hInstance, FARPROC dlgProc, UINT resId )
{
   DLGPROC lpProc;

   /* create, display and release the dialog box */
   lpProc = (DLGPROC) MakeProcInstance( dlgProc, hInstance );
   DialogBox( hInstance, MAKEINTRESOURCE( resId ), NULL, lpProc );
   FreeProcInstance( (FARPROC) lpProc );
}

void CenterDialog( HWND hDlg )
{
   RECT rc, rcParent;
   int newX, newY, centerX, centerY;

   /* get screen rectangle size and dialog box rectangle size */
   GetWindowRect( GetDesktopWindow(), &rcParent );
   GetWindowRect( hDlg, &rc );

   /* calculate center of screen */
   centerX = ( rcParent.left + rcParent.right  ) / 2;
   centerY = ( rcParent.top  + rcParent.bottom ) / 2;

   /* calculate new origin of dialog box */
   newX = centerX - ( ( rc.right  - rc.left ) / 2 );
   newY = centerY - ( ( rc.bottom - rc.top  ) / 2 );

   /* set the dialog box's new location */
   SetWindowPos( hDlg, NULL, newX, newY, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE );
}

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;
}

void ParseCommand( SB *pSB, LPSTR lpCmdLine )
{
   int pos;
   int state;
   int i;
   int len;
   BOOL fLoop;

   /* get the length of the command line */
   len = lstrlen( lpCmdLine );

   /* setup variables */
   pos = state = 0;
   fLoop = TRUE;

   /* loop to scan for cmd line arguments */
   while ( fLoop && pos <= len )
   {
      /* handle the different things we can find on the cmdline */
      switch ( lpCmdLine[pos] )
      {
         case '\0':

            /* we're at the end, stop searching */
            fLoop = FALSE;
            break;

         case ' ':

            /* skip the space character */
            break;

         default:

            /* copy the arguments to the from and to path buffers */
            switch ( state )
            {
               case 0:     /* from path */

                  /* setup the starting position of the copy destination */
                  i = 0;

                  /* save the source media */
                  while ( ' ' != lpCmdLine[pos] && '\0' != lpCmdLine[pos] )
                     pSB->source[i++] = lpCmdLine[pos++];

                  /* set the state to get the dest media next */
                  state++;

                  break;

               case 1:     /* to path */

                  /* setup the starting position of the copy destination */
                  i = 0;

                  /* save the destination media */
                  while ( ' ' != lpCmdLine[pos] && '\0' != lpCmdLine[pos] )
                     pSB->target[i++] = lpCmdLine[pos++];

                  /* set the state to get nothing next */
                  state++;

                  break;
            }
      }

      /* move to the next character */
      pos++;
   }
}

LRESULT CALLBACK ResetDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
   switch ( msg )
   {
      HANDLE_MSG( hDlg, WM_COMMAND,        ResetOnCommand         );
      HANDLE_MSG( hDlg, WM_INITDIALOG,     ResetOnInitDialog      );
   }

   return FALSE;
}

#pragma argsused
void ResetOnCommand( HWND hDlg, int id, HWND hCtl, UINT codeNotify )
{
   int ctlId;

   switch ( id )
   {
      case IDOK:

         /* get the reset code entered into the edit control */
         GetDlgItemText( hDlg, IDC_RESETCODE, sb.code, 18 );

         /* show that there was no error */
         sb.stat1 = 0x0000;

         break;

      case IDCANCEL:

         /* flag that the user hit abort */
         sb.stat1 = 0x7001;

         break;

      default:

         /* we can't handle it so let someone else do the dirty work */
         return;
   }

   /* finish the dialog and clear it out */
   EndDialog( hDlg, 0 );
}

#pragma argsused
BOOL ResetOnInitDialog( HWND hDlg, HWND hWndFocus, LPARAM lParam )
{
   char szTemp[20] = "\0";

   /* blank out the initial edit field contents */
   SetDlgItemText( hDlg, IDC_RESETCODE, szTemp );

   /* build the serial number/use count display field */
   wsprintf( szTemp, "%lu-%u", sb.snp, sb.ruc );

   /* display the serial number/use count in our dialog box */
   SetDlgItemText( hDlg, IDC_SERNUM, szTemp );

   /* display the current system date in the dialog box */
   SetDlgItemText( hDlg, IDC_DATE, sb.cdate );

   /* set the focus to the reset code edit control */
   SetFocus( GetDlgItem( hDlg, IDC_RESETCODE ) );

   /* center the dialog box in the display screen */
   CenterDialog( hDlg );

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

int evmov3( SB __far *lpUserSB )
{
   DWORD dwTotalSize;
   WORD wCodeSize;
   WORD comp_status;
   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) ( EVMOV3Z - EVMOV3 );

   /* 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, EVMOV3, (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 */
   comp_status = 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   comp_status,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 */
   comp_status = 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 comp_status;
}

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 ) );
   }
}
