summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/frontend/applets/general_frontend.cpp99
-rw-r--r--src/core/frontend/applets/general_frontend.h84
-rw-r--r--src/core/frontend/applets/web_browser.cpp6
-rw-r--r--src/core/frontend/applets/web_browser.h8
-rw-r--r--src/core/hle/service/am/am.cpp12
-rw-r--r--src/core/hle/service/am/am.h6
-rw-r--r--src/core/hle/service/am/applet_ae.cpp26
-rw-r--r--src/core/hle/service/am/applet_ae.h3
-rw-r--r--src/core/hle/service/am/applet_oe.cpp14
-rw-r--r--src/core/hle/service/am/applet_oe.h3
-rw-r--r--src/core/hle/service/am/applets/applets.cpp43
-rw-r--r--src/core/hle/service/am/applets/applets.h14
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp116
-rw-r--r--src/core/hle/service/am/applets/general_backend.h30
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp496
-rw-r--r--src/core/hle/service/am/applets/web_browser.h37
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/yuzu/applets/web_browser.cpp4
-rw-r--r--src/yuzu/applets/web_browser.h4
-rw-r--r--src/yuzu/main.cpp12
20 files changed, 890 insertions, 129 deletions
diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp
index b974f2289..c30b36de7 100644
--- a/src/core/frontend/applets/general_frontend.cpp
+++ b/src/core/frontend/applets/general_frontend.cpp
@@ -7,9 +7,38 @@
7 7
8namespace Core::Frontend { 8namespace Core::Frontend {
9 9
10ParentalControlsApplet::~ParentalControlsApplet() = default;
11
12DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default;
13
14void DefaultParentalControlsApplet::VerifyPIN(std::function<void(bool)> finished,
15 bool suspend_future_verification_temporarily) {
16 LOG_INFO(Service_AM,
17 "Application requested frontend to verify PIN (normal), "
18 "suspend_future_verification_temporarily={}, verifying as correct.",
19 suspend_future_verification_temporarily);
20 finished(true);
21}
22
23void DefaultParentalControlsApplet::VerifyPINForSettings(std::function<void(bool)> finished) {
24 LOG_INFO(Service_AM,
25 "Application requested frontend to verify PIN (settings), verifying as correct.");
26 finished(true);
27}
28
29void DefaultParentalControlsApplet::RegisterPIN(std::function<void()> finished) {
30 LOG_INFO(Service_AM, "Application requested frontend to register new PIN");
31 finished();
32}
33
34void DefaultParentalControlsApplet::ChangePIN(std::function<void()> finished) {
35 LOG_INFO(Service_AM, "Application requested frontend to change PIN to new value");
36 finished();
37}
38
10PhotoViewerApplet::~PhotoViewerApplet() = default; 39PhotoViewerApplet::~PhotoViewerApplet() = default;
11 40
12DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() {} 41DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default;
13 42
14void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, 43void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id,
15 std::function<void()> finished) const { 44 std::function<void()> finished) const {
@@ -24,4 +53,72 @@ void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) con
24 finished(); 53 finished();
25} 54}
26 55
56ECommerceApplet::~ECommerceApplet() = default;
57
58DefaultECommerceApplet::~DefaultECommerceApplet() = default;
59
60void DefaultECommerceApplet::ShowApplicationInformation(
61 std::function<void()> finished, u64 title_id, std::optional<u128> user_id,
62 std::optional<bool> full_display, std::optional<std::string> extra_parameter) {
63 const auto value = user_id.value_or(u128{});
64 LOG_INFO(Service_AM,
65 "Application requested frontend show application information for EShop, "
66 "title_id={:016X}, user_id={:016X}{:016X}, full_display={}, extra_parameter={}",
67 title_id, value[1], value[0],
68 full_display.has_value() ? fmt::format("{}", *full_display) : "null",
69 extra_parameter.value_or("null"));
70 finished();
71}
72
73void DefaultECommerceApplet::ShowAddOnContentList(std::function<void()> finished, u64 title_id,
74 std::optional<u128> user_id,
75 std::optional<bool> full_display) {
76 const auto value = user_id.value_or(u128{});
77 LOG_INFO(Service_AM,
78 "Application requested frontend show add on content list for EShop, "
79 "title_id={:016X}, user_id={:016X}{:016X}, full_display={}",
80 title_id, value[1], value[0],
81 full_display.has_value() ? fmt::format("{}", *full_display) : "null");
82 finished();
83}
84
85void DefaultECommerceApplet::ShowSubscriptionList(std::function<void()> finished, u64 title_id,
86 std::optional<u128> user_id) {
87 const auto value = user_id.value_or(u128{});
88 LOG_INFO(Service_AM,
89 "Application requested frontend show subscription list for EShop, title_id={:016X}, "
90 "user_id={:016X}{:016X}",
91 title_id, value[1], value[0]);
92 finished();
93}
94
95void DefaultECommerceApplet::ShowConsumableItemList(std::function<void()> finished, u64 title_id,
96 std::optional<u128> user_id) {
97 const auto value = user_id.value_or(u128{});
98 LOG_INFO(
99 Service_AM,
100 "Application requested frontend show consumable item list for EShop, title_id={:016X}, "
101 "user_id={:016X}{:016X}",
102 title_id, value[1], value[0]);
103 finished();
104}
105
106void DefaultECommerceApplet::ShowShopHome(std::function<void()> finished, u128 user_id,
107 bool full_display) {
108 LOG_INFO(Service_AM,
109 "Application requested frontend show home menu for EShop, user_id={:016X}{:016X}, "
110 "full_display={}",
111 user_id[1], user_id[0], full_display);
112 finished();
113}
114
115void DefaultECommerceApplet::ShowSettings(std::function<void()> finished, u128 user_id,
116 bool full_display) {
117 LOG_INFO(Service_AM,
118 "Application requested frontend show settings menu for EShop, user_id={:016X}{:016X}, "
119 "full_display={}",
120 user_id[1], user_id[0], full_display);
121 finished();
122}
123
27} // namespace Core::Frontend 124} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h
index d4506c999..4b63f828e 100644
--- a/src/core/frontend/applets/general_frontend.h
+++ b/src/core/frontend/applets/general_frontend.h
@@ -5,10 +5,43 @@
5#pragma once 5#pragma once
6 6
7#include <functional> 7#include <functional>
8#include <optional>
8#include "common/common_types.h" 9#include "common/common_types.h"
9 10
10namespace Core::Frontend { 11namespace Core::Frontend {
11 12
13class ParentalControlsApplet {
14public:
15 virtual ~ParentalControlsApplet();
16
17 // Prompts the user to enter a PIN and calls the callback with whether or not it matches the
18 // correct PIN. If the bool is passed, and the PIN was recently entered correctly, the frontend
19 // should not prompt and simply return true.
20 virtual void VerifyPIN(std::function<void(bool)> finished,
21 bool suspend_future_verification_temporarily) = 0;
22
23 // Prompts the user to enter a PIN and calls the callback for correctness. Frontends can
24 // optionally alert the user that this is to change parental controls settings.
25 virtual void VerifyPINForSettings(std::function<void(bool)> finished) = 0;
26
27 // Prompts the user to create a new PIN for pctl and stores it with the service.
28 virtual void RegisterPIN(std::function<void()> finished) = 0;
29
30 // Prompts the user to verify the current PIN and then store a new one into pctl.
31 virtual void ChangePIN(std::function<void()> finished) = 0;
32};
33
34class DefaultParentalControlsApplet final : public ParentalControlsApplet {
35public:
36 ~DefaultParentalControlsApplet() override;
37
38 void VerifyPIN(std::function<void(bool)> finished,
39 bool suspend_future_verification_temporarily) override;
40 void VerifyPINForSettings(std::function<void(bool)> finished) override;
41 void RegisterPIN(std::function<void()> finished) override;
42 void ChangePIN(std::function<void()> finished) override;
43};
44
12class PhotoViewerApplet { 45class PhotoViewerApplet {
13public: 46public:
14 virtual ~PhotoViewerApplet(); 47 virtual ~PhotoViewerApplet();
@@ -25,4 +58,55 @@ public:
25 void ShowAllPhotos(std::function<void()> finished) const override; 58 void ShowAllPhotos(std::function<void()> finished) const override;
26}; 59};
27 60
61class ECommerceApplet {
62public:
63 virtual ~ECommerceApplet();
64
65 // Shows a page with application icons, description, name, and price.
66 virtual void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
67 std::optional<u128> user_id = {},
68 std::optional<bool> full_display = {},
69 std::optional<std::string> extra_parameter = {}) = 0;
70
71 // Shows a page with all of the add on content available for a game, with name, description, and
72 // price.
73 virtual void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
74 std::optional<u128> user_id = {},
75 std::optional<bool> full_display = {}) = 0;
76
77 // Shows a page with all of the subscriptions (recurring payments) for a game, with name,
78 // description, price, and renewal period.
79 virtual void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
80 std::optional<u128> user_id = {}) = 0;
81
82 // Shows a page with a list of any additional game related purchasable items (DLC,
83 // subscriptions, etc) for a particular game, with name, description, type, and price.
84 virtual void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
85 std::optional<u128> user_id = {}) = 0;
86
87 // Shows the home page of the shop.
88 virtual void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) = 0;
89
90 // Shows the user settings page of the shop.
91 virtual void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) = 0;
92};
93
94class DefaultECommerceApplet : public ECommerceApplet {
95public:
96 ~DefaultECommerceApplet() override;
97
98 void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
99 std::optional<u128> user_id, std::optional<bool> full_display,
100 std::optional<std::string> extra_parameter) override;
101 void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
102 std::optional<u128> user_id,
103 std::optional<bool> full_display) override;
104 void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
105 std::optional<u128> user_id) override;
106 void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
107 std::optional<u128> user_id) override;
108 void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) override;
109 void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) override;
110};
111
28} // namespace Core::Frontend 112} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp
index 3a3d3d0bf..528295ffc 100644
--- a/src/core/frontend/applets/web_browser.cpp
+++ b/src/core/frontend/applets/web_browser.cpp
@@ -11,9 +11,9 @@ WebBrowserApplet::~WebBrowserApplet() = default;
11 11
12DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; 12DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
13 13
14void DefaultWebBrowserApplet::OpenPage(std::string_view filename, 14void DefaultWebBrowserApplet::OpenPageLocal(std::string_view filename,
15 std::function<void()> unpack_romfs_callback, 15 std::function<void()> unpack_romfs_callback,
16 std::function<void()> finished_callback) { 16 std::function<void()> finished_callback) {
17 LOG_INFO(Service_AM, 17 LOG_INFO(Service_AM,
18 "(STUBBED) called - No suitable web browser implementation found to open website page " 18 "(STUBBED) called - No suitable web browser implementation found to open website page "
19 "at '{}'!", 19 "at '{}'!",
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h
index f952856af..110e33bc4 100644
--- a/src/core/frontend/applets/web_browser.h
+++ b/src/core/frontend/applets/web_browser.h
@@ -13,16 +13,16 @@ class WebBrowserApplet {
13public: 13public:
14 virtual ~WebBrowserApplet(); 14 virtual ~WebBrowserApplet();
15 15
16 virtual void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, 16 virtual void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
17 std::function<void()> finished_callback) = 0; 17 std::function<void()> finished_callback) = 0;
18}; 18};
19 19
20class DefaultWebBrowserApplet final : public WebBrowserApplet { 20class DefaultWebBrowserApplet final : public WebBrowserApplet {
21public: 21public:
22 ~DefaultWebBrowserApplet() override; 22 ~DefaultWebBrowserApplet() override;
23 23
24 void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, 24 void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
25 std::function<void()> finished_callback) override; 25 std::function<void()> finished_callback) override;
26}; 26};
27 27
28} // namespace Core::Frontend 28} // namespace Core::Frontend
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 4a7bf4acb..33cebb48b 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -887,7 +887,9 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
887 rb.Push(RESULT_SUCCESS); 887 rb.Push(RESULT_SUCCESS);
888} 888}
889 889
890ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { 890ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id)
891 : ServiceFramework("ILibraryAppletCreator"),
892 current_process_title_id(current_process_title_id) {
891 static const FunctionInfo functions[] = { 893 static const FunctionInfo functions[] = {
892 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, 894 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
893 {1, nullptr, "TerminateAllLibraryApplets"}, 895 {1, nullptr, "TerminateAllLibraryApplets"},
@@ -910,7 +912,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
910 static_cast<u32>(applet_id), applet_mode); 912 static_cast<u32>(applet_id), applet_mode);
911 913
912 const auto& applet_manager{Core::System::GetInstance().GetAppletManager()}; 914 const auto& applet_manager{Core::System::GetInstance().GetAppletManager()};
913 const auto applet = applet_manager.GetApplet(applet_id); 915 const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id);
914 916
915 if (applet == nullptr) { 917 if (applet == nullptr) {
916 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); 918 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
@@ -1234,13 +1236,13 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
1234} 1236}
1235 1237
1236void InstallInterfaces(SM::ServiceManager& service_manager, 1238void InstallInterfaces(SM::ServiceManager& service_manager,
1237 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { 1239 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
1238 auto message_queue = std::make_shared<AppletMessageQueue>(); 1240 auto message_queue = std::make_shared<AppletMessageQueue>();
1239 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on 1241 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
1240 // game boot 1242 // game boot
1241 1243
1242 std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager); 1244 std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
1243 std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager); 1245 std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
1244 std::make_shared<IdleSys>()->InstallAsService(service_manager); 1246 std::make_shared<IdleSys>()->InstallAsService(service_manager);
1245 std::make_shared<OMM>()->InstallAsService(service_manager); 1247 std::make_shared<OMM>()->InstallAsService(service_manager);
1246 std::make_shared<SPSM>()->InstallAsService(service_manager); 1248 std::make_shared<SPSM>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 1fa069e56..4ea609d23 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -201,13 +201,15 @@ private:
201 201
202class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { 202class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
203public: 203public:
204 ILibraryAppletCreator(); 204 ILibraryAppletCreator(u64 current_process_title_id);
205 ~ILibraryAppletCreator() override; 205 ~ILibraryAppletCreator() override;
206 206
207private: 207private:
208 void CreateLibraryApplet(Kernel::HLERequestContext& ctx); 208 void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
209 void CreateStorage(Kernel::HLERequestContext& ctx); 209 void CreateStorage(Kernel::HLERequestContext& ctx);
210 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); 210 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
211
212 u64 current_process_title_id;
211}; 213};
212 214
213class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 215class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -264,7 +266,7 @@ public:
264 266
265/// Registers all AM services with the specified service manager. 267/// Registers all AM services with the specified service manager.
266void InstallInterfaces(SM::ServiceManager& service_manager, 268void InstallInterfaces(SM::ServiceManager& service_manager,
267 std::shared_ptr<NVFlinger::NVFlinger> nvflinger); 269 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);
268 270
269} // namespace AM 271} // namespace AM
270} // namespace Service 272} // namespace Service
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 488add8e7..fe5beb8f9 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/process.h"
7#include "core/hle/service/am/am.h" 8#include "core/hle/service/am/am.h"
8#include "core/hle/service/am/applet_ae.h" 9#include "core/hle/service/am/applet_ae.h"
9#include "core/hle/service/nvflinger/nvflinger.h" 10#include "core/hle/service/nvflinger/nvflinger.h"
@@ -13,9 +14,10 @@ namespace Service::AM {
13class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { 14class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
14public: 15public:
15 explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 16 explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
16 std::shared_ptr<AppletMessageQueue> msg_queue) 17 std::shared_ptr<AppletMessageQueue> msg_queue,
18 Core::System& system)
17 : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), 19 : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
18 msg_queue(std::move(msg_queue)) { 20 msg_queue(std::move(msg_queue)), system(system) {
19 // clang-format off 21 // clang-format off
20 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
21 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 23 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -96,7 +98,7 @@ private:
96 98
97 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 99 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
98 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
99 rb.PushIpcInterface<ILibraryAppletCreator>(); 101 rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
100 } 102 }
101 103
102 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 104 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -109,14 +111,15 @@ private:
109 111
110 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 112 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
111 std::shared_ptr<AppletMessageQueue> msg_queue; 113 std::shared_ptr<AppletMessageQueue> msg_queue;
114 Core::System& system;
112}; 115};
113 116
114class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { 117class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
115public: 118public:
116 explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 119 explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
117 std::shared_ptr<AppletMessageQueue> msg_queue) 120 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
118 : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), 121 : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
119 msg_queue(std::move(msg_queue)) { 122 msg_queue(std::move(msg_queue)), system(system) {
120 // clang-format off 123 // clang-format off
121 static const FunctionInfo functions[] = { 124 static const FunctionInfo functions[] = {
122 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 125 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -191,7 +194,7 @@ private:
191 194
192 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 195 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
193 rb.Push(RESULT_SUCCESS); 196 rb.Push(RESULT_SUCCESS);
194 rb.PushIpcInterface<ILibraryAppletCreator>(); 197 rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
195 } 198 }
196 199
197 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { 200 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
@@ -219,6 +222,7 @@ private:
219 } 222 }
220 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 223 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
221 std::shared_ptr<AppletMessageQueue> msg_queue; 224 std::shared_ptr<AppletMessageQueue> msg_queue;
225 Core::System& system;
222}; 226};
223 227
224void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { 228void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -226,7 +230,7 @@ void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
226 230
227 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 231 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
228 rb.Push(RESULT_SUCCESS); 232 rb.Push(RESULT_SUCCESS);
229 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); 233 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue, system);
230} 234}
231 235
232void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { 236void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -234,7 +238,7 @@ void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
234 238
235 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 239 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
236 rb.Push(RESULT_SUCCESS); 240 rb.Push(RESULT_SUCCESS);
237 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); 241 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
238} 242}
239 243
240void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { 244void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
@@ -242,13 +246,13 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
242 246
243 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 247 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
244 rb.Push(RESULT_SUCCESS); 248 rb.Push(RESULT_SUCCESS);
245 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); 249 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
246} 250}
247 251
248AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 252AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
249 std::shared_ptr<AppletMessageQueue> msg_queue) 253 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
250 : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), 254 : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
251 msg_queue(std::move(msg_queue)) { 255 msg_queue(std::move(msg_queue)), system(system) {
252 // clang-format off 256 // clang-format off
253 static const FunctionInfo functions[] = { 257 static const FunctionInfo functions[] = {
254 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, 258 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 902db2665..9e006cd9d 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -18,7 +18,7 @@ namespace AM {
18class AppletAE final : public ServiceFramework<AppletAE> { 18class AppletAE final : public ServiceFramework<AppletAE> {
19public: 19public:
20 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 20 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
21 std::shared_ptr<AppletMessageQueue> msg_queue); 21 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
22 ~AppletAE() override; 22 ~AppletAE() override;
23 23
24 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; 24 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -30,6 +30,7 @@ private:
30 30
31 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 31 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
32 std::shared_ptr<AppletMessageQueue> msg_queue; 32 std::shared_ptr<AppletMessageQueue> msg_queue;
33 Core::System& system;
33}; 34};
34 35
35} // namespace AM 36} // namespace AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index d3a0a1568..6e255fe95 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/process.h"
7#include "core/hle/service/am/am.h" 8#include "core/hle/service/am/am.h"
8#include "core/hle/service/am/applet_oe.h" 9#include "core/hle/service/am/applet_oe.h"
9#include "core/hle/service/nvflinger/nvflinger.h" 10#include "core/hle/service/nvflinger/nvflinger.h"
@@ -13,9 +14,9 @@ namespace Service::AM {
13class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { 14class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
14public: 15public:
15 explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 16 explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
16 std::shared_ptr<AppletMessageQueue> msg_queue) 17 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
17 : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), 18 : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
18 msg_queue(std::move(msg_queue)) { 19 msg_queue(std::move(msg_queue)), system(system) {
19 // clang-format off 20 // clang-format off
20 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
21 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 22 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -87,7 +88,7 @@ private:
87 88
88 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 89 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
89 rb.Push(RESULT_SUCCESS); 90 rb.Push(RESULT_SUCCESS);
90 rb.PushIpcInterface<ILibraryAppletCreator>(); 91 rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID());
91 } 92 }
92 93
93 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 94 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -100,6 +101,7 @@ private:
100 101
101 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 102 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
102 std::shared_ptr<AppletMessageQueue> msg_queue; 103 std::shared_ptr<AppletMessageQueue> msg_queue;
104 Core::System& system;
103}; 105};
104 106
105void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { 107void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
@@ -107,13 +109,13 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
107 109
108 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 110 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
109 rb.Push(RESULT_SUCCESS); 111 rb.Push(RESULT_SUCCESS);
110 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); 112 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);
111} 113}
112 114
113AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 115AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
114 std::shared_ptr<AppletMessageQueue> msg_queue) 116 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system)
115 : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), 117 : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
116 msg_queue(std::move(msg_queue)) { 118 msg_queue(std::move(msg_queue)), system(system) {
117 static const FunctionInfo functions[] = { 119 static const FunctionInfo functions[] = {
118 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, 120 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
119 }; 121 };
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index bbd0108ef..22c05419d 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -18,7 +18,7 @@ namespace AM {
18class AppletOE final : public ServiceFramework<AppletOE> { 18class AppletOE final : public ServiceFramework<AppletOE> {
19public: 19public:
20 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 20 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
21 std::shared_ptr<AppletMessageQueue> msg_queue); 21 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system);
22 ~AppletOE() override; 22 ~AppletOE() override;
23 23
24 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; 24 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -28,6 +28,7 @@ private:
28 28
29 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 29 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
30 std::shared_ptr<AppletMessageQueue> msg_queue; 30 std::shared_ptr<AppletMessageQueue> msg_queue;
31 Core::System& system;
31}; 32};
32 33
33} // namespace AM 34} // namespace AM
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index e3e4ead03..6bdba2468 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -139,12 +139,14 @@ void Applet::Initialize() {
139 139
140AppletFrontendSet::AppletFrontendSet() = default; 140AppletFrontendSet::AppletFrontendSet() = default;
141 141
142AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, 142AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
143 ProfileSelect profile_select, 143 PhotoViewer photo_viewer, ProfileSelect profile_select,
144 SoftwareKeyboard software_keyboard, WebBrowser web_browser) 144 SoftwareKeyboard software_keyboard, WebBrowser web_browser,
145 : error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move( 145 ECommerceApplet e_commerce)
146 profile_select)}, 146 : parental_controls{std::move(parental_controls)}, error{std::move(error)},
147 software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {} 147 photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)},
148 software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)},
149 e_commerce{std::move(e_commerce)} {}
148 150
149AppletFrontendSet::~AppletFrontendSet() = default; 151AppletFrontendSet::~AppletFrontendSet() = default;
150 152
@@ -157,6 +159,8 @@ AppletManager::AppletManager() = default;
157AppletManager::~AppletManager() = default; 159AppletManager::~AppletManager() = default;
158 160
159void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { 161void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
162 if (set.parental_controls != nullptr)
163 frontend.parental_controls = std::move(set.parental_controls);
160 if (set.error != nullptr) 164 if (set.error != nullptr)
161 frontend.error = std::move(set.error); 165 frontend.error = std::move(set.error);
162 if (set.photo_viewer != nullptr) 166 if (set.photo_viewer != nullptr)
@@ -167,17 +171,21 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
167 frontend.software_keyboard = std::move(set.software_keyboard); 171 frontend.software_keyboard = std::move(set.software_keyboard);
168 if (set.web_browser != nullptr) 172 if (set.web_browser != nullptr)
169 frontend.web_browser = std::move(set.web_browser); 173 frontend.web_browser = std::move(set.web_browser);
174 if (set.e_commerce != nullptr)
175 frontend.e_commerce = std::move(set.e_commerce);
170} 176}
171 177
172void AppletManager::SetDefaultAppletFrontendSet() { 178void AppletManager::SetDefaultAppletFrontendSet() {
173 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); 179 ClearAll();
174 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); 180 SetDefaultAppletsIfMissing();
175 frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
176 frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
177 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
178} 181}
179 182
180void AppletManager::SetDefaultAppletsIfMissing() { 183void AppletManager::SetDefaultAppletsIfMissing() {
184 if (frontend.parental_controls == nullptr) {
185 frontend.parental_controls =
186 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
187 }
188
181 if (frontend.error == nullptr) { 189 if (frontend.error == nullptr) {
182 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); 190 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
183 } 191 }
@@ -198,14 +206,20 @@ void AppletManager::SetDefaultAppletsIfMissing() {
198 if (frontend.web_browser == nullptr) { 206 if (frontend.web_browser == nullptr) {
199 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); 207 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
200 } 208 }
209
210 if (frontend.e_commerce == nullptr) {
211 frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
212 }
201} 213}
202 214
203void AppletManager::ClearAll() { 215void AppletManager::ClearAll() {
204 frontend = {}; 216 frontend = {};
205} 217}
206 218
207std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { 219std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const {
208 switch (id) { 220 switch (id) {
221 case AppletId::Auth:
222 return std::make_shared<Auth>(*frontend.parental_controls);
209 case AppletId::Error: 223 case AppletId::Error:
210 return std::make_shared<Error>(*frontend.error); 224 return std::make_shared<Error>(*frontend.error);
211 case AppletId::ProfileSelect: 225 case AppletId::ProfileSelect:
@@ -214,8 +228,11 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
214 return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard); 228 return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard);
215 case AppletId::PhotoViewer: 229 case AppletId::PhotoViewer:
216 return std::make_shared<PhotoViewer>(*frontend.photo_viewer); 230 return std::make_shared<PhotoViewer>(*frontend.photo_viewer);
231 case AppletId::LibAppletShop:
232 return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id,
233 frontend.e_commerce.get());
217 case AppletId::LibAppletOff: 234 case AppletId::LibAppletOff:
218 return std::make_shared<WebBrowser>(*frontend.web_browser); 235 return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id);
219 default: 236 default:
220 UNIMPLEMENTED_MSG( 237 UNIMPLEMENTED_MSG(
221 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", 238 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 05ae739ca..adc973dad 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -13,7 +13,9 @@
13union ResultCode; 13union ResultCode;
14 14
15namespace Core::Frontend { 15namespace Core::Frontend {
16class ECommerceApplet;
16class ErrorApplet; 17class ErrorApplet;
18class ParentalControlsApplet;
17class PhotoViewerApplet; 19class PhotoViewerApplet;
18class ProfileSelectApplet; 20class ProfileSelectApplet;
19class SoftwareKeyboardApplet; 21class SoftwareKeyboardApplet;
@@ -145,15 +147,19 @@ protected:
145}; 147};
146 148
147struct AppletFrontendSet { 149struct AppletFrontendSet {
150 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
148 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; 151 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
149 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; 152 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
150 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; 153 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
151 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; 154 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
152 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; 155 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
156 using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
153 157
154 AppletFrontendSet(); 158 AppletFrontendSet();
155 AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select, 159 AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
156 SoftwareKeyboard software_keyboard, WebBrowser web_browser); 160 PhotoViewer photo_viewer, ProfileSelect profile_select,
161 SoftwareKeyboard software_keyboard, WebBrowser web_browser,
162 ECommerceApplet e_commerce);
157 ~AppletFrontendSet(); 163 ~AppletFrontendSet();
158 164
159 AppletFrontendSet(const AppletFrontendSet&) = delete; 165 AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -162,11 +168,13 @@ struct AppletFrontendSet {
162 AppletFrontendSet(AppletFrontendSet&&) noexcept; 168 AppletFrontendSet(AppletFrontendSet&&) noexcept;
163 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; 169 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
164 170
171 ParentalControlsApplet parental_controls;
165 ErrorApplet error; 172 ErrorApplet error;
166 PhotoViewer photo_viewer; 173 PhotoViewer photo_viewer;
167 ProfileSelect profile_select; 174 ProfileSelect profile_select;
168 SoftwareKeyboard software_keyboard; 175 SoftwareKeyboard software_keyboard;
169 WebBrowser web_browser; 176 WebBrowser web_browser;
177 ECommerceApplet e_commerce;
170}; 178};
171 179
172class AppletManager { 180class AppletManager {
@@ -179,7 +187,7 @@ public:
179 void SetDefaultAppletsIfMissing(); 187 void SetDefaultAppletsIfMissing();
180 void ClearAll(); 188 void ClearAll();
181 189
182 std::shared_ptr<Applet> GetApplet(AppletId id) const; 190 std::shared_ptr<Applet> GetApplet(AppletId id, u64 current_process_title_id) const;
183 191
184private: 192private:
185 AppletFrontendSet frontend; 193 AppletFrontendSet frontend;
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index 54c155dd8..e0def8dff 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -17,6 +17,8 @@
17 17
18namespace Service::AM::Applets { 18namespace Service::AM::Applets {
19 19
20constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
21
20static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { 22static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
21 std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet(); 23 std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
22 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { 24 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
@@ -35,6 +37,120 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
35 } 37 }
36} 38}
37 39
40Auth::Auth(Core::Frontend::ParentalControlsApplet& frontend) : frontend(frontend) {}
41
42Auth::~Auth() = default;
43
44void Auth::Initialize() {
45 Applet::Initialize();
46 complete = false;
47
48 const auto storage = broker.PopNormalDataToApplet();
49 ASSERT(storage != nullptr);
50 const auto data = storage->GetData();
51 ASSERT(data.size() >= 0xC);
52
53 struct Arg {
54 INSERT_PADDING_BYTES(4);
55 AuthAppletType type;
56 u8 arg0;
57 u8 arg1;
58 u8 arg2;
59 INSERT_PADDING_BYTES(1);
60 };
61 static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size.");
62
63 Arg arg{};
64 std::memcpy(&arg, data.data(), sizeof(Arg));
65
66 type = arg.type;
67 arg0 = arg.arg0;
68 arg1 = arg.arg1;
69 arg2 = arg.arg2;
70}
71
72bool Auth::TransactionComplete() const {
73 return complete;
74}
75
76ResultCode Auth::GetStatus() const {
77 return successful ? RESULT_SUCCESS : ERROR_INVALID_PIN;
78}
79
80void Auth::ExecuteInteractive() {
81 UNREACHABLE_MSG("Unexpected interactive applet data.");
82}
83
84void Auth::Execute() {
85 if (complete) {
86 return;
87 }
88
89 const auto unimplemented_log = [this] {
90 UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, "
91 "arg1={:02X}, arg2={:02X}",
92 static_cast<u32>(type), arg0, arg1, arg2);
93 };
94
95 switch (type) {
96 case AuthAppletType::ShowParentalAuthentication: {
97 const auto callback = [this](bool successful) { AuthFinished(successful); };
98
99 if (arg0 == 1 && arg1 == 0 && arg2 == 1) {
100 // ShowAuthenticatorForConfiguration
101 frontend.VerifyPINForSettings(callback);
102 } else if (arg1 == 0 && arg2 == 0) {
103 // ShowParentalAuthentication(bool)
104 frontend.VerifyPIN(callback, static_cast<bool>(arg0));
105 } else {
106 unimplemented_log();
107 }
108 break;
109 }
110 case AuthAppletType::RegisterParentalPasscode: {
111 const auto callback = [this] { AuthFinished(true); };
112
113 if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
114 // RegisterParentalPasscode
115 frontend.RegisterPIN(callback);
116 } else {
117 unimplemented_log();
118 }
119 break;
120 }
121 case AuthAppletType::ChangeParentalPasscode: {
122 const auto callback = [this] { AuthFinished(true); };
123
124 if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
125 // ChangeParentalPasscode
126 frontend.ChangePIN(callback);
127 } else {
128 unimplemented_log();
129 }
130 break;
131 }
132 default:
133 unimplemented_log();
134 }
135}
136
137void Auth::AuthFinished(bool successful) {
138 this->successful = successful;
139
140 struct Return {
141 ResultCode result_code;
142 };
143 static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size.");
144
145 Return return_{GetStatus()};
146
147 std::vector<u8> out(sizeof(Return));
148 std::memcpy(out.data(), &return_, sizeof(Return));
149
150 broker.PushNormalDataFromApplet(IStorage{out});
151 broker.SignalStateChanged();
152}
153
38PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {} 154PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {}
39 155
40PhotoViewer::~PhotoViewer() = default; 156PhotoViewer::~PhotoViewer() = default;
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h
index fb68a2543..0da252044 100644
--- a/src/core/hle/service/am/applets/general_backend.h
+++ b/src/core/hle/service/am/applets/general_backend.h
@@ -8,6 +8,36 @@
8 8
9namespace Service::AM::Applets { 9namespace Service::AM::Applets {
10 10
11enum class AuthAppletType : u32 {
12 ShowParentalAuthentication,
13 RegisterParentalPasscode,
14 ChangeParentalPasscode,
15};
16
17class Auth final : public Applet {
18public:
19 explicit Auth(Core::Frontend::ParentalControlsApplet& frontend);
20 ~Auth() override;
21
22 void Initialize() override;
23 bool TransactionComplete() const override;
24 ResultCode GetStatus() const override;
25 void ExecuteInteractive() override;
26 void Execute() override;
27
28 void AuthFinished(bool successful = true);
29
30private:
31 Core::Frontend::ParentalControlsApplet& frontend;
32 bool complete = false;
33 bool successful = false;
34
35 AuthAppletType type = AuthAppletType::ShowParentalAuthentication;
36 u8 arg0 = 0;
37 u8 arg1 = 0;
38 u8 arg2 = 0;
39};
40
11enum class PhotoViewerAppletMode : u8 { 41enum class PhotoViewerAppletMode : u8 {
12 CurrentApp = 0, 42 CurrentApp = 0,
13 AllApps = 1, 43 AllApps = 1,
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 7878f5136..2762e0653 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -19,7 +19,9 @@
19#include "core/file_sys/nca_metadata.h" 19#include "core/file_sys/nca_metadata.h"
20#include "core/file_sys/registered_cache.h" 20#include "core/file_sys/registered_cache.h"
21#include "core/file_sys/romfs.h" 21#include "core/file_sys/romfs.h"
22#include "core/file_sys/system_archive/system_archive.h"
22#include "core/file_sys/vfs_types.h" 23#include "core/file_sys/vfs_types.h"
24#include "core/frontend/applets/general_frontend.h"
23#include "core/frontend/applets/web_browser.h" 25#include "core/frontend/applets/web_browser.h"
24#include "core/hle/kernel/process.h" 26#include "core/hle/kernel/process.h"
25#include "core/hle/service/am/applets/web_browser.h" 27#include "core/hle/service/am/applets/web_browser.h"
@@ -28,74 +30,187 @@
28 30
29namespace Service::AM::Applets { 31namespace Service::AM::Applets {
30 32
31// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not 33enum class WebArgTLVType : u16 {
32// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant, 34 InitialURL = 0x1,
33// but some may be worth an implementation. 35 ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name.
34constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6; 36 CallbackURL = 0x3,
37 CallbackableURL = 0x4,
38 ApplicationID = 0x5,
39 DocumentPath = 0x6,
40 DocumentKind = 0x7,
41 SystemDataID = 0x8,
42 ShareStartPage = 0x9,
43 Whitelist = 0xA,
44 News = 0xB,
45 UserID = 0xE,
46 AlbumEntry0 = 0xF,
47 ScreenShotEnabled = 0x10,
48 EcClientCertEnabled = 0x11,
49 Unk12 = 0x12,
50 PlayReportEnabled = 0x13,
51 Unk14 = 0x14,
52 Unk15 = 0x15,
53 BootDisplayKind = 0x17,
54 BackgroundKind = 0x18,
55 FooterEnabled = 0x19,
56 PointerEnabled = 0x1A,
57 LeftStickMode = 0x1B,
58 KeyRepeatFrame1 = 0x1C,
59 KeyRepeatFrame2 = 0x1D,
60 BootAsMediaPlayerInv = 0x1E,
61 DisplayUrlKind = 0x1F,
62 BootAsMediaPlayer = 0x21,
63 ShopJumpEnabled = 0x22,
64 MediaAutoPlayEnabled = 0x23,
65 LobbyParameter = 0x24,
66 ApplicationAlbumEntry = 0x26,
67 JsExtensionEnabled = 0x27,
68 AdditionalCommentText = 0x28,
69 TouchEnabledOnContents = 0x29,
70 UserAgentAdditionalString = 0x2A,
71 AdditionalMediaData0 = 0x2B,
72 MediaPlayerAutoCloseEnabled = 0x2C,
73 PageCacheEnabled = 0x2D,
74 WebAudioEnabled = 0x2E,
75 Unk2F = 0x2F,
76 YouTubeVideoWhitelist = 0x31,
77 FooterFixedKind = 0x32,
78 PageFadeEnabled = 0x33,
79 MediaCreatorApplicationRatingAge = 0x34,
80 BootLoadingIconEnabled = 0x35,
81 PageScrollIndicationEnabled = 0x36,
82 MediaPlayerSpeedControlEnabled = 0x37,
83 AlbumEntry1 = 0x38,
84 AlbumEntry2 = 0x39,
85 AlbumEntry3 = 0x3A,
86 AdditionalMediaData1 = 0x3B,
87 AdditionalMediaData2 = 0x3C,
88 AdditionalMediaData3 = 0x3D,
89 BootFooterButton = 0x3E,
90 OverrideWebAudioVolume = 0x3F,
91 OverrideMediaAudioVolume = 0x40,
92 BootMode = 0x41,
93 WebSessionEnabled = 0x42,
94};
95
96enum class ShimKind : u32 {
97 Shop = 1,
98 Login = 2,
99 Offline = 3,
100 Share = 4,
101 Web = 5,
102 Wifi = 6,
103 Lobby = 7,
104};
105
106enum class ShopWebTarget {
107 ApplicationInfo,
108 AddOnContentList,
109 SubscriptionList,
110 ConsumableItemList,
111 Home,
112 Settings,
113};
114
115namespace {
35 116
36struct WebBufferHeader { 117constexpr std::size_t SHIM_KIND_COUNT = 0x8;
118
119struct WebArgHeader {
37 u16 count; 120 u16 count;
38 INSERT_PADDING_BYTES(6); 121 INSERT_PADDING_BYTES(2);
122 ShimKind kind;
39}; 123};
40static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); 124static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
41 125
42struct WebArgumentHeader { 126struct WebArgTLV {
43 u16 type; 127 WebArgTLVType type;
44 u16 size; 128 u16 size;
45 u32 offset; 129 u32 offset;
46}; 130};
47static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size."); 131static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size.");
48 132
49struct WebArgumentResult { 133struct WebCommonReturnValue {
50 u32 result_code; 134 u32 result_code;
135 INSERT_PADDING_BYTES(0x4);
51 std::array<char, 0x1000> last_url; 136 std::array<char, 0x1000> last_url;
52 u64 last_url_size; 137 u64 last_url_size;
53}; 138};
54static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); 139static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
55 140
56static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) { 141struct WebWifiPageArg {
57 WebBufferHeader header; 142 INSERT_PADDING_BYTES(4);
58 ASSERT(sizeof(WebBufferHeader) <= data.size()); 143 std::array<char, 0x100> connection_test_url;
59 std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); 144 std::array<char, 0x400> initial_url;
60 145 std::array<u8, 0x10> nifm_network_uuid;
61 u64 offset = sizeof(WebBufferHeader); 146 u32 nifm_requirement;
62 for (u16 i = 0; i < header.count; ++i) { 147};
63 WebArgumentHeader arg; 148static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size.");
64 ASSERT(offset + sizeof(WebArgumentHeader) <= data.size()); 149
65 std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader)); 150struct WebWifiReturnValue {
66 offset += sizeof(WebArgumentHeader); 151 INSERT_PADDING_BYTES(4);
67 152 u32 result;
68 if (arg.type == type) { 153};
69 std::vector<u8> out(arg.size); 154static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size.");
70 offset += arg.offset; 155
71 ASSERT(offset + arg.size <= data.size()); 156enum class OfflineWebSource : u32 {
72 std::memcpy(out.data(), data.data() + offset, out.size()); 157 OfflineHtmlPage = 0x1,
158 ApplicationLegalInformation = 0x2,
159 SystemDataPage = 0x3,
160};
161
162std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) {
163 if (arg.size() < sizeof(WebArgHeader))
164 return {};
165
166 WebArgHeader header{};
167 std::memcpy(&header, arg.data(), sizeof(WebArgHeader));
168
169 std::map<WebArgTLVType, std::vector<u8>> out;
170 u64 offset = sizeof(WebArgHeader);
171 for (std::size_t i = 0; i < header.count; ++i) {
172 if (arg.size() < (offset + sizeof(WebArgTLV)))
73 return out; 173 return out;
74 }
75 174
76 offset += arg.offset + arg.size; 175 WebArgTLV tlv{};
77 } 176 std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV));
177 offset += sizeof(WebArgTLV);
78 178
79 return {}; 179 offset += tlv.offset;
80} 180 if (arg.size() < (offset + tlv.size))
181 return out;
182
183 std::vector<u8> data(tlv.size);
184 std::memcpy(data.data(), arg.data() + offset, tlv.size);
185 offset += tlv.size;
81 186
82static FileSys::VirtualFile GetManualRomFS() { 187 out.insert_or_assign(tlv.type, data);
83 auto& loader{Core::System::GetInstance().GetAppLoader()}; 188 }
84 189
85 FileSys::VirtualFile out; 190 return out;
86 if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) 191}
87 return out;
88 192
193FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) {
89 const auto& installed{Core::System::GetInstance().GetContentProvider()}; 194 const auto& installed{Core::System::GetInstance().GetContentProvider()};
90 const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(), 195 const auto res = installed.GetEntry(title_id, type);
91 FileSys::ContentRecordType::Manual);
92 196
93 if (res != nullptr) 197 if (res != nullptr) {
94 return res->GetRomFS(); 198 return res->GetRomFS();
199 }
200
201 if (type == FileSys::ContentRecordType::Data) {
202 return FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
203 }
204
95 return nullptr; 205 return nullptr;
96} 206}
97 207
98WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {} 208} // Anonymous namespace
209
210WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id,
211 Core::Frontend::ECommerceApplet* frontend_e_commerce)
212 : frontend(frontend), frontend_e_commerce(frontend_e_commerce),
213 current_process_title_id(current_process_title_id) {}
99 214
100WebBrowser::~WebBrowser() = default; 215WebBrowser::~WebBrowser() = default;
101 216
@@ -111,24 +226,12 @@ void WebBrowser::Initialize() {
111 ASSERT(web_arg_storage != nullptr); 226 ASSERT(web_arg_storage != nullptr);
112 const auto& web_arg = web_arg_storage->GetData(); 227 const auto& web_arg = web_arg_storage->GetData();
113 228
114 const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE); 229 ASSERT(web_arg.size() >= 0x8);
115 filename = Common::StringFromFixedZeroTerminatedBuffer( 230 std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind));
116 reinterpret_cast<const char*>(url_data.data()), url_data.size());
117 231
118 temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + 232 args = GetWebArguments(web_arg);
119 "web_applet_manual",
120 FileUtil::DirectorySeparator::PlatformDefault);
121 FileUtil::DeleteDirRecursively(temporary_dir);
122 233
123 manual_romfs = GetManualRomFS(); 234 InitializeInternal();
124 if (manual_romfs == nullptr) {
125 status = ResultCode(-1);
126 LOG_ERROR(Service_AM, "Failed to find manual for current process!");
127 }
128
129 filename =
130 FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename,
131 FileUtil::DirectorySeparator::PlatformDefault);
132} 235}
133 236
134bool WebBrowser::TransactionComplete() const { 237bool WebBrowser::TransactionComplete() const {
@@ -144,24 +247,25 @@ void WebBrowser::ExecuteInteractive() {
144} 247}
145 248
146void WebBrowser::Execute() { 249void WebBrowser::Execute() {
147 if (complete) 250 if (complete) {
148 return; 251 return;
252 }
149 253
150 if (status != RESULT_SUCCESS) { 254 if (status != RESULT_SUCCESS) {
151 complete = true; 255 complete = true;
152 return; 256 return;
153 } 257 }
154 258
155 frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); 259 ExecuteInternal();
156} 260}
157 261
158void WebBrowser::UnpackRomFS() { 262void WebBrowser::UnpackRomFS() {
159 if (unpacked) 263 if (unpacked)
160 return; 264 return;
161 265
162 ASSERT(manual_romfs != nullptr); 266 ASSERT(offline_romfs != nullptr);
163 const auto dir = 267 const auto dir =
164 FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard); 268 FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
165 const auto& vfs{Core::System::GetInstance().GetFilesystem()}; 269 const auto& vfs{Core::System::GetInstance().GetFilesystem()};
166 const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); 270 const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
167 FileSys::VfsRawCopyD(dir, temp_dir); 271 FileSys::VfsRawCopyD(dir, temp_dir);
@@ -172,17 +276,275 @@ void WebBrowser::UnpackRomFS() {
172void WebBrowser::Finalize() { 276void WebBrowser::Finalize() {
173 complete = true; 277 complete = true;
174 278
175 WebArgumentResult out{}; 279 WebCommonReturnValue out{};
176 out.result_code = 0; 280 out.result_code = 0;
177 out.last_url_size = 0; 281 out.last_url_size = 0;
178 282
179 std::vector<u8> data(sizeof(WebArgumentResult)); 283 std::vector<u8> data(sizeof(WebCommonReturnValue));
180 std::memcpy(data.data(), &out, sizeof(WebArgumentResult)); 284 std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
181 285
182 broker.PushNormalDataFromApplet(IStorage{data}); 286 broker.PushNormalDataFromApplet(IStorage{data});
183 broker.SignalStateChanged(); 287 broker.SignalStateChanged();
184 288
289 if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
290 FileUtil::DeleteDirRecursively(temporary_dir);
291 }
292}
293
294void WebBrowser::InitializeInternal() {
295 using WebAppletInitializer = void (WebBrowser::*)();
296
297 constexpr std::array<WebAppletInitializer, SHIM_KIND_COUNT> functions{
298 nullptr, &WebBrowser::InitializeShop,
299 nullptr, &WebBrowser::InitializeOffline,
300 nullptr, nullptr,
301 nullptr, nullptr,
302 };
303
304 const auto index = static_cast<u32>(kind);
305
306 if (index > functions.size() || functions[index] == nullptr) {
307 LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index);
308 return;
309 }
310
311 const auto function = functions[index];
312 (this->*function)();
313}
314
315void WebBrowser::ExecuteInternal() {
316 using WebAppletExecutor = void (WebBrowser::*)();
317
318 constexpr std::array<WebAppletExecutor, SHIM_KIND_COUNT> functions{
319 nullptr, &WebBrowser::ExecuteShop,
320 nullptr, &WebBrowser::ExecuteOffline,
321 nullptr, nullptr,
322 nullptr, nullptr,
323 };
324
325 const auto index = static_cast<u32>(kind);
326
327 if (index > functions.size() || functions[index] == nullptr) {
328 LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index);
329 return;
330 }
331
332 const auto function = functions[index];
333 (this->*function)();
334}
335
336void WebBrowser::InitializeShop() {
337 if (frontend_e_commerce == nullptr) {
338 LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!");
339 status = ResultCode(-1);
340 return;
341 }
342
343 const auto user_id_data = args.find(WebArgTLVType::UserID);
344
345 user_id = std::nullopt;
346 if (user_id_data != args.end()) {
347 user_id = u128{};
348 std::memcpy(user_id->data(), user_id_data->second.data(), sizeof(u128));
349 }
350
351 const auto url = args.find(WebArgTLVType::ShopArgumentsURL);
352
353 if (url == args.end()) {
354 LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!");
355 status = ResultCode(-1);
356 return;
357 }
358
359 std::vector<std::string> split_query;
360 Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer(
361 reinterpret_cast<const char*>(url->second.data()), url->second.size()),
362 '?', split_query);
363
364 // 2 -> Main URL '?' Query Parameters
365 // Less is missing info, More is malformed
366 if (split_query.size() != 2) {
367 LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed");
368 status = ResultCode(-1);
369 return;
370 }
371
372 std::vector<std::string> queries;
373 Common::SplitString(split_query[1], '&', queries);
374
375 const auto split_single_query =
376 [](const std::string& in) -> std::pair<std::string, std::string> {
377 const auto index = in.find('=');
378 if (index == std::string::npos || index == in.size() - 1) {
379 return {in, ""};
380 }
381
382 return {in.substr(0, index), in.substr(index + 1)};
383 };
384
385 std::transform(queries.begin(), queries.end(),
386 std::inserter(shop_query, std::next(shop_query.begin())), split_single_query);
387
388 const auto scene = shop_query.find("scene");
389
390 if (scene == shop_query.end()) {
391 LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!");
392 status = ResultCode(-1);
393 return;
394 }
395
396 const std::map<std::string, ShopWebTarget, std::less<>> target_map{
397 {"product_detail", ShopWebTarget::ApplicationInfo},
398 {"aocs", ShopWebTarget::AddOnContentList},
399 {"subscriptions", ShopWebTarget::SubscriptionList},
400 {"consumption", ShopWebTarget::ConsumableItemList},
401 {"settings", ShopWebTarget::Settings},
402 {"top", ShopWebTarget::Home},
403 };
404
405 const auto target = target_map.find(scene->second);
406 if (target == target_map.end()) {
407 LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second);
408 status = ResultCode(-1);
409 return;
410 }
411
412 shop_web_target = target->second;
413
414 const auto title_id_data = shop_query.find("dst_app_id");
415 if (title_id_data != shop_query.end()) {
416 title_id = std::stoull(title_id_data->second, nullptr, 0x10);
417 }
418
419 const auto mode_data = shop_query.find("mode");
420 if (mode_data != shop_query.end()) {
421 shop_full_display = mode_data->second == "full";
422 }
423}
424
425void WebBrowser::InitializeOffline() {
426 if (args.find(WebArgTLVType::DocumentPath) == args.end() ||
427 args.find(WebArgTLVType::DocumentKind) == args.end() ||
428 args.find(WebArgTLVType::ApplicationID) == args.end()) {
429 status = ResultCode(-1);
430 LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!");
431 }
432
433 const auto url_data = args[WebArgTLVType::DocumentPath];
434 filename = Common::StringFromFixedZeroTerminatedBuffer(
435 reinterpret_cast<const char*>(url_data.data()), url_data.size());
436
437 OfflineWebSource source;
438 ASSERT(args[WebArgTLVType::DocumentKind].size() >= 4);
439 std::memcpy(&source, args[WebArgTLVType::DocumentKind].data(), sizeof(OfflineWebSource));
440
441 constexpr std::array<const char*, 3> WEB_SOURCE_NAMES{
442 "manual",
443 "legal",
444 "system",
445 };
446
447 temporary_dir =
448 FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" +
449 WEB_SOURCE_NAMES[static_cast<u32>(source) - 1],
450 FileUtil::DirectorySeparator::PlatformDefault);
185 FileUtil::DeleteDirRecursively(temporary_dir); 451 FileUtil::DeleteDirRecursively(temporary_dir);
452
453 u64 title_id = 0; // 0 corresponds to current process
454 ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8);
455 std::memcpy(&title_id, args[WebArgTLVType::ApplicationID].data(), sizeof(u64));
456 FileSys::ContentRecordType type = FileSys::ContentRecordType::Data;
457
458 switch (source) {
459 case OfflineWebSource::OfflineHtmlPage:
460 // While there is an AppID TLV field, in official SW this is always ignored.
461 title_id = 0;
462 type = FileSys::ContentRecordType::Manual;
463 break;
464 case OfflineWebSource::ApplicationLegalInformation:
465 type = FileSys::ContentRecordType::Legal;
466 break;
467 case OfflineWebSource::SystemDataPage:
468 type = FileSys::ContentRecordType::Data;
469 break;
470 }
471
472 if (title_id == 0) {
473 title_id = current_process_title_id;
474 }
475
476 offline_romfs = GetApplicationRomFS(title_id, type);
477 if (offline_romfs == nullptr) {
478 status = ResultCode(-1);
479 LOG_ERROR(Service_AM, "Failed to find offline data for request!");
480 }
481
482 std::string path_additional_directory;
483 if (source == OfflineWebSource::OfflineHtmlPage) {
484 path_additional_directory = std::string(DIR_SEP).append("html-document");
485 }
486
487 filename =
488 FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename,
489 FileUtil::DirectorySeparator::PlatformDefault);
490}
491
492void WebBrowser::ExecuteShop() {
493 const auto callback = [this]() { Finalize(); };
494
495 const auto check_optional_parameter = [this](const auto& p) {
496 if (!p.has_value()) {
497 LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!");
498 status = ResultCode(-1);
499 return false;
500 }
501
502 return true;
503 };
504
505 switch (shop_web_target) {
506 case ShopWebTarget::ApplicationInfo:
507 if (!check_optional_parameter(title_id))
508 return;
509 frontend_e_commerce->ShowApplicationInformation(callback, *title_id, user_id,
510 shop_full_display, shop_extra_parameter);
511 break;
512 case ShopWebTarget::AddOnContentList:
513 if (!check_optional_parameter(title_id))
514 return;
515 frontend_e_commerce->ShowAddOnContentList(callback, *title_id, user_id, shop_full_display);
516 break;
517 case ShopWebTarget::ConsumableItemList:
518 if (!check_optional_parameter(title_id))
519 return;
520 frontend_e_commerce->ShowConsumableItemList(callback, *title_id, user_id);
521 break;
522 case ShopWebTarget::Home:
523 if (!check_optional_parameter(user_id))
524 return;
525 if (!check_optional_parameter(shop_full_display))
526 return;
527 frontend_e_commerce->ShowShopHome(callback, *user_id, *shop_full_display);
528 break;
529 case ShopWebTarget::Settings:
530 if (!check_optional_parameter(user_id))
531 return;
532 if (!check_optional_parameter(shop_full_display))
533 return;
534 frontend_e_commerce->ShowSettings(callback, *user_id, *shop_full_display);
535 break;
536 case ShopWebTarget::SubscriptionList:
537 if (!check_optional_parameter(title_id))
538 return;
539 frontend_e_commerce->ShowSubscriptionList(callback, *title_id, user_id);
540 break;
541 default:
542 UNREACHABLE();
543 }
544}
545
546void WebBrowser::ExecuteOffline() {
547 frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
186} 548}
187 549
188} // namespace Service::AM::Applets 550} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 7e0f34c7d..870f57b64 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -4,15 +4,22 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map>
7#include "core/file_sys/vfs_types.h" 8#include "core/file_sys/vfs_types.h"
8#include "core/hle/service/am/am.h" 9#include "core/hle/service/am/am.h"
9#include "core/hle/service/am/applets/applets.h" 10#include "core/hle/service/am/applets/applets.h"
10 11
11namespace Service::AM::Applets { 12namespace Service::AM::Applets {
12 13
14enum class ShimKind : u32;
15enum class ShopWebTarget;
16enum class WebArgTLVType : u16;
17
13class WebBrowser final : public Applet { 18class WebBrowser final : public Applet {
14public: 19public:
15 WebBrowser(Core::Frontend::WebBrowserApplet& frontend); 20 WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id,
21 Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr);
22
16 ~WebBrowser() override; 23 ~WebBrowser() override;
17 24
18 void Initialize() override; 25 void Initialize() override;
@@ -32,15 +39,41 @@ public:
32 void Finalize(); 39 void Finalize();
33 40
34private: 41private:
42 void InitializeInternal();
43 void ExecuteInternal();
44
45 // Specific initializers for the types of web applets
46 void InitializeShop();
47 void InitializeOffline();
48
49 // Specific executors for the types of web applets
50 void ExecuteShop();
51 void ExecuteOffline();
52
35 Core::Frontend::WebBrowserApplet& frontend; 53 Core::Frontend::WebBrowserApplet& frontend;
36 54
55 // Extra frontends for specialized functions
56 Core::Frontend::ECommerceApplet* frontend_e_commerce;
57
37 bool complete = false; 58 bool complete = false;
38 bool unpacked = false; 59 bool unpacked = false;
39 ResultCode status = RESULT_SUCCESS; 60 ResultCode status = RESULT_SUCCESS;
40 61
41 FileSys::VirtualFile manual_romfs; 62 u64 current_process_title_id;
63
64 ShimKind kind;
65 std::map<WebArgTLVType, std::vector<u8>> args;
66
67 FileSys::VirtualFile offline_romfs;
42 std::string temporary_dir; 68 std::string temporary_dir;
43 std::string filename; 69 std::string filename;
70
71 ShopWebTarget shop_web_target;
72 std::map<std::string, std::string, std::less<>> shop_query;
73 std::optional<u64> title_id = 0;
74 std::optional<u128> user_id;
75 std::optional<bool> shop_full_display;
76 std::string shop_extra_parameter;
44}; 77};
45 78
46} // namespace Service::AM::Applets 79} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index beae9c510..ec9d755b7 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -204,7 +204,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
204 SM::ServiceManager::InstallInterfaces(sm); 204 SM::ServiceManager::InstallInterfaces(sm);
205 205
206 Account::InstallInterfaces(system); 206 Account::InstallInterfaces(system);
207 AM::InstallInterfaces(*sm, nv_flinger); 207 AM::InstallInterfaces(*sm, nv_flinger, system);
208 AOC::InstallInterfaces(*sm); 208 AOC::InstallInterfaces(*sm);
209 APM::InstallInterfaces(*sm); 209 APM::InstallInterfaces(*sm);
210 Audio::InstallInterfaces(*sm); 210 Audio::InstallInterfaces(*sm);
diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp
index ac80b2fa2..33f1c385d 100644
--- a/src/yuzu/applets/web_browser.cpp
+++ b/src/yuzu/applets/web_browser.cpp
@@ -87,8 +87,8 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
87 87
88QtWebBrowser::~QtWebBrowser() = default; 88QtWebBrowser::~QtWebBrowser() = default;
89 89
90void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, 90void QtWebBrowser::OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
91 std::function<void()> finished_callback) { 91 std::function<void()> finished_callback) {
92 this->unpack_romfs_callback = std::move(unpack_romfs_callback); 92 this->unpack_romfs_callback = std::move(unpack_romfs_callback);
93 this->finished_callback = std::move(finished_callback); 93 this->finished_callback = std::move(finished_callback);
94 94
diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h
index 1a3d67353..b38437e46 100644
--- a/src/yuzu/applets/web_browser.h
+++ b/src/yuzu/applets/web_browser.h
@@ -37,8 +37,8 @@ public:
37 explicit QtWebBrowser(GMainWindow& main_window); 37 explicit QtWebBrowser(GMainWindow& main_window);
38 ~QtWebBrowser() override; 38 ~QtWebBrowser() override;
39 39
40 void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, 40 void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
41 std::function<void()> finished_callback) override; 41 std::function<void()> finished_callback) override;
42 42
43signals: 43signals:
44 void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const; 44 void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 66a7080c9..47e46f574 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -814,11 +814,13 @@ bool GMainWindow::LoadROM(const QString& filename) {
814 system.SetGPUDebugContext(debug_context); 814 system.SetGPUDebugContext(debug_context);
815 815
816 system.SetAppletFrontendSet({ 816 system.SetAppletFrontendSet({
817 std::make_unique<QtErrorDisplay>(*this), 817 nullptr, // Parental Controls
818 nullptr, 818 std::make_unique<QtErrorDisplay>(*this), //
819 std::make_unique<QtProfileSelector>(*this), 819 nullptr, // Photo Viewer
820 std::make_unique<QtSoftwareKeyboard>(*this), 820 std::make_unique<QtProfileSelector>(*this), //
821 std::make_unique<QtWebBrowser>(*this), 821 std::make_unique<QtSoftwareKeyboard>(*this), //
822 std::make_unique<QtWebBrowser>(*this), //
823 nullptr, // E-Commerce
822 }); 824 });
823 825
824 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; 826 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};