friend.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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/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, &IFriendService::GetPlayHistoryRegistrationKey, "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_Friend, "(STUBBED) called");
  130. IPC::ResponseBuilder rb{ctx, 3};
  131. rb.Push(ResultSuccess);
  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_Friend, "(STUBBED) called");
  137. IPC::ResponseBuilder rb{ctx, 2};
  138. rb.Push(ResultSuccess);
  139. }
  140. void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
  141. // Stub used by Retro City Rampage
  142. LOG_WARNING(Service_Friend, "(STUBBED) called");
  143. IPC::ResponseBuilder rb{ctx, 2};
  144. rb.Push(ResultSuccess);
  145. }
  146. void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
  147. IPC::RequestParser rp{ctx};
  148. const auto local_play = rp.Pop<bool>();
  149. const auto uuid = rp.PopRaw<Common::UUID>();
  150. LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play,
  151. uuid.Format());
  152. IPC::ResponseBuilder rb{ctx, 2};
  153. rb.Push(ResultSuccess);
  154. }
  155. void GetFriendList(Kernel::HLERequestContext& ctx) {
  156. IPC::RequestParser rp{ctx};
  157. const auto friend_offset = rp.Pop<u32>();
  158. const auto uuid = rp.PopRaw<Common::UUID>();
  159. [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
  160. const auto pid = rp.Pop<u64>();
  161. LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset,
  162. uuid.Format(), pid);
  163. IPC::ResponseBuilder rb{ctx, 3};
  164. rb.Push(ResultSuccess);
  165. rb.Push<u32>(0); // Friend count
  166. // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
  167. }
  168. };
  169. class INotificationService final : public ServiceFramework<INotificationService> {
  170. public:
  171. explicit INotificationService(Common::UUID uuid_, Core::System& system_)
  172. : ServiceFramework{system_, "INotificationService"}, uuid{uuid_}, notification_event{
  173. system.Kernel()} {
  174. // clang-format off
  175. static const FunctionInfo functions[] = {
  176. {0, &INotificationService::GetEvent, "GetEvent"},
  177. {1, &INotificationService::Clear, "Clear"},
  178. {2, &INotificationService::Pop, "Pop"}
  179. };
  180. // clang-format on
  181. RegisterHandlers(functions);
  182. Kernel::KAutoObject::Create(std::addressof(notification_event));
  183. notification_event.Initialize("INotificationService:NotifyEvent");
  184. }
  185. private:
  186. void GetEvent(Kernel::HLERequestContext& ctx) {
  187. LOG_DEBUG(Service_Friend, "called");
  188. IPC::ResponseBuilder rb{ctx, 2, 1};
  189. rb.Push(ResultSuccess);
  190. rb.PushCopyObjects(notification_event.GetReadableEvent());
  191. }
  192. void Clear(Kernel::HLERequestContext& ctx) {
  193. LOG_DEBUG(Service_Friend, "called");
  194. while (!notifications.empty()) {
  195. notifications.pop();
  196. }
  197. std::memset(&states, 0, sizeof(States));
  198. IPC::ResponseBuilder rb{ctx, 2};
  199. rb.Push(ResultSuccess);
  200. }
  201. void Pop(Kernel::HLERequestContext& ctx) {
  202. LOG_DEBUG(Service_Friend, "called");
  203. if (notifications.empty()) {
  204. LOG_ERROR(Service_Friend, "No notifications in queue!");
  205. IPC::ResponseBuilder rb{ctx, 2};
  206. rb.Push(ERR_NO_NOTIFICATIONS);
  207. return;
  208. }
  209. const auto notification = notifications.front();
  210. notifications.pop();
  211. switch (notification.notification_type) {
  212. case NotificationTypes::HasUpdatedFriendsList:
  213. states.has_updated_friends = false;
  214. break;
  215. case NotificationTypes::HasReceivedFriendRequest:
  216. states.has_received_friend_request = false;
  217. break;
  218. default:
  219. // HOS seems not have an error case for an unknown notification
  220. LOG_WARNING(Service_Friend, "Unknown notification {:08X}",
  221. notification.notification_type);
  222. break;
  223. }
  224. IPC::ResponseBuilder rb{ctx, 6};
  225. rb.Push(ResultSuccess);
  226. rb.PushRaw<SizedNotificationInfo>(notification);
  227. }
  228. enum class NotificationTypes : u32 {
  229. HasUpdatedFriendsList = 0x65,
  230. HasReceivedFriendRequest = 0x1
  231. };
  232. struct SizedNotificationInfo {
  233. NotificationTypes notification_type;
  234. INSERT_PADDING_WORDS(
  235. 1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now
  236. u64_le account_id;
  237. };
  238. static_assert(sizeof(SizedNotificationInfo) == 0x10,
  239. "SizedNotificationInfo is an incorrect size");
  240. struct States {
  241. bool has_updated_friends;
  242. bool has_received_friend_request;
  243. };
  244. Common::UUID uuid{Common::INVALID_UUID};
  245. Kernel::KEvent notification_event;
  246. std::queue<SizedNotificationInfo> notifications;
  247. States states{};
  248. };
  249. void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
  250. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  251. rb.Push(ResultSuccess);
  252. rb.PushIpcInterface<IFriendService>(system);
  253. LOG_DEBUG(Service_Friend, "called");
  254. }
  255. void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
  256. IPC::RequestParser rp{ctx};
  257. auto uuid = rp.PopRaw<Common::UUID>();
  258. LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format());
  259. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  260. rb.Push(ResultSuccess);
  261. rb.PushIpcInterface<INotificationService>(uuid, system);
  262. }
  263. Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
  264. const char* name)
  265. : ServiceFramework{system_, name}, module{std::move(module_)} {}
  266. Module::Interface::~Interface() = default;
  267. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  268. auto module = std::make_shared<Module>();
  269. std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager);
  270. std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager);
  271. std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager);
  272. std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager);
  273. std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager);
  274. }
  275. } // namespace Service::Friend