2 * PROJECT: ReactOS AT utility
3 * COPYRIGHT: See COPYING in the top level directory
4 * FILE: base/applications/cmdutils/at/at.c
5 * PURPOSE: ReactOS AT utility
6 * PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org>
24 PWSTR pszDaysOfWeekArray
[7] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
29 FreeDaysOfWeekArray(VOID
)
33 for (i
= 0; i
< 7; i
++)
35 if (pszDaysOfWeekArray
[i
] != NULL
)
36 HeapFree(GetProcessHeap(), 0, pszDaysOfWeekArray
[i
]);
43 InitDaysOfWeekArray(VOID
)
47 for (i
= 0; i
< 7; i
++)
49 nLength
= GetLocaleInfo(LOCALE_USER_DEFAULT
,
50 LOCALE_SABBREVDAYNAME1
+ i
,
54 pszDaysOfWeekArray
[i
] = HeapAlloc(GetProcessHeap(),
56 nLength
* sizeof(WCHAR
));
57 if (pszDaysOfWeekArray
[i
] == NULL
)
59 FreeDaysOfWeekArray();
63 GetLocaleInfo(LOCALE_USER_DEFAULT
,
64 LOCALE_SABBREVDAYNAME1
+ i
,
65 pszDaysOfWeekArray
[i
],
80 WCHAR szHour
[3], szMinute
[3], szAmPm
[5];
81 PWSTR startPtr
, endPtr
;
82 ULONG ulHour
= 0, ulMinute
= 0;
90 /* Extract the hour string */
92 while (*startPtr
!= L
'\0' && iswdigit(*startPtr
))
97 szHour
[nLength
] = *startPtr
;
102 szHour
[nLength
] = L
'\0';
104 /* Check for a valid time separator */
105 if (*startPtr
!= L
':')
108 /* Skip the time separator */
111 /* Extract the minute string */
113 while (*startPtr
!= L
'\0' && iswdigit(*startPtr
))
118 szMinute
[nLength
] = *startPtr
;
123 szMinute
[nLength
] = L
'\0';
125 /* Extract the optional AM/PM indicator string */
127 while (*startPtr
!= L
'\0')
132 if (!iswspace(*startPtr
))
134 szAmPm
[nLength
] = *startPtr
;
140 szAmPm
[nLength
] = L
'\0';
142 /* Convert the hour string */
143 ulHour
= wcstoul(szHour
, &endPtr
, 10);
144 if (ulHour
== 0 && *endPtr
!= UNICODE_NULL
)
147 /* Convert the minute string */
148 ulMinute
= wcstoul(szMinute
, &endPtr
, 10);
149 if (ulMinute
== 0 && *endPtr
!= UNICODE_NULL
)
152 /* Check for valid AM/PM indicator */
153 if (wcslen(szAmPm
) > 0 &&
154 _wcsicmp(szAmPm
, L
"a") != 0 &&
155 _wcsicmp(szAmPm
, L
"am") != 0 &&
156 _wcsicmp(szAmPm
, L
"p") != 0 &&
157 _wcsicmp(szAmPm
, L
"pm") != 0)
160 /* Check for the valid minute range [0-59] */
164 if (wcslen(szAmPm
) > 0)
166 /* 12 hour time format */
168 /* Check for the valid hour range [1-12] */
169 if (ulHour
== 0 || ulHour
> 12)
172 /* Convert 12 hour format to 24 hour format */
173 if (_wcsicmp(szAmPm
, L
"a") == 0 ||
174 _wcsicmp(szAmPm
, L
"am") == 0)
181 if (ulHour
>= 1 && ulHour
<= 11)
187 /* 24 hour time format */
189 /* Check for the valid hour range [0-23] */
194 if (pulJobHour
!= NULL
)
195 *pulJobHour
= ulHour
;
197 if (pulJobMinute
!= NULL
)
198 *pulJobMinute
= ulMinute
;
210 PWSTR startPtr
, endPtr
;
212 BOOL bResult
= FALSE
;
216 ulId
= wcstoul(startPtr
, &endPtr
, 10);
217 if (endPtr
!= NULL
&& *endPtr
== UNICODE_NULL
)
233 PULONG pulDaysOfMonth
)
235 PWSTR startPtr
, endPtr
;
238 if (wcslen(pszBuffer
) == 0)
241 startPtr
= pszBuffer
;
245 ulValue
= wcstoul(startPtr
, &endPtr
, 10);
249 if (ulValue
> 0 && ulValue
<= 31)
250 *pulDaysOfMonth
|= (1 << (ulValue
- 1));
252 if (endPtr
!= NULL
&& *endPtr
== UNICODE_NULL
)
255 startPtr
= endPtr
+ 1;
267 PUCHAR pucDaysOfWeek
)
269 PWSTR startPtr
, endPtr
;
272 if (wcslen(pszBuffer
) == 0)
275 startPtr
= pszBuffer
;
279 endPtr
= wcschr(startPtr
, L
',');
281 nLength
= wcslen(startPtr
);
283 nLength
= (INT
)((ULONG_PTR
)endPtr
- (ULONG_PTR
)startPtr
) / sizeof(WCHAR
);
285 for (i
= 0; i
< 7; i
++)
287 if (nLength
== wcslen(pszDaysOfWeekArray
[i
]) &&
288 _wcsnicmp(startPtr
, pszDaysOfWeekArray
[i
], nLength
) == 0)
290 *pucDaysOfWeek
|= (1 << i
);
298 startPtr
= endPtr
+ 1;
311 PWSTR pszBuffer
= NULL
;
313 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
321 ConPrintf(StdErr
, L
"%s\n", pszBuffer
);
322 LocalFree(pszBuffer
);
328 PrintHorizontalLine(VOID
)
333 for (i
= 0; i
< 79; i
++)
335 szBuffer
[79] = UNICODE_NULL
;
337 ConPrintf(StdOut
, L
"%s\n", szBuffer
);
346 WCHAR szYesBuffer
[8];
354 hInstance
= GetModuleHandleW(NULL
);
355 LoadStringW(hInstance
, IDS_CONFIRM_YES
, szYesBuffer
, _countof(szYesBuffer
));
356 LoadStringW(hInstance
, IDS_CONFIRM_NO
, szNoBuffer
, _countof(szNoBuffer
));
358 ZeroMemory(szInput
, sizeof(szInput
));
360 hFile
= GetStdHandle(STD_INPUT_HANDLE
);
361 GetConsoleMode(hFile
, &dwOldMode
);
363 SetConsoleMode(hFile
, ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
);
367 ConResPrintf(StdOut
, IDS_CONFIRM_QUESTION
);
369 ReadConsoleW(hFile
, szInput
, _countof(szInput
), &dwRead
, NULL
);
371 szInput
[0] = towupper(szInput
[0]);
372 if (szInput
[0] == szYesBuffer
[0])
377 else if (szInput
[0] == 13 || szInput
[0] == szNoBuffer
[0])
383 ConResPrintf(StdOut
, IDS_CONFIRM_INVALID
);
386 SetConsoleMode(hFile
, dwOldMode
);
394 GetTimeAsJobTime(VOID
)
401 JobTime
= (DWORD_PTR
)Time
.wHour
* 3600000 +
402 (DWORD_PTR
)Time
.wMinute
* 60000;
410 GetCurrentDayOfMonth(VOID
)
416 return 1UL << (Time
.wDay
- 1);
428 SYSTEMTIME Time
= {0, 0, 0, 0, 0, 0, 0, 0};
431 Time
.wMinute
= wMinute
;
433 GetTimeFormat(LOCALE_USER_DEFAULT
,
445 PWSTR pszComputerName
,
448 PAT_INFO pBuffer
= NULL
;
449 DWORD_PTR CurrentTime
;
450 WCHAR szStatusBuffer
[16];
451 WCHAR szScheduleBuffer
[60];
452 WCHAR szTimeBuffer
[16];
453 WCHAR szInteractiveBuffer
[16];
454 WCHAR szDateBuffer
[8];
455 INT i
, nDateLength
, nScheduleLength
;
457 NET_API_STATUS Status
;
459 Status
= NetScheduleJobGetInfo(pszComputerName
,
462 if (Status
!= NERR_Success
)
464 PrintErrorMessage(Status
);
468 hInstance
= GetModuleHandle(NULL
);
470 if (pBuffer
->Flags
& JOB_EXEC_ERROR
)
471 LoadStringW(hInstance
, IDS_ERROR
, szStatusBuffer
, _countof(szStatusBuffer
));
473 LoadStringW(hInstance
, IDS_OK
, szStatusBuffer
, _countof(szStatusBuffer
));
475 if (pBuffer
->DaysOfMonth
!= 0)
477 if (pBuffer
->Flags
& JOB_RUN_PERIODICALLY
)
478 LoadStringW(hInstance
, IDS_EVERY
, szScheduleBuffer
, _countof(szScheduleBuffer
));
480 LoadStringW(hInstance
, IDS_NEXT
, szScheduleBuffer
, _countof(szScheduleBuffer
));
482 nScheduleLength
= wcslen(szScheduleBuffer
);
483 for (i
= 0; i
< 31; i
++)
485 if (pBuffer
->DaysOfMonth
& (1 << i
))
487 swprintf(szDateBuffer
, L
" %d", i
+ 1);
488 nDateLength
= wcslen(szDateBuffer
);
489 if (nScheduleLength
+ nDateLength
<= 55)
491 wcscat(szScheduleBuffer
, szDateBuffer
);
492 nScheduleLength
+= nDateLength
;
496 wcscat(szScheduleBuffer
, L
"...");
502 else if (pBuffer
->DaysOfWeek
!= 0)
504 if (pBuffer
->Flags
& JOB_RUN_PERIODICALLY
)
505 LoadStringW(hInstance
, IDS_EVERY
, szScheduleBuffer
, _countof(szScheduleBuffer
));
507 LoadStringW(hInstance
, IDS_NEXT
, szScheduleBuffer
, _countof(szScheduleBuffer
));
509 nScheduleLength
= wcslen(szScheduleBuffer
);
510 for (i
= 0; i
< 7; i
++)
512 if (pBuffer
->DaysOfWeek
& (1 << i
))
514 swprintf(szDateBuffer
, L
" %s", pszDaysOfWeekArray
[i
]);
515 nDateLength
= wcslen(szDateBuffer
);
516 if (nScheduleLength
+ nDateLength
<= 55)
518 wcscat(szScheduleBuffer
, szDateBuffer
);
519 nScheduleLength
+= nDateLength
;
523 wcscat(szScheduleBuffer
, L
"...");
531 CurrentTime
= GetTimeAsJobTime();
532 if (CurrentTime
> pBuffer
->JobTime
)
533 LoadStringW(hInstance
, IDS_TOMORROW
, szScheduleBuffer
, _countof(szScheduleBuffer
));
535 LoadStringW(hInstance
, IDS_TODAY
, szScheduleBuffer
, _countof(szScheduleBuffer
));
538 JobTimeToTimeString(szTimeBuffer
,
539 _countof(szTimeBuffer
),
540 (WORD
)(pBuffer
->JobTime
/ 3600000),
541 (WORD
)((pBuffer
->JobTime
% 3600000) / 60000));
543 if (pBuffer
->Flags
& JOB_NONINTERACTIVE
)
544 LoadStringW(hInstance
, IDS_NO
, szInteractiveBuffer
, _countof(szInteractiveBuffer
));
546 LoadStringW(hInstance
, IDS_YES
, szInteractiveBuffer
, _countof(szInteractiveBuffer
));
548 ConResPrintf(StdOut
, IDS_TASKID
, ulJobId
);
549 ConResPrintf(StdOut
, IDS_STATUS
, szStatusBuffer
);
550 ConResPrintf(StdOut
, IDS_SCHEDULE
, szScheduleBuffer
);
551 ConResPrintf(StdOut
, IDS_TIME
, szTimeBuffer
);
552 ConResPrintf(StdOut
, IDS_INTERACTIVE
, szInteractiveBuffer
);
553 ConResPrintf(StdOut
, IDS_COMMAND
, pBuffer
->Command
);
555 NetApiBufferFree(pBuffer
);
564 PWSTR pszComputerName
)
566 PAT_ENUM pBuffer
= NULL
;
567 DWORD dwRead
= 0, dwTotal
= 0;
568 DWORD dwResume
= 0, i
;
569 DWORD_PTR CurrentTime
;
570 NET_API_STATUS Status
;
572 WCHAR szScheduleBuffer
[32];
573 WCHAR szTimeBuffer
[16];
574 WCHAR szDateBuffer
[8];
576 INT j
, nDateLength
, nScheduleLength
;
578 Status
= NetScheduleJobEnum(pszComputerName
,
580 MAX_PREFERRED_LENGTH
,
584 if (Status
!= NERR_Success
)
586 PrintErrorMessage(Status
);
592 ConResPrintf(StdOut
, IDS_NO_ENTRIES
);
596 ConResPrintf(StdOut
, IDS_JOBS_LIST
);
597 PrintHorizontalLine();
599 hInstance
= GetModuleHandle(NULL
);
601 for (i
= 0; i
< dwRead
; i
++)
603 if (pBuffer
[i
].DaysOfMonth
!= 0)
605 if (pBuffer
[i
].Flags
& JOB_RUN_PERIODICALLY
)
606 LoadStringW(hInstance
, IDS_EVERY
, szScheduleBuffer
, _countof(szScheduleBuffer
));
608 LoadStringW(hInstance
, IDS_NEXT
, szScheduleBuffer
, _countof(szScheduleBuffer
));
610 nScheduleLength
= wcslen(szScheduleBuffer
);
611 for (j
= 0; j
< 31; j
++)
613 if (pBuffer
[i
].DaysOfMonth
& (1 << j
))
615 swprintf(szDateBuffer
, L
" %d", j
+ 1);
616 nDateLength
= wcslen(szDateBuffer
);
617 if (nScheduleLength
+ nDateLength
<= 19)
619 wcscat(szScheduleBuffer
, szDateBuffer
);
620 nScheduleLength
+= nDateLength
;
624 wcscat(szScheduleBuffer
, L
"...");
630 else if (pBuffer
[i
].DaysOfWeek
!= 0)
632 if (pBuffer
[i
].Flags
& JOB_RUN_PERIODICALLY
)
633 LoadStringW(hInstance
, IDS_EVERY
, szScheduleBuffer
, _countof(szScheduleBuffer
));
635 LoadStringW(hInstance
, IDS_NEXT
, szScheduleBuffer
, _countof(szScheduleBuffer
));
637 nScheduleLength
= wcslen(szScheduleBuffer
);
638 for (j
= 0; j
< 7; j
++)
640 if (pBuffer
[i
].DaysOfWeek
& (1 << j
))
642 swprintf(szDateBuffer
, L
" %s", pszDaysOfWeekArray
[j
]);
643 nDateLength
= wcslen(szDateBuffer
);
644 if (nScheduleLength
+ nDateLength
<= 55)
646 wcscat(szScheduleBuffer
, szDateBuffer
);
647 nScheduleLength
+= nDateLength
;
651 wcscat(szScheduleBuffer
, L
"...");
659 CurrentTime
= GetTimeAsJobTime();
660 if (CurrentTime
> pBuffer
[i
].JobTime
)
661 LoadStringW(hInstance
, IDS_TOMORROW
, szScheduleBuffer
, _countof(szScheduleBuffer
));
663 LoadStringW(hInstance
, IDS_TODAY
, szScheduleBuffer
, _countof(szScheduleBuffer
));
666 JobTimeToTimeString(szTimeBuffer
,
667 _countof(szTimeBuffer
),
668 (WORD
)(pBuffer
[i
].JobTime
/ 3600000),
669 (WORD
)((pBuffer
[i
].JobTime
% 3600000) / 60000));
672 L
" %6lu %-21s %-11s %s\n",
679 NetApiBufferFree(pBuffer
);
688 PWSTR pszComputerName
,
693 BOOL bInteractiveJob
,
699 NET_API_STATUS Status
;
701 InfoBuffer
.JobTime
= (DWORD_PTR
)ulJobHour
* 3600000 +
702 (DWORD_PTR
)ulJobMinute
* 60000;
703 InfoBuffer
.DaysOfMonth
= ulDaysOfMonth
;
704 InfoBuffer
.DaysOfWeek
= ucDaysOfWeek
;
705 InfoBuffer
.Flags
= (bInteractiveJob
? 0 : JOB_NONINTERACTIVE
) |
706 (bPeriodicJob
? JOB_RUN_PERIODICALLY
: 0);
707 InfoBuffer
.Command
= pszCommand
;
709 Status
= NetScheduleJobAdd(pszComputerName
,
712 if (Status
!= NERR_Success
)
714 PrintErrorMessage(Status
);
718 ConResPrintf(StdOut
, IDS_NEW_JOB
, ulJobId
);
727 PWSTR pszComputerName
,
731 NET_API_STATUS Status
;
733 if (ulJobId
== (ULONG
)-1 && bForceDelete
== FALSE
)
735 ConResPrintf(StdOut
, IDS_DELETE_ALL
);
740 Status
= NetScheduleJobDel(pszComputerName
,
741 (ulJobId
== (ULONG
)-1) ? 0 : ulJobId
,
742 (ulJobId
== (ULONG
)-1) ? -1 : ulJobId
);
743 if (Status
!= NERR_Success
)
745 PrintErrorMessage(Status
);
753 int wmain(int argc
, WCHAR
**argv
)
755 PWSTR pszComputerName
= NULL
;
756 PWSTR pszCommand
= NULL
;
757 ULONG ulJobId
= (ULONG
)-1;
758 ULONG ulJobHour
= (ULONG
)-1;
759 ULONG ulJobMinute
= (ULONG
)-1;
760 BOOL bDeleteJob
= FALSE
, bForceDelete
= FALSE
;
761 BOOL bInteractiveJob
= FALSE
, bPeriodicJob
= FALSE
;
762 BOOL bPrintUsage
= FALSE
;
763 ULONG ulDaysOfMonth
= 0;
764 UCHAR ucDaysOfWeek
= 0;
768 /* Initialize the Console Standard Streams */
771 if (!InitDaysOfWeekArray())
774 /* Parse the computer name */
778 argv
[i
][0] == L
'\\' &&
781 pszComputerName
= argv
[i
];
786 /* Parse the time or job id */
787 if (i
< argc
&& argv
[i
][0] != L
'/')
789 if (ParseTime(argv
[i
], &ulJobHour
, &ulJobMinute
))
794 else if (ParseId(argv
[i
], &ulJobId
))
801 /* Parse the options */
802 for (; i
< argc
; i
++)
804 if (argv
[i
][0] == L
'/')
806 if (_wcsicmp(argv
[i
], L
"/?") == 0)
811 else if (_wcsicmp(argv
[i
], L
"/delete") == 0)
815 else if (_wcsicmp(argv
[i
], L
"/yes") == 0)
819 else if (_wcsicmp(argv
[i
], L
"/interactive") == 0)
821 bInteractiveJob
= TRUE
;
823 else if (_wcsnicmp(argv
[i
], L
"/every:", 7) == 0)
826 if (ParseDaysOfMonth(&(argv
[i
][7]), &ulDaysOfMonth
) == FALSE
)
828 if (ParseDaysOfWeek(&(argv
[i
][7]), &ucDaysOfWeek
) == FALSE
)
830 ulDaysOfMonth
= GetCurrentDayOfMonth();
834 else if (_wcsnicmp(argv
[i
], L
"/next:", 6) == 0)
836 bPeriodicJob
= FALSE
;
837 if (ParseDaysOfMonth(&(argv
[i
][6]), &ulDaysOfMonth
) == FALSE
)
839 if (ParseDaysOfWeek(&(argv
[i
][6]), &ucDaysOfWeek
) == FALSE
)
841 ulDaysOfMonth
= GetCurrentDayOfMonth();
854 /* Parse the command */
855 if (argc
> minIdx
&& argv
[argc
- 1][0] != L
'/')
857 pszCommand
= argv
[argc
- 1];
860 if (bDeleteJob
== TRUE
)
862 /* Check for invalid options or arguments */
863 if (bInteractiveJob
== TRUE
||
864 ulJobHour
!= (ULONG
)-1 ||
865 ulJobMinute
!= (ULONG
)-1 ||
866 ulDaysOfMonth
!= 0 ||
875 nResult
= DeleteJob(pszComputerName
,
881 if (ulJobHour
!= (ULONG
)-1 && ulJobMinute
!= (ULONG
)-1)
883 /* Check for invalid options or arguments */
884 if (bForceDelete
== TRUE
||
892 nResult
= AddJob(pszComputerName
,
903 /* Check for invalid options or arguments */
904 if (bForceDelete
== TRUE
||
905 bInteractiveJob
== TRUE
||
906 ulDaysOfMonth
!= 0 ||
915 if (ulJobId
== (ULONG
)-1)
917 nResult
= PrintAllJobs(pszComputerName
);
921 nResult
= PrintJobDetails(pszComputerName
,
928 FreeDaysOfWeekArray();
930 if (bPrintUsage
== TRUE
)
931 ConResPuts(StdOut
, IDS_USAGE
);