diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 13fe748..c1682cd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -254,14 +254,6 @@ build-no-doxygen@fedora:37: before_script: - dnf remove -y doxygen -build-no-portal@fedora:37: - extends: - - .fedora-build@template - before_script: - - dnf remove -y libsystemd-devel - variables: - MESON_ARGS: "-Dportal=false" - valgrind@fedora:37: extends: - .fedora-build@template diff --git a/.gitlab-ci/ci.template b/.gitlab-ci/ci.template index b420260..ae3fb8a 100644 --- a/.gitlab-ci/ci.template +++ b/.gitlab-ci/ci.template @@ -275,14 +275,6 @@ build-no-doxygen@{{distro.name}}:{{version}}: before_script: - dnf remove -y doxygen -build-no-portal@{{distro.name}}:{{version}}: - extends: - - .{{distro.name}}-build@template - before_script: - - dnf remove -y libsystemd-devel - variables: - MESON_ARGS: "-Dportal=false" - valgrind@{{distro.name}}:{{version}}: extends: - .{{distro.name}}-build@template diff --git a/doc/mainpage.dox b/doc/mainpage.dox index b183d9f..435500c 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -58,10 +58,6 @@ implementation and sends events. The `eis-demo-server` is a minimal EIS implementation that accepts all requests and prints them to screen. -The `eis-fake-portal` is a minimal [XDG Desktop -Portal](https://github.com/flatpak/xdg-desktop-portal/) implementation that -connects a portal-aware libei client with an EIS implementation. - @section building_against Building against libei or libeis libei and libeis provides diff --git a/examples/libei-client.pseudo b/examples/libei-client.pseudo index 5fc2d38..dbc7509 100644 --- a/examples/libei-client.pseudo +++ b/examples/libei-client.pseudo @@ -2,7 +2,7 @@ function main(): ctx = ei_new() - ei_portal_connect(ctx) + ei_connect(ctx) ei_dispatch(ctx) # let's say this is a blocking wait diff --git a/examples/libeis-server.pseudo b/examples/libeis-server.pseudo index 4a36d77..42b7040 100644 --- a/examples/libeis-server.pseudo +++ b/examples/libeis-server.pseudo @@ -7,7 +7,7 @@ function main(): ctx = eis_new() - eis_portal_init(ctx) + eis_init(ctx) while True: poll(eis_get_fd()): diff --git a/meson.build b/meson.build index 70d885c..ec53ed9 100644 --- a/meson.build +++ b/meson.build @@ -94,25 +94,12 @@ src_libei = [ 'src/libei-proto.h', 'src/libei-proto.c', 'src/libei-region.c', - 'src/libei-stubs.c', proto_headers, ] - -if get_option('portal') - dep_systemd = dependency('libsystemd') - config_h.set10('ENABLE_LIBEI_PORTAL', true) - src_libei += [ - 'src/libei-portal.c', - ] -else - dep_systemd = dependency('', required: false) -endif - deps_libei = [ dep_libutil, dep_protobuf, - dep_systemd, ] lib_libei = shared_library('ei', @@ -133,7 +120,6 @@ pkgconfig.generate(lib_libei, version: meson.project_version(), libraries: lib_libei, variables: [ - 'portal=' + get_option('portal').to_string(), 'protocol_version=' + protocol_version.to_string(), ], ) @@ -238,17 +224,6 @@ executable('ei-debug-events', dependencies: [dep_libutil, dep_libei, dep_libevdev], install: true) -if get_option('portal') - executable('eis-fake-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 if get_option('tests') subproject('munit', default_options: 'werror=false') diff --git a/meson_options.txt b/meson_options.txt index 0b426c3..a2862fc 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,2 @@ -option('portal', type: 'boolean', value: 'true', description: 'Enable/disable org.freedesktop.portal support') option('documentation', type: 'boolean', value: 'false', description: 'Enable/disable building the API documentation') option('tests', type: 'boolean', value: 'true', description: 'Enable/disable tests') diff --git a/portal/org.freedesktop.impl.portal.EmulatedInput.xml b/portal/org.freedesktop.impl.portal.EmulatedInput.xml deleted file mode 100644 index d2daba3..0000000 --- a/portal/org.freedesktop.impl.portal.EmulatedInput.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/portal/org.freedesktop.portal.EmulatedInput.xml b/portal/org.freedesktop.portal.EmulatedInput.xml deleted file mode 100644 index d57cb59..0000000 --- a/portal/org.freedesktop.portal.EmulatedInput.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/libei-portal.c b/src/libei-portal.c deleted file mode 100644 index 096225d..0000000 --- a/src/libei-portal.c +++ /dev/null @@ -1,357 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2020 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 -#include -#include -#include - -#include "libei.h" -#include "libei-private.h" - -#include "util-io.h" -#include "util-macros.h" -#include "util-mem.h" -#include "util-object.h" -#include "util-strings.h" - -struct ei_portal { - struct object object; - struct source *bus_source; - sd_bus *bus; - sd_bus_slot *slot; - - char *busname; -}; - -static void -ei_portal_destroy(struct ei_portal *portal) -{ - free(portal->busname); - sd_bus_unref(portal->bus); -} - -static -OBJECT_IMPLEMENT_CREATE(ei_portal); -static -OBJECT_IMPLEMENT_PARENT(ei_portal, ei); -static -OBJECT_IMPLEMENT_REF(ei_portal); -static -OBJECT_IMPLEMENT_UNREF_CLEANUP(ei_portal); - -static void -interface_portal_destroy(struct ei *ei, void *backend) -{ - struct ei_portal *portal = backend; - ei_portal_unref(portal); -} - -static const struct ei_backend_interface interface = { - .destroy = interface_portal_destroy, -}; - -static char * -xdp_token(sd_bus *bus, char **token_out) -{ - _cleanup_free_ char *sender = NULL; - const char *name = NULL; - - if (sd_bus_get_unique_name(bus, &name) != 0) - return NULL; - - sender = xstrdup(name + 1); /* drop initial : */ - - for (unsigned i = 0; sender[i]; i++) { - if (sender[i] == '.') - sender[i] = '_'; - } - - char *token = xaprintf("ei_%d", rand()); - *token_out = token; - - return xaprintf("/org/freedesktop/portal/desktop/request/%s/%s", sender, token); -} - -static void -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; - struct sd_bus *bus = portal->bus; - struct ei *ei = ei_portal_parent(portal); - int eisfd; - - int rc = sd_bus_call_method(bus, portal->busname, - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.EmulatedInput", - "ConnectToEIS", - &error, - &response, - "oa{sv}", - session_handle, - 0); - - if (rc < 0) { - log_error(ei, "Failed to call method: %s", strerror(-rc)); - goto out; - } - - int status; - rc = sd_bus_message_read(response, "u", &status); - if (rc < 0) { - log_error(ei, "Failed to extract status, invalid message format: %s", strerror(-rc)); - goto out; - } - - if (status != 0) { - log_info(ei, "Unable to get fd from portal"); - 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", strerror(-rc)); - goto out; - } - - if (!streq(key, "fd")) { - log_error(ei, "Invalid key '%s', expected 'fd'", key); - goto out; - } - - /* the fd is owned by the message */ - rc = xerrno(dup(eisfd)); - if (rc < 0) { - log_error(ei, "Failed to dup fd: %s", strerror(-rc)); - goto out; - } else { - eisfd = rc; - int flags = fcntl(eisfd, F_GETFL, 0); - fcntl(eisfd, F_SETFL, flags | O_NONBLOCK); - } - - log_debug(ei, "Initiating ei context with fd %d from portal", eisfd); - - /* We're done with DBus, lets clean up */ - source_remove(portal->bus_source); - source_unref(portal->bus_source); - portal->bus = sd_bus_unref(portal->bus); - - rc = ei_set_connection(ei, eisfd); -out: - if (rc < 0) { - log_error(ei, "Failed to set the connection: %s", strerror(-rc)); - ei_disconnect(ei); - } -} - -static int -portal_response_received(sd_bus_message *m, void *userdata, sd_bus_error *error) -{ - struct ei_portal *portal = userdata; - struct ei *ei = ei_portal_parent(portal); - unsigned response; - - assert(m); - assert(portal); - - /* We'll only get this signal once */ - portal->slot = sd_bus_slot_unref(portal->slot); - - int rc = sd_bus_message_read(m, "u", &response); - if (rc < 0) { - log_error(ei, "Failed to read response from signal: %s", strerror(-rc)); - ei_disconnect(ei); - return 0; - } - - log_debug(ei, "Portal CreateSession reponse is %u", 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", strerror(-rc)); - ei_disconnect(ei); - return 0; - } - - if (!streq(key, "session_handle")) { - log_error(ei, "Invalid or unhandled option: %ss", 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, 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) -{ - struct ei_portal *portal = data; - - /* We need to ref the bus here, portal_connect() may remove - * portal->bus but that needs to stay valid here until the end of - * the loop. - */ - _unref_(sd_bus) *bus = sd_bus_ref(portal->bus); - - int rc; - do { - rc = sd_bus_process(bus, NULL); - } while (rc > 0); - - if (rc != 0) { - log_error(ei_portal_parent(portal), "dbus processing failed with %s", strerror(-rc)); - } -} - -static int -portal_init(struct ei *ei, const char *busname) -{ - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _unref_(sd_bus_message) *response = NULL; - _unref_(sd_bus) *bus = NULL; - _unref_(sd_bus_slot) *slot = NULL; - _unref_(ei_portal) *portal = ei_portal_create(&ei->object); - const char *path = NULL; - - int rc = sd_bus_open_user(&bus); - if (rc < 0) { - log_error(ei, "Failed to init dbus: %s", strerror(-rc)); - return -ECONNREFUSED; - } - - _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, - handle, - "org.freedesktop.portal.Request", - "Response", - portal_response_received, - portal); - if (rc < 0) { - log_error(ei, "Failed to subscribe to signal: %s", strerror(-rc)); - 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", strerror(-rc)); - return -ECONNREFUSED; - } - - rc = sd_bus_call_method(bus, - busname, - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.EmulatedInput", - "CreateSession", - &error, - &response, - "a{sv}", 2, - "handle_token", /* string key */ - "s", token, /* variant string */ - "session_handle_token", /* string key */ - "s", session_token /* variant string */ - ); - - if (rc < 0) { - log_error(ei, "Failed to call method: %s", strerror(-rc)); - return -ECONNREFUSED; - } - - rc = sd_bus_message_read(response, "o", &path); - if (rc < 0) { - log_error(ei, "Failed to parse response: %s", strerror(-rc)); - return -ECONNREFUSED; - } - - log_debug(ei, "portal Response object is %s", path); - - struct source *s = source_new(sd_bus_get_fd(bus), dbus_dispatch, portal); - source_never_close_fd(s); /* the bus object handles the fd */ - rc = sink_add_source(ei->sink, s); - if (rc == 0) { - portal->bus_source = source_ref(s); - portal->bus = sd_bus_ref(bus); - portal->slot = sd_bus_slot_ref(slot); - } - - portal->busname = xstrdup(busname); - - ei->backend = ei_portal_ref(portal); - ei->backend_interface = interface; - - source_unref(s); - - return 0; -} - -_public_ int -ei_setup_backend_portal(struct ei *ei) -{ - return portal_init(ei, "org.freedesktop.portal.Desktop"); -} - -_public_ int -ei_setup_backend_portal_busname(struct ei *ei, const char *busname) -{ - return portal_init(ei, busname); -} diff --git a/src/libei-stubs.c b/src/libei-stubs.c deleted file mode 100644 index 7c934bd..0000000 --- a/src/libei-stubs.c +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2020 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 - -#include "libei.h" - -#include "util-macros.h" - -#if !ENABLE_LIBEI_PORTAL -_public_ int -ei_setup_backend_portal(struct ei *ei) -{ - return -ENOSYS; -} -#endif diff --git a/src/libei.h b/src/libei.h index a9a978b..5fa45af 100644 --- a/src/libei.h +++ b/src/libei.h @@ -581,26 +581,6 @@ ei_setup_backend_socket(struct ei *ei, const char *socketpath); int ei_setup_backend_fd(struct ei *ei, int fd); -/** - * Connect to the `org.freedesktop.portal.Desktop` portal. - * - * @return 0 on success or a negative errno on failure - */ -int -ei_setup_backend_portal(struct ei *ei); - -/** - * Connect to an `org.freedesktop.portal.Desktop` implementation on the - * given busname. - * - * Outside of testing environments, there is usually no reason to use - * this function, use ei_setup_backend_portal() instead. - * - * @return 0 on success or a negative errno on failure - */ -int -ei_setup_backend_portal_busname(struct ei *ei, const char *busname); - /** * Increase the refcount of this struct by one. Use ei_unref() to decrease * the refcount. diff --git a/tools/ei-debug-events.c b/tools/ei-debug-events.c index 311f16e..69c5d5b 100644 --- a/tools/ei-debug-events.c +++ b/tools/ei-debug-events.c @@ -30,8 +30,7 @@ * * Usually, you'd want to: * - run the eis-demo-server (or some other EIS implementation) - * - run the eis-fake-portal (if testing portal clients), otherwise - * export LIBEI_SOCKET=eis-0, or whatever value was given. + * - export LIBEI_SOCKET=eis-0, or whatever value was given * - run the ei-demo-client */ diff --git a/tools/ei-demo-client.c b/tools/ei-demo-client.c index c02a622..88e4fc8 100644 --- a/tools/ei-demo-client.c +++ b/tools/ei-demo-client.c @@ -30,8 +30,7 @@ * * Usually, you'd want to: * - run the eis-demo-server (or some other EIS implementation) - * - run the eis-fake-portal (if testing portal clients), otherwise - * export LIBEI_SOCKET=eis-0, or whatever value was given. + * - export LIBEI_SOCKET=eis-0, or whatever value was given * - run the ei-demo-client */ diff --git a/tools/eis-demo-server.c b/tools/eis-demo-server.c index cee0e71..2279f65 100644 --- a/tools/eis-demo-server.c +++ b/tools/eis-demo-server.c @@ -33,8 +33,7 @@ * * Usually, you'd want to: * - run the eis-demo-server (or some other EIS implementation) - * - run the eis-fake-portal (if testing portal clients), otherwise - * export LIBEI_SOCKET=eis-0, or whatever value was given. + * - export LIBEI_SOCKET=eis-0, or whatever value was given * - run the libei client */ diff --git a/tools/eis-fake-impl-portal.c b/tools/eis-fake-impl-portal.c deleted file mode 100644 index 9843e13..0000000 --- a/tools/eis-fake-impl-portal.c +++ /dev/null @@ -1,377 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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. - */ - -/* A simple tool that sets up the org.freedesktop.impl.portal.EmulatedInput - * DBus interface and provides the required functionality. - * - * This tool is useful for testing portals (e.g. - * xdg-desktop-portal) that need to connect to impl.portal. It provides - * enough data to succeed with the connection. - * - * This tool does not run an EIS server, use e.g. the eis-demo-server. - * - * Usually, you'd want to: - * - run the eis-demo-server (or some other EIS implementation) - * - run the eis-fake-impl-portal - * - run xdg-desktop-portal - * - run the libei client relying on the portal - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "util-io.h" -#include "util-list.h" -#include "util-mem.h" -#include "util-logger.h" -#include "util-strings.h" - -#include "libreis.h" - -#include - -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) -{ - _cleanup_free_ char *cmdline = cmdline_as_str(); - reis_set_property_with_permissions(reis, "ei.application.cmdline", cmdline, REIS_PROPERTY_PERM_NONE); -} - -static void -set_prop_pid(struct reis *reis) -{ - char pid[64]; - - xsnprintf(pid, sizeof(pid), "%i", 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; -} diff --git a/tools/eis-fake-portal.c b/tools/eis-fake-portal.c deleted file mode 100644 index abfdf75..0000000 --- a/tools/eis-fake-portal.c +++ /dev/null @@ -1,417 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2020 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. - */ - -/* A simple tool that sets up the org.freedesktop.portal.EmulatedInput DBus - * interface and provides the required functionality. - * - * This tool is useful for testing the libei portal backend, it provides just - * enough data to have that backend succeed with the connection. - * - * This tool does not run an EIS server, use e.g. the eis-demo-server. - * - * Usually, you'd want to: - * - run the eis-demo-server (or some other EIS implementation) - * - run the eis-fake-portal - * - run the libei client relying on the portal - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "util-io.h" -#include "util-list.h" -#include "util-mem.h" -#include "util-logger.h" -#include "util-strings.h" - -#include "libreis.h" - -#include - -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; - - -#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) -{ - /* 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) -{ - /* 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_SIGNAL("Response", "ua{sv}", 0), - 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.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.portal.Request", - "Response", - "ua{sv}", - response, - 1, - "session_handle",/* string key */ - "s", session_path /* variant string */ - ); - /* note: _unref_ removes object immediately */ -} - -static char * -sender_token(const char *input) -{ - if (!input) - return NULL; - - char *token = strstrip(input, ":"); - for (size_t idx = 0; token[idx]; idx++) { - if (token[idx] == '.') - token[idx] = '_'; - } - - return token; -} - -static int -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 *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)); - if (!sender) - return -ENOMEM; - - /* Send back the object path of the object we're about to create. We - * then create the object, so if that fails we have a problem but - * meh, this is for testing only .*/ - _cleanup_free_ char *objpath = xaprintf("%s/request/%s/%s", - "/org/freedesktop/portal/desktop", - sender, - 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, session_path); -} - -static void -set_prop_cmdline(struct reis *reis) -{ - _cleanup_free_ char *cmdline = cmdline_as_str(); - reis_set_property_with_permissions(reis, "ei.application.cmdline", cmdline, REIS_PROPERTY_PERM_NONE); -} - -static void -set_prop_pid(struct reis *reis) -{ - char pid[64]; - - xsnprintf(pid, sizeof(pid), "%i", 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; - - const char *xdg = getenv("XDG_RUNTIME_DIR"); - 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); - return sd_bus_reply_method_return(m, "ua{sv}", 1, 0); - } - - log_info(portal, "Valid session %s, connecting to EIS\n", session_handle); - - _cleanup_free_ char *sockpath = xstrdup(getenv("LIBEI_SOCKET")); - if (!sockpath) - sockpath = xaprintf("%s/eis-0", xdg); - - int handle = xconnect(sockpath); - if (handle < 0) { - log_error(portal, "Failed to connect to EIS (%s)\n", strerror(-handle)); - return sd_bus_reply_method_return(m, "ua{sv}", 1, 0); - } - - _unref_(reis) *reis = reis_new(handle); - assert(reis); - set_prop_pid(reis); - set_prop_cmdline(reis); - set_prop_type(reis); - - log_debug(portal, "passing Handle %d\n", 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("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, -}; - -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.portal.EmulatedInput", - portal_vtable, - portal); - if (rc < 0) - return rc; - - log_debug(portal, "Portal object at: /org/freedesktop/portal/desktop\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.portal.EmulatedInput interface\n" - "\n" - "Options:\n" - " --busname use the given busname instead of the default org.freedesktop.portal.Desktop\n" - "\n" - "This portal connects directly to the EIS instance at $LIBEI_SOCKET or, if unset, at \n" - "$XDG_RUNTIME_DIR/eis-0. It does **not** use the org.freedesktop.impl.portal.EmulatedInput\n" - "interface.\n" - "", - basename(argv0)); -} - -int -main(int argc, char **argv) -{ - _cleanup_free_ char *busname = xstrdup("org.freedesktop.portal.Desktop"); - - 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.busname = steal(&busname); - portal.logger = logger_new("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; -}