LCOV - code coverage report
Current view: top level - gio - gopenuriportal.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 78.0 % 141 110
Test Date: 2024-11-26 05:23:01 Functions: 100.0 % 7 7
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* GIO - GLib Input, Output and Streaming Library
       2                 :             :  *
       3                 :             :  * Copyright 2017 Red Hat, Inc.
       4                 :             :  *
       5                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       6                 :             :  *
       7                 :             :  * This library is free software; you can redistribute it and/or
       8                 :             :  * modify it under the terms of the GNU Lesser General Public
       9                 :             :  * License as published by the Free Software Foundation; either
      10                 :             :  * version 2.1 of the License, or (at your option) any later version.
      11                 :             :  *
      12                 :             :  * This library is distributed in the hope that it will be useful,
      13                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15                 :             :  * Lesser General Public License for more details.
      16                 :             :  *
      17                 :             :  * You should have received a copy of the GNU Lesser General Public
      18                 :             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19                 :             :  */
      20                 :             : 
      21                 :             : #include "config.h"
      22                 :             : 
      23                 :             : #include <sys/stat.h>
      24                 :             : #include <fcntl.h>
      25                 :             : #include <errno.h>
      26                 :             : #include <string.h>
      27                 :             : 
      28                 :             : #include "gopenuriportal.h"
      29                 :             : #include "xdp-dbus.h"
      30                 :             : #include "gstdio.h"
      31                 :             : 
      32                 :             : #ifdef G_OS_UNIX
      33                 :             : #include "gunixfdlist.h"
      34                 :             : #endif
      35                 :             : 
      36                 :             : #ifndef O_CLOEXEC
      37                 :             : #define O_CLOEXEC 0
      38                 :             : #else
      39                 :             : #define HAVE_O_CLOEXEC 1
      40                 :             : #endif
      41                 :             : 
      42                 :             : gboolean
      43                 :           2 : g_openuri_portal_open_file (GFile       *file,
      44                 :             :                             const char  *parent_window,
      45                 :             :                             const char  *startup_id,
      46                 :             :                             GError     **error)
      47                 :             : {
      48                 :             :   GXdpOpenURI *openuri;
      49                 :             :   GVariantBuilder opt_builder;
      50                 :             :   gboolean res;
      51                 :             : 
      52                 :           2 :   openuri = gxdp_open_uri_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
      53                 :             :                                                   G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
      54                 :             :                                                   G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
      55                 :             :                                                   G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION,
      56                 :             :                                                   "org.freedesktop.portal.Desktop",
      57                 :             :                                                   "/org/freedesktop/portal/desktop",
      58                 :             :                                                   NULL,
      59                 :             :                                                   error);
      60                 :             : 
      61                 :           2 :   if (openuri == NULL)
      62                 :             :     {
      63                 :           0 :       g_prefix_error (error, "Failed to create OpenURI proxy: ");
      64                 :           0 :       return FALSE;
      65                 :             :     }
      66                 :             : 
      67                 :           2 :   g_variant_builder_init_static (&opt_builder, G_VARIANT_TYPE_VARDICT);
      68                 :             : 
      69                 :           2 :   if (startup_id)
      70                 :           2 :     g_variant_builder_add (&opt_builder, "{sv}",
      71                 :             :                            "activation_token",
      72                 :             :                            g_variant_new_string (startup_id));
      73                 :             : 
      74                 :           2 :   if (g_file_is_native (file))
      75                 :             :     {
      76                 :           1 :       char *path = NULL;
      77                 :           1 :       GUnixFDList *fd_list = NULL;
      78                 :             :       int fd, fd_id, errsv;
      79                 :             : 
      80                 :           1 :       path = g_file_get_path (file);
      81                 :             : 
      82                 :           1 :       fd = g_open (path, O_RDONLY | O_CLOEXEC);
      83                 :           1 :       errsv = errno;
      84                 :           1 :       if (fd == -1)
      85                 :             :         {
      86                 :           0 :           g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
      87                 :             :                        "Failed to open ā€˜%sā€™: %s", path, g_strerror (errsv));
      88                 :           0 :           g_free (path);
      89                 :           0 :           g_variant_builder_clear (&opt_builder);
      90                 :           0 :           return FALSE;
      91                 :             :         }
      92                 :             : 
      93                 :             : #ifndef HAVE_O_CLOEXEC
      94                 :             :       fcntl (fd, F_SETFD, FD_CLOEXEC);
      95                 :             : #endif
      96                 :           1 :       fd_list = g_unix_fd_list_new_from_array (&fd, 1);
      97                 :           1 :       fd = -1;
      98                 :           1 :       fd_id = 0;
      99                 :             : 
     100                 :           1 :       res = gxdp_open_uri_call_open_file_sync (openuri,
     101                 :             :                                                parent_window ? parent_window : "",
     102                 :             :                                                g_variant_new ("h", fd_id),
     103                 :             :                                                g_variant_builder_end (&opt_builder),
     104                 :             :                                                fd_list,
     105                 :             :                                                NULL,
     106                 :             :                                                NULL,
     107                 :             :                                                NULL,
     108                 :             :                                                error);
     109                 :           1 :       g_free (path);
     110                 :           1 :       g_object_unref (fd_list);
     111                 :             :     }
     112                 :             :   else
     113                 :             :     {
     114                 :           1 :       char *uri = NULL;
     115                 :             : 
     116                 :           1 :       uri = g_file_get_uri (file);
     117                 :             : 
     118                 :           1 :       res = gxdp_open_uri_call_open_uri_sync (openuri,
     119                 :             :                                               parent_window ? parent_window : "",
     120                 :             :                                               uri,
     121                 :             :                                               g_variant_builder_end (&opt_builder),
     122                 :             :                                               NULL,
     123                 :             :                                               NULL,
     124                 :             :                                               error);
     125                 :           1 :       g_free (uri);
     126                 :             :     }
     127                 :             : 
     128                 :           2 :   g_prefix_error (error, "Failed to call OpenURI portal: ");
     129                 :             : 
     130                 :           2 :   g_clear_object (&openuri);
     131                 :             : 
     132                 :           2 :   return res;
     133                 :             : }
     134                 :             : 
     135                 :             : enum {
     136                 :             :   XDG_DESKTOP_PORTAL_SUCCESS   = 0,
     137                 :             :   XDG_DESKTOP_PORTAL_CANCELLED = 1,
     138                 :             :   XDG_DESKTOP_PORTAL_FAILED    = 2
     139                 :             : };
     140                 :             : 
     141                 :             : typedef struct
     142                 :             : {
     143                 :             :   GXdpOpenURI *proxy;
     144                 :             :   char *response_handle;
     145                 :             :   unsigned int response_signal_id;
     146                 :             :   gboolean open_file;
     147                 :             : } CallData;
     148                 :             : 
     149                 :             : static CallData *
     150                 :           2 : call_data_new (void)
     151                 :             : {
     152                 :           2 :   return g_new0 (CallData, 1);
     153                 :             : }
     154                 :             : 
     155                 :             : static void
     156                 :           2 : call_data_free (gpointer data)
     157                 :             : {
     158                 :           2 :   CallData *call = data;
     159                 :             : 
     160                 :           2 :   g_assert (call->response_signal_id == 0);
     161                 :           2 :   g_clear_object (&call->proxy);
     162                 :           2 :   g_clear_pointer (&call->response_handle, g_free);
     163                 :           2 :   g_free_sized (data, sizeof (CallData));
     164                 :           2 : }
     165                 :             : 
     166                 :             : static void
     167                 :           2 : response_received (GDBusConnection *connection,
     168                 :             :                    const char      *sender_name,
     169                 :             :                    const char      *object_path,
     170                 :             :                    const char      *interface_name,
     171                 :             :                    const char      *signal_name,
     172                 :             :                    GVariant        *parameters,
     173                 :             :                    gpointer         user_data)
     174                 :             : {
     175                 :           2 :   GTask *task = user_data;
     176                 :             :   CallData *call_data;
     177                 :             :   guint32 response;
     178                 :             : 
     179                 :           2 :   call_data = g_task_get_task_data (task);
     180                 :           2 :   g_dbus_connection_signal_unsubscribe (connection, g_steal_handle_id (&call_data->response_signal_id));
     181                 :             : 
     182                 :           2 :   g_variant_get (parameters, "(u@a{sv})", &response, NULL);
     183                 :             : 
     184                 :           2 :   switch (response)
     185                 :             :     {
     186                 :           2 :     case XDG_DESKTOP_PORTAL_SUCCESS:
     187                 :           2 :       g_task_return_boolean (task, TRUE);
     188                 :           2 :       break;
     189                 :           0 :     case XDG_DESKTOP_PORTAL_CANCELLED:
     190                 :           0 :       g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Launch cancelled");
     191                 :           0 :       break;
     192                 :           0 :     case XDG_DESKTOP_PORTAL_FAILED:
     193                 :             :     default:
     194                 :           0 :       g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Launch failed");
     195                 :           0 :       break;
     196                 :             :     }
     197                 :             : 
     198                 :           2 :   g_object_unref (task);
     199                 :           2 : }
     200                 :             : 
     201                 :             : static void
     202                 :           2 : open_call_done (GObject      *source,
     203                 :             :                 GAsyncResult *result,
     204                 :             :                 gpointer      user_data)
     205                 :             : {
     206                 :           2 :   GXdpOpenURI *openuri = GXDP_OPEN_URI (source);
     207                 :             :   GDBusConnection *connection;
     208                 :           2 :   GTask *task = user_data;
     209                 :             :   CallData *call_data;
     210                 :           2 :   GError *error = NULL;
     211                 :             :   gboolean res;
     212                 :           2 :   char *path = NULL;
     213                 :             : 
     214                 :           2 :   call_data = g_task_get_task_data (task);
     215                 :           2 :   connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (openuri));
     216                 :             : 
     217                 :           2 :   if (call_data->open_file)
     218                 :           1 :     res = gxdp_open_uri_call_open_file_finish (openuri, &path, NULL, result, &error);
     219                 :             :   else
     220                 :           1 :     res = gxdp_open_uri_call_open_uri_finish (openuri, &path, result, &error);
     221                 :             : 
     222                 :           2 :   if (!res)
     223                 :             :     {
     224                 :           0 :       g_task_return_error (task, error);
     225                 :           0 :       g_object_unref (task);
     226                 :           0 :       g_free (path);
     227                 :           0 :       return;
     228                 :             :     }
     229                 :             : 
     230                 :           2 :   if (g_strcmp0 (call_data->response_handle, path) != 0)
     231                 :             :     {
     232                 :             :       guint signal_id;
     233                 :             : 
     234                 :           0 :       g_dbus_connection_signal_unsubscribe (connection, g_steal_handle_id (&call_data->response_signal_id));
     235                 :             : 
     236                 :           0 :       signal_id = g_dbus_connection_signal_subscribe (connection,
     237                 :             :                                                       "org.freedesktop.portal.Desktop",
     238                 :             :                                                       "org.freedesktop.portal.Request",
     239                 :             :                                                       "Response",
     240                 :             :                                                       path,
     241                 :             :                                                       NULL,
     242                 :             :                                                       G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
     243                 :             :                                                       response_received,
     244                 :             :                                                       task,
     245                 :             :                                                       NULL);
     246                 :           0 :       g_clear_pointer (&call_data->response_handle, g_free);
     247                 :           0 :       call_data->response_signal_id = g_steal_handle_id (&signal_id);
     248                 :           0 :       call_data->response_handle = g_steal_pointer (&path);
     249                 :             :     }
     250                 :             : 
     251                 :           2 :   g_free (path);
     252                 :             : }
     253                 :             : 
     254                 :             : void
     255                 :           2 : g_openuri_portal_open_file_async (GFile               *file,
     256                 :             :                                   const char          *parent_window,
     257                 :             :                                   const char          *startup_id,
     258                 :             :                                   GCancellable        *cancellable,
     259                 :             :                                   GAsyncReadyCallback  callback,
     260                 :             :                                   gpointer             user_data)
     261                 :             : {
     262                 :             :   CallData *call_data;
     263                 :           2 :   GError *error = NULL;
     264                 :             :   GDBusConnection *connection;
     265                 :             :   GXdpOpenURI *openuri;
     266                 :             :   GTask *task;
     267                 :           2 :   GVariant *opts = NULL;
     268                 :             :   int i;
     269                 :             :   guint signal_id;
     270                 :             : 
     271                 :           2 :   openuri = gxdp_open_uri_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
     272                 :             :                                                   G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
     273                 :             :                                                   G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
     274                 :             :                                                   G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION,
     275                 :             :                                                   "org.freedesktop.portal.Desktop",
     276                 :             :                                                   "/org/freedesktop/portal/desktop",
     277                 :             :                                                   NULL,
     278                 :             :                                                   &error);
     279                 :             : 
     280                 :           2 :   if (openuri == NULL)
     281                 :             :     {
     282                 :           0 :       g_prefix_error (&error, "Failed to create OpenURI proxy: ");
     283                 :           0 :       g_task_report_error (NULL, callback, user_data, NULL, error);
     284                 :           0 :       return;
     285                 :             :     }
     286                 :             : 
     287                 :           2 :   connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (openuri));
     288                 :             : 
     289                 :           2 :   if (callback)
     290                 :             :     {
     291                 :             :       GVariantBuilder opt_builder;
     292                 :             :       char *token;
     293                 :             :       char *sender;
     294                 :             :       char *handle;
     295                 :             : 
     296                 :           2 :       task = g_task_new (NULL, cancellable, callback, user_data);
     297                 :             : 
     298                 :           2 :       token = g_strdup_printf ("gio%d", g_random_int_range (0, G_MAXINT));
     299                 :           2 :       sender = g_strdup (g_dbus_connection_get_unique_name (connection) + 1);
     300                 :           9 :       for (i = 0; sender[i]; i++)
     301                 :           7 :         if (sender[i] == '.')
     302                 :           2 :           sender[i] = '_';
     303                 :             : 
     304                 :           2 :       handle = g_strdup_printf ("/org/freedesktop/portal/desktop/request/%s/%s", sender, token);
     305                 :           2 :       g_free (sender);
     306                 :             : 
     307                 :           2 :       signal_id = g_dbus_connection_signal_subscribe (connection,
     308                 :             :                                                       "org.freedesktop.portal.Desktop",
     309                 :             :                                                       "org.freedesktop.portal.Request",
     310                 :             :                                                       "Response",
     311                 :             :                                                       handle,
     312                 :             :                                                       NULL,
     313                 :             :                                                       G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
     314                 :             :                                                       response_received,
     315                 :             :                                                       task,
     316                 :             :                                                       NULL);
     317                 :             : 
     318                 :           2 :       g_variant_builder_init_static (&opt_builder, G_VARIANT_TYPE_VARDICT);
     319                 :           2 :       g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token));
     320                 :           2 :       g_free (token);
     321                 :             : 
     322                 :           2 :       if (startup_id)
     323                 :           2 :         g_variant_builder_add (&opt_builder, "{sv}",
     324                 :             :                                "activation_token",
     325                 :             :                                g_variant_new_string (startup_id));
     326                 :             : 
     327                 :           2 :       opts = g_variant_builder_end (&opt_builder);
     328                 :             : 
     329                 :           2 :       call_data = call_data_new ();
     330                 :           2 :       call_data->proxy = g_object_ref (openuri);
     331                 :           2 :       call_data->response_handle = g_steal_pointer (&handle);
     332                 :           2 :       call_data->response_signal_id = g_steal_handle_id (&signal_id);
     333                 :           2 :       g_task_set_task_data (task, call_data, call_data_free);
     334                 :             :     }
     335                 :             :   else
     336                 :             :     {
     337                 :           0 :       call_data = NULL;
     338                 :           0 :       task = NULL;
     339                 :             :     }
     340                 :             : 
     341                 :           2 :   if (g_file_is_native (file))
     342                 :             :     {
     343                 :           1 :       char *path = NULL;
     344                 :           1 :       GUnixFDList *fd_list = NULL;
     345                 :             :       int fd, fd_id, errsv;
     346                 :             : 
     347                 :           1 :       if (call_data)
     348                 :           1 :         call_data->open_file = TRUE;
     349                 :             : 
     350                 :           1 :       path = g_file_get_path (file);
     351                 :           1 :       fd = g_open (path, O_RDONLY | O_CLOEXEC);
     352                 :           1 :       errsv = errno;
     353                 :           1 :       if (fd == -1)
     354                 :             :         {
     355                 :           0 :           g_clear_object (&task);
     356                 :           0 :           g_task_report_new_error (NULL, callback, user_data, NULL,
     357                 :           0 :                                    G_IO_ERROR, g_io_error_from_errno (errsv),
     358                 :             :                                    "Failed to open ā€˜%sā€™: %s", path, g_strerror (errsv));
     359                 :           0 :           g_clear_object (&openuri);
     360                 :           0 :           return;
     361                 :             :         }
     362                 :             : 
     363                 :             : #ifndef HAVE_O_CLOEXEC
     364                 :             :       fcntl (fd, F_SETFD, FD_CLOEXEC);
     365                 :             : #endif
     366                 :           1 :       fd_list = g_unix_fd_list_new_from_array (&fd, 1);
     367                 :           1 :       fd = -1;
     368                 :           1 :       fd_id = 0;
     369                 :             : 
     370                 :           1 :       gxdp_open_uri_call_open_file (openuri,
     371                 :             :                                     parent_window ? parent_window : "",
     372                 :             :                                     g_variant_new ("h", fd_id),
     373                 :             :                                     opts,
     374                 :             :                                     fd_list,
     375                 :             :                                     cancellable,
     376                 :           1 :                                     task ? open_call_done : NULL,
     377                 :             :                                     task);
     378                 :           1 :       g_object_unref (fd_list);
     379                 :           1 :       g_free (path);
     380                 :             :     }
     381                 :             :   else
     382                 :             :     {
     383                 :           1 :       char *uri = NULL;
     384                 :             : 
     385                 :           1 :       uri = g_file_get_uri (file);
     386                 :             : 
     387                 :           1 :       gxdp_open_uri_call_open_uri (openuri,
     388                 :             :                                    parent_window ? parent_window : "",
     389                 :             :                                    uri,
     390                 :             :                                    opts,
     391                 :             :                                    cancellable,
     392                 :           1 :                                    task ? open_call_done : NULL,
     393                 :             :                                    task);
     394                 :           1 :       g_free (uri);
     395                 :             :     }
     396                 :             : 
     397                 :           2 :   g_clear_object (&openuri);
     398                 :             : }
     399                 :             : 
     400                 :             : gboolean
     401                 :           2 : g_openuri_portal_open_file_finish (GAsyncResult  *result,
     402                 :             :                                    GError       **error)
     403                 :             : {
     404                 :           2 :   return g_task_propagate_boolean (G_TASK (result), error);
     405                 :             : }
        

Generated by: LCOV version 2.0-1