mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-03 17:10:31 +01:00
tools: update the portal for the latest version
The latest version of the portal communication adds session capabilities and wraps the calls a bit differently. This now also includes a helper tool for the impl.portal part so we can run xdg-desktop-portal against that without the need for a mutter implementation. Use: - run the eis-demo-server - run the eis-fake-impl-portal - run the xdg-desktop-portal (it'll use the fake impl portal) - run an ei client with the portal enabled Note that the ei-fake-portal is a shortcut, it will open eis directly without going through the impl.portal. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
43be3ddc89
commit
df5237a7ea
4 changed files with 563 additions and 25 deletions
|
|
@ -186,6 +186,10 @@ if get_option('portal')
|
|||
'tools/eis-fake-portal.c',
|
||||
include_directories: 'src',
|
||||
dependencies: [dep_libutil, dep_systemd, dep_libreis])
|
||||
executable('eis-fake-impl-portal',
|
||||
'tools/eis-fake-impl-portal.c',
|
||||
include_directories: 'src',
|
||||
dependencies: [dep_libutil, dep_systemd, dep_libreis])
|
||||
endif
|
||||
|
||||
# tests
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ xdp_token(sd_bus *bus, char **token_out)
|
|||
}
|
||||
|
||||
static void
|
||||
portal_connect(struct ei_portal *portal)
|
||||
portal_connect(struct ei_portal *portal, const char *session_handle)
|
||||
{
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_unref_(sd_bus_message) *response = NULL;
|
||||
|
|
@ -107,19 +107,40 @@ portal_connect(struct ei_portal *portal)
|
|||
int rc = sd_bus_call_method(bus, portal->busname,
|
||||
"/org/freedesktop/portal/desktop",
|
||||
"org.freedesktop.portal.EmulatedInput",
|
||||
"Connect",
|
||||
"ConnectToEIS",
|
||||
&error,
|
||||
&response,
|
||||
"a{sv}", 0);
|
||||
"oa{sv}",
|
||||
session_handle,
|
||||
0);
|
||||
|
||||
if (rc < 0) {
|
||||
log_error(ei, "Failed to call method: %s\n", strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = sd_bus_message_read(response, "h", &eisfd);
|
||||
int status;
|
||||
rc = sd_bus_message_read(response, "u", &status);
|
||||
if (rc < 0) {
|
||||
log_error(ei, "Failed to extract fd: %s\n", strerror(-rc));
|
||||
log_error(ei, "Failed to extract status, invalid message format: %s\n", strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
log_info(ei, "Unable to get fd from portal\n");
|
||||
ei_disconnect(ei);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *key;
|
||||
rc = sd_bus_message_read(response, "a{sv}", 1, &key, "h", &eisfd);
|
||||
if (rc < 0) {
|
||||
log_error(ei, "Failed to extract fd, invalid message format: %s\n", strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!streq(key, "fd")) {
|
||||
log_error(ei, "Invalid key '%s', expected 'fd'\n", key);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -162,25 +183,54 @@ portal_response_received(sd_bus_message *m, void *userdata, sd_bus_error *error)
|
|||
/* We'll only get this signal once */
|
||||
portal->slot = sd_bus_slot_unref(portal->slot);
|
||||
|
||||
int rc = sd_bus_message_read(m, "u", &response);
|
||||
int rc = sd_bus_message_read(m, "u", &response);
|
||||
if (rc < 0) {
|
||||
log_error(ei, "Failed to read response from signal: %s\n", strerror(-rc));
|
||||
ei_disconnect(ei);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug(ei, "Portal EmulateInput reponse is %d\n", response);
|
||||
log_debug(ei, "Portal CreateSession reponse is %d\n", response);
|
||||
|
||||
const char *session_handle = NULL;
|
||||
if (response == 0) {
|
||||
const char *key;
|
||||
rc = sd_bus_message_read(m, "a{sv}", 1, &key, "s", &session_handle);
|
||||
if (rc < 0) {
|
||||
log_error(ei, "Failed to read session handle from signal: %s\n", strerror(-rc));
|
||||
ei_disconnect(ei);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!streq(key, "session_handle")) {
|
||||
log_error(ei, "Invalid or unhandled option: %ss\n", key);
|
||||
ei_disconnect(ei);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: we need to subscribe to the sessions Close signal */
|
||||
|
||||
if (response != 0) {
|
||||
ei_disconnect(ei);
|
||||
return 0;
|
||||
}
|
||||
|
||||
portal_connect(portal);
|
||||
portal_connect(portal, session_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
session_closed_received(sd_bus_message *m, void *userdata, sd_bus_error *error)
|
||||
{
|
||||
struct ei_portal *portal = userdata;
|
||||
struct ei *ei = ei_portal_parent(portal);
|
||||
|
||||
log_error(ei, "Session closed received");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_dispatch(struct source *source, void *data)
|
||||
{
|
||||
|
|
@ -221,6 +271,8 @@ portal_init(struct ei *ei, const char *busname)
|
|||
|
||||
_cleanup_free_ char *token = NULL;
|
||||
_cleanup_free_ char *handle = xdp_token(bus, &token);
|
||||
_cleanup_free_ char *session_token = xdp_token(bus, &session_token);
|
||||
_cleanup_free_ char *session_handle = xdp_token(bus, &session_token);
|
||||
|
||||
rc = sd_bus_match_signal(bus, &slot,
|
||||
busname,
|
||||
|
|
@ -234,16 +286,30 @@ portal_init(struct ei *ei, const char *busname)
|
|||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
rc = sd_bus_match_signal(bus, &slot,
|
||||
busname,
|
||||
session_handle,
|
||||
"org.freedesktop.portal.Session",
|
||||
"Closed",
|
||||
session_closed_received,
|
||||
portal);
|
||||
if (rc < 0) {
|
||||
log_error(ei, "Failed to subscribe to signal: %s\n", strerror(-rc));
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
rc = sd_bus_call_method(bus,
|
||||
busname,
|
||||
"/org/freedesktop/portal/desktop",
|
||||
"org.freedesktop.portal.EmulatedInput",
|
||||
"EmulateInput",
|
||||
"CreateSession",
|
||||
&error,
|
||||
&response,
|
||||
"a{sv}", 1,
|
||||
"a{sv}", 2,
|
||||
"handle_token", /* string key */
|
||||
"s", token /* variant string */
|
||||
"s", token, /* variant string */
|
||||
"session_handle_token", /* string key */
|
||||
"s", session_token /* variant string */
|
||||
);
|
||||
|
||||
if (rc < 0) {
|
||||
|
|
|
|||
371
tools/eis-fake-impl-portal.c
Normal file
371
tools/eis-fake-impl-portal.c
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* Copyright © 2021 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util-io.h"
|
||||
#include "util-list.h"
|
||||
#include "util-mem.h"
|
||||
#include "util-logger.h"
|
||||
#include "util-strings.h"
|
||||
|
||||
#include "libreis.h"
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
DEFINE_UNREF_CLEANUP_FUNC(reis);
|
||||
|
||||
struct session {
|
||||
unsigned int version;
|
||||
struct list link;
|
||||
struct sd_bus_slot *slot;
|
||||
char *handle;
|
||||
};
|
||||
|
||||
struct portal {
|
||||
unsigned int version;
|
||||
struct logger *logger;
|
||||
char *busname;
|
||||
|
||||
struct list sessions;
|
||||
} portal;
|
||||
|
||||
|
||||
#define call(_call) do { \
|
||||
int _rc = _call; \
|
||||
if (_rc < 0) { \
|
||||
log_error(portal, "Failed with %s %s:%d\n", strerror(-_rc), __func__, __LINE__); \
|
||||
return _rc; \
|
||||
} } while(0)
|
||||
|
||||
static int
|
||||
session_close(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||
{
|
||||
sd_bus_reply_method_return(m, "");
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable session_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("Close", "", "", session_close, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_PROPERTY("version", "u", NULL, offsetof(struct session, version), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
static int
|
||||
create_session_object(struct portal *portal,
|
||||
sd_bus *bus,
|
||||
const char *objectpath)
|
||||
{
|
||||
struct session *session = calloc(sizeof *session, 1);
|
||||
|
||||
session->handle = xstrdup(objectpath);
|
||||
|
||||
call(sd_bus_add_object_vtable(bus, &session->slot,
|
||||
objectpath,
|
||||
"org.freedesktop.impl.portal.Session",
|
||||
session_vtable,
|
||||
session));
|
||||
|
||||
list_append(&portal->sessions, &session->link);
|
||||
|
||||
log_debug(portal, "Session created on %s\n", objectpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
request_close(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||
{
|
||||
/* We don't live long enough for this to be called */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable request_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("Close", "", "", request_close, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
static int
|
||||
create_request_object(struct portal *portal,
|
||||
sd_bus *bus,
|
||||
const char *objectpath,
|
||||
const char *session_path)
|
||||
{
|
||||
_unref_(sd_bus_slot) *slot = NULL;
|
||||
|
||||
create_session_object(portal, bus, session_path);
|
||||
|
||||
call(sd_bus_add_object_vtable(bus, &slot,
|
||||
objectpath,
|
||||
"org.freedesktop.impl.portal.Request",
|
||||
request_vtable,
|
||||
NULL));
|
||||
|
||||
int response = 0;
|
||||
log_debug(portal, "emitting Response %d on %s\n", response, objectpath);
|
||||
return sd_bus_emit_signal(bus,
|
||||
objectpath,
|
||||
"org.freedesktop.impl.portal.Request",
|
||||
"Response",
|
||||
"ua{sv}",
|
||||
response,
|
||||
1,
|
||||
"session_handle",/* string key */
|
||||
"s", session_path /* variant string */
|
||||
);
|
||||
/* note: _unref_ removes object immediately */
|
||||
}
|
||||
|
||||
static int
|
||||
portal_create_session(sd_bus_message *m, void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct portal *portal = userdata;
|
||||
static int session_id = 1234;
|
||||
|
||||
const char *handle;
|
||||
const char *session_handle;
|
||||
const char *app_id;
|
||||
|
||||
sd_bus_message_read(m, "oosa{sv}",
|
||||
&handle,
|
||||
&session_handle,
|
||||
&app_id, 0);
|
||||
|
||||
log_debug(portal, "CreateSession: app-id %s, session %s, handle %s\n", app_id, session_handle, handle);
|
||||
|
||||
_cleanup_free_ char *sid = xaprintf("%d", session_id++);
|
||||
|
||||
call(sd_bus_reply_method_return(m, "ua{sv}", 0, 1, "session_id", "s", sid));
|
||||
|
||||
return create_request_object(portal, sd_bus_message_get_bus(m), handle, session_handle);
|
||||
}
|
||||
|
||||
static void
|
||||
set_prop_cmdline(struct reis *reis)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
xsnprintf(path, sizeof(path), "/proc/%u/cmdline", getpid());
|
||||
_cleanup_close_ int fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
int len;
|
||||
if ((len = read(fd, path, sizeof(path) - 1)) < 0)
|
||||
return;
|
||||
path[len] = '\0';
|
||||
|
||||
reis_set_property_with_permissions(reis, "ei.application.cmdline", path, REIS_PROPERTY_PERM_NONE);
|
||||
}
|
||||
|
||||
static void
|
||||
set_prop_pid(struct reis *reis)
|
||||
{
|
||||
char pid[64];
|
||||
|
||||
xsnprintf(pid, sizeof(pid), "%u", getpid());
|
||||
reis_set_property_with_permissions(reis, "ei.application.pid", pid, REIS_PROPERTY_PERM_NONE);
|
||||
}
|
||||
|
||||
static void
|
||||
set_prop_type(struct reis *reis)
|
||||
{
|
||||
reis_set_property_with_permissions(reis, "ei.connection.type", "portal", REIS_PROPERTY_PERM_NONE);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_connect_to_eis(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||
{
|
||||
struct portal *portal = userdata;
|
||||
|
||||
log_debug(portal, "Got a connect request\n");
|
||||
|
||||
const char *xdg = getenv("XDG_RUNTIME_DIR");
|
||||
if (!xdg)
|
||||
return -ENOENT;
|
||||
|
||||
const char *session_handle;
|
||||
const char *app_id;
|
||||
call(sd_bus_message_read(m, "os", &session_handle, &app_id));
|
||||
|
||||
log_debug(portal, "Connect request session %s appid %s\n", session_handle, app_id);
|
||||
|
||||
struct session *session;
|
||||
bool found = false;
|
||||
list_for_each_safe(session, &portal->sessions, link) {
|
||||
if (streq(session->handle, session_handle)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We're aborting here because it's a client bug and this is just a
|
||||
* fake portal */
|
||||
if (!found) {
|
||||
log_error(portal, "Invalid session handle %s\n", session_handle);
|
||||
abort();
|
||||
}
|
||||
|
||||
log_error(portal, "Valid session %s, connecting to EIS\n", session_handle);
|
||||
|
||||
_cleanup_free_ char *sockpath = xaprintf("%s/eis-0", xdg);
|
||||
int fd = xconnect(sockpath);
|
||||
if (fd < 0) {
|
||||
log_error(portal, "Failed to connect to EIS (%s)\n", strerror(-fd));
|
||||
return sd_bus_reply_method_return(m, "ua{sv}", 1, 0);
|
||||
}
|
||||
|
||||
_unref_(reis) *reis = reis_new(fd);
|
||||
assert(reis);
|
||||
set_prop_pid(reis);
|
||||
set_prop_cmdline(reis);
|
||||
set_prop_type(reis);
|
||||
|
||||
log_debug(portal, "passing fd %d\n", fd);
|
||||
return sd_bus_reply_method_return(m, "ua{sv}", 0,
|
||||
1, /* array length */
|
||||
"fd", "h", fd /* name: "fd", type handle, value fd */);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable portal_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}", portal_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ConnectToEIS", "osa{sv}", "ua{sv}", portal_connect_to_eis, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_PROPERTY("version", "u", NULL, offsetof(struct portal, version), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
static int
|
||||
run(struct portal *portal)
|
||||
{
|
||||
_unref_(sd_bus) *bus = NULL;
|
||||
_unref_(sd_bus_slot) *slot = NULL;
|
||||
int rc = sd_bus_open_user(&bus);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sd_bus_add_object_vtable(bus, &slot,
|
||||
"/org/freedesktop/portal/desktop",
|
||||
"org.freedesktop.impl.portal.EmulatedInput",
|
||||
portal_vtable,
|
||||
portal);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
sd_bus_add_object_manager(bus, NULL, "/org/freedesktop/portal/desktop");
|
||||
|
||||
log_debug(portal, "Portal object at: /org/freedesktop/ei/EmulatedInput\n");
|
||||
|
||||
rc = sd_bus_request_name(bus, portal->busname, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
log_debug(portal, "Portal DBus name: %s\n", portal->busname);
|
||||
|
||||
_unref_(sd_event) *event = NULL;
|
||||
rc = sd_event_default(&event);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sd_event_set_watchdog(event, true);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sd_bus_attach_event(bus, event, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return sd_event_loop(event);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(FILE *fp, const char *argv0)
|
||||
{
|
||||
fprintf(fp,
|
||||
"Usage: %s [--busname=a.b.c.d]\n"
|
||||
"\n"
|
||||
"Emulates an XDG Desktop portal for the org.freedesktop.impl.portal.EmulatedInput interface\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" --busname use the given busname instead of the default org.freedesktop.impl.portal.eis.EmulatedInput\n"
|
||||
"",
|
||||
basename(argv0));
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
_cleanup_free_ char *busname = xstrdup("org.freedesktop.impl.portal.eis.EmulatedInput");
|
||||
|
||||
while (1) {
|
||||
enum opts {
|
||||
OPT_BUSNAME,
|
||||
};
|
||||
static struct option long_opts[] = {
|
||||
{ "busname", required_argument, 0, OPT_BUSNAME},
|
||||
{ "help", no_argument, 0, 'h'},
|
||||
{ .name = NULL },
|
||||
};
|
||||
|
||||
int optind = 0;
|
||||
int c = getopt_long(argc, argv, "h", long_opts, &optind);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(stdout, argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
case OPT_BUSNAME:
|
||||
free(busname);
|
||||
busname = xstrdup(optarg);
|
||||
break;
|
||||
default:
|
||||
usage(stderr, argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
list_init(&portal.sessions);
|
||||
portal.version = 1;
|
||||
portal.busname = steal(&busname);
|
||||
portal.logger = logger_new("impl.portal", NULL);
|
||||
logger_set_priority(portal.logger, LOGGER_DEBUG);
|
||||
|
||||
int rc = run(&portal);
|
||||
if (rc < 0)
|
||||
fprintf(stderr, "Failed to start fake portal: %s\n", strerror(-rc));
|
||||
|
||||
logger_unref(portal.logger);
|
||||
free(portal.busname);
|
||||
return rc == 0;
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "util-io.h"
|
||||
#include "util-list.h"
|
||||
#include "util-mem.h"
|
||||
#include "util-logger.h"
|
||||
#include "util-strings.h"
|
||||
|
|
@ -40,9 +41,17 @@
|
|||
|
||||
DEFINE_UNREF_CLEANUP_FUNC(reis);
|
||||
|
||||
struct session {
|
||||
struct list link;
|
||||
struct sd_bus_slot *slot;
|
||||
char *handle;
|
||||
};
|
||||
|
||||
struct portal {
|
||||
struct logger *logger;
|
||||
char *busname;
|
||||
|
||||
struct list sessions;
|
||||
} portal;
|
||||
|
||||
|
||||
|
|
@ -53,6 +62,41 @@ struct portal {
|
|||
return _rc; \
|
||||
} } while(0)
|
||||
|
||||
static int
|
||||
session_close(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||
{
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable session_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("Close", "", "", session_close, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_SIGNAL("Closed", "ua{sv}", 0),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
static int
|
||||
create_session_object(struct portal *portal,
|
||||
sd_bus *bus,
|
||||
const char *objectpath)
|
||||
{
|
||||
struct session *session = calloc(sizeof *session, 1);
|
||||
|
||||
session->handle = xstrdup(objectpath);
|
||||
|
||||
call(sd_bus_add_object_vtable(bus, &session->slot,
|
||||
objectpath,
|
||||
"org.freedesktop.portal.Session",
|
||||
session_vtable,
|
||||
NULL));
|
||||
|
||||
list_append(&portal->sessions, &session->link);
|
||||
|
||||
log_debug(portal, "Session created on %s\n", objectpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
request_close(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||
{
|
||||
|
|
@ -70,9 +114,13 @@ static const sd_bus_vtable request_vtable[] = {
|
|||
static int
|
||||
create_request_object(struct portal *portal,
|
||||
sd_bus *bus,
|
||||
const char *objectpath)
|
||||
const char *objectpath,
|
||||
const char *session_path)
|
||||
{
|
||||
_unref_(sd_bus_slot) *slot = NULL;
|
||||
|
||||
create_session_object(portal, bus, session_path);
|
||||
|
||||
call(sd_bus_add_object_vtable(bus, &slot,
|
||||
objectpath,
|
||||
"org.freedesktop.portal.Request",
|
||||
|
|
@ -87,7 +135,9 @@ create_request_object(struct portal *portal,
|
|||
"Response",
|
||||
"ua{sv}",
|
||||
response,
|
||||
0 /* Array size */
|
||||
1,
|
||||
"session_handle",/* string key */
|
||||
"s", session_path /* variant string */
|
||||
);
|
||||
/* note: _unref_ removes object immediately */
|
||||
}
|
||||
|
|
@ -108,18 +158,36 @@ sender_token(const char *input)
|
|||
}
|
||||
|
||||
static int
|
||||
portal_emulate_input(sd_bus_message *m, void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
portal_create_session(sd_bus_message *m, void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
{
|
||||
struct portal *portal = userdata;
|
||||
|
||||
call(sd_bus_message_enter_container(m, 'a', "{sv}"));
|
||||
|
||||
const char *key, *handle_token;
|
||||
call(sd_bus_message_read(m, "{sv}", &key, "s", &handle_token));
|
||||
/* we only have a handle token in the dict so far */
|
||||
if (!streq(key, "handle_token"))
|
||||
const char *session_token = NULL;
|
||||
const char *handle_token = NULL;
|
||||
|
||||
const char *key, *val;
|
||||
call(sd_bus_message_read(m, "{sv}", &key, "s", &val));
|
||||
if (streq(key, "handle_token"))
|
||||
handle_token = val;
|
||||
else if (streq(key, "session_handle_token"))
|
||||
session_token = val;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
call(sd_bus_message_read(m, "{sv}", &key, "s", &val));
|
||||
if (streq(key, "handle_token"))
|
||||
handle_token = val;
|
||||
else if (streq(key, "session_handle_token"))
|
||||
session_token = val;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
assert(handle_token);
|
||||
assert(session_token);
|
||||
|
||||
call(sd_bus_message_exit_container(m));
|
||||
|
||||
_cleanup_free_ char *sender = sender_token(sd_bus_message_get_sender(m));
|
||||
|
|
@ -135,8 +203,13 @@ portal_emulate_input(sd_bus_message *m, void *userdata,
|
|||
handle_token);
|
||||
call(sd_bus_reply_method_return(m, "o", objpath));
|
||||
|
||||
_cleanup_free_ char *session_path = xaprintf("%s/session/%s/%s",
|
||||
"/org/freedesktop/portal/desktop",
|
||||
sender,
|
||||
session_token);
|
||||
|
||||
/* now create the object */
|
||||
return create_request_object(portal, sd_bus_message_get_bus(m), objpath);
|
||||
return create_request_object(portal, sd_bus_message_get_bus(m), objpath, session_path);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -173,8 +246,7 @@ set_prop_type(struct reis *reis)
|
|||
}
|
||||
|
||||
static int
|
||||
portal_connect(sd_bus_message *m, void *userdata,
|
||||
sd_bus_error *ret_error)
|
||||
portal_connect_to_eis(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
|
||||
{
|
||||
struct portal *portal = userdata;
|
||||
|
||||
|
|
@ -182,6 +254,28 @@ portal_connect(sd_bus_message *m, void *userdata,
|
|||
if (!xdg)
|
||||
return -ENOENT;
|
||||
|
||||
const char *session_handle;
|
||||
|
||||
call(sd_bus_message_read(m, "oa{sv}", &session_handle, 0));
|
||||
|
||||
struct session *session;
|
||||
bool found = false;
|
||||
list_for_each_safe(session, &portal->sessions, link) {
|
||||
if (streq(session->handle, session_handle)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We're aborting here because it's a client bug and this is just a
|
||||
* fake portal */
|
||||
if (!found) {
|
||||
log_error(portal, "Invalid session handle %s\n", session_handle);
|
||||
abort();
|
||||
}
|
||||
|
||||
log_info(portal, "Valid session %s, connecting to EIS\n", session_handle);
|
||||
|
||||
_cleanup_free_ char *sockpath = xaprintf("%s/eis-0", xdg);
|
||||
int handle = xconnect(sockpath);
|
||||
if (handle < 0) {
|
||||
|
|
@ -196,13 +290,15 @@ portal_connect(sd_bus_message *m, void *userdata,
|
|||
set_prop_type(reis);
|
||||
|
||||
log_debug(portal, "passing Handle %d\n", handle);
|
||||
return sd_bus_reply_method_return(m, "h", handle);
|
||||
return sd_bus_reply_method_return(m, "ua{sv}", 0,
|
||||
1, /* array size */
|
||||
"fd", "h", handle);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable portal_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("EmulateInput", "a{sv}", "o", portal_emulate_input, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("Connect", "a{sv}", "h", portal_connect, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("CreateSession", "a{sv}", "o", portal_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ConnectToEIS", "oa{sv}", "ua{sv}", portal_connect_to_eis, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
||||
|
|
@ -295,6 +391,7 @@ main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
list_init(&portal.sessions);
|
||||
portal.busname = steal(&busname);
|
||||
portal.logger = logger_new("portal", NULL);
|
||||
logger_set_priority(portal.logger, LOGGER_DEBUG);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue