From 1e58385bd5b3d3e3139a05749197048337695b95 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 15 Nov 2019 14:26:29 -0500 Subject: [PATCH] Added appletGetFriendInvitationStorageChannelEvent, appletTryPopFromFriendInvitationStorageChannel, appletGetNotificationStorageChannelEvent, and appletTryPopFromNotificationStorageChannel. Added appletPushToFriendInvitationStorageChannel/appletPushToNotificationStorageChannel. Added friendsGetFriendInvitationNotificationEvent/friendsTryPopFriendInvitationNotificationInfo. Added notif, for adding notifGetNotificationSystemEvent/notifTryPopNotifiedApplicationParameter. --- nx/include/switch.h | 1 + nx/include/switch/services/applet.h | 56 ++++++++++++++++++++++++++++ nx/include/switch/services/friends.h | 23 ++++++++++++ nx/include/switch/services/notif.h | 31 +++++++++++++++ nx/source/services/applet.c | 49 +++++++++++++++++++++--- nx/source/services/friends.c | 30 +++++++++++++++ nx/source/services/notif.c | 21 +++++++++++ 7 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 nx/include/switch/services/notif.h create mode 100644 nx/source/services/friends.c create mode 100644 nx/source/services/notif.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 2a6506ae..059f3fea 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -102,6 +102,7 @@ extern "C" { #include "switch/services/pdm.h" #include "switch/services/grc.h" #include "switch/services/friends.h" +#include "switch/services/notif.h" #include "switch/display/binder.h" #include "switch/display/parcel.h" diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index f6276ef6..9b992dd8 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -1478,6 +1478,40 @@ Result appletRestartProgram(const void* buffer, size_t size); */ Result appletGetPreviousProgramIndex(s32 *programIndex); +/** + * @brief Gets an Event which is signaled when a new storage is available with \ref appletTryPopFromFriendInvitationStorageChannel where previously no storage was available, this event is automatically cleared by the system once the last storage is popped. + * @note This is used by \ref friendsGetFriendInvitationNotificationEvent. + * @note Only available with AppletType_*Application on [9.0.0+]. + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=false. + */ +Result appletGetFriendInvitationStorageChannelEvent(Event *out_event); + +/** + * @brief Pops a storage from the FriendInvitation StorageChannel. + * @note This is used by \ref friendsTryPopFriendInvitationNotificationInfo. + * @note Only available with AppletType_*Application on [9.0.0+]. + * @param[out] s Storage object. + */ +Result appletTryPopFromFriendInvitationStorageChannel(AppletStorage *s); + +/** + * @brief Gets an Event which is signaled when a new storage is available with \ref appletTryPopFromNotificationStorageChannel where previously no storage was available, this event is automatically cleared by the system once the last storage is popped. + * @note This is used by \ref notifGetNotificationSystemEvent. + * @note Only available with AppletType_*Application on [9.0.0+]. + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=false. + */ +Result appletGetNotificationStorageChannelEvent(Event *out_event); + +/** + * @brief Pops a storage from the Notification StorageChannel. + * @note This is used by \ref notifTryPopNotifiedApplicationParameter. + * @note Only available with AppletType_*Application on [9.0.0+]. + * @param[out] s Storage object. + */ +Result appletTryPopFromNotificationStorageChannel(AppletStorage *s); + /** * @brief GetHealthWarningDisappearedSystemEvent * @note Only available with AppletType_*Application on [9.0.0+]. @@ -1863,6 +1897,28 @@ Result appletApplicationSetApplicationAttribute(AppletApplication *a, const Appl */ Result appletApplicationHasSaveDataAccessPermission(AppletApplication *a, u64 application_id, bool *out); +/** + * @brief Creates a storage using the specified input then pushes it to the FriendInvitation StorageChannel. + * @note The system will clear the StorageChannel before pushing the storage. + * @note Only available on [9.0.0+]. + * @param a \ref AppletApplication + * @param[in] uid \ref AccountUid + * @param[in] buffer Input buffer. + * @param[in] size Input buffer size. + */ +Result appletPushToFriendInvitationStorageChannel(AppletApplication *a, AccountUid uid, const void* buffer, u64 size); + +/** + * @brief Creates a storage using the specified input then pushes it to the Notification StorageChannel. + * @note The system will clear the StorageChannel before pushing the storage. + * @note Only available on [9.0.0+]. + * @param a \ref AppletApplication + * @param[in] uid \ref AccountUid + * @param[in] buffer Input buffer. + * @param[in] size Input buffer size. + */ +Result appletPushToNotificationStorageChannel(AppletApplication *a, const void* buffer, u64 size); + ///@} ///@name ILibraryAppletSelfAccessor diff --git a/nx/include/switch/services/friends.h b/nx/include/switch/services/friends.h index 5174f81a..36a9a2fd 100644 --- a/nx/include/switch/services/friends.h +++ b/nx/include/switch/services/friends.h @@ -6,6 +6,9 @@ */ #pragma once #include "../types.h" +#include "../kernel/event.h" +#include "../services/applet.h" +#include "../services/acc.h" #include "../sf/service.h" /// InAppScreenName @@ -29,3 +32,23 @@ typedef struct { u64 id; ///< Id. } FriendsFriendInvitationGroupId; +/** + * @brief Gets an Event which is signaled when data is available with \ref friendsTryPopFriendInvitationNotificationInfo. + * @note This is a wrapper for \ref appletGetFriendInvitationStorageChannelEvent, see that for the usage requirements. + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=false. + */ +NX_INLINE Result friendsGetFriendInvitationNotificationEvent(Event *out_event) { + return appletGetFriendInvitationStorageChannelEvent(out_event); +} + +/** + * @brief Uses \ref appletTryPopFromFriendInvitationStorageChannel then reads the data from there into the output params. + * @note This is a wrapper for \ref appletTryPopFromFriendInvitationStorageChannel, see that for the usage requirements. + * @param[out] uid \ref AccountUid. Optional, can be NULL. + * @param[out] buffer Output buffer. + * @param[out] size Output buffer size. + * @param[out] out_size Size of the data which was written into the output buffer. Optional, can be NULL. + */ +Result friendsTryPopFriendInvitationNotificationInfo(AccountUid *uid, void* buffer, u64 size, u64 *out_size); + diff --git a/nx/include/switch/services/notif.h b/nx/include/switch/services/notif.h new file mode 100644 index 00000000..f1d83bb0 --- /dev/null +++ b/nx/include/switch/services/notif.h @@ -0,0 +1,31 @@ +/** + * @file notif.h + * @brief Alarm notification (notif:*) service IPC wrapper. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../kernel/event.h" +#include "../services/applet.h" +#include "../sf/service.h" + +/** + * @brief Gets an Event which is signaled when data is available with \ref notifTryPopNotifiedApplicationParameter. + * @note This is a wrapper for \ref appletGetNotificationStorageChannelEvent, see that for the usage requirements. + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=false. + */ +NX_INLINE Result notifGetNotificationSystemEvent(Event *out_event) { + return appletGetNotificationStorageChannelEvent(out_event); +} + +/** + * @brief Uses \ref appletTryPopFromNotificationStorageChannel then reads the data from there into the output params. + * @note This is a wrapper for \ref appletTryPopFromNotificationStorageChannel, see that for the usage requirements. + * @param[out] buffer Output buffer. + * @param[out] size Output buffer size. + * @param[out] out_size Size of the data which was written into the output buffer. Optional, can be NULL. + */ +Result notifTryPopNotifiedApplicationParameter(void* buffer, u64 size, u64 *out_size); + diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 85a0999f..4681cd80 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -2229,11 +2229,15 @@ Result appletRestartProgram(const void* buffer, size_t size) { return _appletExecuteProgram(AppletProgramSpecifyKind_RestartProgram, 0, buffer, size); } -IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletGetPreviousProgramIndex(s32 *programIndex), &g_appletIFunctions, 123, _appletCmdNoInOutU32, !_appletIsApplication(), (5,0,0), (u32*)programIndex) -IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletGetHealthWarningDisappearedSystemEvent(Event *out_event), &g_appletIFunctions, 160, _appletCmdGetEvent, !_appletIsApplication(), (9,0,0), out_event, false) -IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletSetHdcpAuthenticationActivated(bool flag), &g_appletIFunctions, 170, _appletCmdInBoolNoOut, !_appletIsApplication(), (9,0,0), flag) -IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletCreateMovieMaker(Service* srv_out, TransferMemory *tmem), &g_appletIFunctions, 1000, _appletCmdInTmemOutSession, !_appletIsApplication(), (5,0,0), srv_out, tmem) -IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletPrepareForJit(void), &g_appletIFunctions, 1001, _appletCmdNoIO, !_appletIsApplication(), (5,0,0)) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletGetPreviousProgramIndex(s32 *programIndex), &g_appletIFunctions, 123, _appletCmdNoInOutU32, !_appletIsApplication(), (5,0,0), (u32*)programIndex) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletGetFriendInvitationStorageChannelEvent(Event *out_event), &g_appletIFunctions, 140, _appletCmdGetEvent, !_appletIsApplication(), (9,0,0), out_event, false) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletTryPopFromFriendInvitationStorageChannel(AppletStorage *s), &g_appletIFunctions, 141, _appletCmdNoInOutStorage, !_appletIsApplication(), (9,0,0), s) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletGetNotificationStorageChannelEvent(Event *out_event), &g_appletIFunctions, 150, _appletCmdGetEvent, !_appletIsApplication(), (9,0,0), out_event, false) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletTryPopFromNotificationStorageChannel(AppletStorage *s), &g_appletIFunctions, 151, _appletCmdNoInOutStorage, !_appletIsApplication(), (9,0,0), s) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletGetHealthWarningDisappearedSystemEvent(Event *out_event), &g_appletIFunctions, 160, _appletCmdGetEvent, !_appletIsApplication(), (9,0,0), out_event, false) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletSetHdcpAuthenticationActivated(bool flag), &g_appletIFunctions, 170, _appletCmdInBoolNoOut, !_appletIsApplication(), (9,0,0), flag) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletCreateMovieMaker(Service* srv_out, TransferMemory *tmem), &g_appletIFunctions, 1000, _appletCmdInTmemOutSession, !_appletIsApplication(), (5,0,0), srv_out, tmem) +IPC_MAKE_CMD_IMPL_INITEXPR_HOSVER(Result appletPrepareForJit(void), &g_appletIFunctions, 1001, _appletCmdNoIO, !_appletIsApplication(), (5,0,0)) // IHomeMenuFunctions @@ -2474,6 +2478,41 @@ Result appletApplicationHasSaveDataAccessPermission(AppletApplication *a, u64 ap return rc; } +Result appletPushToFriendInvitationStorageChannel(AppletApplication *a, AccountUid uid, const void* buffer, u64 size) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(9,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + AppletStorage storage; + + rc = appletCreateStorage(&storage, size+sizeof(uid)); + if (R_SUCCEEDED(rc)) rc = appletStorageWrite(&storage, 0, &uid, sizeof(uid)); + if (R_SUCCEEDED(rc)) rc = appletStorageWrite(&storage, sizeof(uid), buffer, size); + if (R_SUCCEEDED(rc)) rc = _appletCmdInStorage(&a->s, &storage, 180); + appletStorageClose(&storage); + + return rc; +} + +Result appletPushToNotificationStorageChannel(AppletApplication *a, const void* buffer, u64 size) { + if (!serviceIsActive(&a->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(9,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + Result rc=0; + AppletStorage storage; + + rc = appletCreateStorage(&storage, size); + if (R_SUCCEEDED(rc)) rc = appletStorageWrite(&storage, 0, buffer, size); + if (R_SUCCEEDED(rc)) rc = _appletCmdInStorage(&a->s, &storage, 190); + appletStorageClose(&storage); + + return rc; +} + // ILibraryAppletSelfAccessor IPC_MAKE_CMD_IMPL_INITEXPR( Result appletPopInData(AppletStorage *s), &g_appletILibraryAppletSelfAccessor, 0, _appletCmdNoInOutStorage, __nx_applet_type != AppletType_LibraryApplet, s) diff --git a/nx/source/services/friends.c b/nx/source/services/friends.c new file mode 100644 index 00000000..4195f203 --- /dev/null +++ b/nx/source/services/friends.c @@ -0,0 +1,30 @@ +#include "service_guard.h" +#include "services/friends.h" + +Result friendsTryPopFriendInvitationNotificationInfo(AccountUid *uid, void* buffer, u64 size, u64 *out_size) { + Result rc=0; + AppletStorage storage; + s64 storage_size=0; + u64 data_size = size; + AccountUid tmpuid={0}; + + rc = appletTryPopFromFriendInvitationStorageChannel(&storage); + if (R_SUCCEEDED(rc)) rc = appletStorageGetSize(&storage, &storage_size); + if (R_SUCCEEDED(rc) && storage_size < sizeof(AccountUid)) rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); + if (R_SUCCEEDED(rc)) { + storage_size-=sizeof(AccountUid); + rc = appletStorageRead(&storage, 0, &tmpuid, sizeof(AccountUid)); + if (R_SUCCEEDED(rc)) { + if (data_size > storage_size) data_size = storage_size; + if (data_size) rc = appletStorageRead(&storage, sizeof(AccountUid), buffer, data_size); + if (R_SUCCEEDED(rc)) { + if (out_size) *out_size = data_size; + if (uid) *uid = tmpuid; + } + } + } + + appletStorageClose(&storage); + return rc; +} + diff --git a/nx/source/services/notif.c b/nx/source/services/notif.c new file mode 100644 index 00000000..c03dd98f --- /dev/null +++ b/nx/source/services/notif.c @@ -0,0 +1,21 @@ +#include "service_guard.h" +#include "services/notif.h" + +Result notifTryPopNotifiedApplicationParameter(void* buffer, u64 size, u64 *out_size) { + Result rc=0; + AppletStorage storage; + s64 storage_size=0; + u64 data_size = size; + + rc = appletTryPopFromNotificationStorageChannel(&storage); + if (R_SUCCEEDED(rc)) rc = appletStorageGetSize(&storage, &storage_size); + if (R_SUCCEEDED(rc)) { + if (data_size > storage_size) data_size = storage_size; + if (data_size) rc = appletStorageRead(&storage, 0, buffer, data_size); + if (R_SUCCEEDED(rc) && out_size) *out_size = data_size; + } + + appletStorageClose(&storage); + return rc; +} +