Files
eden/src/core/hle/service/friend/friend.cpp
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

576 lines
25 KiB
C++
Raw Normal View History

// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2018-02-19 17:34:02 -05:00
2019-06-24 12:26:45 +10:00
#include <queue>
#include "common/logging.h"
#include "common/uuid.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
2023-03-06 19:04:12 -05:00
#include "core/hle/service/acc/errors.h"
2018-02-19 17:34:02 -05:00
#include "core/hle/service/friend/friend.h"
#include "core/hle/service/friend/friend_interface.h"
2023-02-19 14:42:12 -05:00
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
2023-02-18 16:26:48 -05:00
#include "core/hle/service/server_manager.h"
2018-02-19 17:34:02 -05:00
namespace Service::Friend {
2018-02-19 17:34:02 -05:00
class IFriendService final : public ServiceFramework<IFriendService> {
public:
explicit IFriendService(Core::System& system_)
2026-09-25 16:26:18 +00:00
: ServiceFramework{system_, "IFriendService"}, service_context{system, "IFriendService"} {
completion_event = service_context.CreateEvent("IFriendService:CompletionEvent");
}
2026-09-25 15:57:13 +00:00
FunctionInfoBase const* FindRequest(u32 key) override {
return HandlerTableGenerateWithFind(key,
2026-09-25 15:53:30 +00:00
FunctionInfo{0, &IFriendService::GetCompletionEvent, "GetCompletionEvent"},
FunctionInfo{1, &IFriendService::Cancel, "Cancel"},
FunctionInfo{10100, nullptr, "GetFriendListIds"},
FunctionInfo{10101, &IFriendService::GetFriendList, "GetFriendList"},
FunctionInfo{10102, nullptr, "UpdateFriendInfo"},
FunctionInfo{10110, nullptr, "GetFriendProfileImage"},
FunctionInfo{10111, nullptr, "GetFriendProfileImageWithImageSize"}, // 18.0.0+
FunctionInfo{10120, &IFriendService::CheckFriendListAvailability, "CheckFriendListAvailability"},
FunctionInfo{10121, nullptr, "EnsureFriendListAvailable"},
FunctionInfo{10200, nullptr, "SendFriendRequestForApplication"},
FunctionInfo{10211, nullptr, "AddFacedFriendRequestForApplication"},
FunctionInfo{10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"},
FunctionInfo{10420, &IFriendService::CheckBlockedUserListAvailability, "CheckBlockedUserListAvailability"},
FunctionInfo{10421, nullptr, "EnsureBlockedUserListAvailable"},
FunctionInfo{10500, nullptr, "GetProfileList"},
FunctionInfo{10501, nullptr, "GetProfileListV2"}, // 18.0.0+
FunctionInfo{10600, nullptr, "DeclareOpenOnlinePlaySession"},
FunctionInfo{10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
FunctionInfo{10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
FunctionInfo{10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"},
FunctionInfo{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
FunctionInfo{10702, nullptr, "AddPlayHistory"},
FunctionInfo{11000, nullptr, "GetProfileImageUrl"},
FunctionInfo{11001, nullptr, "GetProfileImageUrlV2"}, // 18.0.0+
FunctionInfo{20100, &IFriendService::GetFriendCount, "GetFriendCount"},
FunctionInfo{20101, &IFriendService::GetNewlyFriendCount, "GetNewlyFriendCount"},
FunctionInfo{20102, nullptr, "GetFriendDetailedInfo"},
FunctionInfo{20103, nullptr, "SyncFriendList"},
FunctionInfo{20104, &IFriendService::RequestSyncFriendList, "RequestSyncFriendList"},
FunctionInfo{20105, &IFriendService::GetFriendListForViewer, "GetFriendListForViewerV1"},
FunctionInfo{20106, nullptr, "UpdateFriendInfoForViewerV1"},
FunctionInfo{20107, nullptr, "GetFriendDetailedInfoV2"}, // 20.0.0+
FunctionInfo{20108, &IFriendService::GetFriendListForViewer, "GetFriendListForViewerV2"}, // 22.0.0+
FunctionInfo{20109, nullptr, "UpdateFriendInfoForViewerV2"}, // 22.0.0+
FunctionInfo{20110, nullptr, "LoadFriendSettingV1"},
FunctionInfo{20111, nullptr, "LoadFriendSettingV2"}, // 22.0.0+
FunctionInfo{20200, &IFriendService::GetReceivedFriendRequestCount, "GetReceivedFriendRequestCount"},
FunctionInfo{20201, nullptr, "GetFriendRequestListV1"},
FunctionInfo{20202, nullptr, "GetFriendRequestListV2"}, // 20.0.0+
FunctionInfo{20203, nullptr, "GetFriendRequestReceivedNotificationCount"}, // 22.0.0+
FunctionInfo{20300, nullptr, "GetFriendCandidateList"},
FunctionInfo{20301, nullptr, "GetNintendoNetworkIdInfo"},
FunctionInfo{20302, nullptr, "GetSnsAccountLinkage"}, // 5.0.0-19.0.1
FunctionInfo{20303, nullptr, "GetSnsAccountProfile"}, // 5.0.0-19.0.1
FunctionInfo{20304, nullptr, "GetSnsAccountFriendList"}, // 5.0.0-19.0.1
FunctionInfo{20400, nullptr, "GetBlockedUserListV1"},
FunctionInfo{20401, nullptr, "SyncBlockedUserList"},
FunctionInfo{20402, nullptr, "GetBlockedUserListV2"}, // 20.0.0+
FunctionInfo{20500, nullptr, "GetProfileExtraListV1"},
FunctionInfo{20501, nullptr, "GetRelationship"},
FunctionInfo{20502, nullptr, "GetProfileExtraListV2"}, // 19.0.0+
FunctionInfo{20600, &IFriendService::GetUserPresenceView, "GetUserPresenceViewV1"},
FunctionInfo{20601, &IFriendService::GetUserPresenceView, "GetUserPresenceViewV2"}, // 19.0.0+
FunctionInfo{20700, nullptr, "GetPlayHistoryListV1"},
FunctionInfo{20701, &IFriendService::GetPlayHistoryStatistics, "GetPlayHistoryStatistics"},
FunctionInfo{20702, nullptr, "GetPlayHistoryListV2"}, // 19.0.0+
FunctionInfo{20800, &IFriendService::LoadUserSetting, "LoadUserSettingV1"},
FunctionInfo{20801, nullptr, "SyncUserSetting"},
FunctionInfo{20802, &IFriendService::LoadUserSetting, "LoadUserSettingV2"}, // 19.0.0+
FunctionInfo{20900, &IFriendService::RequestListSummaryOverlayNotification, "RequestListSummaryOverlayNotification"},
FunctionInfo{21000, nullptr, "GetExternalApplicationCatalog"},
FunctionInfo{22000, nullptr, "GetReceivedFriendInvitationListV1"},
FunctionInfo{22001, nullptr, "GetReceivedFriendInvitationDetailedInfoV1"},
FunctionInfo{22002, nullptr, "GetReceivedFriendInvitationListV2"}, // 19.0.0+
FunctionInfo{22003, nullptr, "GetReceivedFriendInvitationDetailedInfoV2"}, // 19.0.0+
FunctionInfo{22010, &IFriendService::GetReceivedFriendInvitationCountCache, "GetReceivedFriendInvitationCountCache"},
FunctionInfo{30100, nullptr, "DropFriendNewlyFlags"},
FunctionInfo{30101, nullptr, "DeleteFriend"},
FunctionInfo{30110, nullptr, "DropFriendNewlyFlag"},
FunctionInfo{30120, nullptr, "ChangeFriendFavoriteFlag"},
FunctionInfo{30121, nullptr, "ChangeFriendOnlineNotificationFlag"},
FunctionInfo{30130, nullptr, "SetFriendNote"}, // 22.0.0+
FunctionInfo{30131, nullptr, "RequestUploadPendingNote"}, // 22.0.0+
FunctionInfo{30190, nullptr, "RequestSyncLocalUpdates"}, // 22.0.0+
FunctionInfo{30200, nullptr, "SendFriendRequest"},
FunctionInfo{30201, nullptr, "SendFriendRequestWithApplicationInfoV1"},
FunctionInfo{30202, nullptr, "CancelFriendRequest"},
FunctionInfo{30203, nullptr, "AcceptFriendRequest"},
FunctionInfo{30204, nullptr, "RejectFriendRequest"},
FunctionInfo{30205, nullptr, "ReadFriendRequest"},
FunctionInfo{30210, nullptr, "GetFacedFriendRequestRegistrationKey"},
FunctionInfo{30211, nullptr, "AddFacedFriendRequest"},
FunctionInfo{30212, nullptr, "CancelFacedFriendRequest"},
FunctionInfo{30213, nullptr, "GetFacedFriendRequestProfileImage"},
FunctionInfo{30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"},
FunctionInfo{30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"},
FunctionInfo{30216, nullptr, "ResendFacedFriendRequest"},
FunctionInfo{30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"},
FunctionInfo{30218, nullptr, "SendFriendRequestWithApplicationInfoV2"}, // 20.0.0+
FunctionInfo{30300, nullptr, "GetSnsAccountLinkPageUrl"}, // 5.0.0-19.0.1
FunctionInfo{30301, nullptr, "UnlinkSnsAccount"}, // 5.0.0-19.0.1
FunctionInfo{30400, nullptr, "BlockUser"},
FunctionInfo{30401, nullptr, "BlockUserWithApplicationInfoV1"},
FunctionInfo{30402, nullptr, "UnblockUser"},
FunctionInfo{30403, nullptr, "BlockUserWithApplicationInfoV2"}, // 20.0.0+
FunctionInfo{30500, nullptr, "GetProfileExtraFromFriendCodeV1"},
FunctionInfo{30501, nullptr, "GetProfileExtraFromFriendCodeV2"}, // 19.0.0+
FunctionInfo{30700, nullptr, "DeletePlayHistory"},
FunctionInfo{30701, nullptr, "AddPlayHistoryWithApplication"}, // 19.0.0+
FunctionInfo{30810, nullptr, "ChangePresencePermission"},
FunctionInfo{30811, nullptr, "ChangeFriendRequestReception"},
FunctionInfo{30812, nullptr, "ChangePlayLogPermission"},
FunctionInfo{30820, nullptr, "IssueFriendCode"},
FunctionInfo{30830, nullptr, "ClearPlayLog"},
FunctionInfo{30900, nullptr, "SendFriendInvitationV1"},
FunctionInfo{30901, nullptr, "SendFriendInvitationV2"}, // 19.0.0+
FunctionInfo{30910, nullptr, "ReadFriendInvitation"},
FunctionInfo{30911, nullptr, "ReadAllFriendInvitations"},
FunctionInfo{31000, nullptr, "OpenUser"}, // 19.0.0+
FunctionInfo{40100, nullptr, "DeleteFriendListCache"},
FunctionInfo{40400, nullptr, "DeleteBlockedUserListCache"},
FunctionInfo{49900, nullptr, "DeleteNetworkServiceAccountCache"}
2026-09-25 16:26:18 +00:00
);
}
~IFriendService() override {
service_context.CloseEvent(completion_event);
}
2018-08-11 21:34:14 -04:00
private:
2019-07-09 18:20:58 +10:00
enum class PresenceFilter : u32 {
None = 0,
Online = 1,
OnlinePlay = 2,
OnlineOrOnlinePlay = 3,
};
struct SizedFriendFilter {
PresenceFilter presence;
u8 is_favorite;
u8 same_app;
u8 same_app_played;
2024-01-08 20:31:48 +01:00
u8 arbitrary_app_played;
2019-07-09 18:20:58 +10:00
u64 group_id;
};
static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
struct FriendsUserSetting {
Common::UUID uuid;
u32 presence_permission;
u32 play_log_permission;
u64 friend_request_reception;
char friend_code[0x20];
u64 friend_code_next_issuable_time;
u8 unk_x48[0x7B8];
};
static_assert(sizeof(FriendsUserSetting) == 0x800, "FriendsUserSetting is an invalid size");
2023-02-19 14:42:12 -05:00
void GetCompletionEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
2025-03-26 22:34:43 +00:00
auto& readable_event = completion_event->GetReadableEvent();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(readable_event.Signal(system.Kernel()));
rb.PushCopyObjects(ctx, readable_event);
2025-03-26 22:34:43 +00:00
}
void Cancel(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "(STUBBED) called.");
// TODO (jarrodnorwell)
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetFriendList(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto friend_offset = rp.Pop<u32>();
const auto uuid = rp.PopRaw<Common::UUID>();
[[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
const auto pid = rp.Pop<u64>();
LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
uuid.RawString(), pid);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0); // Friend count
// TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
}
void CheckFriendListAvailability(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid{rp.PopRaw<Common::UUID>()};
LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(true);
}
2023-02-19 14:42:12 -05:00
void GetBlockedUserListIds(HLERequestContext& ctx) {
// This is safe to stub, as there should be no adverse consequences from reporting no
// blocked users.
LOG_WARNING(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0); // Indicates there are no blocked users
}
void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid{rp.PopRaw<Common::UUID>()};
LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(true);
}
2023-02-19 14:42:12 -05:00
void DeclareCloseOnlinePlaySession(HLERequestContext& ctx) {
2018-08-11 21:34:14 -04:00
// Stub used by Splatoon 2
LOG_WARNING(Service_Friend, "(STUBBED) called");
2018-08-11 21:34:14 -04:00
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
2018-08-12 14:00:44 +10:00
}
2023-02-19 14:42:12 -05:00
void UpdateUserPresence(HLERequestContext& ctx) {
2018-08-12 14:00:44 +10:00
// Stub used by Retro City Rampage
LOG_WARNING(Service_Friend, "(STUBBED) called");
2018-08-12 14:00:44 +10:00
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
2018-08-11 21:34:14 -04:00
}
2019-07-09 18:20:58 +10:00
2023-02-19 14:42:12 -05:00
void GetPlayHistoryRegistrationKey(HLERequestContext& ctx) {
2021-03-26 23:13:51 -05:00
IPC::RequestParser rp{ctx};
const auto local_play = rp.Pop<bool>();
const auto uuid = rp.PopRaw<Common::UUID>();
2021-03-26 23:13:51 -05:00
LOG_WARNING(Service_Friend, "(STUBBED) called, local_play={}, uuid=0x{}", local_play,
uuid.RawString());
2021-03-26 23:13:51 -05:00
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
2021-03-26 23:13:51 -05:00
}
void GetFriendCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "(STUBBED) called");
2019-07-09 18:20:58 +10:00
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
2019-07-09 18:20:58 +10:00
}
void GetNewlyFriendCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
2025-03-26 22:34:43 +00:00
void RequestSyncFriendList(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "(STUBBED) called.");
// TODO (jarrodnorwell)
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetFriendListForViewer(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0);
}
void GetReceivedFriendRequestCount(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
[[maybe_unused]] const auto uuid = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(0);
rb.Push(0);
}
2025-03-26 22:34:43 +00:00
void GetUserPresenceView(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_Friend, "(STUBBED) called, uuid={}.", uuid.RawString());
u8 buf[0xe0]{};
ctx.WriteBuffer(buf);
2025-03-26 22:34:43 +00:00
IPC::ResponseBuilder rb{ctx, 3};
2025-03-26 22:34:43 +00:00
rb.Push(ResultSuccess);
}
void GetPlayHistoryStatistics(HLERequestContext& ctx) {
LOG_ERROR(Service_Friend, "(STUBBED) called, check in out");
2023-11-21 01:57:58 +08:00
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void LoadUserSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid = rp.PopRaw<Common::UUID>();
LOG_WARNING(Service_Friend, "(STUBBED) called");
FriendsUserSetting setting{};
setting.uuid = uuid;
setting.presence_permission = 2;
setting.play_log_permission = 5;
setting.friend_request_reception = 1;
setting.friend_code_next_issuable_time = 99999999999;
strcpy(setting.friend_code, "0000-0000-0000");
ctx.WriteBuffer(setting);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void RequestListSummaryOverlayNotification(HLERequestContext& ctx) {
LOG_INFO(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetReceivedFriendInvitationCountCache(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "(STUBBED) called, check in out");
2023-11-21 01:57:58 +08:00
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
2023-11-21 01:57:58 +08:00
}
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* completion_event;
};
2019-06-24 12:26:45 +10:00
class INotificationService final : public ServiceFramework<INotificationService> {
public:
explicit INotificationService(Core::System& system_, Common::UUID uuid_)
2026-09-25 16:26:18 +00:00
: ServiceFramework{system_, "INotificationService"}, uuid{uuid_}
, service_context{system_, "INotificationService"} {
notification_event = service_context.CreateEvent("INotificationService:NotifyEvent");
}
2026-09-25 15:57:13 +00:00
FunctionInfoBase const* FindRequest(u32 key) override {
return HandlerTableGenerateWithFind(key,
2026-09-25 15:53:30 +00:00
FunctionInfo{0, &INotificationService::GetEvent, "GetEvent"},
FunctionInfo{1, &INotificationService::Clear, "Clear"},
FunctionInfo{2, &INotificationService::Pop, "Pop"}
2026-09-25 16:26:18 +00:00
);
}
~INotificationService() override {
service_context.CloseEvent(notification_event);
2019-06-24 12:26:45 +10:00
}
private:
2023-02-19 14:42:12 -05:00
void GetEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
2019-06-24 12:26:45 +10:00
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(ctx, notification_event->GetReadableEvent());
2019-06-24 12:26:45 +10:00
}
2023-02-19 14:42:12 -05:00
void Clear(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
2019-06-24 12:26:45 +10:00
while (!notifications.empty()) {
notifications.pop();
}
2019-06-28 15:29:38 +10:00
std::memset(&states, 0, sizeof(States));
2019-06-24 12:26:45 +10:00
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
2019-06-24 12:26:45 +10:00
}
2023-02-19 14:42:12 -05:00
void Pop(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
2019-06-24 12:26:45 +10:00
if (notifications.empty()) {
LOG_ERROR(Service_Friend, "No notifications in queue!");
IPC::ResponseBuilder rb{ctx, 2};
2023-03-06 19:04:12 -05:00
rb.Push(Account::ResultNoNotifications);
2019-06-24 12:26:45 +10:00
return;
}
2019-06-28 15:29:38 +10:00
const auto notification = notifications.front();
2019-06-24 12:26:45 +10:00
notifications.pop();
switch (notification.notification_type) {
case NotificationTypes::HasUpdatedFriendsList:
states.has_updated_friends = false;
break;
case NotificationTypes::HasReceivedFriendRequest:
states.has_received_friend_request = false;
2019-06-24 12:26:45 +10:00
break;
default:
// HOS seems not have an error case for an unknown notification
LOG_WARNING(Service_Friend, "Unknown notification {:08X}",
notification.notification_type);
2019-06-24 12:26:45 +10:00
break;
}
2019-06-28 15:29:38 +10:00
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw<SizedNotificationInfo>(notification);
2019-06-24 12:26:45 +10:00
}
2019-06-28 15:29:38 +10:00
enum class NotificationTypes : u32 {
2019-06-24 12:26:45 +10:00
HasUpdatedFriendsList = 0x65,
HasReceivedFriendRequest = 0x1
2019-06-24 12:26:45 +10:00
};
struct SizedNotificationInfo {
NotificationTypes notification_type;
INSERT_PADDING_WORDS(
1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now
u64_le account_id;
2019-06-24 12:26:45 +10:00
};
static_assert(sizeof(SizedNotificationInfo) == 0x10,
"SizedNotificationInfo is an incorrect size");
2019-06-24 12:26:45 +10:00
struct States {
bool has_updated_friends;
bool has_received_friend_request;
2019-06-24 12:26:45 +10:00
};
Common::UUID uuid;
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* notification_event;
2019-06-28 15:29:38 +10:00
std::queue<SizedNotificationInfo> notifications;
2019-06-24 12:26:45 +10:00
States states{};
};
2023-02-19 14:42:12 -05:00
void Module::Interface::CreateFriendService(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IFriendService>(ctx, system);
LOG_DEBUG(Service_Friend, "called");
2018-02-19 17:34:02 -05:00
}
2023-02-19 14:42:12 -05:00
void Module::Interface::CreateNotificationService(HLERequestContext& ctx) {
2019-06-24 12:26:45 +10:00
IPC::RequestParser rp{ctx};
auto uuid = rp.PopRaw<Common::UUID>();
2019-06-24 12:26:45 +10:00
LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.RawString());
2019-06-28 15:29:38 +10:00
2019-06-24 12:26:45 +10:00
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INotificationService>(ctx, system, uuid);
2019-06-24 12:26:45 +10:00
}
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, const char* name)
: ServiceFramework{system_, name}, module{std::move(module_)}
{}
2018-02-19 17:34:02 -05:00
Module::Interface::~Interface() = default;
class IServiceForApplication final : public ServiceFramework<IServiceForApplication> {
public:
explicit IServiceForApplication(Core::System& system_)
: ServiceFramework{system_, "nd:app"}
2026-09-25 16:26:18 +00:00
{}
FunctionInfoBase const* FindRequest(u32 key) override {
return HandlerTableGenerateWithFind(key,
2026-09-25 15:53:30 +00:00
FunctionInfo{0, nullptr, "GetReceivableNeighborInfoCountMax"},
FunctionInfo{10, nullptr, "IsNeighborDetectionEnabled"}
2026-09-25 16:26:18 +00:00
);
}
};
class IServiceForSystem final : public ServiceFramework<IServiceForSystem> {
public:
explicit IServiceForSystem(Core::System& system_)
: ServiceFramework{system_, "nd:sys"}
2026-09-25 16:26:18 +00:00
{}
FunctionInfoBase const* FindRequest(u32 key) override {
return HandlerTableGenerateWithFind(key,
2026-09-25 15:53:30 +00:00
FunctionInfo{0, nullptr, "GetReceivableNeighborInfoCountMax"},
FunctionInfo{10, nullptr, "IsNeighborDetectionEnabled"},
FunctionInfo{200, nullptr, "SetSystemData"},
FunctionInfo{201, nullptr, "ClearSystemData"},
FunctionInfo{203, nullptr, "GetReceivableNeighborInfoCountForSystem"},
FunctionInfo{204, nullptr, "ReceiveNeighborInfoForSystem"},
FunctionInfo{205, nullptr, "SetSender"},
FunctionInfo{206, nullptr, "GetSender"},
FunctionInfo{207, nullptr, "CreateScannerForSystem"},
FunctionInfo{208, nullptr, "CreateReceiveEventHolderForSystem"},
FunctionInfo{223, nullptr, "EnableNeighborDetection"},
FunctionInfo{224, nullptr, "DisableNeighborDetection"},
FunctionInfo{226, nullptr, "EnablePowerSave"},
FunctionInfo{227, nullptr, "DisablePowerSave"},
FunctionInfo{228, nullptr, "IsPowerSaveEnabled"},
FunctionInfo{232, nullptr, "ClearBlockedUsers"},
FunctionInfo{233, nullptr, "GetBlockedUserCount"},
FunctionInfo{234, nullptr, "BlockUserByLocalUserId"},
FunctionInfo{235, nullptr, "BlockUserByNetworkUserId"},
FunctionInfo{236, nullptr, "UnblockUserByLocalUserId"},
FunctionInfo{237, nullptr, "UnblockUserByNetworkUserId"},
FunctionInfo{240, nullptr, "DeleteApplication"},
FunctionInfo{250, nullptr, "InitializeApplicationInfo"},
FunctionInfo{260, nullptr, "CreateAccountSystemSaveDataAccessSuppressor"},
FunctionInfo{300, nullptr, "AddReceivedNeighborInfoForSystemForDebug"},
FunctionInfo{301, nullptr, "GetSendDataForDebug"},
FunctionInfo{302, nullptr, "ClearReceiveCounterForDebug"},
FunctionInfo{303, nullptr, "GetNextReceiveCounterForDebug"},
FunctionInfo{304, nullptr, "ListBlockedUsersForDebug"},
FunctionInfo{305, nullptr, "RefreshSendDataIdForDebug"},
FunctionInfo{306, nullptr, "ReloadFwdbgSettingsForDebug"},
FunctionInfo{307, nullptr, "EnableApplicationForDebug"},
FunctionInfo{308, nullptr, "GetNextReceiveCountersForDebug"},
FunctionInfo{309, nullptr, "ListApplicationInfoForDebug"},
FunctionInfo{310, nullptr, "SetApplicationDataForDebug"},
FunctionInfo{400, nullptr, "GetNetworkUserId"},
FunctionInfo{401, nullptr, "DeleteNetworkUserId"}
2026-09-25 16:26:18 +00:00
);
}
};
2023-02-18 16:26:48 -05:00
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
2018-02-19 17:34:02 -05:00
auto module = std::make_shared<Module>();
2023-02-18 16:26:48 -05:00
server_manager->RegisterNamedService("nd:app", std::make_shared<IServiceForApplication>(system));
server_manager->RegisterNamedService("nd:sys", std::make_shared<IServiceForSystem>(system));
server_manager->RegisterNamedService("friend:a", std::make_shared<Friend>(module, system, "friend:a"));
server_manager->RegisterNamedService("friend:m", std::make_shared<Friend>(module, system, "friend:m"));
server_manager->RegisterNamedService("friend:s", std::make_shared<Friend>(module, system, "friend:s"));
server_manager->RegisterNamedService("friend:u", std::make_shared<Friend>(module, system, "friend:u"));
server_manager->RegisterNamedService("friend:v", std::make_shared<Friend>(module, system, "friend:v"));
2023-02-18 16:26:48 -05:00
ServerManager::RunServer(std::move(server_manager));
2018-02-19 17:34:02 -05:00
}
} // namespace Service::Friend