diff --git a/libctru/include/3ds/mii.h b/libctru/include/3ds/mii.h index fc395d956..76898279e 100644 --- a/libctru/include/3ds/mii.h +++ b/libctru/include/3ds/mii.h @@ -6,12 +6,16 @@ */ #pragma once +#define MII_NAME_LEN 10+1 ///< 10-character NULL-terminated UTF-16 mii name + +typedef u16 MiiScreenName[MII_NAME_LEN]; + #include <3ds/types.h> -/// Shared Mii struct +/// Shared Base Mii struct typedef struct { - u8 magic; ///< Always 3? + u8 version; ///< Always 3 /// Mii options struct @@ -20,6 +24,7 @@ typedef struct bool is_private_name : 1; ///< Private name? u8 region_lock : 2; ///< Region lock (0=no lock, 1=JPN, 2=USA, 3=EUR) u8 char_set : 2; ///< Character set (0=JPN+USA+EUR, 1=CHN, 2=KOR, 3=TWN) + u8 _pad : 2; } mii_options; /// Mii position in Mii selector or Mii maker @@ -34,6 +39,7 @@ typedef struct { u8 unknown0 : 4; ///< Mabye padding (always seems to be 0)? u8 origin_console : 3; ///< Console that the Mii was created on (1=WII, 2=DSI, 3=3DS) + u8 _pad : 1; } console_identity; u64 system_id; ///< Identifies the system that the Mii was created on (Determines pants) @@ -47,8 +53,9 @@ typedef struct u16 bday_month : 4; ///< Month of Mii's birthday u16 bday_day : 5; ///< Day of Mii's birthday u16 shirt_color : 4; ///< Color of Mii's shirt - bool favorite : 1; ///< Whether the Mii is one of your 10 favorite Mii's - } mii_details; + u16 favorite : 1; ///< Whether the Mii is one of your 10 favorite Mii's + u16 _pad : 1; + } CTR_PACKED mii_details; u16 mii_name[10]; ///< Name of Mii (Encoded using UTF16) u8 height; ///< How tall the Mii is @@ -57,51 +64,54 @@ typedef struct /// Face style struct { - bool disable_sharing : 1; ///< Whether or not Sharing of the Mii is allowed - u8 shape : 4; ///< Face shape - u8 skinColor : 3; ///< Color of skin - } face_style; + u16 disable_sharing : 1; ///< Whether or not Sharing of the Mii is allowed + u16 shape : 4; ///< Face shape + u16 skinColor : 3; ///< Color of skin + } CTR_PACKED face_style; /// Face details struct { - u8 wrinkles : 4; - u8 makeup : 4; - } face_details; + u16 wrinkles : 4; + u16 makeup : 4; + } CTR_PACKED face_details; u8 hair_style; /// Hair details struct { - u8 color : 3; - bool flip : 1; - } hair_details; + u16 color : 3; + u16 flip : 1; + u16 _pad : 4; + } CTR_PACKED hair_details; /// Eye details struct { - u32 style : 6; - u32 color : 3; - u32 scale : 4; - u32 yscale : 3; - u32 rotation : 5; - u32 xspacing : 4; - u32 yposition : 5; - } eye_details; + u16 style : 6; + u16 color : 3; + u16 scale : 4; + u16 yscale : 3; + u16 rotation : 5; + u16 xspacing : 4; + u16 yposition : 5; + u16 _pad : 2; + } CTR_PACKED eye_details; /// Eyebrow details struct { - u32 style : 5; - u32 color : 3; - u32 scale : 4; - u32 yscale : 3; - u32 pad : 1; - u32 rotation : 5; - u32 xspacing : 4; - u32 yposition : 5; - } eyebrow_details; + u16 style : 5; + u16 color : 3; + u16 scale : 4; + u16 yscale : 3; + u16 _pad : 1; + u16 rotation : 4; + u16 xspacing : 4; + u16 yposition : 5; + u16 _pad2 : 3; + } CTR_PACKED eyebrow_details; /// Nose details struct @@ -109,7 +119,8 @@ typedef struct u16 style : 5; u16 scale : 4; u16 yposition : 5; - } nose_details; + u16 _pad : 2; + } CTR_PACKED nose_details; /// Mouth details struct @@ -118,15 +129,15 @@ typedef struct u16 color : 3; u16 scale : 4; u16 yscale : 3; - } mouth_details; + } CTR_PACKED mouth_details; /// Mustache details struct { u16 mouth_yposition : 5; - u16 mustach_style : 3; - u16 pad : 2; - } mustache_details; + u16 mustache_style : 3; + u16 _pad : 8; + } CTR_PACKED mustache_details; /// Beard details struct @@ -135,7 +146,8 @@ typedef struct u16 color : 3; u16 scale : 4; u16 ypos : 5; - } beard_details; + u16 _pad : 1; + } CTR_PACKED beard_details; /// Glasses details struct @@ -144,16 +156,17 @@ typedef struct u16 color : 3; u16 scale : 4; u16 ypos : 5; - } glasses_details; + } CTR_PACKED glasses_details; /// Mole details struct { bool enable : 1; - u16 scale : 5; + u16 scale : 4; u16 xpos : 5; u16 ypos : 5; - } mole_details; + u16 _pad : 1; + } CTR_PACKED mole_details; u16 author_name[10]; ///< Name of Mii's author (Encoded using UTF16) } CTR_PACKED MiiData; diff --git a/libctru/include/3ds/services/act.h b/libctru/include/3ds/services/act.h new file mode 100644 index 000000000..e01beaf57 --- /dev/null +++ b/libctru/include/3ds/services/act.h @@ -0,0 +1,996 @@ +/** + * @file act.h + * @brief ACT (Account) Services + */ +#pragma once +#include <3ds/services/frd.h> +#include <3ds/types.h> +#include <3ds/mii.h> + +#define ACCOUNT_ID_LEN 16+1 ///< 16-character NULL-terminated ASCII Account ID +#define ACCOUNT_EMAIL_LEN 256+1 ///< 256-character NULL-terminated ASCII email address +#define ACCOUNT_PASSWORD_LEN 17+1 ///< 17-character NULL-terminated ASCII password + +#define ACT_NNAS_SUBDOMAIN_LEN 32+1 ///< 32-character NULL-terminated ASCII NNAS (Nintendo Network Authentication Server) subdomain +#define ACT_UUID_LEN 16 ///< RFC9562 Version 1 UUID + +#define ACT_DEFAULT_ACCOUNT 0xFE + +#define ACT_UUID_REGULAR -1 ///< The final UUID will not be based on any unique ID. +#define ACT_UUID_CURRENT_PROCESS -2 ///< The final UUID will be based on the unique ID of the current process. + +#define ACT_TRANSFERABLE_ID_BASE_COMMON 0xFF ///< Use a common transferable ID base. +#define ACT_TRANSFERABLE_ID_BASE_CURRENT_ACCOUNT 0xFE ///< Use the transferable ID base of the currently loaded account. + +typedef u8 ActUuid[ACT_UUID_LEN]; + +typedef char ActNnasSubdomain[ACT_NNAS_SUBDOMAIN_LEN]; + +typedef char AccountId[ACCOUNT_ID_LEN]; +typedef char AccountPassword[ACCOUNT_PASSWORD_LEN]; +typedef char AccountMailAddress[ACCOUNT_EMAIL_LEN]; + +/// Enum for common / account specific info types +typedef enum +{ + INFO_TYPE_COMMON_NUM_ACCOUNTS = 1, ///< u8 + INFO_TYPE_COMMON_CURRENT_ACCOUNT_SLOT, ///< u8 + INFO_TYPE_COMMON_DEFAULT_ACCOUNT_SLOT, ///< u8 + INFO_TYPE_COMMON_NETWORK_TIME_DIFF, ///< s64, difference between server time and device time in nanoseconds. + INFO_TYPE_PERSISTENT_ID, ///< u32 + INFO_TYPE_COMMON_TRANSFERABLE_ID_BASE, ///< u64 + INFO_TYPE_TRANSFERABLE_ID_BASE = INFO_TYPE_COMMON_TRANSFERABLE_ID_BASE, ///< u64 + INFO_TYPE_MII, ///< CFLStoreData + INFO_TYPE_ACCOUNT_ID, ///< AccountId + INFO_TYPE_MAIL_ADDRESS, ///< AccountMailAddress + INFO_TYPE_BIRTH_DATE, ///< BirthDate structure + INFO_TYPE_COUNTRY_NAME, ///< char[2+1] + INFO_TYPE_PRINCIPAL_ID, ///< u32 + INFO_TYPE_STUB_0xD, /* not handled */ + INFO_TYPE_IS_PASSWORD_CACHE_ENABLED, ///< bool + INFO_TYPE_STUB_0xF, /* not handled */ + INFO_TYPE_STUB_0x10, /* not handled */ + INFO_TYPE_ACCOUNT_INFO, ///< AccountInfo structure + INFO_TYPE_ACCOUNT_SERVER_TYPES, /// AccountServerTypes + INFO_TYPE_GENDER, ///< u8, F = 0, M = 1 + INFO_TYPE_LAST_AUTHENTICATION_RESULT, ///< Result + INFO_TYPE_ASSIGNED_ACCOUNT_ID, ///< AccountId + INFO_TYPE_PARENTAL_CONTROL_SLOT_NUMBER, ///< u8 + INFO_TYPE_SIMPLE_ADDRESS_ID, ///< u32 + INFO_TYPE_STUB_0x18, /* not handled */ + INFO_TYPE_UTC_OFFSET, ///< s64 + INFO_TYPE_IS_COMMITTED, ///< bool + INFO_TYPE_MII_NAME, ///< MiiScreenName + INFO_TYPE_NFS_PASSWORD, ///< char[0x10+1] + INFO_TYPE_HAS_ECI_VIRTUAL_ACCOUNT, ///< bool + INFO_TYPE_TIMEZONE_ID, ///< char[0x40+1] + INFO_TYPE_IS_MII_UPDATED, ///< bool + INFO_TYPE_IS_MAIL_ADDRESS_VALIDATED, ///< bool + INFO_TYPE_ACCOUNT_ACCESS_TOKEN, ///< AccountAccessToken structure + INFO_TYPE_COMMON_IS_APPLICATION_UPDATE_REQUIRED, ///< bool + INFO_TYPE_COMMON_DEFAULT_ACCOUNT_SERVER_TYPES, ///< AccountServerTypes + INFO_TYPE_IS_SERVER_ACCOUNT_DELETED, ///< bool + INFO_TYPE_MII_IMAGE_URL, ///< char[0x100+1] + INFO_TYPE_ASSIGNED_PRINCIPAL_ID, ///< u32 + INFO_TYPE_ACCOUNT_ACCESS_TOKEN_STATE, ///< u32, AccountAccessTokenState enum + INFO_TYPE_ACCOUNT_SERVER_ENVIRONMENT, ///< AccountServerTypesStr structure + INFO_TYPE_COMMON_DEFAULT_ACCOUNT_SERVER_ENVIRONMENT, ///< AccountServerTypesStr structure + INFO_TYPE_COMMON_DEVICE_HASH, ///< u8[8] + INFO_TYPE_FP_LOCAL_ACCOUNT_ID, ///< u8 + INFO_TYPE_AGE, ///< u16 + INFO_TYPE_IS_ENABLED_RECEIVE_ADS, ///< bool + INFO_TYPE_IS_OFF_DEVICE_ENABLED, ///< bool + INFO_TYPE_TRANSLATED_SIMPLE_ADDRESS_ID, ///< u32 +} ACT_InfoType; + +typedef enum +{ + REQUEST_INQUIRE_BINDING_TO_EXISTENT_SERVER_ACCOUNT = 1, ///< ExistentServerAccountData struct + REQUEST_BIND_TO_EXISTENT_SERVER_ACCOUNT, ///< u32, parentalConsentApprovalId + REQUEST_ACQUIRE_EULA, ///< EulaList structure (dynamically sized) + REQUEST_ACQUIRE_EULA_LIST = REQUEST_ACQUIRE_EULA, ///< EulaList structure (dynamically sized) + REQUEST_ACQUIRE_EULA_LANGUAGE_LIST = REQUEST_ACQUIRE_EULA, ///< EulaList structure with only the languageNameOffsets populated (dynamically sized) + REQUEST_ACQUIRE_TIMEZONE_LIST, ///< TimezoneList structure + REQUEST_ACQUIRE_ACCOUNT_INFO, ///< INFO_TYPE_MAIL_ADDRESS: AccountMailAddress + REQUEST_ACQUIRE_ACCOUNT_ID_BY_PRINCIPAL_ID_MULTI, ///< AccountId[count] + REQUEST_ACQUIRE_ACCOUNT_ID_BY_PRINCIPAL_ID, ///< AccountId + REQUEST_ACQUIRE_PRINCIPAL_ID_BY_ACCOUNT_ID_MULTI, ///< u32[count] + REQUEST_ACQUIRE_PRINCIPAL_ID_BY_ACCOUNT_ID, ///< u32 + REQUEST_APPROVE_BY_CREDIT_CARD, ///< u32, approvalId + REQUEST_SEND_COPPA_CODE_MAIL, ///< CoppaCodeMailData structure + REQUEST_ACQUIRE_MII, ///< CFLStoreData[count] + REQUEST_ACQUIRE_ACCOUNT_INFO_RAW, ///< char[0xC00+1], NULL-terminate ASCII raw profile XML data +} ACT_AsyncRequestType; + +/// Enum for Mii image type +typedef enum +{ + MII_IMAGE_PRIMARY = 0, ///< The user's primary Mii image. + MII_IMAGE_1, + MII_IMAGE_2, + MII_IMAGE_3, + MII_IMAGE_4, + MII_IMAGE_5, + MII_IMAGE_6, + MII_IMAGE_7, + MII_IMAGE_8, +} MiiImageType; + +/// Enum for NNAS (Nintendo Network Authentication Server) type +typedef enum +{ + NNAS_PRODUCTION = 0, + NNAS_GAME_DEVELOPMENT, + NNAS_SYSTEM_DEVELOPMENT, + NNAS_LIBRARY_DEVELOPMENT, + NNAS_STAGING, +} NnasServerType; + +/// Enum for account access token state +typedef enum +{ + ACCESS_TOKEN_UNINITIALIZED = 0, + ACCESS_TOKEN_EXPIRED, + ACCESS_TOKEN_VALID, +} AccountAccessTokenState; + +/// Enum for account access token invalidation action +typedef enum +{ + INVALIDATE_ACCESS_TOKEN = BIT(0), ///< Invalidates only the account token itself (and the expiry date). + INVALIDATE_REFRESH_TOKEN = BIT(1), ///< Invalidates only the refresh token. +} InvalidateAccessTokenAction; + +/// Coppa Code Mail Data Structure +typedef struct +{ + char coppaCode[5+1]; + AccountMailAddress parentEmail; +} CoppaCodeMailData; + +#pragma pack(push, 1) + +/// Mii CFLStoreData (CTR Face Library Store Data) structure +typedef struct +{ + MiiData miiData; + u8 pad[2]; + u16 crc16; +} CFLStoreData; + +/// Birth date structure +typedef struct +{ + u16 year; + u8 month; + u8 day; +} BirthDate; + +/// Account info structure +typedef struct +{ + u32 persistentId; + u8 pad[4]; + u64 transferableIdBase; + CFLStoreData mii; + MiiScreenName screenName; + char accountId[ACCOUNT_ID_LEN]; + u8 pad2; + BirthDate birthDate; + u32 principalId; +} AccountInfo; + +/// Account Timezone structure +typedef struct +{ + char timezoneArea[0x40+1]; + char pad[3]; + char timezoneId[0x40+1]; + char pad2[3]; + s64 utcOffset; +} AccountTimezone; + +/// Timezone List structure +typedef struct +{ + u32 capacity; + u32 count; + AccountTimezone timezones[32]; +} TimezoneList; + +/// EULA Info structure +typedef struct +{ + char countryCode[2+1]; ///< ISO 3166-1 A-2 country code + char languageCode[2+1]; ///< ISO 639 Set 1 language code + u16 eulaVersion; +} EulaInfo; + +/// Existent Server Account Data structure +typedef struct +{ + bool hasMii; + u8 pad[3]; + CFLStoreData miiData; + u32 principalId; + bool coppaRequiredFlag; + u8 pad2[3]; + CoppaCodeMailData coppaMailData; + u8 pad3; + BirthDate birthDate; +} ExistentServerAccountData; + +/// EULA entry header structure +typedef struct +{ + char countryCode[2+1]; ///< ISO 3166-1 A-2 country code + u8 pad; + char languageCode[2+1]; ///< ISO 639 Set 1 language code + u8 pad2; + u16 eulaVersion; + u8 pad3[2]; + u32 nextEntryOffset; ///< Offset of next EULA entry, relative to full data blob. + u32 eulaTypeOffset; ///< Offset of the EulaType within textData. + u32 agreeTextOffset; ///< Offset of the AgreeText within textData. + u32 nonAgreeTextOffset; ///< Offset of the NonAgreeText within textData. + u32 languageNameOffset; ///< Offset of the LanguageName within textData. + u32 mainTitleOffset; ///< Offset of the MainTitle within textData. + u32 mainTextOffset; ///< Offset of the MainText within textData. + u32 subTitleOffset; ///< Offset of the SubTitle within textData. + u32 subTextOffset; ///< Offset of the SubText within textData. + char textData[]; +} EulaEntry; + +/// Support Context structure +typedef struct +{ + AccountId accountId; ///< Account ID of the account. + u8 pad[3]; + u32 serialNumber; ///< Serial number of the console (only digits). + u32 principalId; + u16 randomNumber; ///< Random number based on the principalId and serialNumber. + u8 pad2[2]; +} SupportContext; + +#pragma pack(pop) + +/// EULA list structure +typedef struct +{ + u8 numEntries; ///< Number of entries within the list. + u8 entries[]; ///< EULA Entries (dynamically sized) +} EulaList; + +/// Device Info structure +typedef struct +{ + u32 deviceId; + char serialNumber[0xF+1]; +} DeviceInfo; + +/// NEX service token structure +typedef struct +{ + char serviceToken[0x200+1]; + u8 pad[3]; + char password[0x40+1]; + u8 pad2[3]; + char serverHost[0x10]; + u16 serverPort; + u8 pad3[2]; +} NexServiceToken; + +/// Credit Card Info structure +typedef struct +{ + u8 cardType; + char cardNumber[0x10+1]; + char securityCode[3+1]; + u8 expirationMonth; + u8 expirationYear; + char postalCode[6+1]; + AccountMailAddress mailAddress; +} CreditCardInfo; + +/// V1 Independent service token structure +typedef struct +{ + char token[0x200+1]; ///< base64 +} IndependentServiceTokenV1; + +/// V2 Independent service token structure +typedef struct +{ + char token[0x200+1]; ///< base64 + char iv[0x18+1]; ///< base64 + char signature[0x158+1]; ///< base64 + NfsTypeStr nfsTypeStr; +} IndependentServiceTokenV2; + +/// Account server types structure (raw format) +typedef struct +{ + u8 nnasType; ///< NNAS (Nintendo Network Authentication Server) type + u8 nfsType; ///< NFS (Nintendo Friend Server) type + u8 nfsNo; ///< NFS (Nintendo Friend Server) number + u8 pad; +} AccountServerTypes; + +/// Account server types structure (string format) +typedef struct +{ + ActNnasSubdomain nnasSubdomain; ///< NNAS (Nintendo Network Authentication Server) subdomain + NfsTypeStr nfsTypeStr; ///< NFS (Nintendo Friend Server) type string (letter + number) +} AccountServerTypesStr; + +/// Account access token structure +typedef struct +{ + u8 state; ///< AccountAccessTokenState enum + char accessToken[0x20+1]; + char refreshToken[0x28+1]; + u8 pad; +} AccountAccessToken; + +/** + * @brief Initializes ACT services. + * @param forceUser Whether or not to force using the user service act:u instead of the default (admin service act:a). + */ +Result actInit(bool forceUser); + +/// Exits ACT services. +void actExit(void); + +/// Get the ACT user/admin service handle. +Handle *actGetSessionHandle(void); + +/** + * @brief Initializes the current ACT session. + * @param sdkVersion The SDK version of the client process. + * @param sharedMemSize The size of the shared memory block. + * @param sharedMem Handle to the shared memory block. + */ +Result ACT_Initialize(u32 sdkVersion, u32 sharedMemSize, Handle sharedMem); + +/** + * @brief Returns a support error code (XXX-YYYY) for the given ACT result code. + * @param code The result code to convert. + */ +Result ACT_ResultToErrorCode(Result code); + +/** + * @brief Gets the result of the last internal operation. + */ +Result ACT_GetLastResponseResult(); + +/** + * @brief Cancels any currently running async operation. + */ +Result ACT_Cancel(); + +/** + * @brief Retrieves information not specific to any one account. + * @param output Pointer to buffer to output the data to. + * @param outputSize Size of the output buffer. + * @param infoType The type of data to retrieve. + */ +Result ACT_GetCommonInfo(void *output, u32 outputSize, u32 infoType); + +/** + * @brief Retrieves information of a certain account. + * @param output Pointer to buffer to output the data to. + * @param outputSize Size of the output buffer. + * @param accountSlot The account slot number of the account to retrieve information for. + * @param infoType The type of data to retrieve. + */ +Result ACT_GetAccountInfo(void *output, u32 outputSize, u8 accountSlot, u32 infoType); + +/** + * @brief Returns the data resulting from an async request. + * @param outReadSize Pointer to output the number of retrieved bytes to. + * @param output Pointer to buffer to output the data to. + * @param outputSize Size of the output buffer. + * @param requestType The type of async request to retrieve data for. + */ +Result ACT_GetAsyncResult(u32 *outReadSize, void *output, u32 outputSize, u32 requestType); + +/** + * @brief Gets one of the Mii images of a certain account. + * @param outSize Pointer to output the raw size of the image to. + * @param output Pointer to output the image data to. + * @param outputSize Size of the output buffer. + * @param accountSlot The account slot number of the account to get the Mii image for. + * @param miiImageType The type of the Mii image to get. + */ +Result ACT_GetMiiImage(u32 *outSize, void *output, u32 outputSize, u8 accountSlot, u8 miiImageType); + +/** + * @brief Sets the NFS (Nintendo Friend Server) password for a certain account. + * @param accountSlot The account slot number of the account to set the NfsPassword for. + * @param password Pointer to the new NFS password to use. + */ +Result ACT_SetNfsPassword(u8 accountSlot, char *password); + +/** + * @brief Sets the `IsApplicationUpdateRequired` field in the internal account manager. + * @param required The new value to use. + */ +Result ACT_SetIsApplicationUpdateRequired(bool required); + +/** + * @brief Acquires a list of EULA agreements for the specified country. + * @param countryCode The country code of the country to acquire EULA agreements for. + * @param completionEvent The event handle to signal when the request has finished. + */ +Result ACT_AcquireEulaList(u8 countryCode, Handle completionEvent); + +/** + * @brief Acquires a list of timezones for the specified country and language combination. + * @param countryCode The country code of the country to acquire time zones for. + * @param language code The language code of the language to acquire the time zones in. + * @param completionEvent The event handle to signal when the request has finished. + */ +Result ACT_AcquireTimezoneList(u8 countryCode, u8 languageCode, Handle completionEvent); + +/** + * @brief Generates a UUID. + * @param uuid Pointer to output the generated UUID to. + * @param uniqueId The unique ID to use during generation. Special values include `ACT_UUID_REGULAR` and `ACT_UUID_CURRENT_PROCESS`. + */ +Result ACT_GenerateUuid(ActUuid *uuid, u32 uniqueId); + +/** + * @brief Gets a specific account's UUID. + * @param uuid Pointer to output the UUID to. + * @param uniqueId The unique ID to use during the retrieval of the UUID. Special values include `ACT_UUID_REGULAR` and `ACT_UUID_CURRENT_PROCESS`. + */ +Result ACT_GetUuid(ActUuid *uuid, u8 accountSlot, u32 uniqueId); + +/** + * @brief Finds the account slot number of the account having the specified UUID. + * @param accountSlot Pointer to output the account slot number to. + * @param uuid Pointer to the UUID to find the account slot number for. + * @param uniqueId The unique ID to use during internal UUID generation. Special values include `ACT_UUID_REGULAR` and `ACT_UUID_CURRENT_PROCESS`. + */ +Result ACT_FindSlotNoByUuid(u8 *accountSlot, ActUuid *uuid, u32 uniqueId); + +/** + * @brief Saves all pending changes to the ACT system save data. + */ +Result ACT_Save(); + +/** + * @brief Returns a TransferableID for a certain account. + * @param transferableId Pointer to output the generated TransferableID to. + * @param accountSlot The account slot number of the account to generate the TransferableID for. Special values include `ACT_TRANSFERABLE_ID_BASE_COMMON` and `ACT_TRANSFERABLE_ID_BASE_CURRENT_ACCOUNT`. + * @param saltValue The value to use as a salt during generation. + */ +Result ACT_GetTransferableId(u64 *transferableId, u8 accountSlot, u8 saltValue); + +/** + * @brief Acquires an account-specific service token for a NEX server. + * @param accountSlot The account slot number of the account to use for acquiring the token. + * @param serverId The NEX server ID to request a service token for. + * @param doParentalControlsCheck Whether or not to perform a parental controls check before requesting the token. (unused) + * @param callerProcessId The process ID of the process requesting the token. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireNexServiceToken(u8 accountSlot, u32 serverId, bool doParentralControlsCheck, u32 callerProcessId, Handle completionEvent); + +/** + * @brief Gets a NEX service token requested using ACT_AcquireNexServiceToken. + * @param token Pointer to output the NEX service token data to. + */ +Result ACT_GetNexServiceToken(NexServiceToken *token); + +/** + * @brief Requests a V1 independent service token for a specific account. + * @param accountSlot The account slot number of the account to request the token with. + * @param clientId The client ID to use for requesting the independent service token. + * @param cacheDuration The duration in seconds to cache the token. If a token was requested within the past cacheDuration seconds, this command returns that token instead of requesting a new one. Passing 0 will cause ACT to always request a new token. + * @param doParentalControlsCheck Whether or not to perform a parental controls check before requesting the token. (unused) + * @param shared Whether or not this token should be shared with other processes. If set to false, it will only be accessible to the process with the given process ID. + * @param callerProcessId The process ID of the process requesting the token. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireIndependentServiceToken(u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentalControlsCheck, bool shared, u32 callerProcessId, Handle completionEvent); + +/** + * @brief Gets a V1 independent service token requested using ACT_AcquireIndependentServiceToken. + * @param token Pointer to output the V1 independent service token to. + */ +Result ACT_GetIndependentServiceToken(IndependentServiceTokenV1 *token); + +/** + * @brief Acquires account information for the specified account. + * @param accountSlot The account slot number to acquire information for. + * @param infoType The type of info to obtain. (only INFO_TYPE_MAIL_ADDRESS is supported.) + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireAccountInfo(u8 accountSlot, u32 infoType, Handle completionEvent); + +/** + * @brief Acquires account IDs from a list of principal IDs. + * @param principalIds Pointer to the input principal IDs. + * @param principalIdsSize Size of the input principal IDs buffer. + * @param unk Unknown value. Must be 0. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireAccountIdByPrincipalId(u32 *principalIds, u32 principalIdsSize, u8 unk, Handle completionEvent); + +/** + * @brief Acquires principal IDs from a list of account IDs. + * @param accountIds Pointer to input account IDs. + * @param accountIdsSize Size of the input account IDs buffer. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquirePrincipalIdByAccountId(AccountId *accountIds, u32 accountIdsSize, Handle completionHandle); + +/** + * @brief Acquires Miis corresponding to a given list of persistent IDs. + * @param persistentIds Pointer to input persistent IDs to use. + * @param persistentIdsSize Size of the input persistent IDs buffer. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireMii(u32 *persistentIds, u32 persistentIdsSize, Handle completionEvent); + +/** + * @brief Acquires raw (XML) account info for the specified account. + * @param accountSlot The account slot number of the account to acquire raw info for. + */ +Result ACT_AcquireAccountInfoRaw(u8 accountSlot, Handle completionEvent); + +/** + * @brief Gets a cached V1 independent service token for a specific account. + * @param accountSlot The account slot number of the account to get the token for. + * @param clientId The client ID to use for the cache lookup. + * @param cacheDuration The duration in seconds ago this token must have been requested in at least for it to be eligible for retrieval. + * @param doParentalControlsCheck Whether or not to perform a parental controls check before getting the token. (unused) + * @param shared Whether or not to only look for shared (non-process-specific) tokens in the cache. + */ +Result ACT_GetCachedIndependentServiceToken(IndependentServiceTokenV1 *token, u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentralControlsCheck, bool shared); + +/** + * @brief Inquires whether or not the given email address is available for creating a new account. + * @param mailAddress Pointer to the input email address to check. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_InquireMailAddressAvailability(AccountMailAddress *mailAddress, Handle completionEvent); + +/** + * @brief Acquires the EULA for the given country and language combination. + * @param countryCode The country code of the country for the EULA. + * @param languageCode The 2-character ISO 639 Set 1 language code for the EULA. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireEula(u8 countryCode, char *languageCode, Handle completionEvent); + +/** + * @brief Acquires a list of languages the EULA is available in for a given country. + * @param countryCode The country code to acquire the EULA language list for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireEulaLanguageList(u8 countryCode, Handle completionEvent); + +/** + * @brief Requests a V2 independent service token for a specific account. + * @param accountSlot The account slot number of the account to request the token with. + * @param clientId The client ID to use for requesting the independent service token. + * @param cacheDuration The duration in seconds to cache the token. If a token was requested within the past cacheDuration seconds, this command returns that token instead of requesting a new one. Passing 0 will cause ACT to always request a new token. + * @param doParentalControlsCheck Whether or not to perform a parental controls check before requesting the token. (unused) + * @param shared Whether or not this token should be shared with other processes. If set to false, it will only be accessible to the process with the given process ID. + * @param callerProcessId The process ID of the process requesting the token. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACT_AcquireIndependentServiceTokenV2(u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentalControlsCheck, bool shared, u32 callerProcessId, Handle completionEvent); + +/** + * @brief Gets a V2 independent service token requested using ACT_AcquireIndependentServiceTokenV2. + * @param token Pointer to output the V2 independent service token to. + */ +Result ACT_GetIndependentServiceTokenV2(IndependentServiceTokenV2 *token); + +/** + * @brief Gets a cached V2 independent service token for a specific account. + * @param accountSlot The account slot number of the account to get the token for. + * @param clientId The client ID to use for the cache lookup. + * @param cacheDuration The duration in seconds ago this token must have been requested in at least for it to be eligible for retrieval. + * @param doParentalControlsCheck Whether or not to perform a parental controls check before getting the token. (unused) + * @param shared Whether or not to only look for shared (non-process-specific) tokens in the cache. + */ +Result ACT_GetCachedIndependentServiceTokenV2(IndependentServiceTokenV2 *token, u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentralControlsCheck, bool shared); + +/** + * @brief Swaps the account slot numbers of two accounts. + * @param accountSlot1 The first account slot number. + * @param accountSlot2 The second account slot number. + */ +Result ACTA_SwapAccounts(u8 accountSlot1, u8 accountSlot2); + +/** + * @brief Creates a new local console account. + */ +Result ACTA_CreateConsoleAccount(); + +/** + * @brief Sets a local console account as committed. + * @param accountSlot The account slot number of the account to set as committed. + */ +Result ACTA_CommitConsoleAccount(u8 accountSlot); + +/** + * @brief Clears (but does not delete) account data for the given account slot. The FpLocalAccountId will not be cleared. + * @param accountSlot The account slot number of the account to clear. + * @param completely Whether or not to also clear the AssignedAccountId and AssignedPrincipalId in the account data. + */ +Result ACTA_UnbindServerAccount(u8 accountSlot, bool completely); + +/** + * @brief Deletes a local console account. + * @param accountSlot The account slot number of the local console account to delete. + */ +Result ACTA_DeleteConsoleAccount(u8 accountSlot); + +/** + * @brief Loads ("logs in to") a local console account. + * @param accountSlot The account slot number of the local console account to load. + * @param doPasswordCheck Whether or not the check the input password, or if one isn't provided, the cached password (if enabled). + * @param password Pointer to the input password. + * @param useNullPassword Whether or not to forcefully use NULL as the password (= no password). + * @param dryRun Whether or not to execute this command as a "dry run," not actually changing the current account to specified one. + */ +Result ACTA_LoadConsoleAccount(u8 accountSlot, bool doPasswordCheck, AccountPassword *password, bool useNullPassword, bool dryRun); + +/** + * @brief Unloads the currently loaded local console account. + */ +Result ACTA_UnloadConsoleAccount(); + +/** + * @brief Enables or disables the account password cache for a specific account. When the account password cache is enabled, entering the password is not required to log into the account. + * @param accountSlot The account slot number to enable/disable the account password cache for. + * @param enabled Whether or not to enable the account password cache. + */ +Result ACTA_EnableAccountPasswordCache(u8 accountSlot, bool enabled); + +/** + * @brief Sets the default account that is loaded when the ACT module is initialized. + * @param accountSlot The account slot number of the account to set as the default. + */ +Result ACTA_SetDefaultAccount(u8 accountSlot); + +/** + * @brief Replaces the AccountId with the AssignedAccountId for a specific account. + * @param accountSlot The account slot number of the account to perform this replacement for. + */ +Result ACTA_ReplaceAccountId(u8 accountSlot); + +/** + * @brief Creates a support context for a specific account. + * @param supportContext Pointer to write the support context data to. + * @param accountSlot The account slot number of the account to create the support context for. + */ +Result ACTA_GetSupportContext(SupportContext *supportContext, u8 accountSlot); + +/** + * @brief Sets server environment settings for a specific account. This will also update CFG configuration block 0x150002 accordingly. + * @param accountSlot The account slot number of the account to set the host server settings for. + * @param nnasType The NNAS (Nintendo Network Authentication Server) type. + * @param nfsType The NFS (Nintendo Friend Server) type. + * @param nfsNo The NFS (Nintendo Friend Server) number. + */ +Result ACTA_SetHostServerSettings(u8 accountSlot, u8 nnasType, u8 nfsType, u8 nfsNo); + +/** + * @brief Sets default server environment settings. This will also update CFG configuration block 0x150002 accordingly. + * @param nnasType The NNAS (Nintendo Network Authentication Server) type. + * @param nfsType The NFS (Nintendo Friend Server) type. + * @param nfsNo The NFS (Nintendo Friend Server) number. + */ +Result ACTA_SetDefaultHostServerSettings(u8 nnasType, u8 nfsType, u8 nfsNo); + +/** + * @brief Sets server environment settings (in string form) for a specific account. This will also update CFG configuration block 0x150002 accordingly. + * @param accountSlot The account slot number of the account to set the host server settings for. + * @param nnasSubdomain Pointer to the new NNAS (Nintendo Network Authentication Server) subdomain to use. + * @param nfsTypeStr Pointer to the new NFS (Nintendo Friend Server) type to use. + */ +Result ACTA_SetHostServerSettingsStr(u8 accountSlot, ActNnasSubdomain *nnasSubdomain, NfsTypeStr *nfsTypeStr); + +/** + * @brief Sets default server environment settings (in string form). This will also update CFG configuration block 0x150002 accordingly. + * @param nnasSubdomain Pointer to the new NNAS (Nintendo Network Authentication Server) subdomain to use. + * @param nfsTypeStr Pointer to the new NFS (Nintendo Friend Server) type to use. + */ +Result ACTA_SetDefaultHostServerSettingsStr(ActNnasSubdomain *nnasSubdomain, NfsTypeStr *nfsTypeStr); + +/** + * @brief Sets the internal base value for generating new persistent IDs. + * @param head The new base value to use. + */ +Result ACTA_SetPersistentIdHead(u32 head); + +/** + * @brief Sets the internal base value for generating new transferable IDs. + * @param counter The new base value to use. + */ +Result ACTA_SetTransferableIdCounter(u16 counter); + +/** + * @brief Updates a specific account's Mii data and screen name. + * @param accountSlot The account slot number of the account to update the Mii and screen name of. + * @param miiData Pointer to the new Mii data to use. + * @param screenName Pointer to the new screen name to use. + */ +Result ACTA_UpdateMiiData(u8 accountSlot, CFLStoreData *miiData, MiiScreenName *screenName); + +/** + * @brief Updates a Mii image of a specific account. + * @param accountSlot The account slot number of the account to update the Mii image for. + * @param miiImageType The type of Mii image to update. + * @param image Pointer to the Mii image data to use. + * @param imageSize Size of the Mii image data. + */ +Result ACTA_UpdateMiiImage(u8 accountSlot, u8 miiImageType, void *image, u32 imageSize); + +/** + * @brief Checks whether or not the given account ID is available for creating a new server account. + * @param accountSlot The account slot number of the account to perform the check for. + * @param accountId Pointer to the input account ID to check. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_InquireAccountIdAvailability(u8 accountSlot, AccountId *accountId, Handle completionEvent); + +/** + * @brief Links a new server account to a local console account. In other words, this creates and links an NNID. + * @param accountSlot The account slot number of the local console account to bind. + * @param accountId Pointer to the account ID to use for the new server account. + * @param mailAddress Pointer to the email address to use for the new server account. + * @param password Pointer to the password to use for the new server account. + * @param isParentEmail Whether or not the input email address is a parental email address. + * @param marketingFlag Whether or not the user has consented to receiving marketing emails. ("Customized Email Offers") + * @param offDeviceFlag Whether or not the user has allowed using the server account from other devices. ("Access from PCs and Other Devices") + * @param birthDateTimestamp A birth date timestamp in the format milliseconds elapsed since 01.01.2000 00:00:00 UTC. + * @param parentalConsentTimestamp When parental consent is required, the timestamp of parental consent in the format milliseconds elapsed since 01.01.2000 00:00:00 UTC. + * @param parentalConsentId When parental consent is required, the resulting ID corresponding to the consent. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_BindToNewServerAccount(u8 accountSlot, AccountId *accountId, AccountMailAddress *mailAddress, AccountPassword *password, bool isParentEmail, bool marketingFlag, bool offDeviceFlag, s64 birthDateTimestatmp, u8 gender, u32 region, AccountTimezone *timezone, EulaInfo *eulaInfo, s64 parentalConsentTimestamp, u32 parentalConsentId, Handle completionEvent); + +/** + * @brief Links a local console account to an existing server account. In other words, this links an existing NNID. + * @param accountSlot The account slot number of the local console account to bind. + * @param accountId Pointer to the account ID of the existing server account. + * @param mailAddress Pointer to the email address of the existing server account. + * @param password Pointer to the password of the existing server account. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_BindToExistentServerAccount(u8 accountSlot, AccountId *accountId, AccountMailAddress *mailAddress, AccountPassword *password, Handle completionEvent); + +/** + * @brief Acquires information about an existing server account. + * @param accountSlot The account slot number of the local console account to use for the request. + * @param accountId Pointer to the account ID of the existing server account. + * @param mailAddress Pointer to the email address of the existing server account. + * @param password Pointer to the password of the existing server account. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_InquireBindingToExistentServerAccount(u8 accountSlot, AccountId *accountId, AccountMailAddress *mailAddress, AccountPassword *password, Handle completionEvent); + +/** + * @brief Deletes a server account. In other words, this deletes an NNID (server-side). + * @param accountSlot The account slot number of the local console account bound to the server account to delete. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_DeleteServerAccount(u8 accountSlot, Handle completionEvent); + +/** + * @brief Acquires an account token for a specific account. + * @param accountSlot The account slot number of the account to acquire the account token for. + * @param password Pointer to the password of the account. + * @param useNullPassword Whether or not to force NULL as the password (no password). This will cause the account password cache to be used instead, if it is enabled. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_AcquireAccountTokenEx(u8 accountSlot, AccountPassword *password, bool useNullPassword, Handle completionEvent); + +/** + * @brief Submits a EULA agreement to the account server. + * @param accountSlot The account slot number of the account to use to submit the agreement. + * @param eulaInfo Pointer to a EULA information structure describing the agreed EULA. + * @param agreementTimestamp A timestamp in the format milliseconds elapsed since 01.01.2000 00:00:00 UTC of when the user agreed to the EULA. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_AgreeEula(u8 accountSlot, EulaInfo *eulaInfo, s64 agreementTimestamp, Handle completionEvent); + +/** + * @brief Reloads account information from the server for a specific account. + * @param accountSlot The account slot number of the account to reload information for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_SyncAccountInfo(u8 accountSlot, Handle completionEvent); + +/** + * @brief Invalidates a specific account's access token in different ways. + * @param accountSlot The account slot number of the account to invalidate the access token for. + * @param invalidationMask A bitfield of the actions to take to invalidate the access token. + */ +Result ACTA_InvalidateAccountToken(u8 accountSlot, u32 invalidationActionMask); + +/** + * @brief Updates the account password for a specific account. + * @param accountSlot The account slot number of the account to update the password for. + * @param password Pointer to the new password to use. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_UpdateAccountPassword(u8 accountSlot, AccountPassword *newPassword, Handle completionEvent); + +/** + * @brief Requests the issuing of a temporary password (valid for 24 hours) to the email address associated with a specific account. + * @param accountSlot The account slot number of the account to issue the temporary password for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_ReissueAccountPassword(u8 accountSlot, Handle completionEvent); + +/** + * @brief Sets the account password input for a specific account. This value is not stored in the save data and only resides in memory. Following up a call to this command with a call to ACTA_EnableAccountPasswordCache will lead to the account password cache being updated. + */ +Result ACTA_SetAccountPasswordInput(u8 accountSlot, AccountPassword *passwordInput); + +/** + * @brief Uploads the Mii data of a specific account to the account server. + * @param accountSlot The account slot number of the account to upload the Mii for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_UploadMii(u8 accountSlot, Handle completionEvent); + +/** + * @brief Inactivates the device association for a specific account. + * @param accountSlot The account slot number of the account to inactive the device association for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_InactivateDeviceAssociation(u8 accountSlot, Handle completionEvent); + +/** + * @brief Validates the email address of a specific account using the code received via the confirmation email. + * @param accountSlot The account slot number of the account to validate the email address for. + * @param confirmationCode The confirmation code received via email. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_ValidateMailAddress(u8 accountSlot, u32 confirmationCode, Handle completionEvent); + +/** + * @brief Requests parental approval for a specific account. + * @param accountSlot The account slot number of the account to request parental approval for. + * @param parentalEmail Pointer to a parental email to use for parental consent. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_SendPostingApprovalMail(u8 accountSlot, AccountMailAddress *parentalEmail, Handle completionEvent); + +/** + * @brief Requests the email address confirmation mail to be resent for a specific account. + * @param accountSlot The account slot number of the account for which the confirmation mail should be resent. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_SendConfirmationMail(u8 accountSlot, Handle completionEvent); + +/** + * @brief Registers a parental email address to be used in case the parental controls PIN has been forgotten for a specific account. + * @param accountSlot The account slot number of the account to register the fallback parental email for. + * @param parentalEmail Pointer to the parental email to use. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_SendConfirmationMailForPin(u8 accountSlot, AccountMailAddress *parentalEmail, Handle completionEvent); + +/** + * @brief Sends the master key for resetting parental controls to a parental email for a specific account. + * @param accountSlot The account slot number for the account to be used for this operation. + * @param masterKey The master key to send to the parental email address. + * @param parentalEmail Pointer to the parental email address to send the master key to. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_SendMasterKeyMailForPin(u8 accountSlot, u32 masterKey, AccountMailAddress *parentalEmail, Handle completionEvent); + +/** + * @brief Requests COPPA parental consent using credit card information. + * @param accountSlot The account slot number for the account to request approval for. + * @param cardInfo Pointer to the credit card information to use for the approval process. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_ApproveByCreditCard(u8 accountSlot, CreditCardInfo *cardInfo, Handle completionEvent); + +/** + * @brief Requests a COPPA code for a specific account. + * @param accountSlot The account slot number for the account to send the request for. + * @param principalId The principalId of the account to send the request for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_SendCoppaCodeMail(u8 accountSlot, u32 principalId, Handle completionEvent); + +/** + * @brief Set a flag in a specifc account's data that determines whether or not it is necessary to upload the account Mii data to the account server. + * @param accountSlot The account slot number of the account to set the flag for. + * @param isDirty Whether or not the Mii data should be reuploaded to the account server. + */ +Result ACTA_SetIsMiiUpdated(u8 accountSlot, bool isDirty); + +/** + * @brief Initializes a server account transfer of a specific account to another device. + * @param accountSlot The account slot number of the account to transfer the server account of. + * @param newDevice Pointer to device info of the target device. + * @param operator Pointer to operator data for the transfer. + * @param operatorSize Size of the operator data buffer (max: 0x100) + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_ReserveTransfer(u8 accountSlot, DeviceInfo *newDevice, char *operator, u32 operatorSize, Handle completionEvent); + +/** + * @brief Finalizes a server account transfer of a specifc account to another device. + * @param accountSlot The account slot number of the account to complete the transfer for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_CompleteTransfer(u8 accountSlot, Handle completionEvent); + +/** + * @brief Inactivates the account-device association for a specific account. In other words, this deletes an NNID. + * @param accountSlot The account slot number of the account to perform this action on. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_InactivateAccountDeviceAssociation(u8 accountSlot, Handle completionEvent); + +/** + * @brief Set the internal network time field. + * @param timestamp The new server time timestamp to use. The timestamp format is milliseconds elapsed since 01.01.2000 00:00:00 UTC. + */ +Result ACTA_SetNetworkTime(s64 timestamp); + +/** + * @brief Updates the account info of a specific account using raw XML data. + * @param accountSlot The account slot number of the account to update information for. + * @param xmlData Pointer to the input XML data. + * @param xmlDataSize Size of the input XML data. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_UpdateAccountInfo(u8 accountSlot, char *xmlData, u32 xmlDataSize, Handle completionEvent); + +/** + * @brief Updates the email address of a specific account. + * @param accountSlot The account slot number of the account to update the email address for. + * @param newEmail Pointer to the new email address to use. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_UpdateAccountMailAddress(u8 accountSlot, AccountMailAddress *newEmail, Handle completionEvent); + +/** + * @brief Deletes the device association for a specific account. + * @param accountSlot The account slot of the account to perform this action on. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_DeleteDeviceAssociation(u8 accountSlot, Handle completionEvent); + +/** + * @brief Deletes the account-device association for a specific account. + * @param accountSlot The account slot of the account to perform this action on. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_DeleteAccountDeviceAssociation(u8 accountSlot, Handle completionEvent); + +/** + * @brief Cancels a pending server account transfer of a specific account to another device. + * @param accountSlot The account slot number of the account to cancel the transfer for. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_CancelTransfer(u8 accountSlot, Handle completionEvent); + +/** + * @brief Cancels any running HTTP requests, saves all pending changes to the system save data, then signals unloadFinishedEvent. Then, waits for remountAndBlockEvent, and once this has been signaled, remounts the system save, and blocks subsequent attempts to save the system save data (which can be bypassed by entering and exiting sleep mode). + * @param unloadFinishedEvent The event handle for ACT to signal once it has saved pending changes and has unmounted its system save. + * @param remountAndBlockEvent The event handle for the caller to signal once ACT should remount its save data and block subsequent save attempts. + */ +Result ACTA_ReloadAndBlockSaveData(Handle unloadFinishedEvent, Handle remountAndBlockEvent); + +/** + * @brief Initializes server-side account deletion for a specific account. In other words, this deletes an NNID. + * @param accountSlot The account slot number of the account to perform this action on. + * @param completionEvent The event handle to signal once the request has finished. + */ +Result ACTA_ReserveServerAccountDeletion(u8 accountSlot, Handle completionEvent); \ No newline at end of file diff --git a/libctru/include/3ds/services/frd.h b/libctru/include/3ds/services/frd.h index 933aacb5f..1d1436a57 100644 --- a/libctru/include/3ds/services/frd.h +++ b/libctru/include/3ds/services/frd.h @@ -5,9 +5,23 @@ #pragma once #include <3ds/mii.h> -#define FRIEND_SCREEN_NAME_SIZE 0xB ///< 11-byte UTF-16 screen name -#define FRIEND_COMMENT_SIZE 0x21 ///< 33-byte UTF-16 comment -#define FRIEND_LIST_SIZE 0x64 ///< 100 (Max number of friends) +#define FRIEND_COMMENT_LEN 16+1 ///< 16-character NULL-terminated UTF-16 comment +#define FRIEND_GAME_MODE_DESCRIPTION_LEN 127+1 ///< 127-character NULL-terminated UTF-16 game mode description + +#define NASC_INGAMESN_LEN 11+1 ///< 11-character NULL-terminated UTF-16 in-game nickname +#define NASC_KEYHASH_LEN 8+1 ///< 8-character NULL-terminated ASCII NASC `keyhash` value +#define NASC_SVC_LEN 4+1 ///< 4-character NULL-terminated ASCII NASC `svc` value + +#define FRIEND_LIST_SIZE 100 ///< 100 (maximum number of friends) + +#define NFS_TYPESTR_LEN 2+1 ///< 2-character NULL-terminated ASCII NFS (Nintendo Friend Server) type string + +typedef u16 FriendComment[FRIEND_COMMENT_LEN]; +typedef u16 FriendGameModeDescription[FRIEND_GAME_MODE_DESCRIPTION_LEN]; + +typedef u16 ScrambledFriendCode[6]; + +typedef char NfsTypeStr[NFS_TYPESTR_LEN]; #pragma pack(push, 1) @@ -19,15 +33,15 @@ typedef struct u64 localFriendCode; } FriendKey; -/// Friend Title data +/// Game key data typedef struct { - u64 tid; - u32 version; - u32 unk; -} TitleData; + u64 titleId; + u16 version; + u8 reserved[6]; +} GameKey; -/// Friend profile data +/// Base profile data typedef struct { u8 region; ///< The region code for the hardware. @@ -35,63 +49,285 @@ typedef struct u8 area; ///< Area code. u8 language; ///< Language code. u8 platform; ///< Platform code. - u32 padding; + u8 padding[3]; +} Profile; + +/// Friend profile data +typedef struct +{ + Profile profile; ///< Base profile data of this friend. + GameKey favoriteGame; ///< Favorite game of this friend. + u32 ncPrincipalId; ///< NC PrincipalID of this friend. + FriendComment personalMessage; ///< Personal message (comment) of this friend. + u8 pad[2]; + s64 lastOnlineTimestamp; ///< NEX timestamp of when this friend was last seen online. } FriendProfile; -/// Game Description structure +/// Base presence data +typedef struct +{ + u32 joinAvailabilityFlag; + u32 matchmakeSystemType; + u32 joinGameId; + u32 joinGameMode; + u32 ownerPrincipalId; + u32 joinGroupId; + u8 applicationArg[20]; +} Presence; + +/// Current user's presence data +typedef struct +{ + Presence presence; ///< The actual presence data. + FriendGameModeDescription gameModeDescription; ///< The game mode description of the current user. +} MyPresence; + +/// Friend presence data +typedef struct +{ + Presence presence; ///< The actual presence data. + bool isPresenceLoaded; ///< Whether or not the presence data for this user has been loaded from the server. + bool hasSentInvitation; ///< Whether or not this friend has sent the current user an invitation. + bool found; ///< Whether or not this friend was found. + u8 pad; +} FriendPresence; + +/// Friend Mii data +typedef struct +{ + bool profanityFlag; ///< Whether or not the Mii contains profanity. + u8 characterSet; ///< The character set for text data. + bool dirtyFlag; ///< Whether or not the Mii is marked as "dirty" (needs to be uploaded to the server). + u8 pad; + MiiData mii; ///< The actual Mii data. +} FriendMii; + +/// Friend playing game structure +typedef struct +{ + GameKey game; ///< Game key of the game. + FriendGameModeDescription gameModeDescription; +} FriendPlayingGame; + +/// Friend info structure typedef struct { - TitleData data; - u16 desc[128]; -} GameDescription; + FriendKey friendKey; ///< FriendKey of this friend. + s64 addedTimestamp; ///< NEX timestamp of when this friend was added to the current user's friend list. + u8 relationship; ///< The type of the relationship with this friend. + u8 pad[7]; + FriendProfile friendProfile; ///< Friend profile data of this friend. + MiiScreenName screenName; ///< The screen name of this friend. + u8 characterSet; ///< The character set used for the text parts of the data of this friend. + u8 pad2; + FriendMii mii; ///< The Mii of this friend. +} FriendInfo; /// Friend Notification Event structure typedef struct { - u8 type; - u8 padding3[3]; - u32 padding; - FriendKey key; + u8 type; ///< Type of event. + u8 padding[7]; + FriendKey sender; ///< Friend key of friend who caused this notification event to be sent. } NotificationEvent; +/// Game Authentication Data structure +typedef struct +{ + u32 nascResult; ///< NASC result code for the LOGIN operation. + u32 httpStatusCode; ///< HTTP status code for the NASC LOGIN operation. + char serverAddress[0x20]; ///< Address of the game server. + u16 serverPort; ///< Port of the game server. + u8 pad[6]; + char authToken[0x100]; ///< Game server authentication token. + u64 serverTime; ///< NEX timestamp for current server time. +} GameAuthenticationData; + +/// Service Locator Data strcture +typedef struct +{ + u32 nascResult; ///< NASC result code for the SVCLOC operation. + u32 httpStatusCode; ///< HTTP status code for the NASC LOGIN operation. + char serviceHost[0x80]; ///< Host address of the target service. + char serviceToken[0x100]; ///< Token for the target service. + u8 statusData; ///< `statusdata` value from the NASC response data. + u8 padding[7]; + u64 serverTime; ///< NEX timestamp for current server time. +} ServiceLocatorData; + +/// Encrypted inner Approach Context structure +typedef struct +{ + FriendProfile friendProfile; + bool hasMii; + bool profanityFlag; + u8 characterSet; + u8 wrappedMii[0x70]; + MiiScreenName screenName; + u8 reserved[0x10F]; +} ApproachContext; + +/// Encrypted Approach Context structure +typedef struct +{ + u8 unknown0; + u8 unknown1; + u8 unknown2; + u8 unknown3; + struct { + u32 principalId; + u64 friendCode; + } CTR_PACKED nonce; + ApproachContext encryptedPayload; + u8 ccmMac[16]; +} EncryptedApproachContext; + +/// Decrypted Approach Context structure +typedef struct +{ + u8 unknown0; + u8 unknown1; + u8 unknown2; + u8 unknown3; + bool hasMii; ///< Whether or not this friend has a Mii. + bool profanityFlag; + u8 characterSet; ///< Character set for text data. + u8 pad; + FriendKey friendKey; ///< Friend key of this friend. + FriendProfile friendProfile; ///< Friend profile of this friend. + FriendMii mii; ///< Mii data of this friend. + MiiScreenName screenName; ///< UTF-16 screen name of this friend. + u8 reserved[0x12A]; +} DecryptedApproachContext; + #pragma pack(pop) -/// Enum to use with FRD_GetNotificationEvent -typedef enum +/// Enum for character set +typedef enum +{ + CHARSET_JPN_USA_EUR = 0, ///< Character set for JPN, USA, and EUR(+AUS). + CHARSET_CHN, ///< Character set for CHN. + CHARSET_KOR, ///< Character set for KOR. + CHARSET_TWN, ///< Character set for TWN. +} CharacterSet; + +/// Enum for NASC Result +typedef enum +{ + NASC_SUCCESS = 001, + NASC_SERVER_UNDER_MAINTENANCE = 101, + NASC_DEVICE_BANNED = 102, + NASC_INVALID_PRODUCT_CODE = 107, + NASC_INVALID_REQUEST_PARAM = 109, + NASC_SERVER_NO_LONGER_AVAILABLE = 110, + NASC_INVALID_SVC = 112, + NASC_INVALID_FPD_VERSION = 119, + NASC_INVALID_TITLE_VERSION = 120, + NASC_INVALID_DEVICE_CERTIFICATE = 121, + NASC_INVALID_PID_HMAC = 122, + NASC_BANNED_ROM_ID = 123, + NASC_INVALID_GAME_ID = 125, + NASC_INVALID_KEY_HASH = 127, +} NASCResult; + +/// Enum for NASC Server Environment +typedef enum +{ + NASC_PRODUCTION = 0, + NASC_TESTING, + NASC_DEVELOPMENT +} NASCEnvironment; + +/// Enum for notification event types +typedef enum +{ + USER_WENT_ONLINE = 1, ///< Self went online + USER_WENT_OFFLINE, ///< Self went offline + FRIEND_WENT_ONLINE, ///< Friend Went Online + FRIEND_UPDATED_PRESENCE, ///< Friend Presence changed (with matching GameJoinID) + FRIEND_UPDATED_MII, ///< Friend Mii changed + FRIEND_UPDATED_PROFILE, ///< Friend Profile changed + FRIEND_WENT_OFFLINE, ///< Friend went offline + FRIEND_REGISTERED_USER, ///< Friend registered self as friend + FRIEND_SENT_JOINABLE_INVITATION, ///< Friend sent invitation (with matching GameJoinID) + FRIEND_CHANGED_GAME_MODE_DESCRIPTION = 145, ///< Friend changed game mode description + FRIEND_CHANGED_FAVORITE_GAME = 146, ///< Friend changed favorite game + FRIEND_CHANGED_COMMENT = 147, ///< Friend changed comment + FRIEND_CHANGED_ANY_PRESENCE = 148, ///< Friend Presence changed (with nonmatching GameJoinID) + FRIEND_SENT_ANY_INVITATION = 149, ///< Friend sent invitiation (with nonmatching GameJoinID) +} FriendNotificationTypes; + +/// Enum for notification event mask +typedef enum +{ + MASK_USER_WENT_ONLINE = BIT(USER_WENT_ONLINE - 1), + MASK_USER_WENT_OFFLINE = BIT(USER_WENT_OFFLINE - 1), + MASK_FRIEND_WENT_ONLINE = BIT(FRIEND_WENT_ONLINE - 1), + MASK_FRIEND_UPDATED_PRESENCE = BIT(FRIEND_UPDATED_PRESENCE - 1), + MASK_FRIEND_UPDATED_MII = BIT(FRIEND_UPDATED_MII - 1), + MASK_FRIEND_UPDATED_PROFILE = BIT(FRIEND_UPDATED_PROFILE - 1), + MASK_FRIEND_WENT_OFFLINE = BIT(FRIEND_WENT_OFFLINE - 1), + MASK_FRIEND_REGISTERED_USER = BIT(FRIEND_REGISTERED_USER - 1), + MASK_FRIEND_SENT_JOINABLE_INVITATION = BIT(FRIEND_SENT_JOINABLE_INVITATION - 1), + // values >= 145 are not exposed to sessions. +} FriendNotificationMask; + +/// Enum for friend relationship type +typedef enum +{ + RELATIONSHIP_INCOMPLETE = 0, ///< Provisionally registered friend. + RELATIONSHIP_COMPLETE, ///< Fully registered friend. + RELATIONSHIP_NOT_FOUND, ///< Friend not registered at all. + RELATIONSHIP_DELETED, ///< Relationship was deleted. + RELATIONSHIP_LOCAL, ///< Provisionally registered friend (but this relationship has not been sent to the server yet). +} RelationshipType; + +/// Enum for friend attributes according to relationship type +typedef enum +{ + FRIEND_ATTRIBUTE_EVER_REGISTERED = BIT(0), ///< Whether or not the current user has ever been in a friend relationship with the friend. This is set when the relationship type is either incomplete, complete, local, or deleted. + FRIEND_ATTRIBUTE_REGISTRATION_COMPLETE = BIT(1) ///< Whether or not the current user has been fully registered by this friend. Set only when the relationship type is complete. +} FriendAttributes; + +/// Enum for NAT mapping type +typedef enum +{ + NAT_MAPPING_UNKNOWN = 0, + NAT_MAPPING_ENDPOINT_INDEPENDENT, + NAT_MAPPING_ENDPOINT_DEPENDENT +} NatMappingType; + +/// Enum for NAT filtering type +typedef enum { - USER_WENT_ONLINE = 1, ///< Self went online - USER_WENT_OFFLINE, ///< Self went offline - FRIEND_WENT_ONLINE, ///< Friend Went Online - FRIEND_UPDATED_PRESENCE, ///< Friend Presence changed - FRIEND_UPDATED_MII, ///< Friend Mii changed - FRIEND_UPDATED_PROFILE, ///< Friend Profile changed - FRIEND_WENT_OFFLINE, ///< Friend went offline - FRIEND_REGISTERED_USER, ///< Friend registered self as friend - FRIEND_SENT_INVITATION ///< Friend Sent invitation -} NotificationTypes; - -/// Initializes FRD service. -Result frdInit(void); - -/// Exists FRD. + NAT_FILTERING_UNKNOWN = 0, + NAT_FILTERING_PORT_INDEPENDENT, + NAT_FILTERING_PORT_DEPENDENT +} NatFilteringType; + +/** + * @brief Initializes friend services. + * @param forceUser Whether or not to force using the user service frd:u instead of the default (admin service frd:a). + */ +Result frdInit(bool forceUser); + +/// Exits friend services. void frdExit(void); -/// Get FRD handle. +/// Get the friend user/admin service handle. Handle *frdGetSessionHandle(void); + /** * @brief Gets the login status of the current user. * @param state Pointer to write the current user's login status to. */ -Result FRDU_HasLoggedIn(bool *state); +Result FRD_HasLoggedIn(bool *state); /** * @brief Gets the online status of the current user. * @param state Pointer to write the current user's online status to. */ -Result FRDU_IsOnline(bool *state); - -/// Logs out of Nintendo's friend server. -Result FRD_Logout(void); +Result FRD_IsOnline(bool *state); /** * @brief Log in to Nintendo's friend server. @@ -99,6 +335,9 @@ Result FRD_Logout(void); */ Result FRD_Login(Handle event); +/// Logs out of Nintendo's friend server. +Result FRD_Logout(void); + /** * @brief Gets the current user's friend key. * @param key Pointer to write the current user's friend key to. @@ -117,39 +356,64 @@ Result FRD_GetMyPreference(bool *isPublicMode, bool *isShowGameName, bool *isSho * @brief Gets the current user's profile information. * @param profile Pointer to write the current user's profile information to. */ -Result FRD_GetMyProfile(FriendProfile *profile); +Result FRD_GetMyProfile(Profile *profile); + +/** + * @brief Gets the current user's presence information. + * @param presence Pointer to write the current user's presence information to. + */ +Result FRD_GetMyPresence(MyPresence *presence); /** * @brief Gets the current user's screen name. * @param name Pointer to write the current user's screen name to. * @param max_size Max size of the screen name. */ -Result FRD_GetMyScreenName(char *name, size_t max_size); +Result FRD_GetMyScreenName(MiiScreenName *name); /** * @brief Gets the current user's Mii data. * @param mii Pointer to write the current user's mii data to. */ -Result FRD_GetMyMii(MiiData *mii); +Result FRD_GetMyMii(FriendMii *mii); + +/** + * @brief Gets the ID of the current local account. + * @param localAccountId Pointer to write the current local account ID to.\ + */ +Result FRD_GetMyLocalAccountId(u8 *localAccountId); /** * @brief Gets the current user's playing game. * @param titleId Pointer to write the current user's playing game to. */ -Result FRD_GetMyPlayingGame(u64 *titleId); +Result FRD_GetMyPlayingGame(GameKey *playingGame); /** * @brief Gets the current user's favourite game. * @param titleId Pointer to write the title ID of current user's favourite game to. */ -Result FRD_GetMyFavoriteGame(u64 *titleId); +Result FRD_GetMyFavoriteGame(GameKey *favoriteGame); + +/** + * @brief Gets the NcPrincipalId for the current user. + * @param ncPrincipalId Pointer to output the NcPrincipalId to. + */ +Result FRD_GetMyNcPrincipalId(u32 *ncPrincipalId); /** * @brief Gets the current user's comment on their friend profile. * @param comment Pointer to write the current user's comment to. * @param max_size Max size of the comment. */ -Result FRD_GetMyComment(char *comment, size_t max_size); +Result FRD_GetMyComment(FriendComment *comment); + +/** + * @brief Gets the current friend account's NEX password. + * @param password Pointer to write the NEX password to. + * @param max_size Max size of the output buffer. Must not exceed 0x800. + */ +Result FRD_GetMyPassword(char *password, u32 bufsize); /** * @brief Gets the current user's friend key list. @@ -160,64 +424,144 @@ Result FRD_GetMyComment(char *comment, size_t max_size); */ Result FRD_GetFriendKeyList(FriendKey *friendKeyList, u32 *num, u32 offset, u32 size); +/** + * @brief Gets friend presence data for the current user's friends. + * @param friendPresences Pointer to write the friend presence data to. + * @param friendKeyList The friend keys of the friends to get presence data for. + * @param count The number of input friend keys. + */ +Result FRD_GetFriendPresence(FriendPresence *friendPresences, const FriendKey *friendKeyList, u32 count); + +/** + * @brief Gets screen names for the current user's friends. + * @param screenNames Pointer to write the UTF-16 screen names to. + * @param screenNamesLen Number of UTF-16 characters `screenNames` can hold. (max: 0x800) + * @param characterSets Pointer to write the character sets for the screen names to. + * @param characterSetsLen Size of buffer to output character sets to. + * @param friendKeyList The friend keys for the friends to get screen names for. + * @param count The number of input friend keys. + * @param maskNonAscii Whether or not to replace all non-ASCII characters with question marks ('?') if the given character set doesn't match that of the corresponding friend's Mii data. + * @param profanityFlag Setting this to true replaces the screen names with all question marks ('?') if profanityFlag is also set in the corresponding friend's Mii data. + */ +Result FRD_GetMiiScreenName(MiiScreenName *screenNames, u32 screenNamesLen, u8 *characterSets, u32 characterSetsLen, const FriendKey *friendKeyList, u32 count, bool maskNonAscii, bool profanityFlag); + /** * @brief Gets the current user's friends' Mii data. - * @param miiDataList Pointer to write Mii data to. - * @param friendKeyList Pointer to FriendKeys. - * @param size Number of Friendkeys. + * @param miiList Pointer to write Mii data to. + * @param friendKeyList Pointer to input friend keys. + * @param count Number of input friend keys. */ -Result FRD_GetFriendMii(MiiData *miiDataList, const FriendKey *friendKeyList, size_t size); +Result FRD_GetFriendMii(FriendMii *miiList, const FriendKey *friendKeyList, u32 count); /** * @brief Get the current user's friends' profile data. * @param profile Pointer to write profile data to. - * @param friendKeyList Pointer to FriendKeys. - * @param size Number of FriendKeys. + * @param friendKeyList Pointer to input friend keys. + * @param count Number of input friend keys. + */ +Result FRD_GetFriendProfile(Profile *profiles, const FriendKey *friendKeyList, u32 count); + +/** + * @brief Get the relationship type for the current user's friends. + * @param relationships Pointer to output relationship types to. + * @param friendKeyList Pointer to input friend keys to query relationship types for. + * @param count Number of input friend keys. + */ +Result FRD_GetFriendRelationship(u8 *relationships, const FriendKey *friendKeyList, u32 count); + +/** + * @brief Get attributes for the current user's friends. + * @param attributes Pointer to output the attributes to. + * @param friendKeyList Pointer to input friend keys to query attributes for. + * @param count Number of input friend keys. */ -Result FRD_GetFriendProfile(FriendProfile *profile, const FriendKey *friendKeyList, size_t size); +Result FRD_GetFriendAttributeFlags(u32 *attributes, const FriendKey *friendKeyList, u32 count); /** * @brief Get the current user's friends' playing game. - * @param desc Pointer to write Game Description data to. - * @param friendKeyList Pointer to FriendKeys, - * @param size Number Of FriendKeys. + * @param playingGames Pointer to write playing game data to. + * @param friendKeyList Pointer to friend keys. + * @param count Number of input friend keys. */ -Result FRD_GetFriendPlayingGame(GameDescription *desc, const FriendKey *friendKeyList, size_t size); +Result FRD_GetFriendPlayingGame(FriendPlayingGame *playingGames, const FriendKey *friendKeyList, u32 count); /** - * @brief Get the current user's friends' favourite game. - * @param desc Pointer to write Game Description data to. - * @param friendKeyList Pointer to FriendKeys, - * @param count Number Of FriendKeys. + * @brief Get the current user's friends' favourite games. + * @param favoriteGames Pointer to write game key data to. + * @param friendKeyList Pointer to friend keys. + * @param count Number of friend keys. */ -Result FRD_GetFriendFavouriteGame(GameDescription *desc, const FriendKey *friendKeyList, u32 count); +Result FRD_GetFriendFavoriteGame(GameKey *favoriteGames, const FriendKey *friendKeyList, u32 count); /** - * @brief Gets whether a friend key is included in the current user's friend list. - * @param friendKeyList Pointer to a list of friend keys. - * @param isFromList Pointer to a write the friendship status to. + * @brief Get info about the current user's friends. + * @param infos Pointer to output friend info data to. + * @param friendKeyList Pointer to input friend keys. + * @param count Number of input friend keys. + * @param maskNonAscii Whether or not to replace all non-ASCII characters with question marks ('?') if the given character set doesn't match that of the corresponding friend's Mii data. + * @param profanityFlag Setting this to true replaces the screen names with all question marks ('?') if profanityFlag is also set in the corresponding friend's Mii data. */ -Result FRD_IsInFriendList(FriendKey *friendKeyList, bool *isFromList); +Result FRD_GetFriendInfo(FriendInfo *infos, const FriendKey *friendKeyList, u32 count, bool maskNonAscii, bool profanityFlag); + +/** + * @brief Gets whether a friend code is included in the current user's friend list. + * @param friendCode The friend code to check for. + * @param isFromList Pointer to write whether or not the given friend code was found in the current user's friends list. + */ +Result FRD_IsInFriendList(u64 friendCode, bool *isFromList); + +/** + * @brief Unscrambles a scrambled friend code. + * @param unscrambled Pointer to output the unscrambled friend codes to. + * @param scrambled Pointer to the input scrambled friend codes. + * @param count Number of input scrambled codes. + */ +Result FRD_UnscrambleLocalFriendCode(u64 *unscrambled, ScrambledFriendCode *scrambled, u32 count); /** * @brief Updates the game mode description string. - * @param desc Pointer to write the game mode description to. + * @param desc Pointer to the UTF-8 game mode description to use. + */ +Result FRD_UpdateGameModeDescription(FriendGameModeDescription *desc); + +/** + * @brief Updates the current user's presence data and game mode description. + * @param presence The new presence data to use. + * @param desc The new game mode description to use. + */ +Result FRD_UpdateMyPresence(Presence *presence, FriendGameModeDescription *desc); + +/** + * @brief Sends an invitation to the current user's friends. + * @param friendKeyList The friend keys to send an invitation to. + * @param count The number of input friend keys. */ -Result FRD_UpdateGameModeDescription(const char *desc); +Result FRD_SendInvitation(const FriendKey *friendKeyList, u32 count); /** - * @brief Event which is signaled when friend login states change. - * @param event event which will be signaled. + * @brief Registers the event handle that will be signaled to inform the session of various status changes. + * @param event The event handle to register for notification signaling. */ Result FRD_AttachToEventNotification(Handle event); +/** + * @brief Sets the notification mask for the event notification system. + * @param mask The notifications to subscribe to for the event notification system. + */ +Result FRD_SetNotificationMask(FriendNotificationMask mask); + /** * @brief Get Latest Event Notification * @param event Pointer to write recieved notification event struct to. * @param count Number of events * @param recievedNotifCount Number of notification reccieved. */ -Result FRD_GetEventNotification(NotificationEvent *event, u32 count, u32 *recievedNotifCount); +Result FRD_GetEventNotification(NotificationEvent *event, u32 count, u32 *recievedNotifCount); + +/** + * @brief Get the result of the last internal operation. + */ +Result FRD_GetLastResponseResult(); /** * @brief Returns the friend code using the given principal ID. @@ -240,6 +584,89 @@ Result FRD_FriendCodeToPrincipalId(u64 friendCode, u32 *principalId); */ Result FRD_IsValidFriendCode(u64 friendCode, bool *isValid); +/** + * @brief Get a support error code (XXX-YYYY) for the given result code. + * @param errorCode Pointer to write the support error code to. + * @param res The result code to convert. + */ +Result FRD_ResultToErrorCode(u32 *errorCode, Result res); + +/** + * @brief Requests game server authentication. + * @param serverId The ID of the NEX server to request authentication for. + * @param ingamesn The UTF-16 nickname to use in game. + * @param ingamesnSize Buffer size of the input ingamesn buffer. (max: FRIEND_INGAMESN_LEN * 2) + * @param majorSdkVersion The major SDK version. + * @param minorSdkVersion The minor SDK version. + * @param completionEvent The event handle to signal once the operation has completed. + */ +Result FRD_RequestGameAuthentication(u32 serverId, u16 *ingamesn, u32 ingamesnSize, u8 majorSdkVersion, u8 minorSdkVersion, Handle completionEvent); + +/** + * @brief Get game server authentication data requested using FRD_RequestGameAuthentication. + * @param data Pointer to write game server authentication data to. + */ +Result FRD_GetGameAuthenticationData(GameAuthenticationData *data); + +/** + * @brief Request service locator info for a given NEX server. + * @param keyhash The `keyhash` value to use for the NASC request. + * @param svc The svc `value` to use for the NASC request. + * @param majorSdkVersion The major SDK version. + * @param minorSdkVersion The minor SDK version. + * @param completionEvent The event handle to signal once the operation has completed. + * @param serverId + */ +Result FRD_RequestServiceLocator(u32 serverId, char *keyhash, char *svc, u8 majorSdkVersion, u8 minorSdkVersion, Handle completionEvent); + +/** + * @brief Get service locator data requested using FRD_RequestServiceLocator. + * @param data Pointer to write the service locator data to. + */ +Result FRD_GetServiceLocatorData(ServiceLocatorData *data); + +/** + * @brief Starts an internal task to determine the NAT properties of the current internet connection. + * @param completionEvent The event handle to signal once the task has completed. + */ +Result FRD_DetectNatProperties(Handle completionEvent); + +/** + * @brief Returns NAT properties for the current internet connection. + * @param natMappingType Pointer to write the NAT mapping type of the connection to. + * @param natFilteringType Pointer to write the NAT filtering type of the connection to. + */ +Result FRD_GetNatProperties(u32 *natMappingType, u32 *natFilteringType); + +/** + * @brief Returns the difference (in nanoseconds) between server time and device time. This difference is calculated every time the system logs into friend services. + * @param diffMs The pointer to write the time difference (in nanoseconds) to. + */ +Result FRD_GetServerTimeDifference(u64 *diff); + +/** + * @brief Configures the current session to allow or disallow running the friends service in sleep mode (half-awake mode). + * @param allow Whether or not to enable half-awake mode. + */ +Result FRD_AllowHalfAwake(bool allow); + +/** + * @brief Gets the server environment configuration for the current user. + * @param nascEnvironment Pointer to write the NASC server environment type to. + * @param nfsType Pointer to write the NFS (Nintendo Friend Server) type to. + * @param nfsNo Pointer to write the NFS (Nintendo Friend Server) number to. + */ +Result FRD_GetServerTypes(u8 *nascEnvironment, u8 *nfsType, u8 *nfsNo); + +/** + * @brief Gets the comment (personal) message of the current user's friends. + * @param comments Pointer to write the friend comment data to. + * @param commentsLen Number of UTF-16 characters `screenNames` can hold. (max: 0xC00) + * @param friendKeyList Pointer to input friend keys. + * @param count Number of input friend keys. + */ +Result FRD_GetFriendComment(FriendComment *comments, u32 commentsLen, const FriendKey *friendKeyList, u32 count); + /** * @brief Sets the Friend API to use a specific SDK version. * @param sdkVer The SDK version needed to be used. @@ -247,15 +674,143 @@ Result FRD_IsValidFriendCode(u64 friendCode, bool *isValid); Result FRD_SetClientSdkVersion(u32 sdkVer); /** - * @brief Add a Friend online. + * @brief Gets the current user's encrypted approach context. + * @param ctx Pointer to write the encrypted approach context data to. + */ +Result FRD_GetMyApproachContext(EncryptedApproachContext *ctx); + +/** + * @brief Adds a friend using their encrypted approach context. + * @param unkbuf Pointer to unknown (and unused) data. + * @param unkbufSize Size of unknown (and unused) data. (max: 0x600) + * @param ctx Pointer to encrypted approach context data. + * @param completionEvent The event handle to signal when this action is completed. + */ +Result FRD_AddFriendWithApproach(u8 *unkbuf, u32 unkbufSize, EncryptedApproachContext *ctx, Handle completionEvent); + +/** + * @brief Decrypts an encrypted approach context. + * @param decryptedContext Pointer to write the decrypted approach context data to. + * @param encryptedContext Pointer to input encrypted approach context. + * @param maskNonAscii Whether or not to replace all non-ASCII characters with question marks ('?') if the given character set doesn't match that of the corresponding friend's Mii data. + * @param characterSet The character set to use for text conversions. + */ +Result FRD_DecryptApproachContext(DecryptedApproachContext *decryptedContext, EncryptedApproachContext *encryptedContext, bool maskNonAscii, u8 characterSet); + +/** + * @brief Gets extended NAT properties. This is the same as FRD_GetNatProperties, with this version also returning the NAT Mapping Port Increment. + * @param natMappingType Pointer to write the NAT mapping type of the connection to. + * @param natFilteringType Pointer to write the NAT filtering type of the connection to. + * @param natMappingPortIncrement Pointer to write the NAT mapping port increment to. + */ +Result FRD_GetExtendedNatProperties(u32 *natMappingType, u32 *natFilteringType, u32 *natMappingPortIncrement); + +/** + * @brief Creates a new local friends account. + * @param localAccountId The local account ID to use. + * @param nascEnvironment The NASC environment to create this account in. + * @param nfsType The NFS (Nintendo Friend Server) type this account should use. + * @param nfsNo The NFS (Nintendo Friend Server) number this account should use. + */ +Result FRDA_CreateLocalAccount(u8 localAccountId, u8 nascEnvironment, u8 nfsType, u8 nfsNo); + +/** + * @brief Deletes a local friends account. + * @param localAccountId The ID of the local account to delete. + */ +Result FRDA_DeleteLocalAccount(u8 localAccountId); + +/** + * @brief Loads a local friends account. + * @param localAccountId The ID of the local account to load. + */ +Result FRDA_LoadLocalAccount(u8 localAccountId); + +/** + * @brief Unloads the currently active local account. + */ +Result FRDA_UnloadLocalAccount(); + +/** + * @brief Saves all data of the friends module. + */ +Result FRDA_Save(); + +/** + * @brief Adds a friend online ("Internet" option). * @param event Event signaled when friend is registered. * @param principalId PrincipalId of the friend to add. */ -Result FRD_AddFriendOnline(Handle event, u32 principalId); +Result FRDA_AddFriendOnline(Handle event, u32 principalId); + +/** + * @brief Adds a friend offline ("Local" option). + * @param friendKey Pointer to the friend key of the friend to add. + * @param mii Pointer to the Mii of the friend to add. + * @param friendProfile Pointer to the friend profile of the friend to add. + * @param screenName Pointer to the UTF-16 screen name of the friend to add. + * @param profanityFlag Setting this to true will cause calls that return the screen name to replace it with question marks ('?') when profanityFlag is true in those calls. + * @param characterSet The character set to use for text data of the friend. + */ +Result FRDA_AddFriendOffline(FriendKey *friendKey, FriendMii *mii, FriendProfile *friendProfile, MiiScreenName *screenName, bool profanityFlag, u8 characterSet); + +/** + * @brief Updates a friend's display name. + * @param friendKey Pointer to friend key of the friend to update the screen name of. + * @param screenName Pointer to the new screen name to use. + * @param characterSet The character set of the new screen name. + */ +Result FRDA_UpdateMiiScreenName(FriendKey *friendKey, MiiScreenName *screenName, u8 characterSet); /** - * @brief Remove a Friend. + * @brief Remove a friend. * @param principalId PrinipalId of the friend code to remove. * @param localFriendCode LocalFriendCode of the friend code to remove. */ -Result FRD_RemoveFriend(u32 principalId, u64 localFriendCode); +Result FRDA_RemoveFriend(u32 principalId, u64 localFriendCode); + +/** + * @brief Updates the game being played by the current user. + * @param playingGame Pointer to game key of the game being played. + */ +Result FRDA_UpdatePlayingGame(GameKey *playingGame); + +/** + * @brief Updates the current user's friend list preferences. + * @param isPublicMode Whether or not the online status should be public. + * @param isShowGameMode Whether or not the currently played game is shown. + * @param isShowPlayedMode Whether or not the play history is shown. + */ +Result FRDA_UpdatePreference(bool isPublicMode, bool isShowGameMode, bool isShowPlayedMode); + +/** + * @brief Updates the current user's Mii. + * @param mii Pointer to the new Mii data to use. + * @param screenName Pointer to new screen name associated with the new Mii. + * @param profanityFlag Setting this to true will cause calls that return the screen name to replace it with question marks ('?') when profanityFlag is true in those calls. + * @param characterSet The character set to use for the screen name. + */ +Result FRDA_UpdateMii(FriendMii *mii, MiiScreenName *screenName, bool profanityFlag, u8 characterSet); + +/** + * @brief Updates the current user's favorite game. + * @param favoriteGame Pointer to the game key of the new favorite game. + */ +Result FRDA_UpdateFavoriteGame(GameKey *favoriteGame); + +/** + * @brief Sets the NcPrincipalId of the current user. + * @param ncPrincipalId The new NcPrincipalId. + */ +Result FRDA_SetNcPrincipalId(u32 ncPrincipalId); + +/** + * @brief Updates the current user's comment (personal message). + * @param comment Pointer to the new comment (personal message). + */ +Result FRDA_UpdateComment(FriendComment *comment); + +/** + * @brief Increments the move count in the current local account's save data. + */ +Result FRDA_IncrementMoveCount(); diff --git a/libctru/include/3ds/services/frdn.h b/libctru/include/3ds/services/frdn.h new file mode 100644 index 000000000..0a7fd4bef --- /dev/null +++ b/libctru/include/3ds/services/frdn.h @@ -0,0 +1,40 @@ +/** + * @file frdn.h + * @brief Friend Network Daemon Service + */ +#pragma once +#include <3ds/types.h> + +/** + * @brief Initializes the friend network daemon service. + */ +Result frdnInit(); + +/// Exits the friend network daemon service. +void frdnExit(void); + +/// Get the friend network daemon service handle. +Handle *frdnGetSessionHandle(void); + +/** + * @brief Gets the handle signaled whenever the friends daemon changes its status. + * @param evt Pointer to write the shared status changed event handle to. + */ +Result FRDN_GetHandleOfNdmStatusChangedEvent(Handle *evt); + +/** + * @brief Resumes the friends daemon. + */ +Result FRDN_Resume(); + +/** + * @brief Suspends the friends daemon. + * @param immediately Whether or not to suspend immediately. + */ +Result FRDN_SuspendAsync(bool immediately); + +/** + * @brief Queries the status of the friends daemon. + * @param status Pointer to output the status value to. + */ +Result FRDN_QueryStatus(u8 *status); \ No newline at end of file diff --git a/libctru/source/services/act.c b/libctru/source/services/act.c new file mode 100644 index 000000000..0943e21ec --- /dev/null +++ b/libctru/source/services/act.c @@ -0,0 +1,1391 @@ +#include <3ds/synchronization.h> +#include <3ds/services/act.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> +#include + +static Handle actHandle; +static int actRefCount; + +#define MIN(x,y) ((x) > (y) ? (y) : (x)) + +Result actInit(bool forceUser) +{ + Result ret = 0; + + if (AtomicPostIncrement(&actRefCount)) return 0; + + if (forceUser) + ret = srvGetServiceHandle(&actHandle, "act:u"); + else + ret = srvGetServiceHandle(&actHandle, "act:a"); + + if (R_FAILED(ret)) + AtomicDecrement(&actHandle); + + return ret; +} + +void actExit() +{ + if (AtomicDecrement(&actRefCount)) return; + svcCloseHandle(actHandle); +} + +Handle *actGetSessionHandle(void) +{ + return &actHandle; +} + +Result ACT_Initialize(u32 sdkVersion, u32 sharedMemSize, Handle sharedMem) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1,2,4); // 0x10084 + cmdbuf[1] = sdkVersion; + cmdbuf[2] = sharedMemSize; + cmdbuf[3] = IPC_Desc_CurProcessId(); + // cmdbuf[4] = process id + cmdbuf[5] = IPC_Desc_SharedHandles(1); + cmdbuf[6] = sharedMem; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_ResultToErrorCode(Result code) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2,1,0); // 0x20040 + cmdbuf[1] = (u32)code; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetLastResponseResult() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3,0,0); // 0x30000 + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_Cancel() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4,0,0); // 0x40000 + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetCommonInfo(void *output, u32 outputSize, u32 dataType) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x5,2,2); // 0x50042 + cmdbuf[1] = outputSize; + cmdbuf[2] = dataType; + cmdbuf[3] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W); + cmdbuf[4] = (u32)output; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetAccountInfo(void *output, u32 outputSize, u8 accountSlot, u32 infoType) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x6,3,2); // 0x600C2 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = outputSize; + cmdbuf[3] = infoType; + cmdbuf[4] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W); + cmdbuf[5] = (u32)output; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetAsyncResult(u32 *outReadSize, void *output, u32 outputSize, u32 requestType) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x7,2,2); // 0x70082 + cmdbuf[1] = outputSize; + cmdbuf[2] = requestType; + cmdbuf[3] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W); + cmdbuf[4] = (u32)output; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + *outReadSize = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetMiiImage(u32 *outSize, void *output, u32 outputSize, u8 accountSlot, u8 miiImageType) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x8,3,2); // 0x800C2 + cmdbuf[1] = outputSize; + cmdbuf[2] = (u32)miiImageType; + cmdbuf[3] = (u32)accountSlot; + cmdbuf[4] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W); + cmdbuf[5] = (u32)output; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + *outSize = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result ACT_SetNfsPassword(u8 accountSlot, char *password) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x9,6,0); // 0x90180 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14); + memcpy(&cmdbuf[2], password, MIN(strnlen(password, 16), 16)); + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_SetIsApplicationUpdateRequired(bool required) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xA,1,0); // 0xA0040 + cmdbuf[1] = (u32)required; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireEulaList(u8 countryCode, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xB,1,2); // 0xB0042 + cmdbuf[1] = (u32)countryCode; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireTimezoneList(u8 countryCode, u8 languageCode, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xC,2,2); // 0xC0082 + cmdbuf[1] = (u32)countryCode; + cmdbuf[2] = (u32)languageCode; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GenerateUuid(ActUuid *uuid, u32 uniqueId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xD,1,0); // 0xD0040 + cmdbuf[1] = uniqueId; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + memcpy(uuid, &cmdbuf[2], sizeof(ActUuid)); + + return (Result)cmdbuf[1]; +} + +Result ACT_GetUuid(ActUuid *uuid, u8 accountSlot, u32 uniqueId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xE,2,0); // 0xE0080 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = uniqueId; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + memcpy(uuid, &cmdbuf[2], sizeof(ActUuid)); + + return (Result)cmdbuf[1]; +} + +Result ACT_FindSlotNoByUuid(u8 *accountSlot, ActUuid *uuid, u32 uniqueId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xF,5,0); // 0xF0140 + cmdbuf[1] = uniqueId; + memcpy(&cmdbuf[2], uuid, sizeof(ActUuid)); + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + *accountSlot = (u8)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result ACT_Save() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x10,0,0); // 0x100000 + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetTransferableId(u64 *transferableId, u8 accountSlot, u8 saltValue) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x11,2,0); // 0x110080 + cmdbuf[1] = (u32)saltValue; + cmdbuf[2] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + *transferableId = *((u64 *)&cmdbuf[2]); + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireNexServiceToken(u8 accountSlot, u32 serverId, bool doParentralControlsCheck, u32 callerProcessId, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x12,4,2); // 0x120102 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = serverId; + cmdbuf[3] = (u32)doParentralControlsCheck; + cmdbuf[4] = callerProcessId; + cmdbuf[5] = IPC_Desc_SharedHandles(1); + cmdbuf[6] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetNexServiceToken(NexServiceToken *token) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x13,0,2); // 0x130002 + cmdbuf[1] = IPC_Desc_Buffer(sizeof(NexServiceToken), IPC_BUFFER_W); + cmdbuf[2] = (u32)token; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireIndependentServiceToken(u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentalControlsCheck, bool shared, u32 callerProcessId, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x14,14,2); // 0x140382 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x24); + memcpy(&cmdbuf[2], clientId, MIN(strnlen(clientId, 32), 32)); + cmdbuf[11] = cacheDuration; + cmdbuf[12] = (u32)doParentalControlsCheck; + cmdbuf[13] = (u32)shared; + cmdbuf[14] = callerProcessId; + cmdbuf[15] = IPC_Desc_SharedHandles(1); + cmdbuf[16] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetIndependentServiceToken(IndependentServiceTokenV1 *token) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x15,0,2); // 0x150002 + cmdbuf[1] = IPC_Desc_Buffer(sizeof(IndependentServiceTokenV1), IPC_BUFFER_W); + cmdbuf[2] = (u32)token; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireAccountInfo(u8 accountSlot, u32 infoType, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x16,2,2); // 0x160082 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = infoType; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireAccountIdByPrincipalId(u32 *principalIds, u32 principalIdsSize, u8 unk, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x17,2,4); // 0x170084 + cmdbuf[1] = principalIdsSize; + cmdbuf[2] = (u32)unk; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + cmdbuf[5] = IPC_Desc_StaticBuffer(principalIdsSize, 0); + cmdbuf[6] = (u32)principalIds; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquirePrincipalIdByAccountId(AccountId *accountIds, u32 accountIdsSize, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x18,1,4); // 0x180044 + cmdbuf[1] = accountIdsSize; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + cmdbuf[4] = IPC_Desc_StaticBuffer(accountIdsSize, 0); + cmdbuf[5] = (u32)accountIds; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireMii(u32 *persistentIds, u32 persistentIdsSize, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x19,1,4); // 0x190044 + cmdbuf[1] = persistentIdsSize; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + cmdbuf[4] = IPC_Desc_StaticBuffer(persistentIdsSize, 0); + cmdbuf[5] = (u32)persistentIds; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireAccountInfoRaw(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1A,1,2); // 0x1A0042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetCachedIndependentServiceToken(IndependentServiceTokenV1 *token, u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentralControlsCheck, bool shared) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1C,13,2); // 0x1C0342 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x24); + memcpy(&cmdbuf[2], clientId, MIN(strnlen(clientId, 32), 32)); + cmdbuf[11] = cacheDuration; + cmdbuf[12] = (u32)doParentralControlsCheck; + cmdbuf[13] = (u32)shared; + cmdbuf[14] = IPC_Desc_Buffer(sizeof(IndependentServiceTokenV1), IPC_BUFFER_W); + cmdbuf[15] = (u32)token; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_InquireMailAddressAvailability(AccountMailAddress *mailAddress, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1D,0,4); // 0x1D0004 + cmdbuf[1] = IPC_Desc_SharedHandles(1); + cmdbuf[2] = completionEvent; + cmdbuf[3] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[4] = (u32)mailAddress; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireEula(u8 countryCode, char *languageCode, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1E,2,2); // 0x1E0082 + cmdbuf[1] = (u32)countryCode; + cmdbuf[2] = 0; + memcpy(&cmdbuf[2], languageCode, MIN(strnlen(languageCode, 2), 2)); + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireEulaLanguageList(u8 countryCode, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1F,1,2); // 0x1F0042 + cmdbuf[1] = (u32)countryCode; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_AcquireIndependentServiceTokenV2(u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentalControlsCheck, bool shared, u32 callerProcessId, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x20,14,2); // 0x200382 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x24); + memcpy(&cmdbuf[2], clientId, MIN(strnlen(clientId, 32), 32)); + cmdbuf[11] = cacheDuration; + cmdbuf[12] = (u32)doParentalControlsCheck; + cmdbuf[13] = (u32)shared; + cmdbuf[14] = callerProcessId; + cmdbuf[15] = IPC_Desc_SharedHandles(1); + cmdbuf[16] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetIndependentServiceTokenV2(IndependentServiceTokenV2 *token) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x21,0,2); // 0x210002 + cmdbuf[1] = IPC_Desc_Buffer(sizeof(IndependentServiceTokenV2), IPC_BUFFER_W); + cmdbuf[2] = (u32)token; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACT_GetCachedIndependentServiceTokenV2(IndependentServiceTokenV2 *token, u8 accountSlot, char *clientId, u32 cacheDuration, bool doParentralControlsCheck, bool shared) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x22,13,2); // 0x220342 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x24); + memcpy(&cmdbuf[2], clientId, MIN(strnlen(clientId, 32), 32)); + cmdbuf[11] = cacheDuration; + cmdbuf[12] = (u32)doParentralControlsCheck; + cmdbuf[13] = (u32)shared; + cmdbuf[14] = IPC_Desc_Buffer(sizeof(IndependentServiceTokenV2), IPC_BUFFER_W); + cmdbuf[15] = (u32)token; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SwapAccounts(u8 accountSlot1, u8 accountSlot2) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x401,2,0); // 0x4010080 + cmdbuf[1] = (u32)accountSlot1; + cmdbuf[2] = (u32)accountSlot2; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_CreateConsoleAccount() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x402,0,0); // 0x4020000 + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_CommitConsoleAccount(u8 accountSlot) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x403,1,0); // 0x4030040 + cmdbuf[1] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UnbindServerAccount(u8 accountSlot, bool completely) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x404,2,0); // 0x4040080 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = (u32)completely; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_DeleteConsoleAccount(u8 accountSlot) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x405,1,0); // 0x4050040 + cmdbuf[1] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_LoadConsoleAccount(u8 accountSlot, bool doPasswordCheck, AccountPassword *password, bool useNullPassword, bool dryRun) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x406,9,0); // 0x4060240 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = (u32)doPasswordCheck; + memset(&cmdbuf[3], 0, 0x14); + memcpy(&cmdbuf[3], password, sizeof(AccountPassword)); + cmdbuf[8] = (u32)useNullPassword; + cmdbuf[9] = (u32)dryRun; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UnloadConsoleAccount() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x407,0,0); // 0x4070000 + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_EnableAccountPasswordCache(u8 accountSlot, bool enabled) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x408,2,0); // 0x4080080 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = (u32)enabled; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetDefaultAccount(u8 accountSlot) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x409,1,0); // 0x4090040 + cmdbuf[1] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_ReplaceAccountId(u8 accountSlot) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x40A,1,0); // 0x40A0040 + cmdbuf[1] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_GetSupportContext(SupportContext *supportContext, u8 accountSlot) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x40B,1,0); // 0x40B0040 + cmdbuf[1] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + memcpy(supportContext, &cmdbuf[2], sizeof(SupportContext)); + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetHostServerSettings(u8 accountSlot, u8 nnasType, u8 nfsType, u8 nfsNo) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x40C,4,0); // 0x40C0100 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = (u32)nnasType; + cmdbuf[3] = (u32)nfsType; + cmdbuf[4] = (u32)nfsNo; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetDefaultHostServerSettings(u8 nnasType, u8 nfsType, u8 nfsNo) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x40D,3,0); // 0x40C00C0 + cmdbuf[1] = (u32)nnasType; + cmdbuf[2] = (u32)nfsType; + cmdbuf[3] = (u32)nfsNo; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetHostServerSettingsStr(u8 accountSlot, ActNnasSubdomain *nnasSubdomain, NfsTypeStr *nfsTypeStr) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x40E,11,0); // 0x40E02C0 + memset(&cmdbuf[1], 0, 0x24); + memcpy(&cmdbuf[1], nnasSubdomain, sizeof(ActNnasSubdomain)); + cmdbuf[10] = 0; + memcpy(&cmdbuf[10], nfsTypeStr, sizeof(NfsTypeStr)); + cmdbuf[11] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetDefaultHostServerSettingsStr(ActNnasSubdomain *nnasSubdomain, NfsTypeStr *nfsTypeStr) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x40F,10,0); // 0x40F0280 + memset(&cmdbuf[1], 0, 0x24); + memcpy(&cmdbuf[1], nnasSubdomain, sizeof(ActNnasSubdomain)); + cmdbuf[10] = 0; + memcpy(&cmdbuf[10], nfsTypeStr, sizeof(NfsTypeStr)); + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetPersistentIdHead(u32 head) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x410,1,0); // 0x4100040 + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetTransferableIdCounter(u16 counter) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x411,1,0); // 0x4110040 + cmdbuf[1] = (u32)counter; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UpdateMiiData(u8 accountSlot, CFLStoreData *miiData, MiiScreenName *screenName) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x412,31,0); // 0x41207C0 + cmdbuf[1] = (u32)accountSlot; + memcpy(&cmdbuf[2], miiData, sizeof(CFLStoreData)); + memset(&cmdbuf[26], 0, 0x18); + memcpy(&cmdbuf[26], screenName, sizeof(MiiScreenName)); + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UpdateMiiImage(u8 accountSlot, u8 miiImageType, void *image, u32 imageSize) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x413,3,2); // 0x41300C2 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = (u32)miiImageType; + cmdbuf[3] = imageSize; + cmdbuf[4] = IPC_Desc_Buffer(imageSize, IPC_BUFFER_R); + cmdbuf[5] = (u32)image; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_InquireAccountIdAvailability(u8 accountSlot, AccountId *accountId, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x414,6,2); // 0x4140182 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14); + memcpy(&cmdbuf[2], accountId, sizeof(AccountId)); + cmdbuf[7] = IPC_Desc_SharedHandles(1); + cmdbuf[8] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_BindToNewServerAccount(u8 accountSlot, AccountId *accountId, AccountMailAddress *mailAddress, AccountPassword *password, bool isParentEmail, bool marketingFlag, bool offDeviceFlag, s64 birthDateTimestatmp, u8 gender, u32 region, AccountTimezone *timezone, EulaInfo *eulaInfo, s64 parentalConsentTimestamp, u32 parentalConsentId, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x415,59,4); // 0x4150EC4 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14 * 2); + memcpy(&cmdbuf[2], accountId, sizeof(AccountId)); + memcpy(&cmdbuf[7], password, sizeof(AccountPassword)); + cmdbuf[12] = (u32)isParentEmail; + cmdbuf[13] = (u32)marketingFlag; + *((u64 *)&cmdbuf[14]) = birthDateTimestatmp; + cmdbuf[16] = (u32)gender; + cmdbuf[17] = region; + memcpy(&cmdbuf[18], timezone, sizeof(AccountTimezone)); + memcpy(&cmdbuf[54], eulaInfo, sizeof(EulaInfo)); + *((u64 *)&cmdbuf[56]) = parentalConsentTimestamp; + cmdbuf[58] = parentalConsentId; + cmdbuf[59] = (u32)offDeviceFlag; + cmdbuf[60] = IPC_Desc_SharedHandles(1); + cmdbuf[61] = completionEvent; + cmdbuf[62] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[63] = (u32)mailAddress; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_BindToExistentServerAccount(u8 accountSlot, AccountId *accountId, AccountMailAddress *mailAddress, AccountPassword *password, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x416,11,4); // 0x41602C4 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14 * 2); + memcpy(&cmdbuf[2], accountId, sizeof(AccountId)); + memcpy(&cmdbuf[7], password, sizeof(AccountPassword)); + cmdbuf[12] = IPC_Desc_SharedHandles(1); + cmdbuf[13] = completionEvent; + cmdbuf[14] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[15] = (u32)mailAddress; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_InquireBindingToExistentServerAccount(u8 accountSlot, AccountId *accountId, AccountMailAddress *mailAddress, AccountPassword *password, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x417,11,4); // 0x41702C4 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14 * 2); + memcpy(&cmdbuf[2], accountId, sizeof(AccountId)); + memcpy(&cmdbuf[7], password, sizeof(AccountPassword)); + cmdbuf[12] = IPC_Desc_SharedHandles(1); + cmdbuf[13] = completionEvent; + cmdbuf[14] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[15] = (u32)mailAddress; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_DeleteServerAccount(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x418,1,2); // 0x4180042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_AcquireAccountTokenEx(u8 accountSlot, AccountPassword *password, bool useNullPassword, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x41A,7,2); // 0x41A01C2 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14); + memcpy(&cmdbuf[2], password, sizeof(AccountPassword)); + cmdbuf[7] = (u32)useNullPassword; + cmdbuf[8] = IPC_Desc_SharedHandles(1); + cmdbuf[9] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_AgreeEula(u8 accountSlot, EulaInfo *eulaInfo, s64 agreementTimestamp, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x41B,5,2); // 0x41B0142 + cmdbuf[1] = (u32)accountSlot; + memcpy(&cmdbuf[2], eulaInfo, sizeof(EulaInfo)); + *((u64 *)&cmdbuf[4]) = agreementTimestamp; + cmdbuf[6] = IPC_Desc_SharedHandles(1); + cmdbuf[7] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SyncAccountInfo(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x41C,1,2); // 0x41C0042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_InvalidateAccountToken(u8 accountSlot, u32 invalidationActionMask) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x41D,2,0); // 0x41D0080 + cmdbuf[1] = invalidationActionMask; + cmdbuf[2] = (u32)accountSlot; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UpdateAccountPassword(u8 accountSlot, AccountPassword *newPassword, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x41E,6,2); // 0x41E0182 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14); + memcpy(&cmdbuf[2], newPassword, sizeof(AccountPassword)); + cmdbuf[7] = IPC_Desc_SharedHandles(1); + cmdbuf[8] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_ReissueAccountPassword(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x41F,1,2); // 0x41F0042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetAccountPasswordInput(u8 accountSlot, AccountPassword *passwordInput) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x420,6,0); // 0x4200180 + cmdbuf[1] = (u32)accountSlot; + memset(&cmdbuf[2], 0, 0x14); + memcpy(&cmdbuf[2], passwordInput, sizeof(AccountPassword)); + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UploadMii(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x421,1,2); // 0x4210042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_InactivateDeviceAssociation(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x422,1,2); // 0x4220042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_ValidateMailAddress(u8 accountSlot, u32 confirmationCode, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x423,2,2); // 0x4230082 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = confirmationCode; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SendPostingApprovalMail(u8 accountSlot, AccountMailAddress *parentalEmail, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x424,1,4); // 0x4240044 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + cmdbuf[4] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[5] = (u32)parentalEmail; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SendConfirmationMail(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x425,1,2); // 0x4250042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SendConfirmationMailForPin(u8 accountSlot, AccountMailAddress *parentalEmail, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x426,1,4); // 0x4260044 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + cmdbuf[4] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[5] = (u32)parentalEmail; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SendMasterKeyMailForPin(u8 accountSlot, u32 masterKey, AccountMailAddress *parentalEmail, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x427,2,4); // 0x4270084 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = masterKey; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + cmdbuf[5] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[6] = (u32)parentalEmail; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_ApproveByCreditCard(u8 accountSlot, CreditCardInfo *cardInfo, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x428,1,4); + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + cmdbuf[4] = IPC_Desc_StaticBuffer(sizeof(CreditCardInfo), 0); + cmdbuf[5] = (u32)cardInfo; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SendCoppaCodeMail(u8 accountSlot, u32 principalId, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x429,2,2); // 0x4290082 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = principalId; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetIsMiiUpdated(u8 accountSlot, bool isDirty) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x42A,2,0); // 0x42A0080 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = (u32)isDirty; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_ReserveTransfer(u8 accountSlot, DeviceInfo *newDevice, char *operator, u32 operatorSize, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x42B,7,4); // 0x42B01C4 + cmdbuf[1] = (u32)accountSlot; + memcpy(&cmdbuf[2], newDevice, sizeof(DeviceInfo)); + cmdbuf[7] = operatorSize; + cmdbuf[8] = IPC_Desc_SharedHandles(1); + cmdbuf[9] = completionEvent; + cmdbuf[10] = IPC_Desc_Buffer(operatorSize, IPC_BUFFER_R); + cmdbuf[11] = (u32)operator; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_CompleteTransfer(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x42C,1,2); // 0x42C0042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_InactivateAccountDeviceAssociation(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x42D,1,2); // 0x42D0042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_SetNetworkTime(s64 timestamp) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x42E,2,0); // 0x42E0080 + *((u64 *)&cmdbuf[1]) = timestamp; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UpdateAccountInfo(u8 accountSlot, char *xmlData, u32 xmlDataSize, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x42F,2,4); // 0x42F0084 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = xmlDataSize; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = completionEvent; + cmdbuf[5] = IPC_Desc_Buffer(xmlDataSize, IPC_BUFFER_R); + cmdbuf[6] = (u32)xmlData; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_UpdateAccountMailAddress(u8 accountSlot, AccountMailAddress *newEmail, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x430,1,4); // 0x4300044 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + cmdbuf[4] = IPC_Desc_Buffer(sizeof(AccountMailAddress), IPC_BUFFER_R); + cmdbuf[5] = (u32)newEmail; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_DeleteDeviceAssociation(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x431,1,2); // 0x4310042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_DeleteAccountDeviceAssociation(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x432,1,2); // 0x4320042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_CancelTransfer(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x433,1,2); // 0x4330042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_ReloadAndBlockSaveData(Handle unloadFinishedEvent, Handle remountAndBlockEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x434,0,3); // 0x4340003 + cmdbuf[1] = IPC_Desc_SharedHandles(2); + cmdbuf[2] = unloadFinishedEvent; + cmdbuf[3] = remountAndBlockEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result ACTA_ReserveServerAccountDeletion(u8 accountSlot, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x435,1,2); // 0x4350042 + cmdbuf[1] = (u32)accountSlot; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(actHandle))) return ret; + + return (Result)cmdbuf[1]; +} diff --git a/libctru/source/services/frd.c b/libctru/source/services/frd.c index 2a2df7fdf..f0d452cfa 100644 --- a/libctru/source/services/frd.c +++ b/libctru/source/services/frd.c @@ -1,62 +1,30 @@ -#include +#include <3ds/synchronization.h> +#include <3ds/services/frd.h> +#include <3ds/result.h> #include <3ds/types.h> #include <3ds/svc.h> -#include <3ds/synchronization.h> #include <3ds/ipc.h> -#include <3ds/result.h> #include <3ds/srv.h> -#include <3ds/services/frd.h> -#include <3ds/util/utf.h> +#include static Handle frdHandle; static int frdRefCount; -static void frdConvertToUTF8(char* out, const u16* in, size_t max) -{ - if (!in || !*in) - { - out[0] = 0; - return; - } - - ssize_t units = utf16_to_utf8((uint8_t*)out, in, max); - if (units < 0) - { - out[0] = 0; - return; - } - - out[units] = 0; -} +#define MIN(x,y) ((x) > (y) ? (y) : (x)) -static void frdConvertToUTF16(u16* out, const char* in, size_t max) -{ - if (!in || !*in) - { - out[0] = 0; - return; - } - - ssize_t units = utf8_to_utf16(out, (const uint8_t*)in, max-1); - if (units < 0) - { - out[0] = 0; - return; - } - - out[units] = 0; -} - -Result frdInit(void) +Result frdInit(bool forceUser) { Result ret = 0; if (AtomicPostIncrement(&frdRefCount)) return 0; - ret = srvGetServiceHandle(&frdHandle, "frd:a"); - if (R_FAILED(ret)) ret = srvGetServiceHandle(&frdHandle, "frd:n"); - if (R_FAILED(ret)) ret = srvGetServiceHandle(&frdHandle, "frd:u"); - if (R_FAILED(ret)) AtomicDecrement(&frdRefCount); + if (forceUser) + ret = srvGetServiceHandle(&frdHandle, "frd:u"); + else + ret = srvGetServiceHandle(&frdHandle, "frd:a"); + + if (R_FAILED(ret)) + AtomicDecrement(&frdRefCount); return ret; } @@ -72,12 +40,12 @@ Handle *frdGetSessionHandle(void) return &frdHandle; } -Result FRDU_HasLoggedIn(bool *state) +Result FRD_HasLoggedIn(bool *state) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x01,0,0); // 0x10000 + cmdbuf[0] = IPC_MakeHeader(0x1,0,0); // 0x10000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -86,12 +54,12 @@ Result FRDU_HasLoggedIn(bool *state) return (Result)cmdbuf[1]; } -Result FRDU_IsOnline(bool *state) +Result FRD_IsOnline(bool *state) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x02,0,0); // 0x20000 + cmdbuf[0] = IPC_MakeHeader(0x2,0,0); // 0x20000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -105,9 +73,9 @@ Result FRD_Login(Handle event) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x03,0,2); // 0x30002 - cmdbuf[1] = 0; - cmdbuf[2] = (u32)event; + cmdbuf[0] = IPC_MakeHeader(0x3,0,2); // 0x30002 + cmdbuf[1] = IPC_Desc_SharedHandles(1); + cmdbuf[2] = event; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -119,7 +87,7 @@ Result FRD_Logout(void) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x04,0,0); // 0x40000 + cmdbuf[0] = IPC_MakeHeader(0x4,0,0); // 0x40000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -131,7 +99,7 @@ Result FRD_GetMyFriendKey(FriendKey *key) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x05,0,0); // 0x50000 + cmdbuf[0] = IPC_MakeHeader(0x5,0,0); // 0x50000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -145,97 +113,174 @@ Result FRD_GetMyPreference(bool *isPublicMode, bool *isShowGameName, bool *isSho Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x06,0,0); // 0x60000 + cmdbuf[0] = IPC_MakeHeader(0x6,0,0); // 0x60000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + *isPublicMode = (u8)cmdbuf[2]; // Public mode + *isShowGameName = (u8)cmdbuf[3]; // Show current game + *isShowPlayedGame = (u8)cmdbuf[4]; // Show game history. + + return (Result)cmdbuf[1]; +} + +Result FRD_GetMyProfile(Profile *profile) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x7, 0, 0); // 0x70000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + memcpy(profile, &cmdbuf[2], sizeof(Profile)); + + return (Result)cmdbuf[1]; +} + +Result FRD_GetMyPresence(MyPresence *presence) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x8, 0, 0); // 0x80000 + + staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(MyPresence), 0); + staticbufs[1] = (u32)presence; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetMyScreenName(MiiScreenName *name) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x9,0,0); // 0x90000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - *isPublicMode = cmdbuf[2] & 0xFF; // Public mode - *isShowGameName = cmdbuf[3] & 0xFF; // Show current game - *isShowPlayedGame = cmdbuf[4] & 0xFF; // Show game history. + memcpy(name, &cmdbuf[2], sizeof(MiiScreenName)); return (Result)cmdbuf[1]; } -Result FRD_GetMyProfile(FriendProfile *profile) +Result FRD_GetMyMii(FriendMii *mii) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x07, 0, 0); // 0x70000 + cmdbuf[0] = IPC_MakeHeader(0xA,0,0); // 0xA0000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - memcpy(profile, &cmdbuf[2], sizeof(FriendProfile)); + memcpy(mii, &cmdbuf[2], sizeof(FriendMii)); return (Result)cmdbuf[1]; } -Result FRD_GetMyScreenName(char *name, size_t max_size) +Result FRD_GetMyLocalAccountId(u8 *localAccountId) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x09,0,0); // 0x90000 + cmdbuf[0] = IPC_MakeHeader(0xB,0,0); // 0xB0000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - frdConvertToUTF8(name, (u16*)&cmdbuf[2], max_size); + *localAccountId = (u8)cmdbuf[2]; return (Result)cmdbuf[1]; } -Result FRD_GetMyMii(MiiData *mii) +Result FRD_GetMyPlayingGame(GameKey *playingGame) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x0A,0,0); // 0xA0000 + cmdbuf[0] = IPC_MakeHeader(0xC,0,0); // 0xC0000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - memcpy(mii, &cmdbuf[2], sizeof(MiiData)); + memcpy(playingGame, &cmdbuf[2], sizeof(GameKey)); return (Result)cmdbuf[1]; } -Result FRD_GetMyPlayingGame(u64 *titleId) +Result FRD_GetMyFavoriteGame(GameKey *favoriteGame) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x0C,0,0); // 0xC0000 + cmdbuf[0] = IPC_MakeHeader(0xD,0,0); // 0xD0000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - *titleId = (((u64)cmdbuf[3]) << 32 | (u64)cmdbuf[2]); + memcpy(favoriteGame, &cmdbuf[2], sizeof(GameKey)); return (Result)cmdbuf[1]; } -Result FRD_GetMyFavoriteGame(u64 *titleId) +Result FRD_GetMyNcPrincipalId(u32 *ncPrincipalId) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x0D,0,0); // 0xD0000 + cmdbuf[0] = IPC_MakeHeader(0xE,0,0); // 0xE0000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - *titleId = (((u64)cmdbuf[3]) << 32 | (u64)cmdbuf[2]); + *ncPrincipalId = cmdbuf[2]; return (Result)cmdbuf[1]; } -Result FRD_GetMyComment(char *comment, size_t max_size) +Result FRD_GetMyComment(FriendComment *comment) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x0F,0,0); // 0xF0000 + cmdbuf[0] = IPC_MakeHeader(0xF,0,0); // 0xF0000 if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - frdConvertToUTF8(comment, (u16*)&cmdbuf[2], max_size); + memcpy(comment, &cmdbuf[2], sizeof(FriendComment)); + + return (Result)cmdbuf[1]; +} + +Result FRD_GetMyPassword(char *password, u32 bufsize) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x10,1,0); // 0x100040 + cmdbuf[1] = bufsize; + + staticbufs[0] = IPC_Desc_StaticBuffer(bufsize, 0); + staticbufs[1] = (u32)password; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; return (Result)cmdbuf[1]; } @@ -244,121 +289,342 @@ Result FRD_GetFriendKeyList(FriendKey *friendKeyList, u32 *num, u32 offset, u32 { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; cmdbuf[0] = IPC_MakeHeader(0x11,2,0); // 0x110080 cmdbuf[1] = offset; cmdbuf[2] = size; - cmdbuf[64] = (size << 18) | 2; - cmdbuf[65] = (u32)friendKeyList; - if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + staticbufs[0] = IPC_Desc_StaticBuffer(size, 0); + staticbufs[1] = (u32)friendKeyList; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; *num = cmdbuf[2]; return (Result)cmdbuf[1]; } -Result FRD_GetFriendMii(MiiData *miiDataList, const FriendKey *friendKeyList, size_t size) +Result FRD_GetFriendPresence(FriendPresence *friendPresences, const FriendKey *friendKeyList, u32 count) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x12,1,2); // 0x120042 + cmdbuf[1] = count; + // input + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); + cmdbuf[3] = (u32)friendKeyList; + + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(FriendPresence), 0); + staticbufs[1] = (u32)friendPresences; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetMiiScreenName(MiiScreenName *screenNames, u32 screenNamesLen, u8 *characterSets, u32 characterSetsLen, const FriendKey *friendKeyList, u32 count, bool maskNonAscii, bool profanityFlag) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x13,5,2); // 0x130142 + cmdbuf[1] = screenNamesLen; + cmdbuf[2] = characterSetsLen; + cmdbuf[3] = count; + cmdbuf[4] = (u32)maskNonAscii; + cmdbuf[5] = (u32)profanityFlag; + // input + cmdbuf[6] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); + cmdbuf[7] = (u32)friendKeyList; + + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(MiiScreenName), 0); + staticbufs[1] = (u32)screenNames; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetFriendMii(FriendMii *miiList, const FriendKey *friendKeyList, u32 count) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x14,1,4); // 0x140044 - cmdbuf[1] = size; - cmdbuf[2] = (size << 18) | 2; + cmdbuf[1] = count; + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); cmdbuf[3] = (u32)friendKeyList; - cmdbuf[4] = IPC_Desc_Buffer(size * sizeof(MiiData), IPC_BUFFER_W); - cmdbuf[5] = (u32)miiDataList; + cmdbuf[4] = IPC_Desc_Buffer(count * sizeof(FriendMii), IPC_BUFFER_W); + cmdbuf[5] = (u32)miiList; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; return (Result)cmdbuf[1]; } -Result FRD_GetFriendProfile(FriendProfile *profile, const FriendKey *friendKeyList, size_t size) +Result FRD_GetFriendProfile(Profile *profiles, const FriendKey *friendKeyList, u32 count) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; cmdbuf[0] = IPC_MakeHeader(0x15,1,2); // 0x150042 - cmdbuf[1] = size; - cmdbuf[2] = (size << 18) | 2; + cmdbuf[1] = count; + // input + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); cmdbuf[3] = (u32)friendKeyList; - u32 *staticbuf = getThreadStaticBuffers(); - staticbuf[0] = (size << 17)|2; - staticbuf[1] = (u32)profile; + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(Profile), 0); + staticbufs[1] = (u32)profiles; - if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetFriendRelationship(u8 *relationships, const FriendKey *friendKeyList, u32 count) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x16,1,2); // 0x160042 + cmdbuf[1] = count; + // input + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); + cmdbuf[3] = (u32)friendKeyList; + + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(u8), 0); + staticbufs[1] = (u32)relationships; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetFriendAttributeFlags(u32 *attributes, const FriendKey *friendKeyList, u32 count) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x17,1,2); // 0x170042 + cmdbuf[1] = count; + // input + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); + cmdbuf[3] = (u32)friendKeyList; + + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(u32), 0); + staticbufs[1] = (u32)attributes; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; return (Result)cmdbuf[1]; } -Result FRD_GetFriendPlayingGame(GameDescription *desc, const FriendKey *friendKeyList, size_t size) +Result FRD_GetFriendPlayingGame(FriendPlayingGame *playingGames, const FriendKey *friendKeyList, u32 count) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x18,1,4); // 0x180044 - cmdbuf[1] = size; - cmdbuf[2] = (size << 18) | 2; + cmdbuf[1] = count; + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); cmdbuf[3] = (u32)friendKeyList; - cmdbuf[4] = IPC_Desc_Buffer(size * sizeof(GameDescription), IPC_BUFFER_W); - cmdbuf[5] = (u32)desc; + cmdbuf[4] = IPC_Desc_Buffer(count * sizeof(FriendPlayingGame), IPC_BUFFER_W); + cmdbuf[5] = (u32)playingGames; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; return (Result)cmdbuf[1]; } -Result FRD_GetFriendFavouriteGame(GameDescription *desc, const FriendKey *friendKeyList, u32 count) +Result FRD_GetFriendFavoriteGame(GameKey *favoriteGames, const FriendKey *friendKeyList, u32 count) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; cmdbuf[0] = IPC_MakeHeader(0x19,1,2); // 0x190042 cmdbuf[1] = count; - cmdbuf[2] = (count << 18) | 2; + // input + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); cmdbuf[3] = (u32)friendKeyList; - u32 *staticbuf = getThreadStaticBuffers(); + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(GameKey), 0); + staticbufs[1] = (u32)favoriteGames; - staticbuf[0] = (count << 18) | 2; - staticbuf[1] = (u32)desc; + ret = svcSendSyncRequest(frdHandle); - if (R_FAILED(svcSendSyncRequest(frdHandle))) return ret; + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; return (Result)cmdbuf[1]; } -Result FRD_IsInFriendList(FriendKey *friendKeyList, bool *isFromList) +Result FRD_GetFriendInfo(FriendInfo *infos, const FriendKey *friendKeyList, u32 count, bool maskNonAscii, bool profanityFlag) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1A,3,4); // 0x1A00C4 + cmdbuf[1] = count; + cmdbuf[2] = (u32)maskNonAscii; + cmdbuf[3] = (u32)profanityFlag; + cmdbuf[4] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); + cmdbuf[5] = (u32)friendKeyList; + cmdbuf[6] = IPC_Desc_Buffer(count * sizeof(FriendInfo), IPC_BUFFER_W); + cmdbuf[7] = (u32)infos; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_IsInFriendList(u64 friendCode, bool *isFromList) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x1B,2,0); // 0x1B0080 - cmdbuf[1] = (u32)(friendKeyList->localFriendCode & 0xFFFFFFFF); - cmdbuf[2] = (u32)(friendKeyList->localFriendCode >> 32); + *((u64 *)&cmdbuf[1]) = friendCode; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - *isFromList = cmdbuf[2] & 0xFF; + *isFromList = (bool)cmdbuf[2]; return (Result)cmdbuf[1]; } -Result FRD_UpdateGameModeDescription(const char *desc) +Result FRD_UnscrambleLocalFriendCode(u64 *unscrambled, ScrambledFriendCode *scrambled, u32 count) { - u16 u16_desc[strlen(desc) + 1]; + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x1C,1,2); // 0x1C0042 + cmdbuf[1] = count; + // input + cmdbuf[2] = IPC_Desc_StaticBuffer(count * sizeof(ScrambledFriendCode), 1); + cmdbuf[3] = (u32)scrambled; - frdConvertToUTF16(u16_desc, desc, strlen(desc) + 1); + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(u64), 0); + staticbufs[1] = (u32)unscrambled; + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_UpdateGameModeDescription(FriendGameModeDescription *desc) +{ Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x1D,0,2); // 0x1D0002 - cmdbuf[1] = 0x400802; - cmdbuf[2] = (uintptr_t)u16_desc; + cmdbuf[1] = IPC_Desc_StaticBuffer(sizeof(FriendGameModeDescription), 2); + cmdbuf[2] = (u32)desc; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_UpdateMyPresence(Presence *presence, FriendGameModeDescription *desc) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1E,11,2); // 0x1E02C2 + memcpy(&cmdbuf[1], presence, sizeof(Presence)); + cmdbuf[12] = IPC_Desc_StaticBuffer(sizeof(FriendGameModeDescription), 2); + cmdbuf[13] = (u32)desc; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_SendInvitation(const FriendKey *friendKeyList, u32 count) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1F,1,2); // 0x1F0042 + cmdbuf[1] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); + cmdbuf[2] = (u32)friendKeyList; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -370,8 +636,8 @@ Result FRD_AttachToEventNotification(Handle event) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] =IPC_MakeHeader(0x20,0,2); //0x200002; - cmdbuf[1] = 0; + cmdbuf[0] = IPC_MakeHeader(0x20,0,2); // 0x200002 + cmdbuf[1] = IPC_Desc_SharedHandles(1); cmdbuf[2] = (u32)event; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -379,25 +645,60 @@ Result FRD_AttachToEventNotification(Handle event) return (Result)cmdbuf[1]; } +Result FRD_SetNotificationMask(FriendNotificationMask mask) +{ + Result ret = 0; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x21,1,0); // 0x210040 + cmdbuf[1] = (u32)mask; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + Result FRD_GetEventNotification(NotificationEvent *event, u32 count, u32 *recievedNotifCount) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x22,1,0); //0x220040 + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x22,1,0); // 0x220040 cmdbuf[1] = count; - u32 *staticbuf = getThreadStaticBuffers(); - staticbuf[0] = 0x60000 * count | 2; - staticbuf[1] = (u32)event; + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(NotificationEvent), 0); + staticbufs[1] = (u32)event; - if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; *recievedNotifCount = cmdbuf[3]; return (Result)cmdbuf[1]; } +Result FRD_GetLastResponseResult() +{ + Result ret = 0; + + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x23,0,0); + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + Result FRD_PrincipalIdToFriendCode(u32 principalId, u64 *friendCode) { Result ret = 0; @@ -408,7 +709,7 @@ Result FRD_PrincipalIdToFriendCode(u32 principalId, u64 *friendCode) if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; - *friendCode = (((u64)cmdbuf[3]) << 32 | (u64)cmdbuf[2]); + *friendCode = *((u64 *)&cmdbuf[2]); return (Result)cmdbuf[1]; } @@ -419,8 +720,7 @@ Result FRD_FriendCodeToPrincipalId(u64 friendCode, u32 *principalId) u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x25,2,0); // 0x250080 - cmdbuf[1] = (u32)(friendCode & 0xFFFFFFFF); - cmdbuf[2] = (u32)(friendCode >> 32); + *((u64 *)&cmdbuf[2]) = friendCode; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -435,8 +735,7 @@ Result FRD_IsValidFriendCode(u64 friendCode, bool *isValid) u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x26,2,0); // 0x260080 - cmdbuf[1] = (u32)(friendCode & 0xFFFFFFFF); - cmdbuf[2] = (u32)(friendCode >> 32); + *((u64 *)&cmdbuf[1]) = friendCode; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; @@ -445,6 +744,207 @@ Result FRD_IsValidFriendCode(u64 friendCode, bool *isValid) return (Result)cmdbuf[1]; } +Result FRD_ResultToErrorCode(u32 *errorCode, Result res) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x27,1,0); // 0x270040 + cmdbuf[1] = (u32)res; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + *errorCode = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result FRD_RequestGameAuthentication(u32 serverId, u16 *ingamesn, u32 ingamesnSize, u8 majorSdkVersion, u8 minorSdkVersion, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x28,9,4); // 0x280244 + cmdbuf[1] = serverId; + memset(&cmdbuf[2], 0, NASC_INGAMESN_LEN * 2); + memcpy(&cmdbuf[2], ingamesn, MIN(ingamesnSize, NASC_INGAMESN_LEN * 2)); + cmdbuf[8] = (u32)majorSdkVersion; + cmdbuf[9] = (u32)minorSdkVersion; + cmdbuf[10] = IPC_Desc_CurProcessId(); + // cmdbuf[11] = process id + cmdbuf[12] = IPC_Desc_SharedHandles(1); + cmdbuf[13] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetGameAuthenticationData(GameAuthenticationData *data) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x29,0,0); // 0x290000 + + staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(GameAuthenticationData), 0); + staticbufs[1] = (u32)data; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_RequestServiceLocator(u32 serverId, char *keyhash, char *svc, u8 majorSdkVersion, u8 minorSdkVersion, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x2A,8,4); // 0x2A0204 + cmdbuf[1] = serverId; + memset(&cmdbuf[2], 0, NASC_KEYHASH_LEN); + memcpy(&cmdbuf[2], keyhash, MIN(strnlen(keyhash, NASC_KEYHASH_LEN), NASC_KEYHASH_LEN)); + memset(&cmdbuf[5], 0, NASC_SVC_LEN); + memcpy(&cmdbuf[5], svc, MIN(strnlen(svc, NASC_SVC_LEN), NASC_SVC_LEN)); + cmdbuf[7] = (u32)majorSdkVersion; + cmdbuf[8] = (u32)minorSdkVersion; + cmdbuf[9] = IPC_Desc_CurProcessId(); + // cmdbuf[10] = process id + cmdbuf[11] = IPC_Desc_SharedHandles(1); + cmdbuf[12] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetServiceLocatorData(ServiceLocatorData *data) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x2B,0,0); // 0x2B0000 + + staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(ServiceLocatorData), 0); + staticbufs[1] = (u32)data; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_DetectNatProperties(Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x2C,0,2); // 0x2C0002 + cmdbuf[1] = IPC_Desc_SharedHandles(1); + cmdbuf[2] = completionEvent; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetNatProperties(u32 *natMappingType, u32 *natFilteringType) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x2D,0,0); // 0x2D0000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + *natMappingType = cmdbuf[2]; + *natFilteringType = cmdbuf[3]; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetServerTimeDifference(u64 *diff) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x2E,0,0); // 0x2E0000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + *diff = *((u64 *)&cmdbuf[2]); + + return (Result)cmdbuf[1]; +} + +Result FRD_AllowHalfAwake(bool allow) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x2F,1,0); // 0x2F0040 + cmdbuf[1] = (u32)allow; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetServerTypes(u8 *nascEnvironment, u8 *nfsType, u8 *nfsNo) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x30,0,0); // 0x300000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + *nascEnvironment = (u8)cmdbuf[2]; + *nfsType = (u8)cmdbuf[3]; + *nfsNo = (u8)cmdbuf[4]; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetFriendComment(FriendComment *comments, u32 commentsLen, const FriendKey *friendKeyList, u32 count) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x31,2,2); // 0x310082 + cmdbuf[1] = commentsLen; + cmdbuf[2] = count; + // input + cmdbuf[3] = IPC_Desc_StaticBuffer(count * sizeof(FriendKey), 0); + cmdbuf[4] = (u32)friendKeyList; + + // output + staticbufs[0] = IPC_Desc_StaticBuffer(count * sizeof(FriendComment), 0); + staticbufs[1] = (u32)comments; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + Result FRD_SetClientSdkVersion(u32 sdkVer) { Result ret = 0; @@ -453,36 +953,304 @@ Result FRD_SetClientSdkVersion(u32 sdkVer) cmdbuf[0] = IPC_MakeHeader(0x32,1,2); // 0x320042 cmdbuf[1] = sdkVer; cmdbuf[2] = IPC_Desc_CurProcessId(); + // cmdbuf[3] = current process id + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetMyApproachContext(EncryptedApproachContext *ctx) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x33,0,0); // 0x330000 + + staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(EncryptedApproachContext), 0); + staticbufs[1] = (u32)ctx; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_AddFriendWithApproach(u8 *unkbuf, u32 unkbufSize, EncryptedApproachContext *ctx, Handle completionEvent) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x34,1,6); // 0x340046 + cmdbuf[1] = unkbufSize; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = completionEvent; + cmdbuf[4] = IPC_Desc_StaticBuffer(sizeof(EncryptedApproachContext), 3); + cmdbuf[5] = (u32)ctx; + cmdbuf[6] = IPC_Desc_StaticBuffer(MIN(unkbufSize, 0x600), 4); + cmdbuf[7] = (u32)unkbuf; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; return (Result)cmdbuf[1]; } -Result FRD_AddFriendOnline(Handle event, u32 principalId) +Result FRD_DecryptApproachContext(DecryptedApproachContext *decryptedContext, EncryptedApproachContext *encryptedContext, bool maskNonAscii, u8 characterSet) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x406,1,2); //0x4060042; + u32 *staticbufs = getThreadStaticBuffers(); + + u32 save0 = staticbufs[0]; + u32 save1 = staticbufs[1]; + + cmdbuf[0] = IPC_MakeHeader(0x35,2,2); // 0x350082 + cmdbuf[1] = (u32)maskNonAscii; + cmdbuf[2] = (u32)characterSet; + // input + cmdbuf[3] = IPC_Desc_StaticBuffer(sizeof(EncryptedApproachContext), 3); + cmdbuf[4] = (u32)encryptedContext; + + staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(DecryptedApproachContext), 0); + staticbufs[1] = (u32)decryptedContext; + + ret = svcSendSyncRequest(frdHandle); + + staticbufs[0] = save0; + staticbufs[1] = save1; + + if (R_FAILED(ret)) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRD_GetExtendedNatProperties(u32 *natMappingType, u32 *natFilteringType, u32 *natMappingPortIncrement) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x36,0,0); // 0x360000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + *natMappingType = cmdbuf[2]; + *natFilteringType = cmdbuf[3]; + *natMappingPortIncrement = cmdbuf[4]; + + return (Result)cmdbuf[1]; +} + +Result FRDA_CreateLocalAccount(u8 localAccountId, u8 nascEnvironment, u8 nfsType, u8 nfsNo) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x401,4,0); // 0x4010100 + cmdbuf[1] = (u32)localAccountId; + cmdbuf[2] = (u32)nascEnvironment; + cmdbuf[3] = (u32)nfsType; + cmdbuf[4] = (u32)nfsNo; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_DeleteLocalAccount(u8 localAccountId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x402,1,0); // 0x4020040 + cmdbuf[1] = (u32)localAccountId; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_LoadLocalAccount(u8 localAccountId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x403,1,0); // 0x4030040 + cmdbuf[1] = (u32)localAccountId; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_UnloadLocalAccount() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x404,0,0); // 0x4040000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_Save() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x405,0,0); // 0x4050000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_AddFriendOnline(Handle event, u32 principalId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x406,1,2); // 0x4060042 cmdbuf[1] = principalId; - cmdbuf[2] = 0; - cmdbuf[3] = (u32)event; + cmdbuf[2] = IPC_Desc_SharedHandles(1); + cmdbuf[3] = event; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; return (Result)cmdbuf[1]; } -Result FRD_RemoveFriend(u32 principalId, u64 localFriendCode) +Result FRDA_AddFriendOffline(FriendKey *friendKey, FriendMii *mii, FriendProfile *friendProfile, MiiScreenName *screenName, bool profanityFlag, u8 characterSet) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x409,4,0); //0x4090100; + cmdbuf[0] = IPC_MakeHeader(0x407,54,0); // 0x4070D80 + memcpy(&cmdbuf[1], friendKey, sizeof(FriendKey)); + memcpy(&cmdbuf[5], mii, sizeof(FriendMii)); + memcpy(&cmdbuf[29], friendProfile, sizeof(FriendProfile)); + memcpy(&cmdbuf[47], screenName, sizeof(MiiScreenName)); + cmdbuf[53] = (u32)profanityFlag; + cmdbuf[54] = (u32)characterSet; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_UpdateMiiScreenName(FriendKey *friendKey, MiiScreenName *screenName, u8 characterSet) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x408,11,0); // 0x40802C0 + memcpy(&cmdbuf[1], friendKey, sizeof(FriendKey)); + memcpy(&cmdbuf[5], screenName, sizeof(MiiScreenName)); + cmdbuf[11] = (u32)characterSet; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_RemoveFriend(u32 principalId, u64 localFriendCode) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x409,4,0); // 0x4090100 cmdbuf[1] = principalId; - cmdbuf[2] = localFriendCode & 0xffffffff; - cmdbuf[3] = (localFriendCode >> 32) & 0xffffffff; + *((u64 *)&cmdbuf[2]) = localFriendCode; if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; return cmdbuf[1]; } + +Result FRDA_UpdatePlayingGame(GameKey *playingGame) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x40A,4,0); // 0x40A0100 + memcpy(&cmdbuf[1], playingGame, sizeof(GameKey)); + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_UpdatePreference(bool isPublicMode, bool isShowGameMode, bool isShowPlayedMode) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x40B,3,0); // 0x40B00C0 + cmdbuf[1] = (u32)isPublicMode; + cmdbuf[2] = (u32)isShowGameMode; + cmdbuf[3] = (u32)isShowPlayedMode; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_UpdateMii(FriendMii *mii, MiiScreenName *screenName, bool profanityFlag, u8 characterSet) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x40C,32,0); // 0x40C0800 + memcpy(&cmdbuf[1], mii, sizeof(FriendMii)); + memcpy(&cmdbuf[25], screenName, sizeof(MiiScreenName)); + cmdbuf[31] = (u32)profanityFlag; + cmdbuf[32] = (u32)characterSet; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_UpdateFavoriteGame(GameKey *favoriteGame) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x40D,4,0); // 0x40D0100 + memcpy(&cmdbuf[1], favoriteGame, sizeof(GameKey)); + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_SetNcPrincipalId(u32 ncPrincipalId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x40E,1,0); // 0x40E0040 + cmdbuf[1] = ncPrincipalId; + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_UpdateComment(FriendComment *comment) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x40F,9,0); // 0x40F0240 + memcpy(&cmdbuf[1], comment, sizeof(FriendComment)); + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDA_IncrementMoveCount() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x410,0,0); // 0x4100000 + + if (R_FAILED(ret = svcSendSyncRequest(frdHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +#undef MIN \ No newline at end of file diff --git a/libctru/source/services/frdn.c b/libctru/source/services/frdn.c new file mode 100644 index 000000000..e4a6a2aff --- /dev/null +++ b/libctru/source/services/frdn.c @@ -0,0 +1,82 @@ +#include <3ds/synchronization.h> +#include <3ds/services/frdn.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +static Handle frdnHandle; +static int frdnRefCount; + +Result frdnInit() +{ + Result ret = 0; + + if (AtomicPostIncrement(&frdnRefCount)) return 0; + + if (R_FAILED(ret = srvGetServiceHandle(&frdnHandle, "frd:n"))) + AtomicDecrement(&frdnRefCount); + + return ret; +} + +void frdnExit() +{ + if (AtomicDecrement(&frdnRefCount)) return; + svcCloseHandle(frdnHandle); +} + +Handle *frdnGetSessionHandle(void) +{ + return &frdnHandle; +} + +Result FRDN_GetHandleOfNdmStatusChangedEvent(Handle *evt) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x1,0,0); // 0x10000 + + if (R_FAILED(ret = svcSendSyncRequest(frdnHandle))) return ret; + + *evt = cmdbuf[3]; + + return (Result)cmdbuf[1]; +} + +Result FRDN_Resume() +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x2,0,0); // 0x20000 + + if (R_FAILED(ret = svcSendSyncRequest(frdnHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDN_SuspendAsync(bool immediately) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x3,0,0); // 0x30040 + cmdbuf[1] = (u32)immediately; + + if (R_FAILED(ret = svcSendSyncRequest(frdnHandle))) return ret; + + return (Result)cmdbuf[1]; +} + +Result FRDN_QueryStatus(u8 *status) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x4,0,0); // 0x40000 + + if (R_FAILED(ret = svcSendSyncRequest(frdnHandle))) return ret; + + *status = (u8)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} \ No newline at end of file