friend.cpp 12 KB

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