friend.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <queue>
  5. #include "common/logging/log.h"
  6. #include "common/uuid.h"
  7. #include "core/core.h"
  8. #include "core/hle/ipc_helpers.h"
  9. #include "core/hle/kernel/k_event.h"
  10. #include "core/hle/kernel/k_readable_event.h"
  11. #include "core/hle/kernel/k_writable_event.h"
  12. #include "core/hle/service/friend/errors.h"
  13. #include "core/hle/service/friend/friend.h"
  14. #include "core/hle/service/friend/interface.h"
  15. namespace Service::Friend {
  16. class IFriendService final : public ServiceFramework<IFriendService> {
  17. public:
  18. explicit IFriendService(Core::System& system_) : ServiceFramework{system_, "IFriendService"} {
  19. // clang-format off
  20. static const FunctionInfo functions[] = {
  21. {0, nullptr, "GetCompletionEvent"},
  22. {1, nullptr, "Cancel"},
  23. {10100, nullptr, "GetFriendListIds"},
  24. {10101, &IFriendService::GetFriendList, "GetFriendList"},
  25. {10102, nullptr, "UpdateFriendInfo"},
  26. {10110, nullptr, "GetFriendProfileImage"},
  27. {10120, nullptr, "Unknown10120"},
  28. {10121, nullptr, "Unknown10121"},
  29. {10200, nullptr, "SendFriendRequestForApplication"},
  30. {10211, nullptr, "AddFacedFriendRequestForApplication"},
  31. {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"},
  32. {10420, nullptr, "Unknown10420"},
  33. {10421, nullptr, "Unknown10421"},
  34. {10500, nullptr, "GetProfileList"},
  35. {10600, nullptr, "DeclareOpenOnlinePlaySession"},
  36. {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
  37. {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
  38. {10700, nullptr, "GetPlayHistoryRegistrationKey"},
  39. {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
  40. {10702, nullptr, "AddPlayHistory"},
  41. {11000, nullptr, "GetProfileImageUrl"},
  42. {20100, nullptr, "GetFriendCount"},
  43. {20101, nullptr, "GetNewlyFriendCount"},
  44. {20102, nullptr, "GetFriendDetailedInfo"},
  45. {20103, nullptr, "SyncFriendList"},
  46. {20104, nullptr, "RequestSyncFriendList"},
  47. {20110, nullptr, "LoadFriendSetting"},
  48. {20200, nullptr, "GetReceivedFriendRequestCount"},
  49. {20201, nullptr, "GetFriendRequestList"},
  50. {20300, nullptr, "GetFriendCandidateList"},
  51. {20301, nullptr, "GetNintendoNetworkIdInfo"},
  52. {20302, nullptr, "GetSnsAccountLinkage"},
  53. {20303, nullptr, "GetSnsAccountProfile"},
  54. {20304, nullptr, "GetSnsAccountFriendList"},
  55. {20400, nullptr, "GetBlockedUserList"},
  56. {20401, nullptr, "SyncBlockedUserList"},
  57. {20500, nullptr, "GetProfileExtraList"},
  58. {20501, nullptr, "GetRelationship"},
  59. {20600, nullptr, "GetUserPresenceView"},
  60. {20700, nullptr, "GetPlayHistoryList"},
  61. {20701, nullptr, "GetPlayHistoryStatistics"},
  62. {20800, nullptr, "LoadUserSetting"},
  63. {20801, nullptr, "SyncUserSetting"},
  64. {20900, nullptr, "RequestListSummaryOverlayNotification"},
  65. {21000, nullptr, "GetExternalApplicationCatalog"},
  66. {22000, nullptr, "GetReceivedFriendInvitationList"},
  67. {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"},
  68. {22010, nullptr, "GetReceivedFriendInvitationCountCache"},
  69. {30100, nullptr, "DropFriendNewlyFlags"},
  70. {30101, nullptr, "DeleteFriend"},
  71. {30110, nullptr, "DropFriendNewlyFlag"},
  72. {30120, nullptr, "ChangeFriendFavoriteFlag"},
  73. {30121, nullptr, "ChangeFriendOnlineNotificationFlag"},
  74. {30200, nullptr, "SendFriendRequest"},
  75. {30201, nullptr, "SendFriendRequestWithApplicationInfo"},
  76. {30202, nullptr, "CancelFriendRequest"},
  77. {30203, nullptr, "AcceptFriendRequest"},
  78. {30204, nullptr, "RejectFriendRequest"},
  79. {30205, nullptr, "ReadFriendRequest"},
  80. {30210, nullptr, "GetFacedFriendRequestRegistrationKey"},
  81. {30211, nullptr, "AddFacedFriendRequest"},
  82. {30212, nullptr, "CancelFacedFriendRequest"},
  83. {30213, nullptr, "GetFacedFriendRequestProfileImage"},
  84. {30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"},
  85. {30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"},
  86. {30216, nullptr, "ResendFacedFriendRequest"},
  87. {30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"},
  88. {30300, nullptr, "GetSnsAccountLinkPageUrl"},
  89. {30301, nullptr, "UnlinkSnsAccount"},
  90. {30400, nullptr, "BlockUser"},
  91. {30401, nullptr, "BlockUserWithApplicationInfo"},
  92. {30402, nullptr, "UnblockUser"},
  93. {30500, nullptr, "GetProfileExtraFromFriendCode"},
  94. {30700, nullptr, "DeletePlayHistory"},
  95. {30810, nullptr, "ChangePresencePermission"},
  96. {30811, nullptr, "ChangeFriendRequestReception"},
  97. {30812, nullptr, "ChangePlayLogPermission"},
  98. {30820, nullptr, "IssueFriendCode"},
  99. {30830, nullptr, "ClearPlayLog"},
  100. {30900, nullptr, "SendFriendInvitation"},
  101. {30910, nullptr, "ReadFriendInvitation"},
  102. {30911, nullptr, "ReadAllFriendInvitations"},
  103. {40100, nullptr, "Unknown40100"},
  104. {40400, nullptr, "Unknown40400"},
  105. {49900, nullptr, "DeleteNetworkServiceAccountCache"},
  106. };
  107. // clang-format on
  108. RegisterHandlers(functions);
  109. }
  110. private:
  111. enum class PresenceFilter : u32 {
  112. None = 0,
  113. Online = 1,
  114. OnlinePlay = 2,
  115. OnlineOrOnlinePlay = 3,
  116. };
  117. struct SizedFriendFilter {
  118. PresenceFilter presence;
  119. u8 is_favorite;
  120. u8 same_app;
  121. u8 same_app_played;
  122. u8 arbitary_app_played;
  123. u64 group_id;
  124. };
  125. static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
  126. void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) {
  127. // This is safe to stub, as there should be no adverse consequences from reporting no
  128. // blocked users.
  129. LOG_WARNING(Service_ACC, "(STUBBED) called");
  130. IPC::ResponseBuilder rb{ctx, 3};
  131. rb.Push(RESULT_SUCCESS);
  132. rb.Push<u32>(0); // Indicates there are no blocked users
  133. }
  134. void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
  135. // Stub used by Splatoon 2
  136. LOG_WARNING(Service_ACC, "(STUBBED) called");
  137. IPC::ResponseBuilder rb{ctx, 2};
  138. rb.Push(RESULT_SUCCESS);
  139. }
  140. void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
  141. // Stub used by Retro City Rampage
  142. LOG_WARNING(Service_ACC, "(STUBBED) called");
  143. IPC::ResponseBuilder rb{ctx, 2};
  144. rb.Push(RESULT_SUCCESS);
  145. }
  146. void GetFriendList(Kernel::HLERequestContext& ctx) {
  147. IPC::RequestParser rp{ctx};
  148. const auto friend_offset = rp.Pop<u32>();
  149. const auto uuid = rp.PopRaw<Common::UUID>();
  150. [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
  151. const auto pid = rp.Pop<u64>();
  152. LOG_WARNING(Service_ACC, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
  153. uuid.Format(), pid);
  154. IPC::ResponseBuilder rb{ctx, 3};
  155. rb.Push(RESULT_SUCCESS);
  156. rb.Push<u32>(0); // Friend count
  157. // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
  158. }
  159. };
  160. class INotificationService final : public ServiceFramework<INotificationService> {
  161. public:
  162. explicit INotificationService(Common::UUID uuid_, Core::System& system_)
  163. : ServiceFramework{system_, "INotificationService"}, uuid{uuid_} {
  164. // clang-format off
  165. static const FunctionInfo functions[] = {
  166. {0, &INotificationService::GetEvent, "GetEvent"},
  167. {1, &INotificationService::Clear, "Clear"},
  168. {2, &INotificationService::Pop, "Pop"}
  169. };
  170. // clang-format on
  171. RegisterHandlers(functions);
  172. notification_event =
  173. Kernel::KEvent::Create(system.Kernel(), "INotificationService:NotifyEvent");
  174. notification_event->Initialize();
  175. }
  176. private:
  177. void GetEvent(Kernel::HLERequestContext& ctx) {
  178. LOG_DEBUG(Service_ACC, "called");
  179. IPC::ResponseBuilder rb{ctx, 2, 1};
  180. rb.Push(RESULT_SUCCESS);
  181. rb.PushCopyObjects(notification_event->GetReadableEvent());
  182. }
  183. void Clear(Kernel::HLERequestContext& ctx) {
  184. LOG_DEBUG(Service_ACC, "called");
  185. while (!notifications.empty()) {
  186. notifications.pop();
  187. }
  188. std::memset(&states, 0, sizeof(States));
  189. IPC::ResponseBuilder rb{ctx, 2};
  190. rb.Push(RESULT_SUCCESS);
  191. }
  192. void Pop(Kernel::HLERequestContext& ctx) {
  193. LOG_DEBUG(Service_ACC, "called");
  194. if (notifications.empty()) {
  195. LOG_ERROR(Service_ACC, "No notifications in queue!");
  196. IPC::ResponseBuilder rb{ctx, 2};
  197. rb.Push(ERR_NO_NOTIFICATIONS);
  198. return;
  199. }
  200. const auto notification = notifications.front();
  201. notifications.pop();
  202. switch (notification.notification_type) {
  203. case NotificationTypes::HasUpdatedFriendsList:
  204. states.has_updated_friends = false;
  205. break;
  206. case NotificationTypes::HasReceivedFriendRequest:
  207. states.has_received_friend_request = false;
  208. break;
  209. default:
  210. // HOS seems not have an error case for an unknown notification
  211. LOG_WARNING(Service_ACC, "Unknown notification {:08X}", notification.notification_type);
  212. break;
  213. }
  214. IPC::ResponseBuilder rb{ctx, 6};
  215. rb.Push(RESULT_SUCCESS);
  216. rb.PushRaw<SizedNotificationInfo>(notification);
  217. }
  218. enum class NotificationTypes : u32 {
  219. HasUpdatedFriendsList = 0x65,
  220. HasReceivedFriendRequest = 0x1
  221. };
  222. struct SizedNotificationInfo {
  223. NotificationTypes notification_type;
  224. INSERT_PADDING_WORDS(
  225. 1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now
  226. u64_le account_id;
  227. };
  228. static_assert(sizeof(SizedNotificationInfo) == 0x10,
  229. "SizedNotificationInfo is an incorrect size");
  230. struct States {
  231. bool has_updated_friends;
  232. bool has_received_friend_request;
  233. };
  234. Common::UUID uuid{Common::INVALID_UUID};
  235. std::shared_ptr<Kernel::KEvent> notification_event;
  236. std::queue<SizedNotificationInfo> notifications;
  237. States states{};
  238. };
  239. void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
  240. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  241. rb.Push(RESULT_SUCCESS);
  242. rb.PushIpcInterface<IFriendService>(system);
  243. LOG_DEBUG(Service_ACC, "called");
  244. }
  245. void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
  246. IPC::RequestParser rp{ctx};
  247. auto uuid = rp.PopRaw<Common::UUID>();
  248. LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format());
  249. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  250. rb.Push(RESULT_SUCCESS);
  251. rb.PushIpcInterface<INotificationService>(uuid, system);
  252. }
  253. Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
  254. const char* name)
  255. : ServiceFramework{system_, name}, module{std::move(module_)} {}
  256. Module::Interface::~Interface() = default;
  257. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  258. auto module = std::make_shared<Module>();
  259. std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager);
  260. std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager);
  261. std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager);
  262. std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager);
  263. std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager);
  264. }
  265. } // namespace Service::Friend