reactos/base/applications/cmdutils/at/at.c
Hermès Bélusca-Maïto 9393fc320e
[FORMATTING] Remove trailing whitespace. Addendum to 34593d93.
Excluded: 3rd-party code (incl. wine) and most of the win32ss.
2021-09-13 03:52:22 +02:00

936 lines
22 KiB
C

/*
* PROJECT: ReactOS AT utility
* COPYRIGHT: See COPYING in the top level directory
* FILE: base/applications/cmdutils/at/at.c
* PURPOSE: ReactOS AT utility
* PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org>
*/
#include <stdlib.h>
#include <stdio.h>
#include <windef.h>
#include <winbase.h>
#include <winuser.h>
#include <wincon.h>
#include <winnls.h>
#include <lm.h>
#include <conutils.h>
#include "resource.h"
PWSTR pszDaysOfWeekArray[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static
VOID
FreeDaysOfWeekArray(VOID)
{
INT i;
for (i = 0; i < 7; i++)
{
if (pszDaysOfWeekArray[i] != NULL)
HeapFree(GetProcessHeap(), 0, pszDaysOfWeekArray[i]);
}
}
static
BOOL
InitDaysOfWeekArray(VOID)
{
INT i, nLength;
for (i = 0; i < 7; i++)
{
nLength = GetLocaleInfo(LOCALE_USER_DEFAULT,
LOCALE_SABBREVDAYNAME1 + i,
NULL,
0);
pszDaysOfWeekArray[i] = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
nLength * sizeof(WCHAR));
if (pszDaysOfWeekArray[i] == NULL)
{
FreeDaysOfWeekArray();
return FALSE;
}
GetLocaleInfo(LOCALE_USER_DEFAULT,
LOCALE_SABBREVDAYNAME1 + i,
pszDaysOfWeekArray[i],
nLength);
}
return TRUE;
}
static
BOOL
ParseTime(
PWSTR pszTime,
PULONG pulJobHour,
PULONG pulJobMinute)
{
WCHAR szHour[3], szMinute[3], szAmPm[5];
PWSTR startPtr, endPtr;
ULONG ulHour = 0, ulMinute = 0;
INT nLength;
if (pszTime == NULL)
return FALSE;
startPtr = pszTime;
/* Extract the hour string */
nLength = 0;
while (*startPtr != L'\0' && iswdigit(*startPtr))
{
if (nLength >= 2)
return FALSE;
szHour[nLength] = *startPtr;
nLength++;
startPtr++;
}
szHour[nLength] = L'\0';
/* Check for a valid time separator */
if (*startPtr != L':')
return FALSE;
/* Skip the time separator */
startPtr++;
/* Extract the minute string */
nLength = 0;
while (*startPtr != L'\0' && iswdigit(*startPtr))
{
if (nLength >= 2)
return FALSE;
szMinute[nLength] = *startPtr;
nLength++;
startPtr++;
}
szMinute[nLength] = L'\0';
/* Extract the optional AM/PM indicator string */
nLength = 0;
while (*startPtr != L'\0')
{
if (nLength >= 4)
return FALSE;
if (!iswspace(*startPtr))
{
szAmPm[nLength] = *startPtr;
nLength++;
}
startPtr++;
}
szAmPm[nLength] = L'\0';
/* Convert the hour string */
ulHour = wcstoul(szHour, &endPtr, 10);
if (ulHour == 0 && *endPtr != UNICODE_NULL)
return FALSE;
/* Convert the minute string */
ulMinute = wcstoul(szMinute, &endPtr, 10);
if (ulMinute == 0 && *endPtr != UNICODE_NULL)
return FALSE;
/* Check for valid AM/PM indicator */
if (wcslen(szAmPm) > 0 &&
_wcsicmp(szAmPm, L"a") != 0 &&
_wcsicmp(szAmPm, L"am") != 0 &&
_wcsicmp(szAmPm, L"p") != 0 &&
_wcsicmp(szAmPm, L"pm") != 0)
return FALSE;
/* Check for the valid minute range [0-59] */
if (ulMinute > 59)
return FALSE;
if (wcslen(szAmPm) > 0)
{
/* 12 hour time format */
/* Check for the valid hour range [1-12] */
if (ulHour == 0 || ulHour > 12)
return FALSE;
/* Convert 12 hour format to 24 hour format */
if (_wcsicmp(szAmPm, L"a") == 0 ||
_wcsicmp(szAmPm, L"am") == 0)
{
if (ulHour == 12)
ulHour = 0;
}
else
{
if (ulHour >= 1 && ulHour <= 11)
ulHour += 12;
}
}
else
{
/* 24 hour time format */
/* Check for the valid hour range [0-23] */
if (ulHour > 23)
return FALSE;
}
if (pulJobHour != NULL)
*pulJobHour = ulHour;
if (pulJobMinute != NULL)
*pulJobMinute = ulMinute;
return TRUE;
}
static
BOOL
ParseId(
PWSTR pszId,
PULONG pulId)
{
PWSTR startPtr, endPtr;
ULONG ulId = 0;
BOOL bResult = FALSE;
startPtr = pszId;
endPtr = NULL;
ulId = wcstoul(startPtr, &endPtr, 10);
if (endPtr != NULL && *endPtr == UNICODE_NULL)
{
bResult = TRUE;
if (pulId != NULL)
*pulId = ulId;
}
return bResult;
}
static
BOOL
ParseDaysOfMonth(
PWSTR pszBuffer,
PULONG pulDaysOfMonth)
{
PWSTR startPtr, endPtr;
ULONG ulValue;
if (wcslen(pszBuffer) == 0)
return FALSE;
startPtr = pszBuffer;
endPtr = NULL;
for (;;)
{
ulValue = wcstoul(startPtr, &endPtr, 10);
if (ulValue == 0)
return FALSE;
if (ulValue > 0 && ulValue <= 31)
*pulDaysOfMonth |= (1 << (ulValue - 1));
if (endPtr != NULL && *endPtr == UNICODE_NULL)
return TRUE;
startPtr = endPtr + 1;
endPtr = NULL;
}
return FALSE;
}
static
BOOL
ParseDaysOfWeek(
PWSTR pszBuffer,
PUCHAR pucDaysOfWeek)
{
PWSTR startPtr, endPtr;
INT nLength, i;
if (wcslen(pszBuffer) == 0)
return FALSE;
startPtr = pszBuffer;
endPtr = NULL;
for (;;)
{
endPtr = wcschr(startPtr, L',');
if (endPtr == NULL)
nLength = wcslen(startPtr);
else
nLength = (INT)((ULONG_PTR)endPtr - (ULONG_PTR)startPtr) / sizeof(WCHAR);
for (i = 0; i < 7; i++)
{
if (nLength == wcslen(pszDaysOfWeekArray[i]) &&
_wcsnicmp(startPtr, pszDaysOfWeekArray[i], nLength) == 0)
{
*pucDaysOfWeek |= (1 << i);
break;
}
}
if (endPtr == NULL)
return TRUE;
startPtr = endPtr + 1;
endPtr = NULL;
}
return FALSE;
}
static
VOID
PrintErrorMessage(
DWORD dwError)
{
PWSTR pszBuffer = NULL;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
0,
(PWSTR)&pszBuffer,
0,
NULL);
ConPrintf(StdErr, L"%s\n", pszBuffer);
LocalFree(pszBuffer);
}
static
VOID
PrintHorizontalLine(VOID)
{
WCHAR szBuffer[80];
INT i;
for (i = 0; i < 79; i++)
szBuffer[i] = L'-';
szBuffer[79] = UNICODE_NULL;
ConPrintf(StdOut, L"%s\n", szBuffer);
}
static
BOOL
Confirm(VOID)
{
HINSTANCE hInstance;
WCHAR szYesBuffer[8];
WCHAR szNoBuffer[8];
WCHAR szInput[80];
DWORD dwOldMode;
DWORD dwRead = 0;
BOOL ret = FALSE;
HANDLE hFile;
hInstance = GetModuleHandleW(NULL);
LoadStringW(hInstance, IDS_CONFIRM_YES, szYesBuffer, _countof(szYesBuffer));
LoadStringW(hInstance, IDS_CONFIRM_NO, szNoBuffer, _countof(szNoBuffer));
ZeroMemory(szInput, sizeof(szInput));
hFile = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hFile, &dwOldMode);
SetConsoleMode(hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
for (;;)
{
ConResPrintf(StdOut, IDS_CONFIRM_QUESTION);
ReadConsoleW(hFile, szInput, _countof(szInput), &dwRead, NULL);
szInput[0] = towupper(szInput[0]);
if (szInput[0] == szYesBuffer[0])
{
ret = TRUE;
break;
}
else if (szInput[0] == 13 || szInput[0] == szNoBuffer[0])
{
ret = FALSE;
break;
}
ConResPrintf(StdOut, IDS_CONFIRM_INVALID);
}
SetConsoleMode(hFile, dwOldMode);
return ret;
}
static
DWORD_PTR
GetTimeAsJobTime(VOID)
{
SYSTEMTIME Time;
DWORD_PTR JobTime;
GetLocalTime(&Time);
JobTime = (DWORD_PTR)Time.wHour * 3600000 +
(DWORD_PTR)Time.wMinute * 60000;
return JobTime;
}
static
ULONG
GetCurrentDayOfMonth(VOID)
{
SYSTEMTIME Time;
GetLocalTime(&Time);
return 1UL << (Time.wDay - 1);
}
static
VOID
JobTimeToTimeString(
PWSTR pszBuffer,
INT cchBuffer,
WORD wHour,
WORD wMinute)
{
SYSTEMTIME Time = {0, 0, 0, 0, 0, 0, 0, 0};
Time.wHour = wHour;
Time.wMinute = wMinute;
GetTimeFormat(LOCALE_USER_DEFAULT,
TIME_NOSECONDS,
&Time,
NULL,
pszBuffer,
cchBuffer);
}
static
INT
PrintJobDetails(
PWSTR pszComputerName,
ULONG ulJobId)
{
PAT_INFO pBuffer = NULL;
DWORD_PTR CurrentTime;
WCHAR szStatusBuffer[16];
WCHAR szScheduleBuffer[60];
WCHAR szTimeBuffer[16];
WCHAR szInteractiveBuffer[16];
WCHAR szDateBuffer[8];
INT i, nDateLength, nScheduleLength;
HINSTANCE hInstance;
NET_API_STATUS Status;
Status = NetScheduleJobGetInfo(pszComputerName,
ulJobId,
(PBYTE *)&pBuffer);
if (Status != NERR_Success)
{
PrintErrorMessage(Status);
return 1;
}
hInstance = GetModuleHandle(NULL);
if (pBuffer->Flags & JOB_EXEC_ERROR)
LoadStringW(hInstance, IDS_ERROR, szStatusBuffer, _countof(szStatusBuffer));
else
LoadStringW(hInstance, IDS_OK, szStatusBuffer, _countof(szStatusBuffer));
if (pBuffer->DaysOfMonth != 0)
{
if (pBuffer->Flags & JOB_RUN_PERIODICALLY)
LoadStringW(hInstance, IDS_EVERY, szScheduleBuffer, _countof(szScheduleBuffer));
else
LoadStringW(hInstance, IDS_NEXT, szScheduleBuffer, _countof(szScheduleBuffer));
nScheduleLength = wcslen(szScheduleBuffer);
for (i = 0; i < 31; i++)
{
if (pBuffer->DaysOfMonth & (1 << i))
{
swprintf(szDateBuffer, L" %d", i + 1);
nDateLength = wcslen(szDateBuffer);
if (nScheduleLength + nDateLength <= 55)
{
wcscat(szScheduleBuffer, szDateBuffer);
nScheduleLength += nDateLength;
}
else
{
wcscat(szScheduleBuffer, L"...");
break;
}
}
}
}
else if (pBuffer->DaysOfWeek != 0)
{
if (pBuffer->Flags & JOB_RUN_PERIODICALLY)
LoadStringW(hInstance, IDS_EVERY, szScheduleBuffer, _countof(szScheduleBuffer));
else
LoadStringW(hInstance, IDS_NEXT, szScheduleBuffer, _countof(szScheduleBuffer));
nScheduleLength = wcslen(szScheduleBuffer);
for (i = 0; i < 7; i++)
{
if (pBuffer->DaysOfWeek & (1 << i))
{
swprintf(szDateBuffer, L" %s", pszDaysOfWeekArray[i]);
nDateLength = wcslen(szDateBuffer);
if (nScheduleLength + nDateLength <= 55)
{
wcscat(szScheduleBuffer, szDateBuffer);
nScheduleLength += nDateLength;
}
else
{
wcscat(szScheduleBuffer, L"...");
break;
}
}
}
}
else
{
CurrentTime = GetTimeAsJobTime();
if (CurrentTime > pBuffer->JobTime)
LoadStringW(hInstance, IDS_TOMORROW, szScheduleBuffer, _countof(szScheduleBuffer));
else
LoadStringW(hInstance, IDS_TODAY, szScheduleBuffer, _countof(szScheduleBuffer));
}
JobTimeToTimeString(szTimeBuffer,
_countof(szTimeBuffer),
(WORD)(pBuffer->JobTime / 3600000),
(WORD)((pBuffer->JobTime % 3600000) / 60000));
if (pBuffer->Flags & JOB_NONINTERACTIVE)
LoadStringW(hInstance, IDS_NO, szInteractiveBuffer, _countof(szInteractiveBuffer));
else
LoadStringW(hInstance, IDS_YES, szInteractiveBuffer, _countof(szInteractiveBuffer));
ConResPrintf(StdOut, IDS_TASKID, ulJobId);
ConResPrintf(StdOut, IDS_STATUS, szStatusBuffer);
ConResPrintf(StdOut, IDS_SCHEDULE, szScheduleBuffer);
ConResPrintf(StdOut, IDS_TIME, szTimeBuffer);
ConResPrintf(StdOut, IDS_INTERACTIVE, szInteractiveBuffer);
ConResPrintf(StdOut, IDS_COMMAND, pBuffer->Command);
NetApiBufferFree(pBuffer);
return 0;
}
static
INT
PrintAllJobs(
PWSTR pszComputerName)
{
PAT_ENUM pBuffer = NULL;
DWORD dwRead = 0, dwTotal = 0;
DWORD dwResume = 0, i;
DWORD_PTR CurrentTime;
NET_API_STATUS Status;
WCHAR szScheduleBuffer[32];
WCHAR szTimeBuffer[16];
WCHAR szDateBuffer[8];
HINSTANCE hInstance;
INT j, nDateLength, nScheduleLength;
Status = NetScheduleJobEnum(pszComputerName,
(PBYTE *)&pBuffer,
MAX_PREFERRED_LENGTH,
&dwRead,
&dwTotal,
&dwResume);
if (Status != NERR_Success)
{
PrintErrorMessage(Status);
return 1;
}
if (dwTotal == 0)
{
ConResPrintf(StdOut, IDS_NO_ENTRIES);
return 0;
}
ConResPrintf(StdOut, IDS_JOBS_LIST);
PrintHorizontalLine();
hInstance = GetModuleHandle(NULL);
for (i = 0; i < dwRead; i++)
{
if (pBuffer[i].DaysOfMonth != 0)
{
if (pBuffer[i].Flags & JOB_RUN_PERIODICALLY)
LoadStringW(hInstance, IDS_EVERY, szScheduleBuffer, _countof(szScheduleBuffer));
else
LoadStringW(hInstance, IDS_NEXT, szScheduleBuffer, _countof(szScheduleBuffer));
nScheduleLength = wcslen(szScheduleBuffer);
for (j = 0; j < 31; j++)
{
if (pBuffer[i].DaysOfMonth & (1 << j))
{
swprintf(szDateBuffer, L" %d", j + 1);
nDateLength = wcslen(szDateBuffer);
if (nScheduleLength + nDateLength <= 19)
{
wcscat(szScheduleBuffer, szDateBuffer);
nScheduleLength += nDateLength;
}
else
{
wcscat(szScheduleBuffer, L"...");
break;
}
}
}
}
else if (pBuffer[i].DaysOfWeek != 0)
{
if (pBuffer[i].Flags & JOB_RUN_PERIODICALLY)
LoadStringW(hInstance, IDS_EVERY, szScheduleBuffer, _countof(szScheduleBuffer));
else
LoadStringW(hInstance, IDS_NEXT, szScheduleBuffer, _countof(szScheduleBuffer));
nScheduleLength = wcslen(szScheduleBuffer);
for (j = 0; j < 7; j++)
{
if (pBuffer[i].DaysOfWeek & (1 << j))
{
swprintf(szDateBuffer, L" %s", pszDaysOfWeekArray[j]);
nDateLength = wcslen(szDateBuffer);
if (nScheduleLength + nDateLength <= 55)
{
wcscat(szScheduleBuffer, szDateBuffer);
nScheduleLength += nDateLength;
}
else
{
wcscat(szScheduleBuffer, L"...");
break;
}
}
}
}
else
{
CurrentTime = GetTimeAsJobTime();
if (CurrentTime > pBuffer[i].JobTime)
LoadStringW(hInstance, IDS_TOMORROW, szScheduleBuffer, _countof(szScheduleBuffer));
else
LoadStringW(hInstance, IDS_TODAY, szScheduleBuffer, _countof(szScheduleBuffer));
}
JobTimeToTimeString(szTimeBuffer,
_countof(szTimeBuffer),
(WORD)(pBuffer[i].JobTime / 3600000),
(WORD)((pBuffer[i].JobTime % 3600000) / 60000));
ConPrintf(StdOut,
L" %6lu %-21s %-11s %s\n",
pBuffer[i].JobId,
szScheduleBuffer,
szTimeBuffer,
pBuffer[i].Command);
}
NetApiBufferFree(pBuffer);
return 0;
}
static
INT
AddJob(
PWSTR pszComputerName,
ULONG ulJobHour,
ULONG ulJobMinute,
ULONG ulDaysOfMonth,
UCHAR ucDaysOfWeek,
BOOL bInteractiveJob,
BOOL bPeriodicJob,
PWSTR pszCommand)
{
AT_INFO InfoBuffer;
ULONG ulJobId = 0;
NET_API_STATUS Status;
InfoBuffer.JobTime = (DWORD_PTR)ulJobHour * 3600000 +
(DWORD_PTR)ulJobMinute * 60000;
InfoBuffer.DaysOfMonth = ulDaysOfMonth;
InfoBuffer.DaysOfWeek = ucDaysOfWeek;
InfoBuffer.Flags = (bInteractiveJob ? 0 : JOB_NONINTERACTIVE) |
(bPeriodicJob ? JOB_RUN_PERIODICALLY : 0);
InfoBuffer.Command = pszCommand;
Status = NetScheduleJobAdd(pszComputerName,
(PBYTE)&InfoBuffer,
&ulJobId);
if (Status != NERR_Success)
{
PrintErrorMessage(Status);
return 1;
}
ConResPrintf(StdOut, IDS_NEW_JOB, ulJobId);
return 0;
}
static
INT
DeleteJob(
PWSTR pszComputerName,
ULONG ulJobId,
BOOL bForceDelete)
{
NET_API_STATUS Status;
if (ulJobId == (ULONG)-1 && bForceDelete == FALSE)
{
ConResPrintf(StdOut, IDS_DELETE_ALL);
if (!Confirm())
return 0;
}
Status = NetScheduleJobDel(pszComputerName,
(ulJobId == (ULONG)-1) ? 0 : ulJobId,
(ulJobId == (ULONG)-1) ? -1 : ulJobId);
if (Status != NERR_Success)
{
PrintErrorMessage(Status);
return 1;
}
return 0;
}
int wmain(int argc, WCHAR **argv)
{
PWSTR pszComputerName = NULL;
PWSTR pszCommand = NULL;
ULONG ulJobId = (ULONG)-1;
ULONG ulJobHour = (ULONG)-1;
ULONG ulJobMinute = (ULONG)-1;
BOOL bDeleteJob = FALSE, bForceDelete = FALSE;
BOOL bInteractiveJob = FALSE, bPeriodicJob = FALSE;
BOOL bPrintUsage = FALSE;
ULONG ulDaysOfMonth = 0;
UCHAR ucDaysOfWeek = 0;
INT nResult = 0;
INT i, minIdx;
/* Initialize the Console Standard Streams */
ConInitStdStreams();
if (!InitDaysOfWeekArray())
return 1;
/* Parse the computer name */
i = 1;
minIdx = 1;
if (i < argc &&
argv[i][0] == L'\\' &&
argv[i][1] == L'\\')
{
pszComputerName = argv[i];
i++;
minIdx++;
}
/* Parse the time or job id */
if (i < argc && argv[i][0] != L'/')
{
if (ParseTime(argv[i], &ulJobHour, &ulJobMinute))
{
i++;
minIdx++;
}
else if (ParseId(argv[i], &ulJobId))
{
i++;
minIdx++;
}
}
/* Parse the options */
for (; i < argc; i++)
{
if (argv[i][0] == L'/')
{
if (_wcsicmp(argv[i], L"/?") == 0)
{
bPrintUsage = TRUE;
goto done;
}
else if (_wcsicmp(argv[i], L"/delete") == 0)
{
bDeleteJob = TRUE;
}
else if (_wcsicmp(argv[i], L"/yes") == 0)
{
bForceDelete = TRUE;
}
else if (_wcsicmp(argv[i], L"/interactive") == 0)
{
bInteractiveJob = TRUE;
}
else if (_wcsnicmp(argv[i], L"/every:", 7) == 0)
{
bPeriodicJob = TRUE;
if (ParseDaysOfMonth(&(argv[i][7]), &ulDaysOfMonth) == FALSE)
{
if (ParseDaysOfWeek(&(argv[i][7]), &ucDaysOfWeek) == FALSE)
{
ulDaysOfMonth = GetCurrentDayOfMonth();
}
}
}
else if (_wcsnicmp(argv[i], L"/next:", 6) == 0)
{
bPeriodicJob = FALSE;
if (ParseDaysOfMonth(&(argv[i][6]), &ulDaysOfMonth) == FALSE)
{
if (ParseDaysOfWeek(&(argv[i][6]), &ucDaysOfWeek) == FALSE)
{
ulDaysOfMonth = GetCurrentDayOfMonth();
}
}
}
else
{
bPrintUsage = TRUE;
nResult = 1;
goto done;
}
}
}
/* Parse the command */
if (argc > minIdx && argv[argc - 1][0] != L'/')
{
pszCommand = argv[argc - 1];
}
if (bDeleteJob == TRUE)
{
/* Check for invalid options or arguments */
if (bInteractiveJob == TRUE ||
ulJobHour != (ULONG)-1 ||
ulJobMinute != (ULONG)-1 ||
ulDaysOfMonth != 0 ||
ucDaysOfWeek != 0 ||
pszCommand != NULL)
{
bPrintUsage = TRUE;
nResult = 1;
goto done;
}
nResult = DeleteJob(pszComputerName,
ulJobId,
bForceDelete);
}
else
{
if (ulJobHour != (ULONG)-1 && ulJobMinute != (ULONG)-1)
{
/* Check for invalid options or arguments */
if (bForceDelete == TRUE ||
pszCommand == NULL)
{
bPrintUsage = TRUE;
nResult = 1;
goto done;
}
nResult = AddJob(pszComputerName,
ulJobHour,
ulJobMinute,
ulDaysOfMonth,
ucDaysOfWeek,
bInteractiveJob,
bPeriodicJob,
pszCommand);
}
else
{
/* Check for invalid options or arguments */
if (bForceDelete == TRUE ||
bInteractiveJob == TRUE ||
ulDaysOfMonth != 0 ||
ucDaysOfWeek != 0 ||
pszCommand != NULL)
{
bPrintUsage = TRUE;
nResult = 1;
goto done;
}
if (ulJobId == (ULONG)-1)
{
nResult = PrintAllJobs(pszComputerName);
}
else
{
nResult = PrintJobDetails(pszComputerName,
ulJobId);
}
}
}
done:
FreeDaysOfWeekArray();
if (bPrintUsage == TRUE)
ConResPuts(StdOut, IDS_USAGE);
return nResult;
}
/* EOF */