| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -31,6 +31,9 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				namespace Service::Account {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static std::string GetImagePath(Common::UUID uuid) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				           "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -41,20 +44,31 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return static_cast<u32>(std::min(size, max_jpeg_image_size));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class IProfile final : public ServiceFramework<IProfile> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class IProfileCommon : public ServiceFramework<IProfileCommon> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				public:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    explicit IProfile(Common::UUID user_id, ProfileManager& profile_manager)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        : ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            ProfileManager& profile_manager)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        : ServiceFramework(name), profile_manager(profile_manager), user_id(user_id) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        static const FunctionInfo functions[] = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {0, &IProfile::Get, "Get"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {1, &IProfile::GetBase, "GetBase"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {10, &IProfile::GetImageSize, "GetImageSize"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {11, &IProfile::LoadImage, "LoadImage"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {0, &IProfileCommon::Get, "Get"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {1, &IProfileCommon::GetBase, "GetBase"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {10, &IProfileCommon::GetImageSize, "GetImageSize"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            {11, &IProfileCommon::LoadImage, "LoadImage"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        RegisterHandlers(functions);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (editor_commands) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            static const FunctionInfo editor_functions[] = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                {100, &IProfileCommon::Store, "Store"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                {101, &IProfileCommon::StoreWithImage, "StoreWithImage"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            RegisterHandlers(editor_functions);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				private:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				protected:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    void Get(Kernel::HLERequestContext& ctx) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ProfileBase profile_base{};
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -127,10 +141,91 @@ private:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const ProfileManager& profile_manager;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    void Store(Kernel::HLERequestContext& ctx) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        IPC::RequestParser rp{ctx};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const auto base = rp.PopRaw<ProfileBase>();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const auto user_data = ctx.ReadBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                  Common::StringFromFixedZeroTerminatedBuffer(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                      reinterpret_cast<const char*>(base.username.data()), base.username.size()),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                  base.timestamp, base.user_uuid.Format());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (user_data.size() < sizeof(ProfileData)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            rb.Push(ERR_INVALID_BUFFER_SIZE);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ProfileData data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::memcpy(&data, user_data.data(), sizeof(ProfileData));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            LOG_ERROR(Service_ACC, "Failed to update profile data and base!");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            rb.Push(ERR_FAILED_SAVE_DATA);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        rb.Push(RESULT_SUCCESS);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    void StoreWithImage(Kernel::HLERequestContext& ctx) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        IPC::RequestParser rp{ctx};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const auto base = rp.PopRaw<ProfileBase>();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const auto user_data = ctx.ReadBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const auto image_data = ctx.ReadBuffer(1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                  Common::StringFromFixedZeroTerminatedBuffer(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                      reinterpret_cast<const char*>(base.username.data()), base.username.size()),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                  base.timestamp, base.user_uuid.Format());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (user_data.size() < sizeof(ProfileData)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            rb.Push(ERR_INVALID_BUFFER_SIZE);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ProfileData data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::memcpy(&data, user_data.data(), sizeof(ProfileData));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        FileUtil::IOFile image(GetImagePath(user_id), "wb");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (!image.IsOpen() || !image.Resize(image_data.size()) ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            !profile_manager.SetProfileBaseAndData(user_id, base, data)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            rb.Push(ERR_FAILED_SAVE_DATA);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        rb.Push(RESULT_SUCCESS);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ProfileManager& profile_manager;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Common::UUID user_id; ///< The user id this profile refers to.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class IProfile final : public IProfileCommon {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				public:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IProfile(Common::UUID user_id, ProfileManager& profile_manager)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        : IProfileCommon("IProfile", false, user_id, profile_manager) {}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class IProfileEditor final : public IProfileCommon {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				public:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IProfileEditor(Common::UUID user_id, ProfileManager& profile_manager)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        : IProfileCommon("IProfileEditor", true, user_id, profile_manager) {}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				public:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IManagerForApplication() : ServiceFramework("IManagerForApplication") {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -322,6 +417,17 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rb.Push(is_locked);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::RequestParser rp{ctx};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Common::UUID user_id = rp.PopRaw<Common::UUID>();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::ResponseBuilder rb{ctx, 2, 0, 1};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rb.Push(RESULT_SUCCESS);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rb.PushIpcInterface<IProfileEditor>(user_id, *profile_manager);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    LOG_DEBUG(Service_ACC, "called");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // A u8 is passed into this function which we can safely ignore. It's to determine if we have
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				 
 |