libnx/nx/source/services/friends.c
2021-04-10 23:14:24 +02:00

152 lines
5.1 KiB
C

#include "service_guard.h"
#include "sf/sessionmgr.h"
#include "services/friends.h"
static FriendsServiceType g_friendsServiceType;
static Service g_friendsSrv;
static Service g_friendsIFriendService;
static SessionMgr g_friendsSessionMgr;
NX_GENERATE_SERVICE_GUARD_PARAMS(friends, (FriendsServiceType service_type), (service_type));
NX_INLINE bool _friendsObjectIsChild(Service* s) {
return s->session == g_friendsSrv.session;
}
static void _friendsObjectClose(Service* s) {
if (!_friendsObjectIsChild(s)) {
serviceClose(s);
} else {
int slot = sessionmgrAttachClient(&g_friendsSessionMgr);
uint32_t object_id = serviceGetObjectId(s);
serviceAssumeDomain(s);
cmifMakeCloseRequest(armGetTls(), object_id);
svcSendSyncRequest(sessionmgrGetClientSession(&g_friendsSessionMgr, slot));
sessionmgrDetachClient(&g_friendsSessionMgr, slot);
}
}
NX_INLINE Result _friendsObjectDispatchImpl(Service* s, u32 request_id,
const void * in_data, u32 in_data_size,
void * out_data, u32 out_data_size,
SfDispatchParams disp)
{
int slot = -1;
if (_friendsObjectIsChild(s)) {
slot = sessionmgrAttachClient(&g_friendsSessionMgr);
if (slot < 0)
__builtin_unreachable();
disp.target_session = sessionmgrGetClientSession(&g_friendsSessionMgr, slot);
serviceAssumeDomain(s);
}
Result rc = serviceDispatchImpl(s, request_id, in_data, in_data_size, out_data, out_data_size, disp);
if (slot >= 0)
sessionmgrDetachClient(&g_friendsSessionMgr, slot);
return rc;
}
#define _friendsObjectDispatch(_s,_rid,...) \
_friendsObjectDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ })
#define _friendsObjectDispatchIn(_s,_rid,_in,...) \
_friendsObjectDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ })
#define _friendsObjectDispatchOut(_s,_rid,_out,...) \
_friendsObjectDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })
#define _friendsObjectDispatchInOut(_s,_rid,_in,_out,...) \
_friendsObjectDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })
Result _friendsInitialize(FriendsServiceType service_type) {
Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
g_friendsServiceType = service_type;
switch (g_friendsServiceType) {
case FriendsServiceType_User:
rc = smGetService(&g_friendsSrv, "friend:u");
break;
case FriendsServiceType_Administrator:
rc = smGetService(&g_friendsSrv, "friend:a");
break;
case FriendsServiceType_Manager:
rc = smGetService(&g_friendsSrv, "friend:m");
break;
case FriendsServiceType_Viewer:
rc = smGetService(&g_friendsSrv, "friend:v");
break;
case FriendsServiceType_System:
rc = smGetService(&g_friendsSrv, "friend:s");
break;
}
if (R_SUCCEEDED(rc))
rc = serviceConvertToDomain(&g_friendsSrv);
if (R_SUCCEEDED(rc))
rc = sessionmgrCreate(&g_friendsSessionMgr, g_friendsSrv.session, 0x5);
if (R_SUCCEEDED(rc)) {
rc = _friendsObjectDispatch(&g_friendsSrv, 0,
.out_num_objects = 1,
.out_objects = &g_friendsIFriendService
);
}
return rc;
}
void _friendsCleanup(void) {
sessionmgrClose(&g_friendsSessionMgr);
_friendsObjectClose(&g_friendsIFriendService);
serviceClose(&g_friendsSrv);
}
Service* friendsGetServiceSession(void) {
return &g_friendsSrv;
}
Service* friendsGetServiceSession_IFriendsService(void) {
return &g_friendsIFriendService;
}
Result friendsGetUserSetting(AccountUid uid, FriendsUserSetting *user_setting) {
return _friendsObjectDispatchIn(&g_friendsIFriendService, 20800, uid,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out | SfBufferAttr_FixedSize },
.buffers = { { user_setting, sizeof(FriendsUserSetting) } }
);
}
Result friendsTryPopFriendInvitationNotificationInfo(AccountUid *uid, void* buffer, u64 size, u64 *out_size) {
Result rc=0;
AppletStorage storage;
s64 storage_size=0;
u64 data_size = size;
AccountUid tmpuid={0};
rc = appletTryPopFromFriendInvitationStorageChannel(&storage);
if (R_SUCCEEDED(rc)) rc = appletStorageGetSize(&storage, &storage_size);
if (R_SUCCEEDED(rc) && storage_size < sizeof(AccountUid)) rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (R_SUCCEEDED(rc)) {
storage_size-=sizeof(AccountUid);
rc = appletStorageRead(&storage, 0, &tmpuid, sizeof(AccountUid));
if (R_SUCCEEDED(rc)) {
if (data_size > storage_size) data_size = storage_size;
if (data_size) rc = appletStorageRead(&storage, sizeof(AccountUid), buffer, data_size);
if (R_SUCCEEDED(rc)) {
if (out_size) *out_size = data_size;
if (uid) *uid = tmpuid;
}
}
}
appletStorageClose(&storage);
return rc;
}