// NTFlTask.cpp: implementation of the NTFlTask class.
//
//////////////////////////////////////////////////////////////////////
#pragma warning( disable : 4996 )
#include "stdafx.h"
#include "Registration.h"
#include "winbase.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define REGSTR_VALUE_USESCRPASSWORD _T("ScreenSaverIsSecure")
#define REGSTR_PATH_SCREENSAVE      _T("Control Panel\\Desktop")
#define REGSTR_VALUE_POLSYSTEM      _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System")
#define REGSTR_VALUE_POLEXPLORER    _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer")
#define REGSTR_VALUE_TIMEZONE       _T("SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation")
#define REGSTR_VALUE_TIMEZONES      _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones")

using namespace System;
using namespace System::Globalization;



/////////////////////////////////////////////////////////////////////////////
// Description: Event function, only purpose is to let the system save the new
// tag value, on the tag object.
//
// Parameter: 
// 
// Returns: 
// 
// Comment: 
// 
/////////////////////////////////////////////////////////////////////////////
void SaveTagValueFL( FlTag *tag, void *data)
{
} //SaveTagValueFL


/////////////////////////////////////////////////////////////////////////////
// Description: Event function used for writing event message to the NT event
// viewer.
// 
// Parameter: 
// 
// Returns: 
// 
// Comment: 
// 
/////////////////////////////////////////////////////////////////////////////
void EventLogFL( FlTag *tag, void *data)
{

  C2EventLog *elog = (C2EventLog *)data;

  //digital trigger?
  if ((int)tag == 0) return;

  //log the message to the event viewer
  elog->theTask->Log2EventViewer( elog->GetEventType(), elog->GetLogText());

  //set the completion tag
  if (elog->flcompl.IsValid())
  {

    VAL val;
    val.dig = 1;
    elog->flcompl.Value( val);
    elog->flcompl.ForcedWrite();
  }
}


//////////////////////////////////////////////////////////////////////
// void ShutdownSystem( FlTag *tag, void *data)
// 
// 
//////////////////////////////////////////////////////////////////////
void ShutdownFL( FlTag *tag, void *data)
{

  CShutdown *shut = (CShutdown *)data;
  char lpDirectoryName[] = _T("A:\\");
  ULARGE_INTEGER FreeBytesAvailableToCaller;
  ULARGE_INTEGER TotalNumberOfBytes;
  ULARGE_INTEGER TotalNumberOfFreeBytes; 
  BOOL bRet = FALSE;
  int iRet = 0;
  int b = -1;
  long sectime = 0;
  int secyear  = 0;
  int secmonth = 0;
  int secday   = 0;

  
  //tag is digital, check for trigger
  if (tag->Type() == FL_DIGITAL)
  {
    if (!(int)(*tag)) return;
  }

  //action depends on flag info
  switch (shut->GetFlag())
  {

    case 1:
    case 2:
    case 3:
    case 4:

      //read parameter to determine if fl needs a shutdown
      if (shut->paratag.Type() != FL_UNDEFINED)
      {
        shut->paratag.Read();
        shut->para = shut->paratag;
        if (shut->para) shut->theTask->SetFlStop( true);
      }

      //first exit FactoryLink
      shut->theTask->SetShutdown( shut->GetFlag());

      //save our shutdown mode, we gon'a used it afterwards...
      break;

    case 5: //lock the workstation
      shut->theTask->LockSystem(); 
      break;   

    case 10: //set screen saver activation
      if (shut->paratag.Type() != FL_UNDEFINED)
      {
        shut->paratag.Read();
        shut->para = shut->paratag;
      }

      bRet = (shut->para != 0) ? 1: 0;
      b = SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, bRet, NULL, 0);
      if (!b)
        shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");
      break;

    case 11: //get screen saver activation

      if (shut->paratag.Type() != FL_UNDEFINED)
      {

        b = SystemParametersInfo( SPI_GETSCREENSAVEACTIVE, 0, &bRet, 0);

        //break if we failed
        if (!b)
        {
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
          break;
        }

        //check if a screen saver is defined
        if (bRet)
        {

          HKEY m_hkResult;

          if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                            REGSTR_PATH_SCREENSAVE,
                            0,
                            KEY_ALL_ACCESS,
                            &m_hkResult) == ERROR_SUCCESS)
          {

            DWORD dwSize=0; 

            //get the current value
            bRet =!RegQueryValueEx( m_hkResult, _T("SCRNSAVE.EXE"), 
                                  NULL, NULL, NULL, &dwSize);
              
            RegCloseKey( m_hkResult);
          }
        }

        shut->paratag = (bRet == 0) ? 0: 1;
        shut->paratag.ForcedWrite();
      }
      break;

    case 12: //set screen saver timeout

      if (shut->paratag.Type() != FL_UNDEFINED)
      {
        shut->paratag.Read();
        shut->para = shut->paratag;
      }

      iRet = shut->para;
      b = SystemParametersInfo( SPI_SETSCREENSAVETIMEOUT, iRet, 0, 0);
      if (!b)
        shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");
      break;
    case 13: //get screen saver timeout

      b = SystemParametersInfo( SPI_GETSCREENSAVETIMEOUT, 0, &iRet, 0);

      //break if we failed
      if (!b)
      {
        shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
        break;
      }

      if (shut->paratag.Type() != FL_UNDEFINED)
      {
        shut->paratag = iRet;
        shut->paratag.ForcedWrite();
      }
      break;
    case 14: //start screen saver

      //digital tag as trigger
      if (shut->fltag.Type() == FL_DIGITAL)
      {

        if (shut->fltag.Read()) break;
        if ((int)shut->fltag != (int)1) break;
      }

      //screensaver can only start if screensaver is allowed
      //bRet = TRUE;
      //SystemParametersInfo( SPI_GETSCREENSAVEACTIVE, 0, &bRet, 0);
      //if (!bRet) break;
      {
      SendMessage( GetDesktopWindow(), WM_SYSCOMMAND, SC_SCREENSAVE,0);
      }
/*
      if (SystemParametersInfo( SPI_GETSCREENSAVETIMEOUT, 0, &iRet, 0))
      {

        SystemParametersInfo( SPI_SETSCREENSAVETIMEOUT, 1, 0, 0);

        for (int i = 0; i < 200; i++)
          shut->theTask->FlSleep( 10);

        SystemParametersInfo( SPI_SETSCREENSAVETIMEOUT, iRet, 0, 0);
      }*/
      break;

    case 20: //is screen saver secure

      if (shut->paratag.Type() != FL_UNDEFINED)
      {

        HKEY m_hkResult;

        if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                          REGSTR_PATH_SCREENSAVE,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          unsigned char val[ 40] = _T("0");
          DWORD dwSize=40; 

          //get the current value
          if (RegQueryValueEx( m_hkResult, REGSTR_VALUE_USESCRPASSWORD, 
                               NULL, NULL, val, &dwSize))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
              
          shut->paratag = (*val == '0') ? 0: 1;
          shut->paratag.ForcedWrite();

          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
      }
      break;   

    case 21: //set screen saver secure

      {

        HKEY m_hkResult;

        if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                          REGSTR_PATH_SCREENSAVE,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          if (shut->paratag.Type() != FL_UNDEFINED)
            shut->paratag.Read();

          int TagVal = shut->paratag;
          CString pw = TagVal ? _T("1"): _T("0");

          if (RegSetValueEx( m_hkResult, REGSTR_VALUE_USESCRPASSWORD,
                             0, REG_SZ, (unsigned char *)((LPCTSTR)pw), 2))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");

          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");
      }
      break;   

    case 30: //get button state lock system

      if (shut->paratag.Type() != FL_UNDEFINED)
      {

        HKEY m_hkResult;
        unsigned char val[ 40] = _T("0");

        if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                          REGSTR_VALUE_POLSYSTEM,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          DWORD dwSize=40; 

          //get the current value
          if (RegQueryValueEx( m_hkResult, _T("DisableLockWorkstation"), 
                               NULL, NULL, val, &dwSize))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
              
          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");

        shut->paratag = (*val == '0') ? 0: 1;
        shut->paratag.ForcedWrite();
      }
      break;   

    case 31: //set button state lock system

      {

        HKEY m_hkResult;

        if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                          REGSTR_VALUE_POLSYSTEM,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          if (shut->paratag.Type() != FL_UNDEFINED)
            shut->paratag.Read();

          int TagVal = shut->paratag;
          DWORD dWord = TagVal ? 1: 0;

          if (RegSetValueEx( m_hkResult, _T("DisableLockWorkstation"),
                             0, REG_DWORD, (unsigned char *)(&dWord), sizeof(DWORD)))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");

          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");
      }
      break;   

    case 32: //get button state taskmanager

      if (shut->paratag.Type() != FL_UNDEFINED)
      {

        HKEY m_hkResult;
        unsigned char val[ 40] = _T("0");

        if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                          REGSTR_VALUE_POLSYSTEM,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          DWORD dwSize=40; 

          //get the current value
          if (RegQueryValueEx( m_hkResult, _T("DisableTaskMgr"), 
                               NULL, NULL, val, &dwSize))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
              
          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");

        shut->paratag = (*val == '0') ? 0: 1;
        shut->paratag.ForcedWrite();
      }
      break;   

    case 33: //set button state taskmanager

      {

        HKEY m_hkResult;

        if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                          REGSTR_VALUE_POLSYSTEM,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          if (shut->paratag.Type() != FL_UNDEFINED)
            shut->paratag.Read();

          int TagVal = shut->paratag;
          DWORD dWord = TagVal ? 1: 0;

          if (RegSetValueEx( m_hkResult, _T("DisableTaskMgr"),
                             0, REG_DWORD, (unsigned char *)(&dWord), sizeof(DWORD)))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");

          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFWRITE");
      }
      break;   

    case 40: //get activetimebias

      if (shut->paratag.Type() != FL_UNDEFINED)
      {

        HKEY m_hkResult;
        unsigned char val[ 40] = _T("0");

        if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                          REGSTR_VALUE_TIMEZONE,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          DWORD dwSize=40; 

          //get the current value
          if (RegQueryValueEx( m_hkResult, _T("ActiveTimeBias"), 
                               NULL, NULL, val, &dwSize))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
              
          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");

        shut->paratag = (*((int *)val)) * 60;
        shut->paratag.ForcedWrite();
      }
      break;   

    case 41: //get active timebias for daylight saving time
    case 42: //set UTC time, corrected with daylight saving time
    case 43: //remove daylight saving time offset
    case 44: //find if given time is within daylight saving

      if (shut->paratag.Type() != FL_UNDEFINED)
      {

        HKEY m_hkResult;
        unsigned char actbias[ 40] = _T("0");
        unsigned char zbias[ 40] = _T("0");
		    int actualbias = 0;
        int zonebias = 0;
        unsigned char dlbias[ 40] = _T("0");
		    int daylight = 0;

        if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                          REGSTR_VALUE_TIMEZONE,
                          0,
                          KEY_ALL_ACCESS,
                          &m_hkResult) == ERROR_SUCCESS)
        {

          DWORD dwSize=40; 

          //get the current value
          if (RegQueryValueEx( m_hkResult, _T("ActiveTimeBias"), NULL, NULL, actbias, &dwSize))
            shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
		      else
          {
            if (RegQueryValueEx( m_hkResult, _T("DaylightBias"), NULL, NULL, dlbias, &dwSize))
              shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
			      else
            {
              if (RegQueryValueEx( m_hkResult, _T("Bias"), NULL, NULL, zbias, &dwSize))
                shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
              else
			        {
                zonebias = *((int *)zbias);
                actualbias = *((int *)actbias);
                if (zonebias == actualbias)
                  daylight = (int)0;
                else
                  daylight = *((int *)dlbias);
			        }
            }
		      }    
          RegCloseKey( m_hkResult);
        }
        else
          shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");

        if (shut->GetFlag() == 41)
        {
          shut->paratag = (int)(daylight) * 60;
          shut->paratag.ForcedWrite();
        }

        if (shut->GetFlag() == 42)
        {
          LANA utc = tag->Value().lana;
          //daylight = (int)(actualbias - daylight) * 60;
          utc = utc + ((LANA)actualbias * 60);
          shut->paratag = utc;
          shut->paratag.ForcedWrite();
        }

        if (shut->GetFlag() == 43)
        {
          LANA utc = tag->Value().lana;
          utc = utc + ((LANA)(daylight) * 60);
          shut->paratag = utc;
          shut->paratag.ForcedWrite();
        }

        if (shut->GetFlag() == 44)
        {
          //TIME_ZONE_INFORMATION dtz;
          //GetTimeZoneInformation( &dtz);
          HKEY m_hkTzone;
          unsigned char tzInfo[ 500] = _T("0");
          DWORD tzSize = 500;

          DateTime nowDT = DateTime::Now;
          sectime = (long)tag->Value().lana;
          secyear  = (sectime > 86400) ? 1980 : nowDT.Year;
          secmonth = (sectime > 86400) ? 1    : nowDT.Month;
          secday   = (sectime > 86400) ? 1    : nowDT.Day;

          DateTime myDT = DateTime(secyear, secmonth, secday).AddSeconds( (double)((long)tag->Value().lana));
          char regkey[250];
          //char zname[250];

          //int i = 0;
          
          //while(myTZ->CurrentTimeZone->StandardName[i] != '\0')
          //{
          //  zname[i] = (CHAR)myTZ->CurrentTimeZone->StandardName[i];
          //  ++i;
          //}

          sprintf( regkey, "%s\\%s", REGSTR_VALUE_TIMEZONES, shut->theTask->GetTimeZone());

          if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                            (LPCSTR)regkey,
                            0,
                            KEY_QUERY_VALUE,
                            &m_hkTzone) == ERROR_SUCCESS)
          {

            if (RegQueryValueEx( m_hkTzone, _T("TZI"), NULL, NULL, tzInfo, &tzSize))
              shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
            else
            {

              //TIME_ZONE_INFORMATION *tz = ((TIME_ZONE_INFORMATION *)tzInfo);
              SYSTEMTIME *dayTm = ((SYSTEMTIME *)(&tzInfo[28]));
              SYSTEMTIME *stnTm = ((SYSTEMTIME *)(&tzInfo[12]));

              /*typedef struct _SYSTEMTIME {
                WORD wYear;
                WORD wMonth;
                WORD wDayOfWeek;
                WORD wDay;
                WORD wHour;
                WORD wMinute;
                WORD wSecond;
                WORD wMilliseconds;
              } SYSTEMTIME, *PSYSTEMTIME;*/

              DateTime myDayLight = DateTime( myDT.Year, dayTm->wMonth + 1, 1, dayTm->wHour, 0, 0); 
              myDayLight = myDayLight.AddSeconds( (double)((long)myDayLight.DayOfWeek * -86400L));
              DateTime myStnLight = DateTime( myDT.Year, stnTm->wMonth + 1, 1, stnTm->wHour, 0, 0); 
              myStnLight = myStnLight.AddSeconds( (double)((long)myStnLight.DayOfWeek * -86400L));

              int zomertijd = ((myDT <= myStnLight) && (myDT >= myDayLight));
              int offset = 0;
              if (zomertijd && (daylight == 0)) offset = 3600;
              shut->paratag = tag->Value().lana + offset;
              shut->paratag.ForcedWrite();
            }

            RegCloseKey( m_hkTzone);
          }
          else shut->theTask->RunTimeManager( FLS_ERROR, "SYSINFOREAD");
        }
      }
      break;   
    case 45: //convert sectime to ISO8601	year-mo-dyThr:mi:sc.mse

      if (shut->paratag.Type() != FL_UNDEFINED)
      {

        DateTime nowDT = DateTime::Now;
        sectime = (long)tag->Value().lana;
        secyear  = (sectime > 864000) ? 1980 : nowDT.Year;
        secmonth = (sectime > 864000) ? 1    : nowDT.Month;
        secday   = (sectime > 864000) ? 1    : nowDT.Day;

        DateTime myDT = DateTime(secyear, secmonth, secday);
        myDT = myDT.AddSeconds( (double)sectime);
        char msgDT[100];
        int iyear = myDT.Year;
        int imonth = myDT.Month;
        int iday = myDT.Day;
        int ihour = myDT.Hour;
        int imin = myDT.Minute;
        int isec = myDT.Second;
        if (secyear == 1980)
          sprintf( msgDT, "%4d-%02d-%02d %02d:%02d:%02d", iyear, imonth, iday, ihour, imin, isec);
        else
          sprintf( msgDT, "%02d:%02d:%02d", ihour, imin, isec);

        shut->paratag = msgDT;
        shut->paratag.ForcedWrite();
      }
      break;

    case 100: //get free disk space
    case 101:
    case 102:
    case 103:
    case 104:
    case 105:
    case 106:
    case 107:
    case 108:
    case 109:
    case 110:
    case 111:
    case 112:
    case 113:
    case 114:
    case 115:
    case 116:
    case 117:
    case 118:
    case 119:
    case 120:
    case 121:
    case 122:
    case 123:
    case 124:
    case 125:
      //get free diskspace
      lpDirectoryName[0] += (shut->GetFlag() % 100);
      b = GetDiskFreeSpaceEx( lpDirectoryName, &FreeBytesAvailableToCaller,
                              &TotalNumberOfBytes, &TotalNumberOfFreeBytes);
      //FreeBytesAvailableToCaller.LowPart = (FreeBytesAvailableToCaller.LowPart >> 10) & 0x003fffff;
      //FreeBytesAvailableToCaller.HighPart = (FreeBytesAvailableToCaller.HighPart << 32) & 0xfffffC00;
      //FreeBytesAvailableToCaller.LowPart |= FreeBytesAvailableToCaller.HighPart;
      FreeBytesAvailableToCaller.QuadPart = (FreeBytesAvailableToCaller.QuadPart >> 10);

      if (shut->theTask->GetUseGB())
        FreeBytesAvailableToCaller.QuadPart = (FreeBytesAvailableToCaller.QuadPart >> 20);
      else
      {
        if (shut->theTask->GetUseMB())
          FreeBytesAvailableToCaller.QuadPart = (FreeBytesAvailableToCaller.QuadPart >> 10);
      }
      if (!b)
        shut->theTask->RunTimeManager( FLS_ERROR, "DISKACCESS", lpDirectoryName);
      else
      {

        //write the output tag
        if (shut->paratag.Type() != FL_UNDEFINED)
        {
          shut->paratag = FreeBytesAvailableToCaller.LowPart;
          shut->paratag.ForcedWrite();
        }
      }
      break;

    case 200: //get used disk space
    case 201:
    case 202:
    case 203:
    case 204:
    case 205:
    case 206:
    case 207:
    case 208:
    case 209:
    case 210:
    case 211:
    case 212:
    case 213:
    case 214:
    case 215:
    case 216:
    case 217:
    case 218:
    case 219:
    case 220:
    case 221:
    case 222:
    case 223:
    case 224:
    case 225:
      //get used disk space
      lpDirectoryName[0] += (shut->GetFlag() % 200);
      GetDiskFreeSpaceEx( lpDirectoryName, &FreeBytesAvailableToCaller,
                          &TotalNumberOfBytes, &TotalNumberOfFreeBytes);
      //TotalNumberOfBytes.LowPart = (TotalNumberOfBytes.LowPart >> 10) & 0x003fffff;
      //TotalNumberOfBytes.HighPart = (TotalNumberOfBytes.HighPart << 32) & 0xfffffC00;
      //TotalNumberOfBytes.LowPart |= TotalNumberOfBytes.HighPart;

      FreeBytesAvailableToCaller.QuadPart = (FreeBytesAvailableToCaller.QuadPart >> 10);
      TotalNumberOfBytes.QuadPart = (TotalNumberOfBytes.QuadPart >> 10);

      if (shut->theTask->GetUseGB())
      {
        TotalNumberOfBytes.QuadPart = (TotalNumberOfBytes.QuadPart >> 20);
        FreeBytesAvailableToCaller.QuadPart = (FreeBytesAvailableToCaller.QuadPart >> 20);
      }
      else
      {
        if (shut->theTask->GetUseMB())
        {
          TotalNumberOfBytes.QuadPart = (TotalNumberOfBytes.QuadPart >> 10);
          FreeBytesAvailableToCaller.QuadPart = (FreeBytesAvailableToCaller.QuadPart >> 10);
        }
      }

      if (!b)
        shut->theTask->RunTimeManager( FLS_ERROR, "DISKACCESS", lpDirectoryName);
      else
      {

        //write the output tag
        if (shut->paratag.Type() != FL_UNDEFINED)
        {
          //number of used bytes: total size - used size
          shut->paratag = TotalNumberOfBytes.LowPart - FreeBytesAvailableToCaller.LowPart;
          shut->paratag.ForcedWrite();
        }
      }
      break;

    case 300: //get total disk space
    case 301:
    case 302:
    case 303:
    case 304:
    case 305:
    case 306:
    case 307:
    case 308:
    case 309:
    case 310:
    case 311:
    case 312:
    case 313:
    case 314:
    case 315:
    case 316:
    case 317:
    case 318:
    case 319:
    case 320:
    case 321:
    case 322:
    case 323:
    case 324:
    case 325:
      //get total disk space
      lpDirectoryName[0] += (shut->GetFlag() % 300);
      GetDiskFreeSpaceEx( lpDirectoryName, &FreeBytesAvailableToCaller,
                          &TotalNumberOfBytes, &TotalNumberOfFreeBytes);
      //TotalNumberOfBytes.LowPart = (TotalNumberOfBytes.LowPart >> 10) & 0x003fffff;
      //TotalNumberOfBytes.HighPart = (TotalNumberOfBytes.HighPart << 32) & 0xfffffC00;
      //TotalNumberOfBytes.LowPart |= TotalNumberOfBytes.HighPart;
      TotalNumberOfBytes.QuadPart = (TotalNumberOfBytes.QuadPart >> 10);

      if (shut->theTask->GetUseGB())
        TotalNumberOfBytes.QuadPart = (TotalNumberOfBytes.QuadPart >> 20);
      else
      {
        if (shut->theTask->GetUseMB())
          TotalNumberOfBytes.QuadPart = (TotalNumberOfBytes.QuadPart >> 10);
      }

      if (!b)
        shut->theTask->RunTimeManager( FLS_ERROR, "DISKACCESS", lpDirectoryName);
      else
      {

        //write the output tag
        if (shut->paratag.Type() != FL_UNDEFINED)
        {
          shut->paratag = TotalNumberOfBytes.LowPart;
          shut->paratag.ForcedWrite();
        }
      }
      break;

    default:
      break;
  }

  //set the completion tag
  if (shut->flcompl.IsValid())
  {

    VAL val;
    val.dig = 1;
    shut->flcompl.Value( val);
    shut->flcompl.ForcedWrite();
  }
}


//////////////////////////////////////////////////////////////////////
// void KeyQuery( FlTag *tag, void *data)
// 
// 
//////////////////////////////////////////////////////////////////////
void KeyQuery( FlTag *tag, void *data)
{

  CKeyStroke *key = (CKeyStroke *)data;
  VAL val;


  //digital trigger?
  if ((int)tag == 0) return;

  val.dig =0; //default is locking off

  //check if keyboard dirver is present, up and running
  if (!key->theTask->m_oKeyFilter.IsAttached())
    key->theTask->RunTimeManager( FLS_ERROR, "NOKEYBOARD");
  else 
  {
    int mykey;

    //get actual key state
    key->theTask->m_oKeyFilter.IsKeyDisabled( &mykey,
                                              key->GetKey(),
                                              key->GetShift(),
                                              key->GetAlt(),
                                              key->GetControl());
    
    if (mykey) val.dig = 1; //defined value!!!
  }

  //set the (actual) key-state tag
  if (key->flstate.IsValid())
  {
    
    key->flstate.Value( val);
    key->flstate.Write();
  }

  //set completion tag
  if (key->flcompl.IsValid())
  {

    val.dig = 1;
    key->flcompl.Value( val);
    key->flcompl.ForcedWrite();
  }
}


//////////////////////////////////////////////////////////////////////
// void KeyFiltering( FlTag *tag, void *data)
// 
// 
//////////////////////////////////////////////////////////////////////
void KeyFiltering( FlTag *tag, void *data)
{

  CKeyStroke *key = (CKeyStroke *)data;
  VAL val;


  val.dig = 0;

  //check if keyboard dirver is present, up and running
  if (!key->theTask->m_oKeyFilter.IsAttached())
    key->theTask->RunTimeManager( FLS_ERROR, "NOKEYBOARD");
  else
  {

    if ((int)(*tag)) 
    {

      key->theTask->m_oKeyFilter.ReplaceKey( key->GetKey(),
                                             key->GetShift(),
                                             key->GetAlt(),
                                             key->GetControl(), 
                                             key->GetReplaceKey());
      val.dig = 1;
    }
    else
      key->theTask->m_oKeyFilter.EnableKey( key->GetKey(), 
                                            key->GetShift(), 
                                            key->GetAlt(), 
                                            key->GetControl()); 
  }

  //set the (actual) key-state tag
  if (key->flstate.IsValid())
  {

    key->flstate.Value( val);
    key->flstate.Write();
  }

  //set completion tag
  if (key->flcompl.IsValid())
  {

    val.dig = 1;
    key->flcompl.Value( val);
    key->flcompl.ForcedWrite();
  }
}


//////////////////////////////////////////////////////////////////////
// UINT MyControllingFunction( LPVOID pParam)
// 
// 
//////////////////////////////////////////////////////////////////////
UINT MyControllingFunction( LPVOID pParam)
{

  CMbox *mbox = (CMbox *)pParam;
 

  //clear the time out counter
  mbox->ResetCounter();

  //display the message box
  int ret = MessageBox( GetDesktopWindow(), mbox->dialog_text, mbox->dialog_title, mbox->m_iT);

  //generate the desired return coe for the thread
  int type = mbox->m_iT & (MB_ABORTRETRYIGNORE|MB_OKCANCEL|MB_RETRYCANCEL|MB_YESNO|MB_YESNOCANCEL);
  switch (type)
  {

    case MB_ABORTRETRYIGNORE:
      if (ret == IDABORT) ret = 0;
      if (ret == IDRETRY) ret = 1;
      if (ret == IDIGNORE) ret = 2;
      break;

    case MB_OKCANCEL:
      if (ret == IDOK) ret = 1;
      else ret = 0;
      break;

    case MB_RETRYCANCEL:
      if (ret == IDRETRY) ret = 1;
      else ret = 0;
      break;

    case MB_YESNO:
      if (ret == IDYES) ret = 1;
      else ret = 0;
      break;

    case MB_YESNOCANCEL:
      if (ret == IDYES) ret = 1;
      if (ret == IDNO) ret = 0;
      if (ret == IDCANCEL) ret = 2;
      break;

    default: break;
  }
  return ret;
}


//////////////////////////////////////////////////////////////////////
// void FlNTMessagebox( FlTag *tag, void *data)
// 
// 
//////////////////////////////////////////////////////////////////////
void FlNTMessagebox( FlTag *tag, void *data)
{

  CMbox *mbox = (CMbox *)data;

  //trigger to show the message box, otherwise keep quiet
  if ((int)(*tag)) 
  {

    //UINT t = (mbox->dialog_topmost) ? MB_TOPMOST|MB_SETFOREGROUND: MB_SETFOREGROUND;
    UINT t = (mbox->dialog_topmost) ? MB_TOPMOST: 0;

    //type of message box
    switch (mbox->dialog_type)
    {

      case 1: t |= MB_ABORTRETRYIGNORE; break;
      case 3: t |= MB_OKCANCEL; break;
      case 4: t |= MB_RETRYCANCEL; break;
      case 5: t |= MB_YESNO; break;
      case 6: t |= MB_YESNOCANCEL; break;
      default: t |= MB_OK; break;
    }

    //icon for message box
    switch (mbox->dialog_icon)
    {

      case 1: t |= MB_ICONEXCLAMATION; break;
      case 2: t |= MB_ICONWARNING; break;
      case 3: t |= MB_ICONINFORMATION; break;
      case 4: t |= MB_ICONASTERISK; break;
      case 5: t |= MB_ICONQUESTION; break;
      case 6: t |= MB_ICONSTOP; break;
      case 7: t |= MB_ICONERROR; break;
      case 8: t |= MB_ICONHAND; break;
      default: break;
    }

    //load the text
    int x = mbox->fltext.Type();
    if (x != FL_UNDEFINED)
    {
      if (!mbox->fltext.Read())
        strcpy( mbox->dialog_text, (char *)(mbox->fltext));
    }

    //load the title
    if (mbox->fltitle.Type() != FL_UNDEFINED)
    {
      if (!mbox->fltitle.Read())
      strcpy( mbox->dialog_title, (char *)(mbox->fltitle));
    }

    //show the message box
    (mbox->theTask)->SetRunMode( 0);
    mbox->m_iT = t;

    //start a thread, on completion we have the value to return to FL
    //AfxBeginThread( MyControllingFunction, (void *)mbox);
    if (mbox->m_Thread == NULL)
    {

      mbox->m_Thread = new CWinThread( MyControllingFunction, (void *)mbox);
      mbox->m_Thread->m_bAutoDelete = FALSE;
      mbox->m_Thread->CreateThread();

      mbox->theTask->FlSleep( 100);

      for( int i =0; i < 40; i++)
      {

        HWND hWnd = FindWindow( NULL, mbox->dialog_title);

        if (hWnd)
        {
          if (GetForegroundWindow() == hWnd)
          {

            mbox->theTask->FlSleep( 50);
            Beep( 200, 10);
            Beep( 500, 20);
            break;
          }
          else
          {
            //BringWindowToTop( hWnd);
            //SetWindowPos( hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE|SW_RESTORE);
            //SetWindowPos( hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
            SetForegroundWindow( hWnd);

            //SetWindowPos( hWnd, HWND_TOP, 500, 500, 0, 0,SWP_NOSIZE); 
 
            //SetActiveWindow( hWnd)
          }
        }

        mbox->theTask->FlSleep( 5);
      }
    }
  }
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// NTFlTask::NTFlTask( char *Name, char *Desc)
// 
// 
//////////////////////////////////////////////////////////////////////
NTFlTask::NTFlTask( char *Name, char *Desc)
  : FlTask( Name, Desc)
{

  m_iShutdown = 0;
  FlShutdown = NULL;
  DlgRegistration = NULL;
  m_bFlStop = false;
}

//////////////////////////////////////////////////////////////////////
// NTFlTask::~NTFlTask()
// 
// 
//////////////////////////////////////////////////////////////////////
NTFlTask::~NTFlTask()
{


  //task must be running, according to FactoryLink
  if (GetId() >= 0)
    Stopping();
}

//////////////////////////////////////////////////////////////////////
// Overloaded functions
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// void NTFlTask::CTload()
// 
// 
//////////////////////////////////////////////////////////////////////
void NTFlTask::CTload()
{

  FlCTfile      CTfile;
  int           i, ct;
  CT_KEYSTROKE  *key_info;
  CT_SHUTDOWN   *shut_info;
  #ifdef INCLUDE_MSGBOX
  CT_MESSAGEBOX *mess_box;
  #endif
  CT_EVENTLOG   *elog_info;
  CKeyStroke    *keystroke;
  CShutdown     *shutdown;
  #ifdef INCLUDE_MSGBOX
  CMbox         *mbox;
  #endif
  C2EventLog    *elog;


  //check for opened CT archive file
  if (!CTfile.IsOpen() ||!CTfile.NoTables())
  {

    //adjust message according to situation 
    if (!CTfile.NoTables())
      RunTimeManager( FLS_ERROR, "NOTRIGGERS");
    else
      RunTimeManager( FLS_ERROR, "NOCT");

    return;
  }

  //loop through the tables, processing each in turn
  for (ct = 0; ct < CTfile.NoTables(); ct++)
  {

    //read the index for this table
    if (CTfile.ReadIndex( ct) != GOOD)
      continue;

    //continue if there are no records
    if (!CTfile.NoRecords())
      continue;

    switch (CTfile.Type())
    {

      //parameter AD conversion
      case CTID_KEYSTROKES:

        //read all the records of the CT
        for (i = 0; i < CTfile.NoRecords(); i++)
        {

          //read the main record
          key_info = (CT_KEYSTROKE *)CTfile.ReadRecord( i);

          //allocate memory for the new object
          if (!(keystroke = new CKeyStroke( key_info, this))) //&theFlTask)))
            return;

          //add element to list
          m_aKey.Add( keystroke);

          //add trigger: input tag
          SetEvent( keystroke->theTag, KeyFiltering, keystroke);
        }
        break;

      case CTID_SHUTDOWNS:

        //read all the records of the CT
        for (i = 0; i < CTfile.NoRecords(); i++)
        {

          //read the main record
          shut_info = (CT_SHUTDOWN *)CTfile.ReadRecord( i);

          //allocate memory for the new object
          if (!(shutdown = new CShutdown( shut_info, this)))//&theFlTask)))
            return;

          //add element to list
          m_aShutdown.Add( shutdown);

          //add trigger: input tag
          SetEvent( shutdown->fltag, ShutdownFL, shutdown);
        }
        break;

      case CTID_MESSAGEBOX:

        #ifdef INCLUDE_MSGBOX
        //read all the records of the CT
        for (i = 0; i < CTfile.NoRecords(); i++)
        {

          //read the main record
          mess_box = (CT_MESSAGEBOX *)CTfile.ReadRecord( i);

          //allocate memory for the new object
          if (!(mbox = new CMbox( mess_box, this)))//&theFlTask)))
            return;

          //add element to list
          m_aMessageBox.Add( mbox);

          //add trigger: input tag
          SetEvent( mbox->fltag, FlNTMessagebox, mbox);
        }
        #endif
        break;

      case CTID_EVENTLOG:

        //read all the records of the CT
        for (i = 0; i < CTfile.NoRecords(); i++)
        {

          //read the main record
          elog_info = (CT_EVENTLOG *)CTfile.ReadRecord( i);

          //allocate memory for the new object
          if (!(elog = new C2EventLog( elog_info, this)))//&theFlTask)))
            return;

          //add element to list
          m_aEventLog.Add( elog);

          //add trigger: event type
          if (elog->flevent.IsValid()) SetEvent( elog->flevent, SaveTagValueFL, elog);

          //add trigger: message
          if (elog->fltext.IsValid()) SetEvent( elog->fltext, SaveTagValueFL, elog);

          //add trigger: log action
          if (elog->fltag.IsValid()) SetEvent( elog->fltag, EventLogFL, elog);
        }
        break;
    }
  }
}


//////////////////////////////////////////////////////////////////////
// void NTFlTask::Starting()
// 
// 
//////////////////////////////////////////////////////////////////////
void NTFlTask::Starting()
{

  int i;


  //initialise shutdown tag
  FlShutdown = new FlTag( GT_SHUTDOWN);
  FlShutdown->Read();
  TAG  t = {3, 34};
  FlTag          RTMmsg( t); 
  RTMmsg.Read();

  //check registration
  //Registration();

  //load additional ini settings
  m_iUseMB = GetPrivateProfileInteger( _T("DiskSpace"), _T("UseMB"), 0);
  m_iUseGB = GetPrivateProfileInteger( _T("DiskSpace"), _T("UseGB"), 0);

  m_sTimeZoneName = GetPrivateProfileString( _T("TimeZone"), _T("TimeZoneName"), _T("W. Europe Standard Time"));

  //walk through the key list and do all the enabling/disabling
  for (i = 0; i < m_aKey.GetSize(); i++)
  {

    //first read the tag
    m_aKey.GetAt( i)->theTag.Read();
    KeyFiltering( &m_aKey.GetAt( i)->theTag, m_aKey.GetAt( i));
  }

  //walk through the shutdown list
//  for (i = 0; i < m_aShutdown.GetSize(); i++)
//  {

    //first read the tag
//    m_aShutdown.GetAt( i)->fltag.Read();
//    ShutdownFL( &m_aShutdown.GetAt( i)->fltag, m_aShutdown.GetAt( i));
//  }

  //walk through the msgbox list
//  for (i = 0; i < m_aMessageBox.GetSize(); i++)
//  {

    //first read the tag
//    m_aMessageBox.GetAt( i)->fltag.Read();
//    FlNTMessagebox( &m_aMessageBox.GetAt( i)->fltag, m_aMessageBox.GetAt( i));
//  }
}

//////////////////////////////////////////////////////////////////////
// void NTFlTask::ShutdownSystem()
// 
// Shutdown the system, thsi is done after we told the FL runtime ma-
// nager we are closed, so don't use any call were we need our (inva-
// lid) FL-id
//////////////////////////////////////////////////////////////////////
void NTFlTask::ShutdownSystem()
{

  //do a shutdown if needed
  if (m_iShutdown)
  {

    //wait until FL is gone, the are no more users
    if (m_bFlStop)
    {

      while (fl_get_nkusrs() != -1)
        Sleep( 10);
    }

    //now we can shutdown our system, first get the rights needed
    //only user limitations can now block us
    HANDLE token = NULL;

    if (OpenProcessToken( GetCurrentProcess(), 
                          TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
                          &token))
    {

      //get the LUID for SE_SHUTDOWN_NAME, on our own system
      LUID Luid;
      LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &Luid);

      //get the privileges
      char privileges[ 1024];
      DWORD ret = 0;
      if (GetTokenInformation( token, TokenPrivileges, (void *)privileges, 
                               sizeof( privileges), &ret))
      {

        TOKEN_PRIVILEGES *viewp = (TOKEN_PRIVILEGES *)privileges;
        int i;

        //find the one we need and enable
        for (i = 0; i < (int)viewp->PrivilegeCount; i++)
        {

          if ((viewp->Privileges[ i].Luid.LowPart == Luid.LowPart) &&
              (viewp->Privileges[ i].Luid.HighPart == Luid.HighPart))
          {

            viewp->Privileges[ i].Attributes = SE_PRIVILEGE_ENABLED;

            AdjustTokenPrivileges( token, FALSE, viewp, 0, NULL, NULL);
            break;
          }
        }
      }

      //do a shutdown, force applications to close
      ExitWindowsEx( m_lShutdownFlag, EWX_FORCE);
    }
  }
}

//////////////////////////////////////////////////////////////////////
// void NTFlTask::SetShutdown(long Flag)
// 
// 
//////////////////////////////////////////////////////////////////////
void NTFlTask::SetShutdown(long Flag)
{

  m_iShutdown = 1;


  //convert flag for shutdown
  switch (Flag)
  {

    case 1: m_lShutdownFlag = EWX_LOGOFF; break;
    case 2: m_lShutdownFlag = EWX_POWEROFF; break;
    case 3: m_lShutdownFlag = EWX_REBOOT; break;
    case 4: m_lShutdownFlag = EWX_SHUTDOWN; break;
    default: m_iShutdown = 0; break;
  }

  if (m_bFlStop)
  {

    if (FlShutdown)
    {

      *FlShutdown = m_iShutdown;
      if (m_iShutdown) FlShutdown->ForcedWrite(); //STOP FactoryLink
    }
    else
      RunTimeManager( FLS_ERROR, "NOSTOPTAG");
  }
  else
  {

    //factorylink is not stopping, just exit windows....
    ShutdownSystem();
  }
}

//////////////////////////////////////////////////////////////////////
// void NTFlTask::LockSystem()
// 
// Lock the workstation
//////////////////////////////////////////////////////////////////////
void NTFlTask::LockSystem()
{

  LockWorkStation(); //not supported
}

//////////////////////////////////////////////////////////////////////
// void NTFlTask::Polling()
// 
// This is for us, we are processing a messagebox, just wait until it
// is closed, then we can write the return value.
//////////////////////////////////////////////////////////////////////
void NTFlTask::Polling()
{

  int i;
  int s = m_aMessageBox.GetSize();
  CMbox *mbox;
  DWORD exitcode;


  //check all posible message box threads
  for (i = 0; i < s; i++)
  {

    mbox = m_aMessageBox.ElementAt(i);

    //if we have a handle, get the return value, if already present
    if (mbox->m_Thread != NULL)
    {

      mbox->TimeOut();

      if (!GetExitCodeThread(  mbox->m_Thread->m_hThread, &exitcode))
        exitcode = 0; //error assume no exit code

      if (exitcode == STILL_ACTIVE)
        continue;  //go to next thread
      else
      {

        //we have a return code, just write it
        mbox->flresult = (int)exitcode;
        mbox->flresult.ForcedWrite();
        mbox->m_Thread->Delete(); //destroy the thread
        delete mbox->m_Thread;
        mbox->m_Thread = NULL;
        SetRunMode();
      }
    }
  }

  //call the original one, it does some sleeping...
  FlTask::Polling();
}

//////////////////////////////////////////////////////////////////////
// void NTFlTask::Registration()
// 
// Registraiton window if task is not registered
//////////////////////////////////////////////////////////////////////
void NTFlTask::Registration()
{

  if (DlgRegistration == NULL)
    DlgRegistration = new CRegistration;

  //check if applicaiton is registrated
  if (!DlgRegistration->IsRegistered()) 
    DlgRegistration->DoModal();
}


//////////////////////////////////////////////////////////////////////
// void NTFlTask::Stopping()
// 
// 
//////////////////////////////////////////////////////////////////////
void NTFlTask::Stopping()
{

  int i;


  //clean all keystroke objects
  for (i = 0; i < m_aKey.GetSize(); i++)
    delete m_aKey.GetAt( i);

  //clean all keystroke objects
  for (i = 0; i < m_aMessageBox.GetSize(); i++)
    delete m_aMessageBox.GetAt( i);

  //clean all shutdown objects
  for (i = 0; i < m_aShutdown.GetSize(); i++)
    delete m_aShutdown.GetAt( i);

  //delete the object arrays
  m_aKey.RemoveAll();
  m_aMessageBox.RemoveAll();
  m_aShutdown.RemoveAll();

  if (DlgRegistration != NULL)
    delete DlgRegistration;

  //delete the shutdown tag
  if (FlShutdown)
    delete FlShutdown;
}


//////////////////////////////////////////////////////////////////////
// void NTFlTask::SetFlStop(BOOL flag)
// 
// 
//////////////////////////////////////////////////////////////////////
void NTFlTask::SetFlStop(BOOL flag)
{


  m_bFlStop = flag;
}


//////////////////////////////////////////////////////////////////////
// void CMbox::ResetCounter()
// 
// 
//////////////////////////////////////////////////////////////////////
void CMbox::ResetCounter()
{

  m_iCounter50 = 0;
}

//////////////////////////////////////////////////////////////////////
// BOOL CMbox::TimeOut(BOOL update)
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CMbox::TimeOut(BOOL update)
{

  //return false if there is no timeout
  if (!dialog_time) return FALSE;

  if (m_iCounter50 > (dialog_time * 20))
    return Kill();
  else
    m_iCounter50++;

  return FALSE;
}


//////////////////////////////////////////////////////////////////////
// BOOL CMbox::Kill()
// 
// Destroy the messagbox displayed.
//////////////////////////////////////////////////////////////////////
BOOL CMbox::Kill()
{


  if ((m_hMbox = FindWindow( NULL, dialog_title)) == NULL) 
    return FALSE;

  SendMessage( m_hMbox, WM_SYSCOMMAND, SC_CLOSE,0);
  return TRUE;
}

void CMbox::ToFront()
{

//  if ((m_hMbox = FindWindow( NULL, dialog_title)) == NULL) 
//    return;

  SendMessage( GetDesktopWindow(), WM_SYSCOMMAND, SC_SCREENSAVE,0);
}

int NTFlTask::GetUseMB()
{

  return m_iUseMB;
}

int NTFlTask::GetUseGB()
{

  return m_iUseGB;
}


char *NTFlTask::GetTimeZone()
{

  return m_sTimeZoneName.GetBuffer();
}
