libnx/nx/source/services/news.c
2020-08-04 19:37:34 +02:00

309 lines
9.1 KiB
C

#define NX_SERVICE_ASSUME_NON_DOMAIN
#include "services/news.h"
#include "service_guard.h"
#include "runtime/hosversion.h"
#include <string.h>
static NewsServiceType g_newsServiceType;
static Service g_newsCreatorSrv;
static Service g_newsSrv;
static Result _newsCreateNewsService(Service *srv_out);
NX_GENERATE_SERVICE_GUARD_PARAMS(news, (NewsServiceType service_type), (service_type));
Result _newsInitialize(NewsServiceType service_type) {
Result rc;
if (service_type >= NewsServiceType_Count)
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
static const char* const service_names[] = {
"news:a",
"news:c",
"news:m",
"news:p",
"news:v",
};
g_newsServiceType = service_type;
if (hosversionBefore(2,0,0)) {
rc = smGetService(&g_newsSrv, service_names[g_newsServiceType]);
} else {
rc = smGetService(&g_newsCreatorSrv, service_names[g_newsServiceType]);
if (R_SUCCEEDED(rc)) rc = _newsCreateNewsService(&g_newsSrv);
}
return rc;
}
void _newsCleanup(void) {
serviceClose(&g_newsSrv);
serviceClose(&g_newsCreatorSrv);
}
Service *newsGetServiceSession(void) {
return &g_newsSrv;
}
static Result _newsSrvOut(Service *srv, Service *srv_out, u32 cmd_id) {
return serviceDispatch(srv, cmd_id,
.out_num_objects = 1,
.out_objects = srv_out,
);
}
static Result _newsCreateNewsService(Service *srv_out) {
return _newsSrvOut(&g_newsCreatorSrv, srv_out, 0);
}
Result newsCreateNewlyArrivedEventHolder(NewsNewlyArrivedEventHolder *out) {
Service *srv;
u32 cmd_id;
if (hosversionBefore(2,0,0)) {
srv = &g_newsSrv;
cmd_id = 30900;
} else {
srv = &g_newsCreatorSrv;
cmd_id = 1;
}
return _newsSrvOut(srv, &out->s, cmd_id);
}
Result newsCreateNewsDataService(NewsDataService *out) {
Service *srv;
u32 cmd_id;
if (hosversionBefore(2,0,0)) {
srv = &g_newsSrv;
cmd_id = 30901;
} else {
srv = &g_newsCreatorSrv;
cmd_id = 2;
}
return _newsSrvOut(srv, &out->s, cmd_id);
}
Result newsCreateNewsDatabaseService(NewsDatabaseService *out) {
Service *srv;
u32 cmd_id;
if (hosversionBefore(2,0,0)) {
srv = &g_newsSrv;
cmd_id = 30902;
} else {
srv = &g_newsCreatorSrv;
cmd_id = 3;
}
return _newsSrvOut(srv, &out->s, cmd_id);
}
Result newsCreateOverwriteEventHolder(NewsOverwriteEventHolder *out) {
if (hosversionBefore(2,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _newsSrvOut(&g_newsCreatorSrv, &out->s, 4);
}
Result newsPostLocalNews(const void *news, size_t size) {
return serviceDispatch(&g_newsSrv, 10100,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { news, size }, },
);
}
Result newsSetPassphrase(u64 program_id, const char *passphrase) {
return serviceDispatchIn(&g_newsSrv, 20100, program_id,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { passphrase, strlen(passphrase) + 1 }, },
);
}
Result newsGetSubscriptionStatus(const char *filter, u32 *status) {
return serviceDispatchOut(&g_newsSrv, 30100, *status,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { filter, strlen(filter) + 1 }, },
);
}
Result newsGetTopicList(u32 unk, u32 *out_count, NewsTopicName *out, u32 max_count) {
if (hosversionBefore(3,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchInOut(&g_newsSrv, 30101, unk, *out_count,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out, max_count * sizeof(*out) }, },
);
}
Result newsGetSavedataUsage(u64 *current, u64 *total) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
struct {
u64 current;
u64 total;
} out;
Result rc = serviceDispatchOut(&g_newsSrv, 30110, out);
if (R_SUCCEEDED(rc)) {
if (current) *current = out.current;
if (total) *total = out.total;
}
return rc;
}
Result newsIsSystemUpdateRequired(bool *out) {
u8 tmp=0;
Result rc = serviceDispatchOut(&g_newsSrv, 30200, tmp);
if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
return rc;
}
Result newsGetDatabaseVersion(u32 *version) {
if (hosversionBefore(10,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchOut(&g_newsSrv, 30210, *version);
}
Result newsRequestImmediateReception(const char *filter) {
return serviceDispatch(&g_newsSrv, 30300,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { filter, strlen(filter) + 1 }, },
);
}
Result newsSetSubscriptionStatus(const char *filter, u32 status) {
return serviceDispatchIn(&g_newsSrv, 40100, status,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { filter, strlen(filter) + 1 }, },
);
}
Result newsClearStorage(void) {
return serviceDispatch(&g_newsSrv, 40200);
}
Result newsClearSubscriptionStatusAll(void) {
return serviceDispatch(&g_newsSrv, 40201);
}
Result newsGetNewsDatabaseDump(void *buffer, u64 size, u64 *out) {
return serviceDispatchOut(&g_newsSrv, 90100, *out,
.buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias },
.buffers = { { buffer, size }, },
);
}
void newsNewlyArrivedEventHolderClose(NewsNewlyArrivedEventHolder *srv) {
serviceClose(&srv->s);
}
Result newsNewlyArrivedEventHolderGet(NewsNewlyArrivedEventHolder *srv, Event *out) {
Handle tmp_handle = INVALID_HANDLE;
Result rc = 0;
rc = serviceDispatch(&srv->s, 0,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
.out_handles = &tmp_handle,
);
if (R_SUCCEEDED(rc)) eventLoadRemote(out, tmp_handle, true);
return rc;
}
void newsDataClose(NewsDataService *srv) {
serviceClose(&srv->s);
}
Result newsDataOpen(NewsDataService *srv, const char *file_name) {
return serviceDispatch(&srv->s, 0,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { file_name, strlen(file_name) + 1 }, },
);
}
Result newsDataOpenWithNewsRecordV1(NewsDataService *srv, NewsRecordV1 *record) {
return serviceDispatchIn(&srv->s, 1, *record);
}
Result newsDataRead(NewsDataService *srv, u64 *bytes_read, u64 offset, void *out, size_t out_size) {
return serviceDispatchInOut(&srv->s, 2, offset, *bytes_read,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = { { out, out_size }, },
);
}
Result newsDataGetSize(NewsDataService *srv, u64 *size) {
return serviceDispatchOut(&srv->s, 3, *size);
}
Result newsDataOpenWithNewsRecord(NewsDataService *srv, NewsRecord *record) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchIn(&srv->s, 1001, *record);
}
void newsDatabaseClose(NewsDatabaseService *srv) {
serviceClose(&srv->s);
}
Result newsDatabaseGetListV1(NewsDatabaseService *srv, NewsRecordV1 *out, u32 max_count, const char *where, const char *order, u32 *count, u32 offset) {
return serviceDispatchInOut(&srv->s, 0, offset, *count,
.buffer_attrs = {
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
SfBufferAttr_HipcPointer | SfBufferAttr_In,
SfBufferAttr_HipcPointer | SfBufferAttr_In,
},
.buffers = {
{ out, max_count * sizeof(NewsRecordV1) },
{ where, strlen(where) + 1 },
{ order, strlen(order) + 1 },
},
);
}
Result newsDatabaseCount(NewsDatabaseService *srv, const char *filter, u32 *count) {
return serviceDispatchOut(&srv->s, 1, *count,
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
.buffers = { { filter, strlen(filter) + 1 }, },
);
}
Result newsDatabaseGetList(NewsDatabaseService *srv, NewsRecord *out, u32 max_count, const char *where, const char *order, u32 *count, u32 offset) {
if (hosversionBefore(6,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchInOut(&srv->s, 1000, offset, *count,
.buffer_attrs = {
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
SfBufferAttr_HipcPointer | SfBufferAttr_In,
SfBufferAttr_HipcPointer | SfBufferAttr_In,
},
.buffers = {
{ out, max_count * sizeof(NewsRecord) },
{ where, strlen(where) + 1 },
{ order, strlen(order) + 1 },
},
);
}
void newsOverwriteEventHolderClose(NewsOverwriteEventHolder *srv) {
serviceClose(&srv->s);
}
Result newsOverwriteEventHolderGet(NewsOverwriteEventHolder *srv, Event *out) {
Handle tmp_handle = INVALID_HANDLE;
Result rc = 0;
rc = serviceDispatch(&srv->s, 0,
.out_handle_attrs = { SfOutHandleAttr_HipcCopy },
.out_handles = &tmp_handle,
);
if (R_SUCCEEDED(rc)) eventLoadRemote(out, tmp_handle, true);
return rc;
}