/ src / Ryujinx.HLE / HOS / Services / Pctl / ParentalControlServiceFactory / IParentalControlService.cs
IParentalControlService.cs
1 using Ryujinx.Common.Logging; 2 using Ryujinx.HLE.HOS.Services.Arp; 3 using System; 4 using static LibHac.Ns.ApplicationControlProperty; 5 6 namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory 7 { 8 class IParentalControlService : IpcService 9 { 10 private readonly ulong _pid; 11 private readonly int _permissionFlag; 12 private ulong _titleId; 13 private ParentalControlFlagValue _parentalControlFlag; 14 #pragma warning disable IDE0052, CS0414 // Remove unread private member 15 private int[] _ratingAge; 16 17 // TODO: Find where they are set. 18 private readonly bool _restrictionEnabled = false; 19 private readonly bool _featuresRestriction = false; 20 private bool _freeCommunicationEnabled = false; 21 private readonly bool _stereoVisionRestrictionConfigurable = true; 22 private bool _stereoVisionRestriction = false; 23 #pragma warning restore IDE0052, CS0414 24 25 public IParentalControlService(ServiceCtx context, ulong pid, bool withInitialize, int permissionFlag) 26 { 27 _pid = pid; 28 _permissionFlag = permissionFlag; 29 30 if (withInitialize) 31 { 32 Initialize(context); 33 } 34 } 35 36 [CommandCmif(1)] // 4.0.0+ 37 // Initialize() 38 public ResultCode Initialize(ServiceCtx context) 39 { 40 if ((_permissionFlag & 0x8001) == 0) 41 { 42 return ResultCode.PermissionDenied; 43 } 44 45 ResultCode resultCode = ResultCode.InvalidPid; 46 47 if (_pid != 0) 48 { 49 if ((_permissionFlag & 0x40) == 0) 50 { 51 ulong titleId = ApplicationLaunchProperty.GetByPid(context).TitleId; 52 53 if (titleId != 0) 54 { 55 _titleId = titleId; 56 57 // TODO: Call nn::arp::GetApplicationControlProperty here when implemented, if it return ResultCode.Success we assign fields. 58 _ratingAge = Array.ConvertAll(context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge.ItemsRo.ToArray(), Convert.ToInt32); 59 _parentalControlFlag = context.Device.Processes.ActiveApplication.ApplicationControlProperties.ParentalControlFlag; 60 } 61 } 62 63 if (_titleId != 0) 64 { 65 // TODO: Service store some private fields in another object. 66 67 if ((_permissionFlag & 0x8040) == 0) 68 { 69 // TODO: Service store TitleId and FreeCommunicationEnabled in another object. 70 // When it's done it signal an event in this object. 71 Logger.Stub?.PrintStub(LogClass.ServicePctl); 72 } 73 } 74 75 resultCode = ResultCode.Success; 76 } 77 78 return resultCode; 79 } 80 81 [CommandCmif(1001)] 82 // CheckFreeCommunicationPermission() 83 public ResultCode CheckFreeCommunicationPermission(ServiceCtx context) 84 { 85 if (_parentalControlFlag == ParentalControlFlagValue.FreeCommunication && _restrictionEnabled) 86 { 87 // TODO: It seems to checks if an entry exists in the FreeCommunicationApplicationList using the TitleId. 88 // Then it returns FreeCommunicationDisabled if the entry doesn't exist. 89 90 return ResultCode.FreeCommunicationDisabled; 91 } 92 93 _freeCommunicationEnabled = true; 94 95 Logger.Stub?.PrintStub(LogClass.ServicePctl); 96 97 return ResultCode.Success; 98 } 99 100 [CommandCmif(1017)] // 10.0.0+ 101 // EndFreeCommunication() 102 public ResultCode EndFreeCommunication(ServiceCtx context) 103 { 104 _freeCommunicationEnabled = false; 105 106 return ResultCode.Success; 107 } 108 109 [CommandCmif(1013)] // 4.0.0+ 110 // ConfirmStereoVisionPermission() 111 public ResultCode ConfirmStereoVisionPermission(ServiceCtx context) 112 { 113 return IsStereoVisionPermittedImpl(); 114 } 115 116 [CommandCmif(1018)] 117 // IsFreeCommunicationAvailable() 118 public ResultCode IsFreeCommunicationAvailable(ServiceCtx context) 119 { 120 if (_parentalControlFlag == ParentalControlFlagValue.FreeCommunication && _restrictionEnabled) 121 { 122 // TODO: It seems to checks if an entry exists in the FreeCommunicationApplicationList using the TitleId. 123 // Then it returns FreeCommunicationDisabled if the entry doesn't exist. 124 125 return ResultCode.FreeCommunicationDisabled; 126 } 127 128 Logger.Stub?.PrintStub(LogClass.ServicePctl); 129 130 return ResultCode.Success; 131 } 132 133 [CommandCmif(1031)] 134 // IsRestrictionEnabled() -> b8 135 public ResultCode IsRestrictionEnabled(ServiceCtx context) 136 { 137 if ((_permissionFlag & 0x140) == 0) 138 { 139 return ResultCode.PermissionDenied; 140 } 141 142 context.ResponseData.Write(_restrictionEnabled); 143 144 return ResultCode.Success; 145 } 146 147 [CommandCmif(1061)] // 4.0.0+ 148 // ConfirmStereoVisionRestrictionConfigurable() 149 public ResultCode ConfirmStereoVisionRestrictionConfigurable(ServiceCtx context) 150 { 151 if ((_permissionFlag & 2) == 0) 152 { 153 return ResultCode.PermissionDenied; 154 } 155 156 if (_stereoVisionRestrictionConfigurable) 157 { 158 return ResultCode.Success; 159 } 160 else 161 { 162 return ResultCode.StereoVisionRestrictionConfigurableDisabled; 163 } 164 } 165 166 [CommandCmif(1062)] // 4.0.0+ 167 // GetStereoVisionRestriction() -> bool 168 public ResultCode GetStereoVisionRestriction(ServiceCtx context) 169 { 170 if ((_permissionFlag & 0x200) == 0) 171 { 172 return ResultCode.PermissionDenied; 173 } 174 175 #pragma warning disable // Remove unnecessary value assignment 176 bool stereoVisionRestriction = false; 177 #pragma warning restore IDE0059 178 179 if (_stereoVisionRestrictionConfigurable) 180 { 181 stereoVisionRestriction = _stereoVisionRestriction; 182 } 183 184 context.ResponseData.Write(stereoVisionRestriction); 185 186 return ResultCode.Success; 187 } 188 189 [CommandCmif(1063)] // 4.0.0+ 190 // SetStereoVisionRestriction(bool) 191 public ResultCode SetStereoVisionRestriction(ServiceCtx context) 192 { 193 if ((_permissionFlag & 0x200) == 0) 194 { 195 return ResultCode.PermissionDenied; 196 } 197 198 bool stereoVisionRestriction = context.RequestData.ReadBoolean(); 199 200 if (!_featuresRestriction) 201 { 202 if (_stereoVisionRestrictionConfigurable) 203 { 204 _stereoVisionRestriction = stereoVisionRestriction; 205 206 // TODO: It signals an internal event of service. We have to determine where this event is used. 207 } 208 } 209 210 return ResultCode.Success; 211 } 212 213 [CommandCmif(1064)] // 5.0.0+ 214 // ResetConfirmedStereoVisionPermission() 215 public ResultCode ResetConfirmedStereoVisionPermission(ServiceCtx context) 216 { 217 return ResultCode.Success; 218 } 219 220 [CommandCmif(1065)] // 5.0.0+ 221 // IsStereoVisionPermitted() -> bool 222 public ResultCode IsStereoVisionPermitted(ServiceCtx context) 223 { 224 bool isStereoVisionPermitted = false; 225 226 ResultCode resultCode = IsStereoVisionPermittedImpl(); 227 228 if (resultCode == ResultCode.Success) 229 { 230 isStereoVisionPermitted = true; 231 } 232 233 context.ResponseData.Write(isStereoVisionPermitted); 234 235 return resultCode; 236 } 237 238 private ResultCode IsStereoVisionPermittedImpl() 239 { 240 /* 241 // TODO: Application Exemptions are read from file "appExemptions.dat" in the service savedata. 242 // Since we don't support the pctl savedata for now, this can be implemented later. 243 244 if (appExemption) 245 { 246 return ResultCode.Success; 247 } 248 */ 249 250 if (_stereoVisionRestrictionConfigurable && _stereoVisionRestriction) 251 { 252 return ResultCode.StereoVisionDenied; 253 } 254 else 255 { 256 return ResultCode.Success; 257 } 258 } 259 } 260 }