From 7f158396ad2a8e13237f65d4a16944df435992d4 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Wed, 28 Mar 2018 19:31:36 -0400 Subject: [PATCH] Added impl for accountProfile*. If the inital smGetService fails, attempt to use 'acc:u0'. --- nx/include/switch/services/acc.h | 36 +++++++ nx/source/services/acc.c | 162 ++++++++++++++++++++++++++++++- 2 files changed, 197 insertions(+), 1 deletion(-) diff --git a/nx/include/switch/services/acc.h b/nx/include/switch/services/acc.h index 481320d7..826f2cba 100644 --- a/nx/include/switch/services/acc.h +++ b/nx/include/switch/services/acc.h @@ -8,9 +8,45 @@ #include "../types.h" #include "sm.h" +typedef struct { + Handle h; +} AccountProfile; + +typedef struct +{ + u32 unk_x0; + u32 iconID; ///< Icon ID. 0 = Mii, the rest are character icon IDs. + u8 iconBackgroundColorID; ///< Profile icon background color ID + u8 unk_x9[0x7]; + u8 miiID[0x10]; ///< Some ID related to the Mii? All zeros when a character icon is used. + u8 unk_x20[0x60]; ///< Usually zeros? +} PACKED AccountUserData; + +typedef struct +{ + u128 userID; + u64 lastEditTimestamp; ///< POSIX UTC timestamp, for the last account edit. + char username[0x20]; ///< UTF-8 Username. +} PACKED AccountProfileBase; + Result accountInitialize(void); void accountExit(void); Service* accountGetService(void); /// Get the userID for the currently active user. The output userID is only valid when the output account_selected==1, otherwise no user is currently selected. +/// An user is only selected when the user-account selection applet was used to select an user at least once before. Result accountGetActiveUser(u128 *userID, bool *account_selected); + +/// Get an AccountProfile for the specified userID. +Result accountGetProfile(AccountProfile* out, u128 userID); + +/// Get \ref AccountUserData and \ref AccountProfileBase for the specified profile, userdata is optional (can be NULL). +Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase); + +/// Get the icon image size. +Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size); + +/// Load the JPEG profile icon, valid for both Miis and character icons. The output image_size is the same as the one from \ref accountProfileGetImageSize. +Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size); + +void accountProfileClose(AccountProfile* profile); diff --git a/nx/source/services/acc.c b/nx/source/services/acc.c index 49050b62..4db65dc1 100644 --- a/nx/source/services/acc.c +++ b/nx/source/services/acc.c @@ -1,3 +1,5 @@ +#include + #include "types.h" #include "arm/atomics.h" #include "services/acc.h" @@ -8,12 +10,17 @@ static u64 g_refCnt; Result accountInitialize(void) { + Result rc=0; + atomicIncrement64(&g_refCnt); if (serviceIsActive(&g_accSrv)) return 0; - return smGetService(&g_accSrv, "acc:u1"); + rc = smGetService(&g_accSrv, "acc:u1"); + if (R_FAILED(rc)) rc = smGetService(&g_accSrv, "acc:u0"); + + return rc; } void accountExit(void) @@ -67,3 +74,156 @@ Result accountGetActiveUser(u128 *userID, bool *account_selected) return rc; } +Result accountGetProfile(AccountProfile* out, u128 userID) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u128 userID; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 5; + raw->userID = userID; + + Result rc = serviceIpcDispatch(&g_accSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + out->h = r.Handles[0]; + } + } + + return rc; +} + +//IProfile implementation +Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) { + IpcCommand c; + ipcInitialize(&c); + if (userdata) ipcAddRecvStatic(&c, userdata, sizeof(AccountUserData), 0); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = userdata==NULL ? 1 : 0; + + Result rc = ipcDispatch(profile->h); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + AccountProfileBase profilebase; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && profilebase) memcpy(profilebase, &resp->profilebase, sizeof(AccountProfileBase)); + } + + return rc; +} + +Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 10; + + Result rc = ipcDispatch(profile->h); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u32 image_size; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *image_size = resp->image_size; + } + } + + return rc; +} + +Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buf, len, 0); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 11; + + Result rc = ipcDispatch(profile->h); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u32 image_size; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *image_size = resp->image_size; + } + } + + return rc; +} + +void accountProfileClose(AccountProfile* profile) { + if(profile->h != INVALID_HANDLE) { + svcCloseHandle(profile->h); + profile->h = INVALID_HANDLE; + } +} +