diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h index dd5ab686..31fd597e 100644 --- a/nx/include/switch/services/ns.h +++ b/nx/include/switch/services/ns.h @@ -244,6 +244,10 @@ Service* nsGetServiceSession_GetterInterface(void); /// Gets the Service object for IApplicationManagerInterface. Service* nsGetServiceSession_ApplicationManagerInterface(void); +/// Gets the Service object for IECommerceInterface via the cmd for that. +/// Only available on [4.0.0+]. +Result nsGetECommerceInterface(Service* srv_out); + /// Gets the Service object for IFactoryResetInterface via the cmd for that. /// Only available on [3.0.0+]. Result nsGetFactoryResetInterface(Service* srv_out); @@ -258,6 +262,36 @@ Result nsGetContentManagementInterface(Service* srv_out); ///@} +///@name IECommerceInterface +///@{ + +/** + * @brief RequestLinkDevice + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [4.0.0+]. + * @param[out] a \ref AsyncResult + * @param[in] uid \ref AccountUid + */ +Result nsRequestLinkDevice(AsyncResult *a, AccountUid uid); + +/** + * @brief RequestSyncRights + * @note Only available on [6.0.0+]. + * @param[out] a \ref AsyncResult + */ +Result nsRequestSyncRights(AsyncResult *a); + +/** + * @brief RequestUnlinkDevice + * @note \ref nifmInitialize must be used prior to this. Before using the cmd, this calls \ref nifmIsAnyInternetRequestAccepted with the output from \ref nifmGetClientId, an error is returned when that returns false. + * @note Only available on [6.0.0+]. + * @param[out] a \ref AsyncResult + * @param[in] uid \ref AccountUid + */ +Result nsRequestUnlinkDevice(AsyncResult *a, AccountUid uid); + +///@} + ///@name IFactoryResetInterface ///@{ diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c index f0bba149..076e648f 100644 --- a/nx/source/services/ns.c +++ b/nx/source/services/ns.c @@ -46,6 +46,13 @@ Service* nsGetServiceSession_ApplicationManagerInterface(void) { return &g_nsAppManSrv; } +Result nsGetECommerceInterface(Service* srv_out) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsGetSession(&g_nsGetterSrv, srv_out, 7992); +} + Result nsGetFactoryResetInterface(Service* srv_out) { if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); @@ -251,10 +258,73 @@ static Result _nsCmdInU64OutAsyncResult(Service* srv, AsyncResult *a, u64 inval, return rc; } +static Result _nsCmdInUidOutAsyncResult(Service* srv, AsyncResult *a, AccountUid uid, u32 cmd_id) { + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + Result rc = serviceDispatchIn(srv, cmd_id, uid, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + static Result _nsCheckNifm(void) { return nifmIsAnyInternetRequestAccepted(nifmGetClientId()) ? 0 : MAKERESULT(16, 340); } +// IECommerceInterface + +Result nsRequestLinkDevice(AsyncResult *a, AccountUid uid) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + Service srv={0}; + rc = nsGetECommerceInterface(&srv); + + if (R_SUCCEEDED(rc)) rc = _nsCmdInUidOutAsyncResult(&srv, a, uid, 0); + + serviceClose(&srv); + return rc; +} + +Result nsRequestSyncRights(AsyncResult *a) { + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Service srv={0}; + Result rc = nsGetECommerceInterface(&srv); + + if (R_SUCCEEDED(rc)) rc = _nsCmdNoInOutAsyncResult(&srv, a, 3); + + serviceClose(&srv); + return rc; +} + +Result nsRequestUnlinkDevice(AsyncResult *a, AccountUid uid) { + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc = _nsCheckNifm(); + if (R_FAILED(rc)) return rc; + + Service srv={0}; + rc = nsGetECommerceInterface(&srv); + + if (R_SUCCEEDED(rc)) rc = _nsCmdInUidOutAsyncResult(&srv, a, uid, 4); + + serviceClose(&srv); + return rc; +} + // IFactoryResetInterface Result nsResetToFactorySettings(void) { @@ -1311,7 +1381,7 @@ Result nsRequestEnsureDownloadTask(AsyncResult *a) { else srv_ptr = &g_nsAppManSrv; - if (R_SUCCEEDED(rc)) rc =_nsCmdNoInOutAsyncResult(srv_ptr, a, 703); + if (R_SUCCEEDED(rc)) rc = _nsCmdNoInOutAsyncResult(srv_ptr, a, 703); serviceClose(&srv); return rc; @@ -1349,7 +1419,7 @@ Result nsRequestDownloadTaskListData(AsyncValue *a) { else srv_ptr = &g_nsAppManSrv; - if (R_SUCCEEDED(rc)) rc =_nsCmdNoInOutAsyncValue(srv_ptr, a, 705); + if (R_SUCCEEDED(rc)) rc = _nsCmdNoInOutAsyncValue(srv_ptr, a, 705); serviceClose(&srv); return rc;