/* * 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 */ #include #include #include #include #include #include #include #include #include #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 */