From 81d988b0225c91dfda6f73a60d2a2b9b4db37ba1 Mon Sep 17 00:00:00 2001
From: mailwl <mailwl@gmail.com>
Date: Tue, 1 Mar 2016 20:41:40 +0300
Subject: [PATCH] frd:u: Initial stub some functions

---
 src/common/logging/backend.cpp     |   1 +
 src/common/logging/log.h           |   1 +
 src/core/hle/service/frd/frd.cpp   |  91 ++++++++++++++++++++++++
 src/core/hle/service/frd/frd.h     |  88 ++++++++++++++++++++++++
 src/core/hle/service/frd/frd_u.cpp | 107 +++++++++++++++--------------
 src/core/hle/service/service.cpp   |   3 +-
 6 files changed, 236 insertions(+), 55 deletions(-)

diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 4c86151ab..757e0cf47 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -34,6 +34,7 @@ namespace Log {
         SUB(Kernel, SVC) \
         CLS(Service) \
         SUB(Service, SRV) \
+        SUB(Service, FRD) \
         SUB(Service, FS) \
         SUB(Service, ERR) \
         SUB(Service, APT) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index e4c39c308..4da4831c3 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -49,6 +49,7 @@ enum class Class : ClassType {
     Service,                    ///< HLE implementation of system services. Each major service
                                 ///  should have its own subclass.
     Service_SRV,                ///< The SRV (Service Directory) implementation
+    Service_FRD,                ///< The FRD (Friends) service
     Service_FS,                 ///< The FS (Filesystem) service implementation
     Service_ERR,                ///< The ERR (Error) port implementation
     Service_APT,                ///< The APT (Applets) service
diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp
index c13ffd9d2..15d604bb6 100644
--- a/src/core/hle/service/frd/frd.cpp
+++ b/src/core/hle/service/frd/frd.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/string_util.h"
+
 #include "core/hle/service/service.h"
 #include "core/hle/service/frd/frd.h"
 #include "core/hle/service/frd/frd_a.h"
@@ -10,6 +12,95 @@
 namespace Service {
 namespace FRD {
 
+static FriendKey my_friend_key = {0, 0, 0ull};
+static MyPresence my_presence = {};
+
+void GetMyPresence(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    u32 shifted_out_size = cmd_buff[64];
+    u32 my_presence_addr = cmd_buff[65];
+
+    ASSERT(shifted_out_size == ((sizeof(MyPresence) << 14) | 2));
+
+    Memory::WriteBlock(my_presence_addr, reinterpret_cast<const u8*>(&my_presence), sizeof(MyPresence));
+
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+    LOG_WARNING(Service_FRD, "(STUBBED) called");
+}
+
+void GetFriendKeyList(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    u32 unknown = cmd_buff[1];
+    u32 frd_count = cmd_buff[2];
+    u32 frd_key_addr = cmd_buff[65];
+
+    FriendKey zero_key = {};
+    for (u32 i = 0; i < frd_count; ++i) {
+        Memory::WriteBlock(frd_key_addr + i * sizeof(FriendKey),
+                           reinterpret_cast<const u8*>(&zero_key), sizeof(FriendKey));
+    }
+
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = 0; // 0 friends
+    LOG_WARNING(Service_FRD, "(STUBBED) called, unknown=%d, frd_count=%d, frd_key_addr=0x%08X",
+                unknown, frd_count, frd_key_addr);
+}
+
+void GetFriendProfile(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    u32 count = cmd_buff[1];
+    u32 frd_key_addr = cmd_buff[3];
+    u32 profiles_addr = cmd_buff[65];
+
+    Profile zero_profile = {};
+    for (u32 i = 0; i < count; ++i) {
+        Memory::WriteBlock(profiles_addr + i * sizeof(Profile),
+            reinterpret_cast<const u8*>(&zero_profile), sizeof(Profile));
+    }
+
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_FRD, "(STUBBED) called, count=%d, frd_key_addr=0x%08X, profiles_addr=0x%08X",
+                count, frd_key_addr, profiles_addr);
+}
+
+void GetFriendAttributeFlags(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    u32 count           = cmd_buff[1];
+    u32 frd_key_addr    = cmd_buff[3];
+    u32 attr_flags_addr = cmd_buff[65];
+
+    for (u32 i = 0; i < count; ++i) {
+        //TODO:(mailwl) figure out AttributeFlag size and zero all buffer. Assume 1 byte
+        Memory::Write8(attr_flags_addr + i, 0);
+    }
+
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_FRD, "(STUBBED) called, count=%d, frd_key_addr=0x%08X, attr_flags_addr=0x%08X",
+                count, frd_key_addr, attr_flags_addr);
+}
+
+void GetMyFriendKey(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    Memory::WriteBlock(cmd_buff[2], reinterpret_cast<const u8*>(&my_friend_key), sizeof(FriendKey));
+    LOG_WARNING(Service_FRD, "(STUBBED) called");
+}
+
+void GetMyScreenName(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    // TODO: (mailwl) get the name from config
+    Common::UTF8ToUTF16("Citra").copy(reinterpret_cast<char16_t*>(&cmd_buff[2]), 11);
+    LOG_WARNING(Service_FRD, "(STUBBED) called");
+}
+
 void Init() {
     using namespace Kernel;
 
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h
index f9f88b444..c8283a7f3 100644
--- a/src/core/hle/service/frd/frd.h
+++ b/src/core/hle/service/frd/frd.h
@@ -4,9 +4,97 @@
 
 #pragma once
 
+#include "common/common_types.h"
+
 namespace Service {
+
+class Interface;
+
 namespace FRD {
 
+struct FriendKey {
+    u32 friend_id;
+    u32 unknown;
+    u64 friend_code;
+};
+
+struct MyPresence {
+    u8 unknown[0x12C];
+};
+
+struct Profile {
+    u8 region;
+    u8 country;
+    u8 area;
+    u8 language;
+    u32 unknown;
+};
+
+/**
+ * FRD::GetMyPresence service function
+ *  Inputs:
+ *      64 : sizeof (MyPresence) << 14 | 2
+ *      65 : Address of MyPresence structure
+ *  Outputs:
+ *      1 : Result of function, 0 on success, otherwise error code
+ */
+void GetMyPresence(Service::Interface* self);
+
+/**
+ * FRD::GetFriendKeyList service function
+ *  Inputs:
+ *      1 : Unknown
+ *      2 : Max friends count
+ *      65 : Address of FriendKey List
+ *  Outputs:
+ *      1 : Result of function, 0 on success, otherwise error code
+ *      2 : FriendKey count filled
+ */
+void GetFriendKeyList(Service::Interface* self);
+
+/**
+ * FRD::GetFriendProfile service function
+ *  Inputs:
+ *      1 : Friends count
+ *      2 : Friends count << 18 | 2
+ *      3 : Address of FriendKey List
+ *      64 : (count * sizeof (Profile)) << 10 | 2
+ *      65 : Address of Profiles List
+ *  Outputs:
+ *      1 : Result of function, 0 on success, otherwise error code
+ */
+void GetFriendProfile(Service::Interface* self);
+
+/**
+ * FRD::GetFriendAttributeFlags service function
+ *  Inputs:
+ *      1 : Friends count
+ *      2 : Friends count << 18 | 2
+ *      3 : Address of FriendKey List
+ *      65 : Address of AttributeFlags
+ *  Outputs:
+ *      1 : Result of function, 0 on success, otherwise error code
+ */
+void GetFriendAttributeFlags(Service::Interface* self);
+
+/**
+ * FRD::GetMyFriendKey service function
+ *  Inputs:
+ *      none
+ *  Outputs:
+ *      1 : Result of function, 0 on success, otherwise error code
+ *      2-5 : FriendKey
+ */
+void GetMyFriendKey(Service::Interface* self);
+
+/**
+ * FRD::GetMyScreenName service function
+ *  Outputs:
+ *      1 : Result of function, 0 on success, otherwise error code
+ *      2 : UTF16 encoded name (max 11 symbols)
+ */
+void GetMyScreenName(Service::Interface* self);
+
 /// Initialize FRD service(s)
 void Init();
 
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 2c6885377..db8666416 100644
--- a/src/core/hle/service/frd/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -2,65 +2,66 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "core/hle/service/frd/frd.h"
 #include "core/hle/service/frd/frd_u.h"
 
 namespace Service {
 namespace FRD {
 
 const Interface::FunctionInfo FunctionTable[] = {
-    {0x00010000, nullptr,               "HasLoggedIn"},
-    {0x00020000, nullptr,               "IsOnline"},
-    {0x00030000, nullptr,               "Login"},
-    {0x00040000, nullptr,               "Logout"},
-    {0x00050000, nullptr,               "GetMyFriendKey"},
-    {0x00060000, nullptr,               "GetMyPreference"},
-    {0x00070000, nullptr,               "GetMyProfile"},
-    {0x00080000, nullptr,               "GetMyPresence"},
-    {0x00090000, nullptr,               "GetMyScreenName"},
-    {0x000A0000, nullptr,               "GetMyMii"},
-    {0x000B0000, nullptr,               "GetMyLocalAccountId"},
-    {0x000C0000, nullptr,               "GetMyPlayingGame"},
-    {0x000D0000, nullptr,               "GetMyFavoriteGame"},
-    {0x000E0000, nullptr,               "GetMyNcPrincipalId"},
-    {0x000F0000, nullptr,               "GetMyComment"},
-    {0x00100040, nullptr,               "GetMyPassword"},
-    {0x00110080, nullptr,               "GetFriendKeyList"},
-    {0x00120042, nullptr,               "GetFriendPresence"},
-    {0x00130142, nullptr,               "GetFriendScreenName"},
-    {0x00140044, nullptr,               "GetFriendMii"},
-    {0x00150042, nullptr,               "GetFriendProfile"},
-    {0x00160042, nullptr,               "GetFriendRelationship"},
-    {0x00170042, nullptr,               "GetFriendAttributeFlags"},
-    {0x00180044, nullptr,               "GetFriendPlayingGame"},
-    {0x00190042, nullptr,               "GetFriendFavoriteGame"},
-    {0x001A00C4, nullptr,               "GetFriendInfo"},
-    {0x001B0080, nullptr,               "IsIncludedInFriendList"},
-    {0x001C0042, nullptr,               "UnscrambleLocalFriendCode"},
-    {0x001D0002, nullptr,               "UpdateGameModeDescription"},
-    {0x001E02C2, nullptr,               "UpdateGameMode"},
-    {0x001F0042, nullptr,               "SendInvitation"},
-    {0x00200002, nullptr,               "AttachToEventNotification"},
-    {0x00210040, nullptr,               "SetNotificationMask"},
-    {0x00220040, nullptr,               "GetEventNotification"},
-    {0x00230000, nullptr,               "GetLastResponseResult"},
-    {0x00240040, nullptr,               "PrincipalIdToFriendCode"},
-    {0x00250080, nullptr,               "FriendCodeToPrincipalId"},
-    {0x00260080, nullptr,               "IsValidFriendCode"},
-    {0x00270040, nullptr,               "ResultToErrorCode"},
-    {0x00280244, nullptr,               "RequestGameAuthentication"},
-    {0x00290000, nullptr,               "GetGameAuthenticationData"},
-    {0x002A0204, nullptr,               "RequestServiceLocator"},
-    {0x002B0000, nullptr,               "GetServiceLocatorData"},
-    {0x002C0002, nullptr,               "DetectNatProperties"},
-    {0x002D0000, nullptr,               "GetNatProperties"},
-    {0x002E0000, nullptr,               "GetServerTimeInterval"},
-    {0x002F0040, nullptr,               "AllowHalfAwake"},
-    {0x00300000, nullptr,               "GetServerTypes"},
-    {0x00310082, nullptr,               "GetFriendComment"},
-    {0x00320042, nullptr,               "SetClientSdkVersion"},
-    {0x00330000, nullptr,               "GetMyApproachContext"},
-    {0x00340046, nullptr,               "AddFriendWithApproach"},
-    {0x00350082, nullptr,               "DecryptApproachContext"},
+    {0x00010000, nullptr,                 "HasLoggedIn"},
+    {0x00020000, nullptr,                 "IsOnline"},
+    {0x00030000, nullptr,                 "Login"},
+    {0x00040000, nullptr,                 "Logout"},
+    {0x00050000, GetMyFriendKey,          "GetMyFriendKey"},
+    {0x00060000, nullptr,                 "GetMyPreference"},
+    {0x00070000, nullptr,                 "GetMyProfile"},
+    {0x00080000, GetMyPresence,           "GetMyPresence"},
+    {0x00090000, GetMyScreenName,         "GetMyScreenName"},
+    {0x000A0000, nullptr,                 "GetMyMii"},
+    {0x000B0000, nullptr,                 "GetMyLocalAccountId"},
+    {0x000C0000, nullptr,                 "GetMyPlayingGame"},
+    {0x000D0000, nullptr,                 "GetMyFavoriteGame"},
+    {0x000E0000, nullptr,                 "GetMyNcPrincipalId"},
+    {0x000F0000, nullptr,                 "GetMyComment"},
+    {0x00100040, nullptr,                 "GetMyPassword"},
+    {0x00110080, GetFriendKeyList,        "GetFriendKeyList"},
+    {0x00120042, nullptr,                 "GetFriendPresence"},
+    {0x00130142, nullptr,                 "GetFriendScreenName"},
+    {0x00140044, nullptr,                 "GetFriendMii"},
+    {0x00150042, GetFriendProfile,        "GetFriendProfile"},
+    {0x00160042, nullptr,                 "GetFriendRelationship"},
+    {0x00170042, GetFriendAttributeFlags, "GetFriendAttributeFlags"},
+    {0x00180044, nullptr,                 "GetFriendPlayingGame"},
+    {0x00190042, nullptr,                 "GetFriendFavoriteGame"},
+    {0x001A00C4, nullptr,                 "GetFriendInfo"},
+    {0x001B0080, nullptr,                 "IsIncludedInFriendList"},
+    {0x001C0042, nullptr,                 "UnscrambleLocalFriendCode"},
+    {0x001D0002, nullptr,                 "UpdateGameModeDescription"},
+    {0x001E02C2, nullptr,                 "UpdateGameMode"},
+    {0x001F0042, nullptr,                 "SendInvitation"},
+    {0x00200002, nullptr,                 "AttachToEventNotification"},
+    {0x00210040, nullptr,                 "SetNotificationMask"},
+    {0x00220040, nullptr,                 "GetEventNotification"},
+    {0x00230000, nullptr,                 "GetLastResponseResult"},
+    {0x00240040, nullptr,                 "PrincipalIdToFriendCode"},
+    {0x00250080, nullptr,                 "FriendCodeToPrincipalId"},
+    {0x00260080, nullptr,                 "IsValidFriendCode"},
+    {0x00270040, nullptr,                 "ResultToErrorCode"},
+    {0x00280244, nullptr,                 "RequestGameAuthentication"},
+    {0x00290000, nullptr,                 "GetGameAuthenticationData"},
+    {0x002A0204, nullptr,                 "RequestServiceLocator"},
+    {0x002B0000, nullptr,                 "GetServiceLocatorData"},
+    {0x002C0002, nullptr,                 "DetectNatProperties"},
+    {0x002D0000, nullptr,                 "GetNatProperties"},
+    {0x002E0000, nullptr,                 "GetServerTimeInterval"},
+    {0x002F0040, nullptr,                 "AllowHalfAwake"},
+    {0x00300000, nullptr,                 "GetServerTypes"},
+    {0x00310082, nullptr,                 "GetFriendComment"},
+    {0x00320042, nullptr,                 "SetClientSdkVersion"},
+    {0x00330000, nullptr,                 "GetMyApproachContext"},
+    {0x00340046, nullptr,                 "AddFriendWithApproach"},
+    {0x00350082, nullptr,                 "DecryptApproachContext"},
 };
 
 FRD_U_Interface::FRD_U_Interface() {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 35b648409..833a68f05 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -70,9 +70,8 @@ ResultVal<bool> Interface::SyncRequest() {
         // TODO(bunnei): Hack - ignore error
         cmd_buff[1] = 0;
         return MakeResult<bool>(false);
-    } else {
-        LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
     }
+    LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
 
     itr->second.func(this);