friend.cpp 12 KB

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