summaryrefslogtreecommitdiffstats
path: root/toolkit/components/taskscheduler/nsWinTaskScheduler.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /toolkit/components/taskscheduler/nsWinTaskScheduler.cpp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/taskscheduler/nsWinTaskScheduler.cpp')
-rw-r--r--toolkit/components/taskscheduler/nsWinTaskScheduler.cpp308
1 files changed, 308 insertions, 0 deletions
diff --git a/toolkit/components/taskscheduler/nsWinTaskScheduler.cpp b/toolkit/components/taskscheduler/nsWinTaskScheduler.cpp
new file mode 100644
index 0000000000..21b2909805
--- /dev/null
+++ b/toolkit/components/taskscheduler/nsWinTaskScheduler.cpp
@@ -0,0 +1,308 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsWinTaskScheduler.h"
+
+#include <windows.h>
+#include <comdef.h>
+#include <taskschd.h>
+
+#include "nsString.h"
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/ResultVariant.h"
+
+using namespace mozilla;
+
+struct SysFreeStringDeleter {
+ void operator()(BSTR aPtr) { ::SysFreeString(aPtr); }
+};
+using BStrPtr = mozilla::UniquePtr<OLECHAR, SysFreeStringDeleter>;
+
+static nsresult ToNotFoundOrFailure(HRESULT hr) {
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
+ return NS_ERROR_FILE_NOT_FOUND;
+ } else {
+ return NS_ERROR_FAILURE;
+ }
+}
+
+static nsresult ToAlreadyExistsOrFailure(HRESULT hr) {
+ if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) {
+ return NS_ERROR_FILE_ALREADY_EXISTS;
+ } else {
+ return NS_ERROR_FAILURE;
+ }
+}
+
+[[nodiscard]] static Result<RefPtr<ITaskFolder>, HRESULT> GetTaskFolder(
+ const char16_t* aFolderName) {
+ HRESULT hr;
+ RefPtr<ITaskService> scheduler = nullptr;
+
+ hr = CoCreateInstance(CLSID_TaskScheduler, nullptr, CLSCTX_INPROC_SERVER,
+ IID_ITaskService, getter_AddRefs(scheduler));
+ if (FAILED(hr)) {
+ return Err(hr);
+ }
+
+ // Connect to the local Task Scheduler.
+ hr = scheduler->Connect(VARIANT{}, VARIANT{}, VARIANT{}, VARIANT{});
+ if (FAILED(hr)) {
+ return Err(hr);
+ }
+
+ BStrPtr bstrFolderName =
+ BStrPtr(::SysAllocString(reinterpret_cast<const OLECHAR*>(aFolderName)));
+
+ RefPtr<ITaskFolder> folder = nullptr;
+ hr = scheduler->GetFolder(bstrFolderName.get(), getter_AddRefs(folder));
+ if (FAILED(hr)) {
+ return Err(hr);
+ }
+
+ return folder;
+}
+
+[[nodiscard]] static Result<RefPtr<IRegisteredTask>, HRESULT> GetRegisteredTask(
+ const char16_t* aFolderName, const char16_t* aTaskName) {
+ auto folder = GetTaskFolder(aFolderName);
+ if (!folder.isOk()) {
+ return Err(folder.unwrapErr());
+ }
+
+ BStrPtr bstrTaskName =
+ BStrPtr(::SysAllocString(reinterpret_cast<const OLECHAR*>(aTaskName)));
+
+ RefPtr<IRegisteredTask> task = nullptr;
+ HRESULT hr =
+ folder.unwrap()->GetTask(bstrTaskName.get(), getter_AddRefs(task));
+ if (FAILED(hr)) {
+ return Err(hr);
+ }
+
+ return task;
+}
+
+NS_IMPL_ISUPPORTS(nsWinTaskSchedulerService, nsIWinTaskSchedulerService)
+
+NS_IMETHODIMP
+nsWinTaskSchedulerService::GetTaskXML(const char16_t* aFolderName,
+ const char16_t* aTaskName,
+ nsAString& aResult) {
+ if (!aFolderName || !aTaskName) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ auto task = GetRegisteredTask(aFolderName, aTaskName);
+ if (!task.isOk()) {
+ return ToNotFoundOrFailure(task.unwrapErr());
+ }
+
+ {
+ BSTR bstrXml = nullptr;
+ if (FAILED(task.unwrap()->get_Xml(&bstrXml))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ aResult.Assign(bstrXml, ::SysStringLen(bstrXml));
+ ::SysFreeString(bstrXml);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWinTaskSchedulerService::RegisterTask(const char16_t* aFolderName,
+ const char16_t* aTaskName,
+ const char16_t* aDefinitionXML,
+ bool aUpdateExisting) {
+ if (!aFolderName || !aTaskName || !aDefinitionXML) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ auto folder = GetTaskFolder(aFolderName);
+ if (!folder.isOk()) {
+ return ToNotFoundOrFailure(folder.unwrapErr());
+ }
+
+ BStrPtr bstrTaskName =
+ BStrPtr(::SysAllocString(reinterpret_cast<const OLECHAR*>(aTaskName)));
+ BStrPtr bstrXml = BStrPtr(
+ ::SysAllocString(reinterpret_cast<const OLECHAR*>(aDefinitionXML)));
+ LONG flags = aUpdateExisting ? TASK_CREATE_OR_UPDATE : TASK_CREATE;
+ TASK_LOGON_TYPE logonType = TASK_LOGON_INTERACTIVE_TOKEN;
+
+ // The outparam is not needed, but not documented as optional.
+ RefPtr<IRegisteredTask> unusedTaskOutput = nullptr;
+ HRESULT hr = folder.unwrap()->RegisterTask(
+ bstrTaskName.get(), bstrXml.get(), flags, VARIANT{} /* userId */,
+ VARIANT{} /* password */, logonType, VARIANT{} /* sddl */,
+ getter_AddRefs(unusedTaskOutput));
+
+ if (FAILED(hr)) {
+ return ToAlreadyExistsOrFailure(hr);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWinTaskSchedulerService::ValidateTaskDefinition(
+ const char16_t* aDefinitionXML, int32_t* aResult) {
+ if (!aDefinitionXML) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ auto folder = GetTaskFolder(reinterpret_cast<const char16_t*>(L"\\"));
+ if (!folder.isOk()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ BStrPtr bstrXml = BStrPtr(
+ ::SysAllocString(reinterpret_cast<const OLECHAR*>(aDefinitionXML)));
+ LONG flags = TASK_VALIDATE_ONLY;
+ TASK_LOGON_TYPE logonType = TASK_LOGON_INTERACTIVE_TOKEN;
+
+ // The outparam is not needed, but not documented as optional.
+ RefPtr<IRegisteredTask> unusedTaskOutput = nullptr;
+ HRESULT hr = folder.unwrap()->RegisterTask(
+ nullptr /* path */, bstrXml.get(), flags, VARIANT{} /* userId */,
+ VARIANT{} /* password */, logonType, VARIANT{} /* sddl */,
+ getter_AddRefs(unusedTaskOutput));
+
+ if (aResult) {
+ *aResult = hr;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWinTaskSchedulerService::DeleteTask(const char16_t* aFolderName,
+ const char16_t* aTaskName) {
+ if (!aFolderName || !aTaskName) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ auto folder = GetTaskFolder(aFolderName);
+ if (!folder.isOk()) {
+ return ToNotFoundOrFailure(folder.unwrapErr());
+ }
+
+ BStrPtr bstrTaskName =
+ BStrPtr(::SysAllocString(reinterpret_cast<const OLECHAR*>(aTaskName)));
+
+ HRESULT hr = folder.unwrap()->DeleteTask(bstrTaskName.get(), 0 /* flags */);
+ if (FAILED(hr)) {
+ return ToNotFoundOrFailure(hr);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWinTaskSchedulerService::GetFolderTasks(const char16_t* aFolderName,
+ nsTArray<nsString>& aResult) {
+ if (!aFolderName) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ auto folder = GetTaskFolder(aFolderName);
+ if (!folder.isOk()) {
+ return ToNotFoundOrFailure(folder.unwrapErr());
+ }
+
+ RefPtr<IRegisteredTaskCollection> taskCollection = nullptr;
+ if (FAILED(folder.unwrap()->GetTasks(TASK_ENUM_HIDDEN,
+ getter_AddRefs(taskCollection)))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ LONG taskCount = 0;
+ if (FAILED(taskCollection->get_Count(&taskCount))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ aResult.Clear();
+
+ for (LONG i = 0; i < taskCount; ++i) {
+ RefPtr<IRegisteredTask> task = nullptr;
+
+ // nb: Collections are indexed from 1.
+ if (FAILED(taskCollection->get_Item(_variant_t(i + 1),
+ getter_AddRefs(task)))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ BStrPtr bstrTaskName;
+ {
+ BSTR tempTaskName = nullptr;
+ if (FAILED(task->get_Name(&tempTaskName))) {
+ return NS_ERROR_FAILURE;
+ }
+ bstrTaskName = BStrPtr(tempTaskName);
+ }
+
+ aResult.AppendElement(nsString(bstrTaskName.get()));
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWinTaskSchedulerService::CreateFolder(const char16_t* aParentFolderName,
+ const char16_t* aSubFolderName) {
+ if (!aParentFolderName || !aSubFolderName) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ auto parentFolder = GetTaskFolder(aParentFolderName);
+ if (!parentFolder.isOk()) {
+ return ToNotFoundOrFailure(parentFolder.unwrapErr());
+ }
+
+ BStrPtr bstrSubFolderName = BStrPtr(
+ ::SysAllocString(reinterpret_cast<const OLECHAR*>(aSubFolderName)));
+
+ HRESULT hr = parentFolder.unwrap()->CreateFolder(bstrSubFolderName.get(),
+ VARIANT{}, // sddl
+ nullptr); // ppFolder
+
+ if (FAILED(hr)) {
+ return ToAlreadyExistsOrFailure(hr);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWinTaskSchedulerService::DeleteFolder(const char16_t* aParentFolderName,
+ const char16_t* aSubFolderName) {
+ if (!aParentFolderName || !aSubFolderName) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ auto parentFolder = GetTaskFolder(aParentFolderName);
+ if (!parentFolder.isOk()) {
+ return ToNotFoundOrFailure(parentFolder.unwrapErr());
+ }
+
+ BStrPtr bstrSubFolderName = BStrPtr(
+ ::SysAllocString(reinterpret_cast<const OLECHAR*>(aSubFolderName)));
+
+ HRESULT hr = parentFolder.unwrap()->DeleteFolder(bstrSubFolderName.get(),
+ 0 /* flags */);
+
+ if (FAILED(hr)) {
+ if (hr == HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY)) {
+ return NS_ERROR_FILE_DIR_NOT_EMPTY;
+ } else {
+ return ToNotFoundOrFailure(hr);
+ }
+ }
+
+ return NS_OK;
+}