friend.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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, nullptr, "GetFriendList"},
  23. {10102, nullptr, "UpdateFriendInfo"},
  24. {10110, nullptr, "GetFriendProfileImage"},
  25. {10200, nullptr, "SendFriendRequestForApplication"},
  26. {10211, nullptr, "AddFacedFriendRequestForApplication"},
  27. {10400, nullptr, "GetBlockedUserListIds"},
  28. {10500, nullptr, "GetProfileList"},
  29. {10600, nullptr, "DeclareOpenOnlinePlaySession"},
  30. {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
  31. {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
  32. {10700, nullptr, "GetPlayHistoryRegistrationKey"},
  33. {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
  34. {10702, nullptr, "AddPlayHistory"},
  35. {11000, nullptr, "GetProfileImageUrl"},
  36. {20100, nullptr, "GetFriendCount"},
  37. {20101, nullptr, "GetNewlyFriendCount"},
  38. {20102, nullptr, "GetFriendDetailedInfo"},
  39. {20103, nullptr, "SyncFriendList"},
  40. {20104, nullptr, "RequestSyncFriendList"},
  41. {20110, nullptr, "LoadFriendSetting"},
  42. {20200, nullptr, "GetReceivedFriendRequestCount"},
  43. {20201, nullptr, "GetFriendRequestList"},
  44. {20300, nullptr, "GetFriendCandidateList"},
  45. {20301, nullptr, "GetNintendoNetworkIdInfo"},
  46. {20302, nullptr, "GetSnsAccountLinkage"},
  47. {20303, nullptr, "GetSnsAccountProfile"},
  48. {20304, nullptr, "GetSnsAccountFriendList"},
  49. {20400, nullptr, "GetBlockedUserList"},
  50. {20401, nullptr, "SyncBlockedUserList"},
  51. {20500, nullptr, "GetProfileExtraList"},
  52. {20501, nullptr, "GetRelationship"},
  53. {20600, nullptr, "GetUserPresenceView"},
  54. {20700, nullptr, "GetPlayHistoryList"},
  55. {20701, nullptr, "GetPlayHistoryStatistics"},
  56. {20800, nullptr, "LoadUserSetting"},
  57. {20801, nullptr, "SyncUserSetting"},
  58. {20900, nullptr, "RequestListSummaryOverlayNotification"},
  59. {21000, nullptr, "GetExternalApplicationCatalog"},
  60. {30100, nullptr, "DropFriendNewlyFlags"},
  61. {30101, nullptr, "DeleteFriend"},
  62. {30110, nullptr, "DropFriendNewlyFlag"},
  63. {30120, nullptr, "ChangeFriendFavoriteFlag"},
  64. {30121, nullptr, "ChangeFriendOnlineNotificationFlag"},
  65. {30200, nullptr, "SendFriendRequest"},
  66. {30201, nullptr, "SendFriendRequestWithApplicationInfo"},
  67. {30202, nullptr, "CancelFriendRequest"},
  68. {30203, nullptr, "AcceptFriendRequest"},
  69. {30204, nullptr, "RejectFriendRequest"},
  70. {30205, nullptr, "ReadFriendRequest"},
  71. {30210, nullptr, "GetFacedFriendRequestRegistrationKey"},
  72. {30211, nullptr, "AddFacedFriendRequest"},
  73. {30212, nullptr, "CancelFacedFriendRequest"},
  74. {30213, nullptr, "GetFacedFriendRequestProfileImage"},
  75. {30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"},
  76. {30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"},
  77. {30216, nullptr, "ResendFacedFriendRequest"},
  78. {30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"},
  79. {30300, nullptr, "GetSnsAccountLinkPageUrl"},
  80. {30301, nullptr, "UnlinkSnsAccount"},
  81. {30400, nullptr, "BlockUser"},
  82. {30401, nullptr, "BlockUserWithApplicationInfo"},
  83. {30402, nullptr, "UnblockUser"},
  84. {30500, nullptr, "GetProfileExtraFromFriendCode"},
  85. {30700, nullptr, "DeletePlayHistory"},
  86. {30810, nullptr, "ChangePresencePermission"},
  87. {30811, nullptr, "ChangeFriendRequestReception"},
  88. {30812, nullptr, "ChangePlayLogPermission"},
  89. {30820, nullptr, "IssueFriendCode"},
  90. {30830, nullptr, "ClearPlayLog"},
  91. {49900, nullptr, "DeleteNetworkServiceAccountCache"},
  92. };
  93. // clang-format on
  94. RegisterHandlers(functions);
  95. }
  96. private:
  97. void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
  98. // Stub used by Splatoon 2
  99. LOG_WARNING(Service_ACC, "(STUBBED) called");
  100. IPC::ResponseBuilder rb{ctx, 2};
  101. rb.Push(RESULT_SUCCESS);
  102. }
  103. void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
  104. // Stub used by Retro City Rampage
  105. LOG_WARNING(Service_ACC, "(STUBBED) called");
  106. IPC::ResponseBuilder rb{ctx, 2};
  107. rb.Push(RESULT_SUCCESS);
  108. }
  109. };
  110. class INotificationService final : public ServiceFramework<INotificationService> {
  111. public:
  112. INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) {
  113. // clang-format off
  114. static const FunctionInfo functions[] = {
  115. {0, &INotificationService::GetEvent, "GetEvent"},
  116. {1, &INotificationService::Clear, "Clear"},
  117. {2, &INotificationService::Pop, "Pop"}
  118. };
  119. // clang-format on
  120. RegisterHandlers(functions);
  121. }
  122. private:
  123. void GetEvent(Kernel::HLERequestContext& ctx) {
  124. LOG_DEBUG(Service_ACC, "called");
  125. IPC::ResponseBuilder rb{ctx, 2, 1};
  126. rb.Push(RESULT_SUCCESS);
  127. if (is_event_created) {
  128. rb.PushCopyObjects(notification_event.readable);
  129. } else {
  130. auto& kernel = Core::System::GetInstance().Kernel();
  131. notification_event = Kernel::WritableEvent::CreateEventPair(
  132. kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent");
  133. is_event_created = true;
  134. rb.PushCopyObjects(notification_event.readable);
  135. }
  136. }
  137. void Clear(Kernel::HLERequestContext& ctx) {
  138. LOG_DEBUG(Service_ACC, "called");
  139. while (!notifications.empty()) {
  140. notifications.pop();
  141. }
  142. states.has_received_friend_request = false;
  143. states.has_updated_friends = false;
  144. IPC::ResponseBuilder rb{ctx, 2};
  145. rb.Push(RESULT_SUCCESS);
  146. }
  147. void Pop(Kernel::HLERequestContext& ctx) {
  148. LOG_DEBUG(Service_ACC, "called");
  149. if (notifications.empty()) {
  150. LOG_ERROR(Service_ACC, "No notifications in queue!");
  151. IPC::ResponseBuilder rb{ctx, 2};
  152. rb.Push(ERR_NO_NOTIFICATIONS);
  153. return;
  154. }
  155. IPC::ResponseBuilder rb{ctx, 6};
  156. auto notification = notifications.front();
  157. notifications.pop();
  158. switch (notification.notification_type) {
  159. case NotificationTypes::HasUpdatedFriendsList:
  160. states.has_updated_friends = false;
  161. break;
  162. case NotificationTypes::HasReceivedFriendRequest:
  163. states.has_received_friend_request = false;
  164. break;
  165. default:
  166. // HOS seems not have an error case for an unknown notification
  167. LOG_WARNING(Service_ACC, "Unknown notification {:08X}",
  168. static_cast<u32>(notification.notification_type));
  169. break;
  170. }
  171. rb.Push(RESULT_SUCCESS);
  172. rb.PushRaw<SizedNotificationInfo>(notification);
  173. }
  174. enum class NotificationTypes : u32_le {
  175. HasUpdatedFriendsList = 0x65,
  176. HasReceivedFriendRequest = 0x1
  177. };
  178. struct SizedNotificationInfo {
  179. NotificationTypes notification_type;
  180. INSERT_PADDING_WORDS(
  181. 1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now
  182. Common::UUID user_uuid;
  183. };
  184. struct States {
  185. bool has_updated_friends;
  186. bool has_received_friend_request;
  187. };
  188. Common::UUID uuid{};
  189. bool is_event_created = false;
  190. Kernel::EventPair notification_event;
  191. std::queue<SizedNotificationInfo> notifications{};
  192. States states{};
  193. };
  194. void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
  195. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  196. rb.Push(RESULT_SUCCESS);
  197. rb.PushIpcInterface<IFriendService>();
  198. LOG_DEBUG(Service_ACC, "called");
  199. }
  200. void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
  201. IPC::RequestParser rp{ctx};
  202. auto uuid = rp.PopRaw<Common::UUID>();
  203. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  204. rb.Push(RESULT_SUCCESS);
  205. rb.PushIpcInterface<INotificationService>(uuid);
  206. LOG_DEBUG(Service_ACC, "called");
  207. }
  208. Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
  209. : ServiceFramework(name), module(std::move(module)) {}
  210. Module::Interface::~Interface() = default;
  211. void InstallInterfaces(SM::ServiceManager& service_manager) {
  212. auto module = std::make_shared<Module>();
  213. std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager);
  214. std::make_shared<Friend>(module, "friend:m")->InstallAsService(service_manager);
  215. std::make_shared<Friend>(module, "friend:s")->InstallAsService(service_manager);
  216. std::make_shared<Friend>(module, "friend:u")->InstallAsService(service_manager);
  217. std::make_shared<Friend>(module, "friend:v")->InstallAsService(service_manager);
  218. }
  219. } // namespace Service::Friend