/* * Copyright © 2016 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Matthias Clasen */ #include "config.h" #include #include #include #include #include #include #include #include #include "account.h" #include "request.h" #include "documents.h" #include "xdp-dbus.h" #include "xdp-impl-dbus.h" #include "xdp-utils.h" typedef struct _Account Account; typedef struct _AccountClass AccountClass; struct _Account { XdpDbusAccountSkeleton parent_instance; }; struct _AccountClass { XdpDbusAccountSkeletonClass parent_class; }; static XdpDbusImplAccount *impl; static Account *account; GType account_get_type (void) G_GNUC_CONST; static void account_iface_init (XdpDbusAccountIface *iface); G_DEFINE_TYPE_WITH_CODE (Account, account, XDP_DBUS_TYPE_ACCOUNT_SKELETON, G_IMPLEMENT_INTERFACE (XDP_DBUS_TYPE_ACCOUNT, account_iface_init)); static void send_response_in_thread_func (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { Request *request = task_data; guint response; GVariant *results; GVariantBuilder new_results; g_autoptr(GVariant) idv = NULL; g_autoptr(GVariant) namev = NULL; const char *image; g_variant_builder_init (&new_results, G_VARIANT_TYPE_VARDICT); REQUEST_AUTOLOCK (request); response = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (request), "response")); results = (GVariant *)g_object_get_data (G_OBJECT (request), "results"); if (response != 0) goto out; idv = g_variant_lookup_value (results, "id", G_VARIANT_TYPE_STRING); namev = g_variant_lookup_value (results, "name", G_VARIANT_TYPE_STRING); g_variant_builder_add (&new_results, "{sv}", "id", idv); g_variant_builder_add (&new_results, "{sv}", "name", namev); if (g_variant_lookup (results, "image", "&s", &image)) { g_autofree char *ruri = NULL; g_autoptr(GError) error = NULL; if (xdp_app_info_is_host (request->app_info)) ruri = g_strdup (image); else ruri = register_document (image, xdp_app_info_get_id (request->app_info), DOCUMENT_FLAG_NONE, &error); if (ruri == NULL) g_warning ("Failed to register %s: %s", image, error->message); else { g_debug ("convert uri '%s' -> '%s'\n", image, ruri); g_variant_builder_add (&new_results, "{sv}", "image", g_variant_new_string (ruri)); } } out: if (request->exported) { xdp_dbus_request_emit_response (XDP_DBUS_REQUEST (request), response, g_variant_builder_end (&new_results)); request_unexport (request); } } static void get_user_information_done (GObject *source, GAsyncResult *result, gpointer data) { g_autoptr(Request) request = data; guint response = 2; g_autoptr(GVariant) results = NULL; g_autoptr(GError) error = NULL; g_autoptr(GTask) task = NULL; if (!xdp_dbus_impl_account_call_get_user_information_finish (XDP_DBUS_IMPL_ACCOUNT (source), &response, &results, result, &error)) { g_dbus_error_strip_remote_error (error); g_warning ("Backend call failed: %s", error->message); } g_object_set_data (G_OBJECT (request), "response", GINT_TO_POINTER (response)); if (results) g_object_set_data_full (G_OBJECT (request), "results", g_variant_ref (results), (GDestroyNotify)g_variant_unref); task = g_task_new (NULL, NULL, NULL, NULL); g_task_set_task_data (task, g_object_ref (request), g_object_unref); g_task_run_in_thread (task, send_response_in_thread_func); } static gboolean validate_reason (const char *key, GVariant *value, GVariant *options, GError **error) { const char *string = g_variant_get_string (value, NULL); if (g_utf8_strlen (string, -1) > 256) { g_set_error (error, XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT, "Not accepting overly long reasons"); return FALSE; } return TRUE; } static XdpOptionKey user_information_options[] = { { "reason", G_VARIANT_TYPE_STRING, validate_reason }, }; static gboolean handle_get_user_information (XdpDbusAccount *object, GDBusMethodInvocation *invocation, const gchar *arg_parent_window, GVariant *arg_options) { Request *request = request_from_invocation (invocation); const char *app_id = xdp_app_info_get_id (request->app_info); g_autoptr(GError) error = NULL; g_autoptr(XdpDbusImplRequest) impl_request = NULL; GVariantBuilder options; g_debug ("Handling GetUserInformation"); REQUEST_AUTOLOCK (request); impl_request = xdp_dbus_impl_request_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (impl)), G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, g_dbus_proxy_get_name (G_DBUS_PROXY (impl)), request->id, NULL, &error); if (!impl_request) { g_dbus_method_invocation_return_gerror (invocation, error); return G_DBUS_METHOD_INVOCATION_HANDLED; } request_set_impl_request (request, impl_request); request_export (request, g_dbus_method_invocation_get_connection (invocation)); g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT); xdp_filter_options (arg_options, &options, user_information_options, G_N_ELEMENTS (user_information_options), NULL); g_debug ("options filtered"); xdp_dbus_impl_account_call_get_user_information (impl, request->id, app_id, arg_parent_window, g_variant_builder_end (&options), NULL, get_user_information_done, g_object_ref (request)); xdp_dbus_account_complete_get_user_information (object, invocation, request->id); return G_DBUS_METHOD_INVOCATION_HANDLED; } static void account_iface_init (XdpDbusAccountIface *iface) { iface->handle_get_user_information = handle_get_user_information; } static void account_init (Account *account) { xdp_dbus_account_set_version (XDP_DBUS_ACCOUNT (account), 1); } static void account_class_init (AccountClass *klass) { } GDBusInterfaceSkeleton * account_create (GDBusConnection *connection, const char *dbus_name) { g_autoptr(GError) error = NULL; impl = xdp_dbus_impl_account_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, dbus_name, DESKTOP_PORTAL_OBJECT_PATH, NULL, &error); if (impl == NULL) { g_warning ("Failed to create account proxy: %s", error->message); return NULL; } g_debug ("using %s at %s\n", "org.freedesktop.impl.portal.Account", dbus_name); g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (impl), G_MAXINT); account = g_object_new (account_get_type (), NULL); return G_DBUS_INTERFACE_SKELETON (account); }