/* ********************************************************************* */
/* *                                                                   * */
/* * Copyright (c) 2010 Dipl.-Ing. Dirk Kraue                          * */
/* *                                                                   * */
/* * All rights reserved.                                              * */
/* *                                                                   * */
/* * Redistribution and use in source and binary forms,                * */
/* * with or without modification, are permitted provided              * */
/* * that the following conditions are met:                            * */
/* *                                                                   * */
/* * * Redistributions of source code must retain the above            * */
/* *   copyright notice, this list of conditions and the               * */
/* *   following disclaimer.                                           * */
/* * * Redistributions in binary form must reproduce the above         * */
/* *   opyright notice, this list of conditions and the following      * */
/* *   disclaimer in the documentation and/or other materials          * */
/* *   provided with the distribution.                                 * */
/* * * Neither the name of Dirk Krause nor the names of                * */
/* *   contributors may be used to endorse or promote                  * */
/* *   products derived from this software without specific            * */
/* *   prior written permission.                                       * */
/* *                                                                   * */
/* * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND            * */
/* * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,       * */
/* * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF          * */
/* * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE          * */
/* * DISCLAIMED.                                                       * */
/* * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE          * */
/* * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,             * */
/* * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT           * */
/* * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          * */
/* * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)          * */
/* * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN         * */
/* * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE         * */
/* * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS           * */
/* * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH              * */
/* * DAMAGE.                                                           * */
/* *                                                                   * */
/* ********************************************************************* */

/**	@file	kwintool.c	The kwintool main module.
*/



#include "kwintool.h"


#line 48 "kwintool.ctr"



/**	Exit code returned by the program.
*/
static int exval = 0;


/**	Commands known.
*/
static WCHAR const * const commands[] = {
/*  0 */	L"cwd",
/*  1 */	L"cwd.last",
/*  2 */	L"file.cat",
/*  3 */	L"time",
/*  4 */	L"file.compare",
/*  5 */	L"file.timecheck",
/*  6 */	L"desktop.cleartype",
/*  7 */	L"desktop.wallpaper",
/*  8 */	L"lprm.local",
/*  9 */	L"lprm.lpd",
/* 10 */	L"users",
/* 11 */	L"boot",
/* 12 */	L"login",
/* 13 */	L"logout",
/* 14 */	L"shutdown",
/* 15 */	L"ls",
/* 16 */	L"cleanup.disable",
/* 17 */	L"cleanup.enable",
NULL
};


/**	File name suffixes.
*/
static WCHAR const * const n[] = {
/*  0 */	L".exe",
/*  1 */	L".txt",
NULL
};


/**	Texts for boolean values false.
*/
static WCHAR const * const no_values[] = {
L"off", L"no", L"false", L"0", L"-",
NULL
};



/**	Keywords used by the program.
*/
static WCHAR const * const kw[] = {
  /*   0 */ L" ",
  NULL
};


/**	Show file contents.
	@param	fn	File name.
*/
static
void
show_file(WCHAR const *fn)
{
  FILE *fipo;
  char buffer[KWINTOOL_BUFFER_SIZE];
  int cc;
  size_t rs;
  int old_mode;

  fipo = _wfopen(fn, L"rb");
  if(fipo) {
    old_mode = _setmode(1, _O_BINARY);
    do {
      cc = 0;
      rs = fread((void *)buffer, 1, sizeof(buffer), fipo);
      if(rs > 0) {
        cc = 1;
	fwrite((void *)buffer, 1, rs, stdout);
      }
    } while(cc);
    if(old_mode != 1) { _setmode(1, old_mode); }
    fclose(fipo);
  } else {
    exval = 1;
  }
}




/**	Print help text.
*/
static
void
print_help(void)
{
  WCHAR fn[KWINTOOL_BUFFER_SIZE], *ptr;
  FILE *fipo; char b[KWINTOOL_BUFFER_SIZE];
  size_t lgt, l1, l2, rs;
  int cc;
  if(GetModuleFileName(GetModuleHandle(NULL), fn, SIZEOF(fn,WCHAR)-1)) {
    lgt = wcslen(fn); l1 = wcslen(n[0]); l2 = wcslen(n[1]);
    if(lgt > l1) {
      ptr = &(fn[lgt-l1]);
      if((lgt - l1 + l2) < SIZEOF(fn,WCHAR)) {
        wcscpy(ptr, n[1]);
	fipo = _wfopen(fn, L"r");
	if(fipo) {
	  do {
	    cc = 0;
	    rs = fread((void *)b, 1, sizeof(b), fipo);
	    if(rs > 0) {
	      cc = 1;
	      fwrite((void *)b, 1, rs, stdout);
	    }
	  } while(cc);
	  fclose(fipo);
	} else {
	  exval = 1;
	}
      } else {
        exval = 1;
      }
    } else {
      exval = 1;
    }
  } else {
    exval = 1;
  }
}


/**	Set up desktop wallpaper.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
run_desktop_wallpaper(int argc, WCHAR const * const *argv)
{
#if VERSION_BEFORE_20101123
  BOOL res;
  if(argc > 2) {
    res = SystemParametersInfo(
      SPI_SETDESKWALLPAPER,
      (1 + wcslen(argv[2])),
      argv[2],
      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
    );
    if(!res) {
      exval = 1;
    }
  } else {
    exval = 1;
  }
#else
  WCHAR fn[ _MAX_PATH ];
  int i;
  size_t sz_fn;
  BOOL is_first;
  BOOL res;

  sz_fn = sizeof(fn)/sizeof(WCHAR);
  is_first = TRUE;
  res = TRUE;
  for(i = 2; i < argc; i++) {
    if(is_first) {
      if(wcslen(argv[i]) < sz_fn) {
        wcscpy(fn, argv[i]);
      } else {
        res = FALSE;
      }
    } else {
      if((wcslen(fn) + wcslen(argv[i]) + 1) < sz_fn) {
        wcscat(fn, kw[0]);
	wcscat(fn, argv[i]);
      } else {
        res = FALSE;
      }
    }
    is_first = FALSE;
  }
  if(is_first) {
    res = FALSE;
  }
  if(res) {
    res = SystemParametersInfo(
      SPI_SETDESKWALLPAPER,
      (1 + wcslen(fn)),
      fn,
      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
    );
  }
  if(res) {
    exval = 0;
  } else {
    exval = 1;
  }
#endif
}


/**	Activate Cleartype font smoothing.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
run_desktop_cleartype(int argc, WCHAR const * const *argv)
{
  int action_enable = 1;
  BOOL res;
  if(argc > 2) {
    if(wstr_array_index(no_values, argv[2]) != -1) {
      action_enable = 0;
    }
  }
  if(action_enable) {
    res = SystemParametersInfo(
      SPI_SETFONTSMOOTHING,
      TRUE,
      0,
      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
    );
    if(res) {
      res = SystemParametersInfo(
        SPI_SETFONTSMOOTHINGTYPE,
        FE_FONTSMOOTHINGCLEARTYPE,
        0,
        SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
      );
      if(!res) { exval = 1; }
    } else {
      exval = 1;
    }
  } else {
    res = SystemParametersInfo(
      SPI_SETFONTSMOOTHING,
      FALSE,
      0,
      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
    );
    if(!res) { exval = 1; }
  }
}


/**	Compare modification timestamps of two files.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
run_file_timecheck(int argc, WCHAR const * const *argv)
{
  struct _stat stsrc, stdst;
  if(argc > 3) {
    if(_wstat(argv[2], &stsrc) == 0) {
      if(_wstat(argv[3], &stdst) == 0) {
        if(stsrc.st_mtime >= stdst.st_mtime) {
	  exval = 1;
	}
      } else {
        exval = 1;
      }
    } else {
      exval = 1;
    }
  } else {
    exval = 1;
  }
}



/**	Compare two files.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static 
void
run_file_compare(int argc, WCHAR const * const *argv)
{
  char b1[KWINTOOL_BUFFER_SIZE], b2[sizeof(b1)];
  FILE *f1, *f2;
  size_t r1, r2;
  int cc;
  if(argc > 3) {
    f1 = _wfopen(argv[2], L"rb");
    if(f1) {
      f2 = _wfopen(argv[3], L"rb");
      if(f2) {
        do {
	  cc = 0;
	  r1 = fread((void *)b1, 1, sizeof(b1), f1);
	  r2 = fread((void *)b2, 1, sizeof(b2), f2);
	  if(r1 == r2) {
	    if(r1 > 0) {
	      if(memcmp((void *)b1, (void *)b2, r1)) {
	        exval = 1;
	      } else {
	        cc = 1;
	      }
	    }
	  } else {
	    exval = 1;
	  }
	} while(cc);
        fclose(f2);
      } else {
        exval = 1;
      }
      fclose(f1);
    } else {
      exval = 1;
    }
  } else {
    exval = 1;
  }
}


/**	Print current time.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
run_time(int argc, WCHAR const * const *argv)
{
  time_t timer;
  struct tm *tm;
  time(&timer);
  tm = localtime(&timer);
  if(tm) {
    fwprintf(
      stdout,
      L"%04d-%02d-%02d %02d:%02d:%02d\n",
      (1900 + tm->tm_year),
      (1 + tm->tm_mon),
      tm->tm_mday,
      tm->tm_hour,
      tm->tm_min,
      tm->tm_sec
    );
  } else {
    exval = 1;
  }
}


/**	Print file contents.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
run_file_cat(int argc, WCHAR const * const *argv)
{
  if(argc > 2) {
    show_file(argv[2]);
  } else {
    exval = 1;
  }
}


/**	Check whether last part of current directory matches a given text.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
run_cwd_last(int argc, WCHAR const * const *argv)
{
  WCHAR b[KWINTOOL_BUFFER_SIZE], *ptr;
  if(_wgetcwd(b, SIZEOF(b,WCHAR)-1)) {
    ptr = wcsrchr(b, L'\\');
    if(ptr) { ptr++; } else { ptr = b; }
    if(argc > 2) {
      if(_wcsicmp(ptr, argv[2])) { exval = 1; }
    } else {
      fwprintf(stdout, L"%ls\n", ptr);
    }
  } else {
    exval = 1;
  }
}


/**	Print current working directory.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
*/
static
void
run_cwd(int argc, WCHAR const * const *argv)
{
  WCHAR b[KWINTOOL_BUFFER_SIZE];
  if(_wgetcwd(b, SIZEOF(b,WCHAR)-1)) {
    if(argc > 2) {
      if(_wcsicmp(b, argv[2])) { exval = 1; }
    } else {
      fwprintf(stdout, L"%ls\n", b);
    }
  } else {
    exval = 1;
  }
}


/**	Show local users.
*/
static
void
show_local_users(void)
{
   LPUSER_INFO_0 pBuf = NULL;
   LPUSER_INFO_0 pTmpBuf;
   DWORD dwLevel = 0;
   DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
   DWORD dwEntriesRead = 0;
   DWORD dwTotalEntries = 0;
   DWORD dwResumeHandle = 0;
   DWORD i;
   DWORD dwTotalCount = 0;
   NET_API_STATUS nStatus;
   LPTSTR pszServerName = NULL;

   do /* begin do
 */
   {
      nStatus = NetUserEnum(pszServerName,
                            dwLevel,
                            FILTER_NORMAL_ACCOUNT, /* global users
 */
                            (LPBYTE*)&pBuf,
                            dwPrefMaxLen,
                            &dwEntriesRead,
                            &dwTotalEntries,
                            &dwResumeHandle);
      if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
      {
         if ((pTmpBuf = pBuf) != NULL)
         {
            for (i = 0; (i < dwEntriesRead); i++)
            {
               if (pTmpBuf != NULL) {
                 wprintf(L"%ls\n", pTmpBuf->usri0_name);
                 pTmpBuf++;
                 dwTotalCount++;
	       }
            }
         }
      }
      if (pBuf != NULL)
      {
         NetApiBufferFree(pBuf);
         pBuf = NULL;
      }
   } while (nStatus == ERROR_MORE_DATA); /* end do
 */
   if (pBuf != NULL) NetApiBufferFree(pBuf);
}


/**	Set exit value.
	@param	i	New exit value.
*/
void
kwt_set_exval(int i) { exval = i; }


/**	Main program.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
	@return	0 on success, any other value indicates an error.
*/
int
wmain(int argc, WCHAR *argv[])
{
  int action = -1;
  
#line 530 "kwintool.ctr"

  
  if(argc > 1) {
    action = wstr_array_index(commands, argv[1]);
  }
  switch(action) {
    case 0: {	/* cwd
 */
      run_cwd(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 1: {
      run_cwd_last(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 2: {
      run_file_cat(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 3: {
      run_time(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 4: {
      run_file_compare(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 5: {
      run_file_timecheck(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 6: {
      run_desktop_cleartype(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 7: {
      run_desktop_wallpaper(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 8: {
      kwt_run_lprm_local(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 9: {
      kwt_run_lprm_lpd(argc, (KWT_W_CSTR_CPTR)argv);
    } break;
    case 10: {
      show_local_users();
    } break;
    case 11: {
      kwt_boot_login_logout_shutdown(0);
    } break;
    case 12: {
      kwt_boot_login_logout_shutdown(1);
    } break;
    case 13: {
      kwt_boot_login_logout_shutdown(2);
    } break;
    case 14: {
      kwt_boot_login_logout_shutdown(3);
    } break;
    case 15: {	/* ls
 */
      kwt_ls(argc, argv);
    } break;
    case 16: {	/* no-cleanup
 */
      kwt_no_cleanup();
    } break;
    case 17: {
      kwt_yes_cleanup();
    } break;
    default: {
      print_help();
      exval = 1;
    } break;
  } 
  
#line 595 "kwintool.ctr"

  exit(exval); return exval;
}


