2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2014-06-02 19:27:24 +02:00
# include "Emu/System.h"
2021-04-21 22:12:21 +02:00
# include "Emu/system_utils.hpp"
2020-02-15 23:36:20 +01:00
# include "Emu/VFS.h"
2021-04-21 23:20:33 +02:00
# include "Emu/IdManager.h"
2016-03-21 20:43:03 +01:00
# include "Emu/Cell/PPUModule.h"
2021-04-21 23:20:33 +02:00
# include "Emu/RSX/Overlays/overlay_user_list_dialog.h"
2014-03-11 18:40:37 +01:00
# include "cellUserInfo.h"
2016-04-27 00:27:24 +02:00
# include "Utilities/StrUtil.h"
2018-02-08 21:56:38 +01:00
# include "cellSysutil.h"
2016-04-27 00:27:24 +02:00
2018-08-25 14:39:00 +02:00
LOG_CHANNEL ( cellUserInfo ) ;
2014-03-11 18:40:37 +01:00
2021-04-21 23:20:33 +02:00
struct user_info_manager
{
atomic_t < bool > enable_overlay { false } ;
atomic_t < bool > dialog_opened { false } ;
} ;
std : : string get_username ( const u32 user_id )
{
std : : string username ;
2021-04-21 22:12:21 +02:00
if ( const fs : : file file { rpcs3 : : utils : : get_hdd0_dir ( ) + fmt : : format ( " home/%08d/localusername " , user_id ) } )
2021-04-21 23:20:33 +02:00
{
username = file . to_string ( ) ;
username . resize ( CELL_USERINFO_USERNAME_SIZE ) ; // TODO: investigate
}
return username ;
}
2016-08-16 17:46:24 +02:00
template < >
void fmt_class_string < CellUserInfoError > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto error )
{
switch ( error )
{
STR_CASE ( CELL_USERINFO_ERROR_BUSY ) ;
STR_CASE ( CELL_USERINFO_ERROR_INTERNAL ) ;
STR_CASE ( CELL_USERINFO_ERROR_PARAM ) ;
STR_CASE ( CELL_USERINFO_ERROR_NOUSER ) ;
}
return unknown ;
} ) ;
}
2021-04-21 23:20:33 +02:00
template < >
void fmt_class_string < cell_user_callback_result > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto error )
{
switch ( error )
{
STR_CASE ( CELL_USERINFO_RET_OK ) ;
STR_CASE ( CELL_USERINFO_RET_CANCEL ) ;
}
return unknown ;
} ) ;
}
2017-05-15 13:30:14 +02:00
error_code cellUserInfoGetStat ( u32 id , vm : : ptr < CellUserInfoUserStat > stat )
2014-03-11 18:40:37 +01:00
{
2016-01-12 22:57:16 +01:00
cellUserInfo . warning ( " cellUserInfoGetStat(id=%d, stat=*0x%x) " , id , stat ) ;
2014-03-11 18:40:37 +01:00
2015-12-11 18:09:24 +01:00
if ( id > CELL_SYSUTIL_USERID_MAX )
2016-04-09 12:03:53 +02:00
{
2020-03-20 12:15:28 +01:00
// ****** sysutil userinfo parameter error : 1 ******
return { CELL_USERINFO_ERROR_PARAM , " 1 " } ;
2016-04-09 12:03:53 +02:00
}
2014-03-11 18:40:37 +01:00
2015-12-11 18:09:24 +01:00
if ( id = = CELL_SYSUTIL_USERID_CURRENT )
{
2018-03-17 07:17:27 +01:00
// We want the int value, not the string.
id = Emu . GetUsrId ( ) ;
2015-12-11 18:09:24 +01:00
}
2021-04-21 23:20:33 +02:00
const std : : string path = vfs : : get ( fmt : : format ( " /dev_hdd0/home/%08d/ " , id ) ) ;
2016-04-09 12:03:53 +02:00
2016-03-21 20:43:03 +01:00
if ( ! fs : : is_dir ( path ) )
2016-04-09 12:03:53 +02:00
{
cellUserInfo . error ( " cellUserInfoGetStat(): CELL_USERINFO_ERROR_NOUSER. User %d doesn't exist. Did you delete the user folder? " , id ) ;
2014-03-11 18:40:37 +01:00
return CELL_USERINFO_ERROR_NOUSER ;
2016-04-09 12:03:53 +02:00
}
2014-03-11 18:40:37 +01:00
2016-03-21 20:43:03 +01:00
const fs : : file f ( path + " localusername " ) ;
2016-04-09 12:03:53 +02:00
2016-03-21 20:43:03 +01:00
if ( ! f )
2016-04-09 12:03:53 +02:00
{
2019-10-14 10:26:17 +02:00
cellUserInfo . error ( " cellUserInfoGetStat(): CELL_USERINFO_ERROR_INTERNAL. Username for user %08u doesn't exist. Did you delete the username file? " , id ) ;
2014-03-11 18:40:37 +01:00
return CELL_USERINFO_ERROR_INTERNAL ;
2016-04-09 12:03:53 +02:00
}
2014-03-11 18:40:37 +01:00
2020-03-20 12:15:28 +01:00
if ( stat )
{
stat - > id = id ;
strcpy_trunc ( stat - > name , f . to_string ( ) ) ;
}
2016-04-09 12:03:53 +02:00
2014-03-11 18:40:37 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code cellUserInfoSelectUser_ListType ( vm : : ptr < CellUserInfoTypeSet > listType , vm : : ptr < CellUserInfoFinishCallback > funcSelect , u32 container , vm : : ptr < void > userdata )
2014-03-11 18:40:37 +01:00
{
2021-04-21 23:20:33 +02:00
cellUserInfo . warning ( " cellUserInfoSelectUser_ListType(listType=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x) " , listType , funcSelect , container , userdata ) ;
if ( ! listType | | ! funcSelect ) // TODO: confirm
{
return CELL_USERINFO_ERROR_PARAM ;
}
if ( g_fxo - > get < user_info_manager > ( ) . dialog_opened )
{
return CELL_USERINFO_ERROR_BUSY ;
}
std : : vector < u32 > user_ids ;
2021-04-21 22:12:21 +02:00
const std : : string home_dir = rpcs3 : : utils : : get_hdd0_dir ( ) + " home " ;
2021-04-21 23:20:33 +02:00
for ( const auto & user_folder : fs : : dir ( home_dir ) )
{
if ( ! user_folder . is_directory )
{
continue ;
}
// Is the folder name exactly 8 all-numerical characters long?
2021-04-21 22:12:21 +02:00
const u32 user_id = rpcs3 : : utils : : check_user ( user_folder . name ) ;
2021-04-21 23:20:33 +02:00
if ( user_id = = 0 )
{
continue ;
}
// Does the localusername file exist?
if ( ! fs : : is_file ( home_dir + " / " + user_folder . name + " /localusername " ) )
{
continue ;
}
// TODO: maybe also restrict this to CELL_USERINFO_USER_MAX
if ( listType - > type ! = CELL_USERINFO_LISTTYPE_NOCURRENT | | user_id ! = Emu . GetUsrId ( ) )
{
user_ids . push_back ( user_id ) ;
}
}
if ( auto manager = g_fxo - > try_get < rsx : : overlays : : display_manager > ( ) )
{
if ( g_fxo - > get < user_info_manager > ( ) . dialog_opened . exchange ( true ) )
{
return CELL_USERINFO_ERROR_BUSY ;
}
const std : : string title = listType - > title . get_ptr ( ) ;
const u32 focused = listType - > focus ;
cellUserInfo . warning ( " cellUserInfoSelectUser_ListType: opening user_list_dialog with: title='%s', focused=%d " , title , focused ) ;
const bool enable_overlay = g_fxo - > get < user_info_manager > ( ) . enable_overlay ;
const error_code result = manager - > create < rsx : : overlays : : user_list_dialog > ( ) - > show ( title , focused , user_ids , enable_overlay , [ funcSelect , userdata ] ( s32 status )
{
s32 callback_result = CELL_USERINFO_RET_CANCEL ;
u32 selected_user_id = 0 ;
std : : string selected_username ;
if ( status > = 0 )
{
callback_result = CELL_USERINFO_RET_OK ;
selected_user_id = static_cast < u32 > ( status ) ;
selected_username = get_username ( selected_user_id ) ;
}
cellUserInfo . warning ( " cellUserInfoSelectUser_ListType: callback_result=%s, selected_user_id=%d, selected_username='%s' " , callback_result , selected_user_id , selected_username ) ;
sysutil_register_cb ( [ = ] ( ppu_thread & ppu ) - > s32
{
vm : : var < CellUserInfoUserStat > selectUser ;
if ( status > = 0 )
{
selectUser - > id = selected_user_id ;
strcpy_trunc ( selectUser - > name , selected_username ) ;
}
funcSelect ( ppu , callback_result , selectUser , userdata ) ;
return CELL_OK ;
} ) ;
g_fxo - > get < user_info_manager > ( ) . dialog_opened = false ;
} ) ;
return result ;
}
cellUserInfo . error ( " User selection is only possible when the native user interface is enabled in the settings. The currently active user will be selected as a fallback. " ) ;
2018-02-08 21:56:38 +01:00
sysutil_register_cb ( [ = ] ( ppu_thread & ppu ) - > s32
{
vm : : var < CellUserInfoUserStat > selectUser ;
2021-04-21 23:20:33 +02:00
selectUser - > id = Emu . GetUsrId ( ) ;
strcpy_trunc ( selectUser - > name , get_username ( Emu . GetUsrId ( ) ) ) ;
funcSelect ( ppu , CELL_USERINFO_RET_OK , selectUser , userdata ) ;
2018-02-08 21:56:38 +01:00
return CELL_OK ;
} ) ;
2014-03-11 18:40:37 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code cellUserInfoSelectUser_SetList ( vm : : ptr < CellUserInfoListSet > setList , vm : : ptr < CellUserInfoFinishCallback > funcSelect , u32 container , vm : : ptr < void > userdata )
2014-03-11 18:40:37 +01:00
{
2021-04-21 23:20:33 +02:00
cellUserInfo . warning ( " cellUserInfoSelectUser_SetList(setList=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x) " , setList , funcSelect , container , userdata ) ;
if ( ! setList | | ! funcSelect ) // TODO: confirm
{
return CELL_USERINFO_ERROR_PARAM ;
}
if ( g_fxo - > get < user_info_manager > ( ) . dialog_opened )
{
return CELL_USERINFO_ERROR_BUSY ;
}
std : : vector < u32 > user_ids ;
for ( usz i = 0 ; i < CELL_USERINFO_USER_MAX & & i < setList - > fixedListNum ; i + + )
{
if ( const u32 id = setList - > fixedList - > userId [ i ] )
{
user_ids . push_back ( id ) ;
}
}
if ( user_ids . empty ( ) )
{
// TODO: Confirm. Also check if this is possible in cellUserInfoSelectUser_ListType.
cellUserInfo . error ( " cellUserInfoSelectUser_SetList: callback_result=%s " , CELL_USERINFO_ERROR_NOUSER ) ;
sysutil_register_cb ( [ = ] ( ppu_thread & ppu ) - > s32
{
vm : : var < CellUserInfoUserStat > selectUser ;
funcSelect ( ppu , CELL_USERINFO_ERROR_NOUSER , selectUser , userdata ) ;
return CELL_OK ;
} ) ;
return CELL_OK ;
}
// TODO: does this function return an error if any (user_id > 0 && not_found) ?
if ( auto manager = g_fxo - > try_get < rsx : : overlays : : display_manager > ( ) )
{
if ( g_fxo - > get < user_info_manager > ( ) . dialog_opened . exchange ( true ) )
{
return CELL_USERINFO_ERROR_BUSY ;
}
const std : : string title = setList - > title . get_ptr ( ) ;
const u32 focused = setList - > focus ;
cellUserInfo . warning ( " cellUserInfoSelectUser_SetList: opening user_list_dialog with: title='%s', focused=%d " , title , focused ) ;
const bool enable_overlay = g_fxo - > get < user_info_manager > ( ) . enable_overlay ;
const error_code result = manager - > create < rsx : : overlays : : user_list_dialog > ( ) - > show ( title , focused , user_ids , enable_overlay , [ funcSelect , userdata ] ( s32 status )
{
s32 callback_result = CELL_USERINFO_RET_CANCEL ;
u32 selected_user_id = 0 ;
std : : string selected_username ;
if ( status > = 0 )
{
callback_result = CELL_USERINFO_RET_OK ;
selected_user_id = static_cast < u32 > ( status ) ;
selected_username = get_username ( selected_user_id ) ;
}
cellUserInfo . warning ( " cellUserInfoSelectUser_SetList: callback_result=%s, selected_user_id=%d, selected_username='%s' " , callback_result , selected_user_id , selected_username ) ;
sysutil_register_cb ( [ = ] ( ppu_thread & ppu ) - > s32
{
vm : : var < CellUserInfoUserStat > selectUser ;
if ( status > = 0 )
{
selectUser - > id = selected_user_id ;
strcpy_trunc ( selectUser - > name , selected_username ) ;
}
funcSelect ( ppu , callback_result , selectUser , userdata ) ;
return CELL_OK ;
} ) ;
g_fxo - > get < user_info_manager > ( ) . dialog_opened = false ;
} ) ;
return result ;
}
cellUserInfo . error ( " User selection is only possible when the native user interface is enabled in the settings. The currently active user will be selected as a fallback. " ) ;
2018-02-08 21:56:38 +01:00
sysutil_register_cb ( [ = ] ( ppu_thread & ppu ) - > s32
{
vm : : var < CellUserInfoUserStat > selectUser ;
2021-04-21 23:20:33 +02:00
selectUser - > id = Emu . GetUsrId ( ) ;
strcpy_trunc ( selectUser - > name , get_username ( Emu . GetUsrId ( ) ) ) ;
funcSelect ( ppu , CELL_USERINFO_RET_OK , selectUser , userdata ) ;
2018-02-08 21:56:38 +01:00
return CELL_OK ;
} ) ;
2014-03-11 18:40:37 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
void cellUserInfoEnableOverlay ( s32 enable )
2014-03-11 18:40:37 +01:00
{
2021-04-21 23:20:33 +02:00
cellUserInfo . notice ( " cellUserInfoEnableOverlay(enable=%d) " , enable ) ;
auto & manager = g_fxo - > get < user_info_manager > ( ) ;
manager . enable_overlay = enable ! = 0 ;
2014-03-11 18:40:37 +01:00
}
2016-08-16 17:46:24 +02:00
error_code cellUserInfoGetList ( vm : : ptr < u32 > listNum , vm : : ptr < CellUserInfoUserList > listBuf , vm : : ptr < u32 > currentUserId )
2014-03-11 18:40:37 +01:00
{
2021-04-21 23:20:33 +02:00
cellUserInfo . warning ( " cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x) " , listNum , listBuf , currentUserId ) ;
2014-03-11 18:40:37 +01:00
2014-05-25 22:31:40 +02:00
// If only listNum is NULL, an error will be returned
2019-10-16 05:46:43 +02:00
if ( ! listNum )
2016-04-09 12:03:53 +02:00
{
2019-10-16 05:46:43 +02:00
if ( listBuf | | ! currentUserId )
{
return CELL_USERINFO_ERROR_PARAM ;
}
2016-04-09 12:03:53 +02:00
}
2021-04-21 22:12:21 +02:00
const std : : string home_dir = rpcs3 : : utils : : get_hdd0_dir ( ) + " home " ;
2021-04-21 23:20:33 +02:00
std : : vector < u32 > user_ids ;
for ( const auto & user_folder : fs : : dir ( home_dir ) )
{
if ( ! user_folder . is_directory )
{
continue ;
}
// Is the folder name exactly 8 all-numerical characters long?
2021-04-21 22:12:21 +02:00
const u32 user_id = rpcs3 : : utils : : check_user ( user_folder . name ) ;
2021-04-21 23:20:33 +02:00
if ( user_id = = 0 )
{
continue ;
}
// Does the localusername file exist?
if ( ! fs : : is_file ( home_dir + " / " + user_folder . name + " /localusername " ) )
{
continue ;
}
if ( user_ids . size ( ) < CELL_USERINFO_USER_MAX )
{
user_ids . push_back ( user_id ) ;
}
else
{
cellUserInfo . warning ( " cellUserInfoGetList: Cannot add user %s. Too many users. " , user_folder . name ) ;
}
}
2014-09-01 02:51:48 +02:00
if ( listNum )
2016-04-09 12:03:53 +02:00
{
2021-04-21 23:20:33 +02:00
* listNum = static_cast < u32 > ( user_ids . size ( ) ) ;
2016-04-09 12:03:53 +02:00
}
2014-09-01 02:51:48 +02:00
if ( listBuf )
2016-04-09 12:03:53 +02:00
{
2021-04-21 23:20:33 +02:00
for ( usz i = 0 ; i < CELL_USERINFO_USER_MAX ; i + + )
{
if ( i < user_ids . size ( ) )
{
listBuf - > userId [ i ] = user_ids [ i ] ;
}
else
{
listBuf - > userId [ i ] = 0 ;
}
}
2016-04-09 12:03:53 +02:00
}
2014-05-19 15:05:53 +02:00
2014-09-01 02:51:48 +02:00
if ( currentUserId )
2016-04-09 12:03:53 +02:00
{
2018-03-17 07:17:27 +01:00
// We want the int value, not the string.
* currentUserId = Emu . GetUsrId ( ) ;
2016-04-09 12:03:53 +02:00
}
2017-12-16 01:03:49 +01:00
2014-03-11 18:40:37 +01:00
return CELL_OK ;
}
2016-03-21 20:43:03 +01:00
DECLARE ( ppu_module_manager : : cellUserInfo ) ( " cellUserInfo " , [ ] ( )
2014-03-11 18:40:37 +01:00
{
2015-02-20 14:58:40 +01:00
REG_FUNC ( cellUserInfo , cellUserInfoGetStat ) ;
REG_FUNC ( cellUserInfo , cellUserInfoSelectUser_ListType ) ;
REG_FUNC ( cellUserInfo , cellUserInfoSelectUser_SetList ) ;
REG_FUNC ( cellUserInfo , cellUserInfoEnableOverlay ) ;
REG_FUNC ( cellUserInfo , cellUserInfoGetList ) ;
2015-02-18 17:22:06 +01:00
} ) ;