LCOV - code coverage report
Current view: top level - src/plugins/share - valent-share-plugin.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 78.8 % 575 453
Test Date: 2024-04-23 06:02:46 Functions: 82.9 % 35 29
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 44.1 % 374 165

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-share-plugin"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <glib/gi18n.h>
       9                 :             : #include <gio/gio.h>
      10                 :             : #include <gtk/gtk.h>
      11                 :             : #include <json-glib/json-glib.h>
      12                 :             : #include <valent.h>
      13                 :             : 
      14                 :             : #include "valent-share-plugin.h"
      15                 :             : #include "valent-share-download.h"
      16                 :             : #include "valent-share-text-dialog.h"
      17                 :             : #include "valent-share-upload.h"
      18                 :             : 
      19                 :             : 
      20                 :             : struct _ValentSharePlugin
      21                 :             : {
      22                 :             :   ValentDevicePlugin  parent_instance;
      23                 :             : 
      24                 :             :   GHashTable         *transfers;
      25                 :             :   ValentTransfer     *upload;
      26                 :             :   ValentTransfer     *download;
      27                 :             : 
      28                 :             :   GPtrArray          *windows;
      29                 :             : };
      30                 :             : 
      31   [ +  +  +  - ]:         107 : G_DEFINE_FINAL_TYPE (ValentSharePlugin, valent_share_plugin, VALENT_TYPE_DEVICE_PLUGIN)
      32                 :             : 
      33                 :             : 
      34                 :             : static GFile *
      35                 :           7 : valent_share_plugin_create_download_file (ValentSharePlugin *self,
      36                 :             :                                           const char        *filename,
      37                 :             :                                           gboolean           unique)
      38                 :             : {
      39                 :           7 :   GSettings *settings;
      40                 :          14 :   g_autofree char *download_folder = NULL;
      41                 :             : 
      42         [ +  - ]:           7 :   g_return_val_if_fail (VALENT_IS_SHARE_PLUGIN (self), NULL);
      43         [ -  + ]:           7 :   g_return_val_if_fail (filename != NULL, NULL);
      44                 :             : 
      45                 :             :   /* Check for a configured download directory, returning a fallback if
      46                 :             :    * necessary, but don't save the fallback as though it were configured. */
      47                 :           7 :   settings = valent_extension_get_settings (VALENT_EXTENSION (self));
      48                 :           7 :   download_folder = g_settings_get_string (settings, "download-folder");
      49                 :             : 
      50   [ +  -  +  - ]:           7 :   if (download_folder == NULL || *download_folder == '\0')
      51                 :             :     {
      52                 :           7 :       const char *user_download = NULL;
      53                 :             : 
      54                 :           7 :       user_download = valent_get_user_directory (G_USER_DIRECTORY_DOWNLOAD);
      55                 :           7 :       g_set_str (&download_folder, user_download);
      56                 :             :     }
      57                 :             : 
      58         [ -  + ]:           7 :   if (g_mkdir_with_parents (download_folder, 0700) == -1)
      59                 :             :     {
      60                 :           0 :       int error = errno;
      61                 :             : 
      62                 :           0 :       g_critical ("%s(): creating \"%s\": %s",
      63                 :             :                   G_STRFUNC,
      64                 :             :                   download_folder,
      65                 :             :                   g_strerror (error));
      66                 :             :     }
      67                 :             : 
      68                 :           7 :   return valent_get_user_file (download_folder, filename, unique);
      69                 :             : }
      70                 :             : 
      71                 :             : /*
      72                 :             :  * File Downloads
      73                 :             :  */
      74                 :             : static void
      75                 :          10 : valent_share_download_file_notification (ValentSharePlugin *self,
      76                 :             :                                          ValentTransfer    *transfer)
      77                 :             : {
      78                 :          10 :   g_autoptr (ValentDevice) device = NULL;
      79   [ +  -  -  - ]:          10 :   g_autoptr (GNotification) notification = NULL;
      80   [ +  -  -  - ]:          10 :   g_autoptr (GIcon) icon = NULL;
      81                 :          10 :   const char *title = NULL;
      82   [ +  -  -  - ]:          10 :   g_autofree char *body = NULL;
      83                 :          10 :   g_autofree char *id = NULL;
      84                 :          10 :   unsigned int n_files = 0;
      85                 :          10 :   const char *device_name;
      86                 :          10 :   ValentTransferState state = VALENT_TRANSFER_STATE_PENDING;
      87                 :             : 
      88         [ +  - ]:          10 :   g_return_if_fail (VALENT_IS_TRANSFER (transfer));
      89         [ -  + ]:          10 :   g_return_if_fail (VALENT_IS_SHARE_DOWNLOAD (transfer));
      90                 :             : 
      91         [ +  - ]:          10 :   if ((n_files = g_list_model_get_n_items (G_LIST_MODEL (transfer))) == 0)
      92                 :             :     return;
      93                 :             : 
      94                 :          10 :   g_object_get (transfer,
      95                 :             :                 "device", &device,
      96                 :             :                 "id",     &id,
      97                 :             :                 "state",  &state,
      98                 :             :                 NULL);
      99                 :          10 :   device_name = valent_device_get_name (device);
     100                 :             : 
     101   [ +  +  -  - ]:          10 :   switch (state)
     102                 :             :     {
     103                 :           6 :     case VALENT_TRANSFER_STATE_PENDING:
     104                 :             :     case VALENT_TRANSFER_STATE_ACTIVE:
     105                 :           6 :       icon = g_themed_icon_new ("document-save-symbolic");
     106                 :           6 :       title = _("Transferring Files");
     107                 :           6 :       body = g_strdup_printf (ngettext ("Receiving one file from %1$s",
     108                 :             :                                         "Receiving %2$d files from %1$s",
     109                 :             :                                         n_files),
     110                 :             :                               device_name, n_files);
     111                 :           6 :       break;
     112                 :             : 
     113                 :           4 :     case VALENT_TRANSFER_STATE_COMPLETE:
     114                 :           4 :       icon = g_themed_icon_new ("document-save-symbolic");
     115                 :           4 :       title = _("Transfer Complete");
     116                 :           4 :       body = g_strdup_printf (ngettext ("Received one file from %1$s",
     117                 :             :                                         "Received %2$d files from %1$s",
     118                 :             :                                         n_files),
     119                 :             :                               device_name, n_files);
     120                 :           4 :       break;
     121                 :             : 
     122                 :           0 :     case VALENT_TRANSFER_STATE_FAILED:
     123                 :           0 :       icon = g_themed_icon_new ("dialog-warning-symbolic");
     124                 :           0 :       title = _("Transfer Failed");
     125                 :           0 :       body = g_strdup_printf (ngettext ("Receiving one file from %1$s",
     126                 :             :                                         "Receiving %2$d files from %1$s",
     127                 :             :                                         n_files),
     128                 :             :                               device_name, n_files);
     129                 :           0 :       break;
     130                 :             :     }
     131                 :             : 
     132                 :          10 :   notification = g_notification_new (title);
     133                 :          10 :   g_notification_set_body (notification, body);
     134                 :          10 :   g_notification_set_icon (notification, icon);
     135                 :             : 
     136         [ +  + ]:          10 :   if (state == VALENT_TRANSFER_STATE_ACTIVE)
     137                 :             :     {
     138                 :           6 :       valent_notification_add_device_button (notification,
     139                 :             :                                              device,
     140                 :           6 :                                              _("Cancel"),
     141                 :             :                                              "share.cancel",
     142                 :             :                                              g_variant_new_string (id));
     143                 :             :     }
     144         [ +  - ]:           4 :   else if (state == VALENT_TRANSFER_STATE_COMPLETE)
     145                 :             :     {
     146                 :          14 :       g_autoptr (ValentTransfer) item = NULL;
     147         [ +  - ]:           4 :       g_autoptr (GFile) file = NULL;
     148         [ +  - ]:           4 :       g_autoptr (GFile) dir = NULL;
     149         [ +  - ]:           4 :       g_autofree char *dirname = NULL;
     150                 :             : 
     151                 :           4 :       item = g_list_model_get_item (G_LIST_MODEL (transfer), 0);
     152                 :           4 :       file = valent_device_transfer_ref_file (VALENT_DEVICE_TRANSFER (item));
     153                 :           4 :       dir = g_file_get_parent (file);
     154                 :           4 :       dirname = g_file_get_uri (dir);
     155                 :             : 
     156                 :           4 :       valent_notification_add_device_button (notification,
     157                 :             :                                              device,
     158                 :           4 :                                              _("Open Folder"),
     159                 :             :                                              "share.view",
     160                 :             :                                              g_variant_new_string (dirname));
     161                 :             : 
     162         [ +  - ]:           4 :       if (n_files == 1)
     163                 :             :         {
     164                 :           4 :           g_autofree char *uri = NULL;
     165                 :             : 
     166                 :           4 :           uri = g_file_get_uri (file);
     167                 :           8 :           valent_notification_add_device_button (notification,
     168                 :             :                                                  device,
     169                 :           4 :                                                  _("Open File"),
     170                 :             :                                                  "share.view",
     171                 :             :                                                  g_variant_new_string (uri));
     172                 :             :         }
     173                 :             :     }
     174                 :             : 
     175                 :          10 :   valent_device_plugin_show_notification (VALENT_DEVICE_PLUGIN (self),
     176                 :             :                                           id,
     177                 :             :                                           notification);
     178                 :             : }
     179                 :             : 
     180                 :             : static void
     181                 :           4 : valent_share_download_file_cb (ValentTransfer *transfer,
     182                 :             :                                GAsyncResult   *result,
     183                 :             :                                gpointer        user_data)
     184                 :             : {
     185                 :           8 :   g_autoptr (ValentSharePlugin) self = VALENT_SHARE_PLUGIN (user_data);
     186                 :           4 :   g_autofree char *id = NULL;
     187                 :           4 :   g_autoptr (GError) error = NULL;
     188                 :             : 
     189         [ +  - ]:           4 :   g_assert (VALENT_IS_TRANSFER (transfer));
     190                 :             : 
     191                 :           4 :   id = valent_transfer_dup_id (transfer);
     192                 :             : 
     193   [ -  +  -  - ]:           4 :   if (valent_transfer_execute_finish (transfer, result, &error) ||
     194                 :           0 :       !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     195                 :           4 :     valent_share_download_file_notification (self, transfer);
     196                 :             :   else
     197                 :           0 :     valent_device_plugin_hide_notification (VALENT_DEVICE_PLUGIN (self), id);
     198                 :             : 
     199         [ +  + ]:           4 :   if (self->download == transfer)
     200         [ +  - ]:           3 :     g_clear_object (&self->download);
     201                 :             : 
     202         [ -  + ]:           4 :   g_hash_table_remove (self->transfers, id);
     203                 :           4 : }
     204                 :             : 
     205                 :             : /*
     206                 :             :  * File Download (Open)
     207                 :             :  */
     208                 :             : static void
     209                 :           1 : valent_share_download_open_notification (ValentSharePlugin *self,
     210                 :             :                                          ValentTransfer    *transfer)
     211                 :             : {
     212                 :           1 :   g_autoptr (ValentDevice) device = NULL;
     213   [ +  -  -  - ]:           1 :   g_autoptr (GFile) file = NULL;
     214   [ +  -  -  - ]:           1 :   g_autoptr (GNotification) notification = NULL;
     215   [ +  -  -  - ]:           1 :   g_autoptr (GIcon) icon = NULL;
     216                 :           1 :   const char *title = NULL;
     217   [ +  -  -  - ]:           1 :   g_autofree char *body = NULL;
     218                 :           1 :   g_autofree char *id = NULL;
     219                 :           1 :   g_autofree char *filename = NULL;
     220                 :           1 :   const char *device_name;
     221                 :           1 :   ValentTransferState state = VALENT_TRANSFER_STATE_PENDING;
     222                 :             : 
     223         [ +  - ]:           1 :   g_return_if_fail (VALENT_IS_TRANSFER (transfer));
     224         [ -  + ]:           1 :   g_return_if_fail (VALENT_IS_DEVICE_TRANSFER (transfer));
     225                 :             : 
     226                 :           1 :   g_object_get (transfer,
     227                 :             :                 "device", &device,
     228                 :             :                 "file",   &file,
     229                 :             :                 "id",     &id,
     230                 :             :                 "state",  &state,
     231                 :             :                 NULL);
     232                 :           1 :   device_name = valent_device_get_name (device);
     233                 :           1 :   filename = g_file_get_basename (file);
     234                 :             : 
     235   [ +  -  -  - ]:           1 :   switch (state)
     236                 :             :     {
     237                 :           1 :     case VALENT_TRANSFER_STATE_PENDING:
     238                 :             :     case VALENT_TRANSFER_STATE_ACTIVE:
     239                 :           1 :       icon = g_themed_icon_new ("document-save-symbolic");
     240                 :           1 :       title = _("Transferring File");
     241                 :           1 :       body = g_strdup_printf (_("Opening “%s” from %s"), filename, device_name);
     242                 :           1 :       break;
     243                 :             : 
     244                 :           0 :     case VALENT_TRANSFER_STATE_COMPLETE:
     245                 :           0 :       valent_device_plugin_hide_notification (VALENT_DEVICE_PLUGIN (self), id);
     246                 :           0 :       return;
     247                 :             : 
     248                 :           0 :     case VALENT_TRANSFER_STATE_FAILED:
     249                 :           0 :       icon = g_themed_icon_new ("dialog-warning-symbolic");
     250                 :           0 :       title = _("Transfer Failed");
     251                 :           0 :       body = g_strdup_printf (_("Opening “%s” from %s"), filename, device_name);
     252                 :           0 :       break;
     253                 :             :     }
     254                 :             : 
     255                 :           1 :   notification = g_notification_new (title);
     256                 :           1 :   g_notification_set_body (notification, body);
     257                 :           1 :   g_notification_set_icon (notification, icon);
     258                 :             : 
     259         [ +  - ]:           1 :   if (state == VALENT_TRANSFER_STATE_ACTIVE)
     260                 :             :     {
     261                 :           1 :       valent_notification_add_device_button (notification,
     262                 :             :                                              device,
     263                 :           1 :                                              _("Cancel"),
     264                 :             :                                              "share.cancel",
     265                 :             :                                              g_variant_new_string (id));
     266                 :             :     }
     267                 :             : 
     268                 :           1 :   valent_device_plugin_show_notification (VALENT_DEVICE_PLUGIN (self),
     269                 :             :                                           id,
     270                 :             :                                           notification);
     271                 :             : }
     272                 :             : 
     273                 :             : static void
     274                 :           1 : valent_share_download_open_cb (ValentTransfer *transfer,
     275                 :             :                                GAsyncResult   *result,
     276                 :             :                                gpointer        user_data)
     277                 :             : {
     278                 :           2 :   g_autoptr (ValentSharePlugin) self = VALENT_SHARE_PLUGIN (user_data);
     279                 :           1 :   g_autofree char *id = NULL;
     280                 :           1 :   g_autoptr (GError) error = NULL;
     281                 :             : 
     282         [ +  - ]:           1 :   g_assert (VALENT_IS_TRANSFER (transfer));
     283                 :             : 
     284                 :           1 :   id = valent_transfer_dup_id (transfer);
     285                 :             : 
     286         [ +  - ]:           1 :   if (valent_transfer_execute_finish (transfer, result, &error))
     287                 :             :     {
     288                 :           2 :       g_autoptr (GFile) file = NULL;
     289         [ +  - ]:           1 :       g_autofree char *uri = NULL;
     290                 :             : 
     291                 :           1 :       file = valent_device_transfer_ref_file (VALENT_DEVICE_TRANSFER (transfer));
     292                 :           1 :       uri = g_file_get_uri (file);
     293                 :             : 
     294                 :           1 :       g_app_info_launch_default_for_uri_async (uri, NULL, NULL, NULL, NULL);
     295                 :           1 :       valent_device_plugin_hide_notification (VALENT_DEVICE_PLUGIN (self), id);
     296                 :             :     }
     297         [ #  # ]:           0 :   else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     298                 :             :     {
     299                 :           0 :       valent_share_download_open_notification (self, transfer);
     300                 :             :     }
     301                 :             : 
     302         [ -  + ]:           1 :   g_hash_table_remove (self->transfers, id);
     303                 :           1 : }
     304                 :             : 
     305                 :             : /*
     306                 :             :  * File Upload (Open)
     307                 :             :  */
     308                 :             : static void
     309                 :           2 : valent_share_upload_open_notification (ValentSharePlugin *self,
     310                 :             :                                        ValentTransfer    *transfer)
     311                 :             : {
     312                 :           2 :   g_autoptr (ValentDevice) device = NULL;
     313   [ +  -  -  - ]:           2 :   g_autoptr (GFile) file = NULL;
     314   [ +  -  -  - ]:           2 :   g_autoptr (GNotification) notification = NULL;
     315   [ +  -  -  - ]:           2 :   g_autoptr (GIcon) icon = NULL;
     316                 :           2 :   const char *title = NULL;
     317   [ +  -  -  - ]:           2 :   g_autofree char *body = NULL;
     318                 :           2 :   g_autofree char *id = NULL;
     319                 :           2 :   g_autofree char *filename = NULL;
     320                 :           2 :   const char *device_name;
     321                 :           2 :   ValentTransferState state = VALENT_TRANSFER_STATE_PENDING;
     322                 :             : 
     323         [ +  - ]:           2 :   g_return_if_fail (VALENT_IS_TRANSFER (transfer));
     324         [ -  + ]:           2 :   g_return_if_fail (VALENT_IS_DEVICE_TRANSFER (transfer));
     325                 :             : 
     326                 :           2 :   g_object_get (transfer,
     327                 :             :                 "device", &device,
     328                 :             :                 "file",   &file,
     329                 :             :                 "id",     &id,
     330                 :             :                 "state",  &state,
     331                 :             :                 NULL);
     332                 :           2 :   device_name = valent_device_get_name (device);
     333                 :           2 :   filename = g_file_get_basename (file);
     334                 :             : 
     335   [ +  +  -  - ]:           2 :   switch (state)
     336                 :             :     {
     337                 :           1 :     case VALENT_TRANSFER_STATE_PENDING:
     338                 :             :     case VALENT_TRANSFER_STATE_ACTIVE:
     339                 :           1 :       icon = g_themed_icon_new ("document-send-symbolic");
     340                 :           1 :       title = _("Transferring File");
     341                 :           1 :       body = g_strdup_printf (_("Opening “%s” on %s"), filename, device_name);
     342                 :           1 :       break;
     343                 :             : 
     344                 :           1 :     case VALENT_TRANSFER_STATE_COMPLETE:
     345                 :           1 :       icon = g_themed_icon_new ("document-send-symbolic");
     346                 :           1 :       title = _("Transfer Complete");
     347                 :           1 :       body = g_strdup_printf (_("Opened “%s” on %s"), filename, device_name);
     348                 :           1 :       break;
     349                 :             : 
     350                 :           0 :     case VALENT_TRANSFER_STATE_FAILED:
     351                 :           0 :       icon = g_themed_icon_new ("dialog-warning-symbolic");
     352                 :           0 :       title = _("Transfer Failed");
     353                 :           0 :       body = g_strdup_printf (_("Opening “%s” on %s"), filename, device_name);
     354                 :           0 :       break;
     355                 :             :     }
     356                 :             : 
     357                 :           2 :   notification = g_notification_new (title);
     358                 :           2 :   g_notification_set_body (notification, body);
     359                 :           2 :   g_notification_set_icon (notification, icon);
     360                 :             : 
     361         [ +  + ]:           2 :   if (state == VALENT_TRANSFER_STATE_ACTIVE)
     362                 :             :     {
     363                 :           1 :       valent_notification_add_device_button (notification,
     364                 :             :                                              device,
     365                 :           1 :                                              _("Cancel"),
     366                 :             :                                              "share.cancel",
     367                 :             :                                              g_variant_new_string (id));
     368                 :             :     }
     369                 :             : 
     370                 :           2 :   valent_device_plugin_show_notification (VALENT_DEVICE_PLUGIN (self),
     371                 :             :                                           id,
     372                 :             :                                           notification);
     373                 :             : }
     374                 :             : 
     375                 :             : static void
     376                 :           1 : valent_share_upload_open_cb (ValentTransfer *transfer,
     377                 :             :                              GAsyncResult   *result,
     378                 :             :                              gpointer        user_data)
     379                 :             : {
     380                 :           2 :   g_autoptr (ValentSharePlugin) self = VALENT_SHARE_PLUGIN (user_data);
     381                 :           1 :   g_autofree char *id = NULL;
     382                 :           1 :   g_autoptr (GError) error = NULL;
     383                 :             : 
     384         [ +  - ]:           1 :   g_assert (VALENT_IS_DEVICE_TRANSFER (transfer));
     385         [ -  + ]:           1 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     386                 :             : 
     387                 :           1 :   id = valent_transfer_dup_id (transfer);
     388                 :             : 
     389   [ -  +  -  - ]:           1 :   if (valent_transfer_execute_finish (transfer, result, &error) ||
     390                 :           0 :       !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     391                 :           1 :     valent_share_upload_open_notification (self, transfer);
     392                 :             :   else
     393                 :           0 :     valent_device_plugin_hide_notification (VALENT_DEVICE_PLUGIN (self), id);
     394                 :             : 
     395         [ -  + ]:           1 :   g_hash_table_remove (self->transfers, id);
     396                 :           1 : }
     397                 :             : 
     398                 :             : static void
     399                 :           1 : valent_share_plugin_open_file (ValentSharePlugin *self,
     400                 :             :                                GFile             *file)
     401                 :             : {
     402                 :           1 :   ValentDevice *device = NULL;
     403                 :           2 :   g_autoptr (ValentTransfer) transfer = NULL;
     404         [ +  - ]:           1 :   g_autofree char *filename = NULL;
     405                 :           1 :   g_autoptr (JsonBuilder) builder = NULL;
     406         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     407                 :             : 
     408                 :           1 :   filename = g_file_get_basename (file);
     409                 :             : 
     410                 :           1 :   valent_packet_init (&builder, "kdeconnect.share.request");
     411                 :           1 :   json_builder_set_member_name (builder, "filename");
     412                 :           1 :   json_builder_add_string_value (builder, filename);
     413                 :           1 :   json_builder_set_member_name (builder, "open");
     414                 :           1 :   json_builder_add_boolean_value (builder, TRUE);
     415                 :           1 :   packet = valent_packet_end (&builder);
     416                 :             : 
     417                 :             :   /* File uploads that request to be opened are sent as discrete transfers
     418                 :             :    * because the remote client (i.e. kdeconnect-android) may download them
     419                 :             :    * discretely. Otherwise the remote client may get confused by the
     420                 :             :    * `numberOfFiles` field and consider a concurrent multi-file transfer as
     421                 :             :    * incomplete.
     422                 :             :    */
     423                 :           1 :   device = valent_extension_get_object (VALENT_EXTENSION (self));
     424                 :           1 :   transfer = valent_device_transfer_new (device, packet, file);
     425                 :           2 :   g_hash_table_insert (self->transfers,
     426                 :           1 :                        valent_transfer_dup_id (transfer),
     427                 :             :                        g_object_ref (transfer));
     428                 :             : 
     429                 :           1 :   valent_transfer_execute (transfer,
     430                 :             :                            NULL,
     431                 :             :                            (GAsyncReadyCallback)valent_share_upload_open_cb,
     432                 :             :                            g_object_ref (self));
     433         [ +  - ]:           1 :   valent_share_upload_open_notification (self, transfer);
     434                 :           1 : }
     435                 :             : 
     436                 :             : /*
     437                 :             :  * File Uploads
     438                 :             :  */
     439                 :             : static void
     440                 :           7 : valent_share_upload_file_notification (ValentSharePlugin *self,
     441                 :             :                                        ValentTransfer    *transfer)
     442                 :             : {
     443                 :           7 :   g_autoptr (ValentDevice) device = NULL;
     444   [ +  -  -  - ]:           7 :   g_autoptr (GNotification) notification = NULL;
     445   [ +  -  -  - ]:           7 :   g_autoptr (GIcon) icon = NULL;
     446                 :           7 :   const char *title = NULL;
     447   [ +  -  -  - ]:           7 :   g_autofree char *body = NULL;
     448                 :           7 :   g_autofree char *id = NULL;
     449                 :           7 :   unsigned int n_files = 0;
     450                 :           7 :   const char *device_name;
     451                 :           7 :   ValentTransferState state = VALENT_TRANSFER_STATE_PENDING;
     452                 :             : 
     453         [ +  - ]:           7 :   g_return_if_fail (VALENT_IS_TRANSFER (transfer));
     454         [ -  + ]:           7 :   g_return_if_fail (VALENT_IS_SHARE_UPLOAD (transfer));
     455                 :             : 
     456         [ +  - ]:           7 :   if ((n_files = g_list_model_get_n_items (G_LIST_MODEL (transfer))) == 0)
     457                 :             :     return;
     458                 :             : 
     459                 :           7 :   g_object_get (transfer,
     460                 :             :                 "device", &device,
     461                 :             :                 "id",     &id,
     462                 :             :                 "state",  &state,
     463                 :             :                 NULL);
     464                 :           7 :   device_name = valent_device_get_name (device);
     465                 :             : 
     466   [ +  +  -  - ]:           7 :   switch (state)
     467                 :             :     {
     468                 :           5 :     case VALENT_TRANSFER_STATE_PENDING:
     469                 :             :     case VALENT_TRANSFER_STATE_ACTIVE:
     470                 :           5 :       icon = g_themed_icon_new ("document-send-symbolic");
     471                 :           5 :       title = _("Transferring Files");
     472                 :           5 :       body = g_strdup_printf (ngettext ("Sending one file to %1$s",
     473                 :             :                                         "Sending %2$d files to %1$s",
     474                 :             :                                         n_files),
     475                 :             :                               device_name, n_files);
     476                 :           5 :       break;
     477                 :             : 
     478                 :           2 :     case VALENT_TRANSFER_STATE_COMPLETE:
     479                 :           2 :       icon = g_themed_icon_new ("document-send-symbolic");
     480                 :           2 :       title = _("Transfer Complete");
     481                 :           2 :       body = g_strdup_printf (ngettext ("Sent one file to %1$s",
     482                 :             :                                         "Sent %2$d files to %1$s",
     483                 :             :                                         n_files),
     484                 :             :                               device_name, n_files);
     485                 :           2 :       break;
     486                 :             : 
     487                 :           0 :     case VALENT_TRANSFER_STATE_FAILED:
     488                 :           0 :       icon = g_themed_icon_new ("dialog-warning-symbolic");
     489                 :           0 :       title = _("Transfer Failed");
     490                 :           0 :       body = g_strdup_printf (ngettext ("Sending one file to %1$s",
     491                 :             :                                         "Sending %2$d files to %1$s",
     492                 :             :                                         n_files),
     493                 :             :                               device_name, n_files);
     494                 :           0 :       break;
     495                 :             :     }
     496                 :             : 
     497                 :           7 :   notification = g_notification_new (title);
     498                 :           7 :   g_notification_set_body (notification, body);
     499                 :           7 :   g_notification_set_icon (notification, icon);
     500                 :             : 
     501         [ +  + ]:           7 :   if (state == VALENT_TRANSFER_STATE_ACTIVE)
     502                 :             :     {
     503                 :           5 :       valent_notification_add_device_button (notification,
     504                 :             :                                              device,
     505                 :           5 :                                              _("Cancel"),
     506                 :             :                                              "share.cancel",
     507                 :             :                                              g_variant_new_string (id));
     508                 :             :     }
     509                 :             : 
     510                 :           7 :   valent_device_plugin_show_notification (VALENT_DEVICE_PLUGIN (self),
     511                 :             :                                           id,
     512                 :             :                                           notification);
     513                 :             : }
     514                 :             : 
     515                 :             : static void
     516                 :           2 : valent_share_upload_file_cb (ValentTransfer *transfer,
     517                 :             :                              GAsyncResult   *result,
     518                 :             :                              gpointer        user_data)
     519                 :             : {
     520                 :           4 :   g_autoptr (ValentSharePlugin) self = VALENT_SHARE_PLUGIN (user_data);
     521                 :           2 :   g_autofree char *id = NULL;
     522                 :           2 :   g_autoptr (GError) error = NULL;
     523                 :             : 
     524         [ +  - ]:           2 :   g_assert (VALENT_IS_SHARE_UPLOAD (transfer));
     525         [ -  + ]:           2 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     526                 :             : 
     527                 :           2 :   id = valent_transfer_dup_id (transfer);
     528                 :             : 
     529   [ -  +  -  - ]:           2 :   if (valent_transfer_execute_finish (transfer, result, &error) ||
     530                 :           0 :       !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     531                 :           2 :     valent_share_upload_file_notification (self, transfer);
     532                 :             :   else
     533                 :           0 :     valent_device_plugin_hide_notification (VALENT_DEVICE_PLUGIN (self), id);
     534                 :             : 
     535         [ +  - ]:           2 :   if (self->upload == transfer)
     536         [ +  - ]:           2 :     g_clear_object (&self->upload);
     537                 :             : 
     538         [ -  + ]:           2 :   g_hash_table_remove (self->transfers, id);
     539                 :           2 : }
     540                 :             : 
     541                 :             : static void
     542                 :           5 : valent_share_upload_files_added (ValentTransfer    *transfer,
     543                 :             :                                  unsigned int       position,
     544                 :             :                                  unsigned int       removed,
     545                 :             :                                  unsigned int       added,
     546                 :             :                                  ValentSharePlugin *self)
     547                 :             : {
     548         [ +  - ]:           5 :   g_assert (VALENT_IS_SHARE_UPLOAD (transfer));
     549         [ -  + ]:           5 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     550                 :             : 
     551                 :             :   /* If no files were added, something went wrong */
     552         [ -  + ]:           5 :   g_return_if_fail (added > 0);
     553                 :             : 
     554                 :             :   /* Start the transfer, if necessary */
     555         [ +  + ]:           5 :   if (valent_transfer_get_state (transfer) == VALENT_TRANSFER_STATE_PENDING)
     556                 :             :     {
     557                 :           2 :       valent_transfer_execute (transfer,
     558                 :             :                                NULL,
     559                 :             :                                (GAsyncReadyCallback)valent_share_upload_file_cb,
     560                 :             :                                g_object_ref (self));
     561                 :             :     }
     562                 :             : 
     563                 :           5 :   valent_share_upload_file_notification (self, transfer);
     564                 :             : }
     565                 :             : 
     566                 :             : static void
     567                 :           5 : valent_share_plugin_upload_file (ValentSharePlugin *self,
     568                 :             :                                  GFile             *file)
     569                 :             : {
     570         [ +  - ]:           5 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     571   [ +  -  +  -  :           5 :   g_assert (G_IS_FILE (file));
             +  -  -  + ]
     572                 :             : 
     573                 :             :   /* Create a new transfer, if necessary */
     574         [ +  + ]:           5 :   if (self->upload == NULL)
     575                 :             :     {
     576                 :           2 :       ValentDevice *device;
     577                 :             : 
     578                 :           2 :       device = valent_extension_get_object (VALENT_EXTENSION (self));
     579                 :             : 
     580                 :           2 :       self->upload = valent_share_upload_new (device);
     581                 :           2 :       g_signal_connect_object (self->upload,
     582                 :             :                                "items-changed",
     583                 :             :                                G_CALLBACK (valent_share_upload_files_added),
     584                 :             :                                self, 0);
     585                 :           2 :       g_hash_table_replace (self->transfers,
     586                 :           2 :                             valent_transfer_dup_id (self->upload),
     587                 :           2 :                             g_object_ref (self->upload));
     588                 :             :     }
     589                 :             : 
     590                 :           5 :   valent_share_upload_add_file (VALENT_SHARE_UPLOAD (self->upload), file);
     591                 :           5 : }
     592                 :             : 
     593                 :             : static void
     594                 :           0 : valent_share_plugin_upload_files (ValentSharePlugin *self,
     595                 :             :                                   GListModel        *files)
     596                 :             : {
     597         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     598         [ #  # ]:           0 :   g_assert (G_IS_LIST_MODEL (files));
     599         [ #  # ]:           0 :   g_assert (g_list_model_get_item_type (files) == G_TYPE_FILE);
     600                 :             : 
     601                 :             :   /* Create a new transfer, if necessary */
     602         [ #  # ]:           0 :   if (self->upload == NULL)
     603                 :             :     {
     604                 :           0 :       ValentDevice *device;
     605                 :             : 
     606                 :           0 :       device = valent_extension_get_object (VALENT_EXTENSION (self));
     607                 :             : 
     608                 :           0 :       self->upload = valent_share_upload_new (device);
     609                 :           0 :       g_signal_connect_object (self->upload,
     610                 :             :                                "items-changed",
     611                 :             :                                G_CALLBACK (valent_share_upload_files_added),
     612                 :             :                                self, 0);
     613                 :           0 :       g_hash_table_replace (self->transfers,
     614                 :           0 :                             valent_transfer_dup_id (self->upload),
     615                 :           0 :                             g_object_ref (self->upload));
     616                 :             :     }
     617                 :             : 
     618                 :           0 :   valent_share_upload_add_files (VALENT_SHARE_UPLOAD (self->upload), files);
     619                 :           0 : }
     620                 :             : 
     621                 :             : /*
     622                 :             :  * GActions
     623                 :             :  */
     624                 :             : static void
     625                 :           0 : gtk_file_dialog_open_multiple_cb (GtkFileDialog     *dialog,
     626                 :             :                                   GAsyncResult      *result,
     627                 :             :                                   ValentSharePlugin *self)
     628                 :             : {
     629                 :           0 :   g_autoptr (GListModel) files = NULL;
     630                 :           0 :   g_autoptr (GError) error = NULL;
     631                 :             : 
     632                 :           0 :   files = gtk_file_dialog_open_multiple_finish (dialog, result, &error);
     633                 :             : 
     634         [ #  # ]:           0 :   if (files == NULL)
     635                 :             :     {
     636   [ #  #  #  # ]:           0 :       if (!g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED) &&
     637                 :           0 :           !g_error_matches (error, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED))
     638                 :           0 :         g_warning ("%s(): %s", G_STRFUNC, error->message);
     639                 :             : 
     640         [ #  # ]:           0 :       return;
     641                 :             :     }
     642                 :             : 
     643         [ #  # ]:           0 :   valent_share_plugin_upload_files (self, files);
     644                 :             : }
     645                 :             : 
     646                 :             : /**
     647                 :             :  * ValentSharePlugin|share.chooser:
     648                 :             :  * @parameter: %NULL
     649                 :             :  *
     650                 :             :  * The default share action opens the platform-specific dialog for selecting
     651                 :             :  * files, typically a `GtkFileChooserDialog`.
     652                 :             :  */
     653                 :             : static void
     654                 :           0 : share_chooser_action (GSimpleAction *action,
     655                 :             :                       GVariant      *parameter,
     656                 :             :                       gpointer       user_data)
     657                 :             : {
     658                 :           0 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (user_data);
     659                 :           0 :   g_autoptr (GCancellable) destroy = NULL;
     660                 :           0 :   GtkFileDialog *dialog;
     661                 :             : 
     662         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     663                 :             : 
     664         [ #  # ]:           0 :   if (!gtk_is_initialized ())
     665                 :             :     {
     666                 :           0 :       g_warning ("%s: No display available", G_OBJECT_TYPE_NAME (self));
     667                 :           0 :       return;
     668                 :             :     }
     669                 :             : 
     670                 :           0 :   dialog = g_object_new (GTK_TYPE_FILE_DIALOG,
     671                 :             :                          "title",           _("Share Files"),
     672                 :             :                          "accept-label",    _("Share"),
     673                 :             :                          NULL);
     674                 :             : 
     675                 :           0 :   destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
     676         [ #  # ]:           0 :   gtk_file_dialog_open_multiple (dialog,
     677                 :             :                                  NULL,
     678                 :             :                                  destroy,
     679                 :             :                                  (GAsyncReadyCallback)gtk_file_dialog_open_multiple_cb,
     680                 :             :                                  self);
     681                 :             : }
     682                 :             : 
     683                 :             : /**
     684                 :             :  * ValentSharePlugin|share.cancel:
     685                 :             :  * @parameter: "s"
     686                 :             :  * @id: The transfer ID
     687                 :             :  *
     688                 :             :  * Each transfer is given a UUID for the purposes of cancelling it. Usually this
     689                 :             :  * action will only be activated from the transfer notification as sent by
     690                 :             :  * upload_operation() or the incoming file handler.
     691                 :             :  */
     692                 :             : static void
     693                 :           0 : share_cancel_action (GSimpleAction *action,
     694                 :             :                      GVariant      *parameter,
     695                 :             :                      gpointer       user_data)
     696                 :             : {
     697                 :           0 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (user_data);
     698                 :           0 :   ValentTransfer *transfer;
     699                 :           0 :   const char *id;
     700                 :             : 
     701         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     702                 :             : 
     703                 :           0 :   id = g_variant_get_string (parameter, NULL);
     704                 :           0 :   transfer = g_hash_table_lookup (self->transfers, id);
     705                 :             : 
     706         [ #  # ]:           0 :   if (transfer != NULL)
     707                 :           0 :     valent_transfer_cancel (transfer);
     708                 :           0 : }
     709                 :             : 
     710                 :             : /**
     711                 :             :  * ValentSharePlugin|share.open:
     712                 :             :  * @parameter: "s"
     713                 :             :  * @uri: File URI to open
     714                 :             :  *
     715                 :             :  * This action is used to open a URI.
     716                 :             :  *
     717                 :             :  * By convention, the remote device will open the URI with the default handler
     718                 :             :  * for that type.
     719                 :             :  *
     720                 :             :  * If the URI scheme is `file://`, it will be converted to a file upload,
     721                 :             :  * requesting it be opened after transfer.
     722                 :             :  */
     723                 :             : static void
     724                 :           2 : share_open_action (GSimpleAction *action,
     725                 :             :                    GVariant      *parameter,
     726                 :             :                    gpointer       user_data)
     727                 :             : {
     728                 :           2 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (user_data);
     729                 :           2 :   const char *uri_string = NULL;
     730                 :           2 :   g_autoptr (GUri) uri = NULL;
     731                 :           2 :   g_autoptr (GError) error = NULL;
     732                 :             : 
     733         [ +  - ]:           2 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     734         [ -  + ]:           2 :   g_assert (g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
     735                 :             : 
     736                 :           2 :   uri_string = g_variant_get_string (parameter, NULL);
     737                 :             : 
     738         [ -  + ]:           2 :   if ((uri = g_uri_parse (uri_string, G_URI_FLAGS_NONE, &error)) == NULL)
     739                 :             :     {
     740                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, error->message);
     741         [ #  # ]:           0 :       return;
     742                 :             :     }
     743                 :             : 
     744         [ +  - ]:           2 :   if (g_str_equal ("file", g_uri_get_scheme (uri)) ||
     745         [ +  + ]:           2 :       g_str_equal ("resource", g_uri_get_scheme (uri)))
     746                 :             :     {
     747         [ -  + ]:           2 :       g_autoptr (GFile) file = NULL;
     748                 :             : 
     749                 :           1 :       file = g_file_new_for_uri (uri_string);
     750         [ +  - ]:           1 :       valent_share_plugin_open_file (self, file);
     751                 :             :     }
     752                 :             :   else
     753                 :             :     {
     754                 :           1 :       g_autoptr (JsonBuilder) builder = NULL;
     755         [ -  + ]:           1 :       g_autoptr (JsonNode) packet = NULL;
     756                 :             : 
     757                 :           1 :       valent_packet_init (&builder, "kdeconnect.share.request");
     758                 :           1 :       json_builder_set_member_name (builder, "url");
     759                 :           1 :       json_builder_add_string_value (builder, uri_string);
     760                 :           1 :       packet = valent_packet_end (&builder);
     761                 :             : 
     762         [ +  - ]:           1 :       valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), packet);
     763                 :             :     }
     764                 :             : }
     765                 :             : 
     766                 :             : /**
     767                 :             :  * ValentSharePlugin|share.text:
     768                 :             :  * @parameter: "s"
     769                 :             :  * @text: text to share
     770                 :             :  *
     771                 :             :  * This action simply sends a chunk of text to the remote device. Ultimately,
     772                 :             :  * how the remote device handles the text is undefined. It may be copied to the
     773                 :             :  * clipboard, stored as a temporary file or just displayed.
     774                 :             :  */
     775                 :             : static void
     776                 :           1 : share_text_action (GSimpleAction *action,
     777                 :             :                    GVariant      *parameter,
     778                 :             :                    gpointer       user_data)
     779                 :             : {
     780                 :           1 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (user_data);
     781                 :           1 :   const char *text;
     782                 :           2 :   g_autoptr (JsonBuilder) builder = NULL;
     783         [ -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     784                 :             : 
     785         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     786         [ -  + ]:           1 :   g_assert (g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
     787                 :             : 
     788                 :           1 :   text = g_variant_get_string (parameter, NULL);
     789                 :             : 
     790                 :           1 :   valent_packet_init (&builder, "kdeconnect.share.request");
     791                 :           1 :   json_builder_set_member_name (builder, "text");
     792                 :           1 :   json_builder_add_string_value (builder, text);
     793                 :           1 :   packet = valent_packet_end (&builder);
     794                 :             : 
     795         [ +  - ]:           1 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), packet);
     796                 :           1 : }
     797                 :             : 
     798                 :             : /**
     799                 :             :  * ValentSharePlugin|share.uri:
     800                 :             :  * @parameter: "s"
     801                 :             :  * @uri: URI to share
     802                 :             :  *
     803                 :             :  * This action is used to share a URI.
     804                 :             :  *
     805                 :             :  * By convention, the remote device will open the URI with the default handler
     806                 :             :  * for that type.
     807                 :             :  *
     808                 :             :  * If the URI scheme is `file://`, it will be converted to a file upload.
     809                 :             :  */
     810                 :             : static void
     811                 :           9 : share_uri_action (GSimpleAction *action,
     812                 :             :                   GVariant      *parameter,
     813                 :             :                   gpointer       user_data)
     814                 :             : {
     815                 :           9 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (user_data);
     816                 :           9 :   const char *uri_string = NULL;
     817                 :           9 :   g_autoptr (GUri) uri = NULL;
     818                 :           9 :   g_autoptr (GError) error = NULL;
     819                 :             : 
     820         [ +  - ]:           9 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     821         [ -  + ]:           9 :   g_assert (g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
     822                 :             : 
     823                 :           9 :   uri_string = g_variant_get_string (parameter, NULL);
     824                 :             : 
     825         [ -  + ]:           9 :   if ((uri = g_uri_parse (uri_string, G_URI_FLAGS_NONE, &error)) == NULL)
     826                 :             :     {
     827                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, error->message);
     828         [ #  # ]:           0 :       return;
     829                 :             :     }
     830                 :             : 
     831         [ +  - ]:           9 :   if (g_str_equal ("file", g_uri_get_scheme (uri)) ||
     832         [ +  + ]:           9 :       g_str_equal ("resource", g_uri_get_scheme (uri)))
     833                 :             :     {
     834         [ -  + ]:           9 :       g_autoptr (GFile) file = NULL;
     835                 :             : 
     836                 :           5 :       file = g_file_new_for_uri (uri_string);
     837         [ +  - ]:           5 :       valent_share_plugin_upload_file (self, file);
     838                 :             :     }
     839                 :             :   else
     840                 :             :     {
     841                 :           4 :       g_autoptr (JsonBuilder) builder = NULL;
     842         [ -  + ]:           4 :       g_autoptr (JsonNode) packet = NULL;
     843                 :             : 
     844                 :           4 :       valent_packet_init (&builder, "kdeconnect.share.request");
     845                 :           4 :       json_builder_set_member_name (builder, "url");
     846                 :           4 :       json_builder_add_string_value (builder, uri_string);
     847                 :           4 :       packet = valent_packet_end (&builder);
     848                 :             : 
     849         [ +  - ]:           4 :       valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), packet);
     850                 :             :     }
     851                 :             : }
     852                 :             : 
     853                 :             : /**
     854                 :             :  * ValentSharePlugin|share.uris:
     855                 :             :  * @parameter: "as"
     856                 :             :  * @uris: a list of URIs
     857                 :             :  *
     858                 :             :  * This action is a convenience for sending multiple URIs, as with the
     859                 :             :  * `ValentSharePlugin|share.uri` `GAction`.
     860                 :             :  */
     861                 :             : static void
     862                 :           1 : share_uris_action (GSimpleAction *action,
     863                 :             :                    GVariant      *parameter,
     864                 :             :                    gpointer       user_data)
     865                 :             : {
     866                 :           1 :   GVariantIter iter;
     867                 :           1 :   GVariant *child;
     868                 :             : 
     869         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_PLUGIN (user_data));
     870         [ -  + ]:           1 :   g_assert (g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING_ARRAY));
     871                 :             : 
     872                 :           1 :   g_variant_iter_init (&iter, parameter);
     873                 :             : 
     874         [ +  + ]:           9 :   while ((child = g_variant_iter_next_value (&iter)) != NULL)
     875                 :             :     {
     876                 :           7 :       share_uri_action (action, child, user_data);
     877                 :           8 :       g_clear_pointer (&child, g_variant_unref);
     878                 :             :     }
     879                 :           1 : }
     880                 :             : 
     881                 :             : /**
     882                 :             :  * ValentSharePlugin|share.view:
     883                 :             :  * @parameter: "s"
     884                 :             :  * @uri: File or directory URI to view
     885                 :             :  *
     886                 :             :  * This action opens a file or directory.
     887                 :             :  */
     888                 :             : static void
     889                 :           0 : share_view_action (GSimpleAction *action,
     890                 :             :                    GVariant      *parameter,
     891                 :             :                    gpointer       user_data)
     892                 :             : {
     893                 :           0 :   const char *uri;
     894                 :             : 
     895         [ #  # ]:           0 :   g_assert (VALENT_IS_SHARE_PLUGIN (user_data));
     896         [ #  # ]:           0 :   g_assert (g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
     897                 :             : 
     898                 :           0 :   uri = g_variant_get_string (parameter, NULL);
     899                 :           0 :   g_app_info_launch_default_for_uri_async (uri, NULL, NULL, NULL, NULL);
     900                 :           0 : }
     901                 :             : 
     902                 :             : static GActionEntry actions[] = {
     903                 :             :     {"chooser", share_chooser_action, NULL, NULL, NULL},
     904                 :             :     {"cancel",  share_cancel_action,  "s",  NULL, NULL},
     905                 :             :     {"open",    share_open_action,    "s",  NULL, NULL},
     906                 :             :     {"text",    share_text_action,    "s",  NULL, NULL},
     907                 :             :     {"uri",     share_uri_action,     "s",  NULL, NULL},
     908                 :             :     {"uris",    share_uris_action,    "as", NULL, NULL},
     909                 :             :     {"view",    share_view_action,    "s",  NULL, NULL}
     910                 :             : };
     911                 :             : 
     912                 :             : /*
     913                 :             :  * Packet Handlers
     914                 :             :  */
     915                 :             : static void
     916                 :           7 : valent_share_plugin_handle_file (ValentSharePlugin *self,
     917                 :             :                                  JsonNode          *packet)
     918                 :             : {
     919                 :           7 :   g_autoptr (ValentTransfer) transfer = NULL;
     920                 :           7 :   ValentDevice *device;
     921                 :           7 :   const char *filename;
     922   [ +  -  +  - ]:           7 :   g_autoptr (GFile) file = NULL;
     923                 :           7 :   int64_t number_of_files = 0;
     924                 :             : 
     925         [ +  - ]:           7 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
     926         [ -  + ]:           7 :   g_assert (VALENT_IS_PACKET (packet));
     927                 :             : 
     928                 :             :   /* Common packet fields */
     929         [ -  + ]:           7 :   if (!valent_packet_has_payload (packet))
     930                 :             :     {
     931                 :           0 :       g_warning ("%s(): missing payload info", G_STRFUNC);
     932                 :           0 :       return;
     933                 :             :     }
     934                 :             : 
     935         [ -  + ]:           7 :   if (!valent_packet_get_string (packet, "filename", &filename))
     936                 :             :     {
     937                 :           0 :       g_debug ("%s(): expected \"filename\" field holding a string",
     938                 :             :                G_STRFUNC);
     939                 :           0 :       return;
     940                 :             :     }
     941                 :             : 
     942                 :             :   /* Newer implementations support sequential multi-file transfers */
     943         [ +  + ]:           7 :   if (!valent_packet_get_int (packet, "numberOfFiles", &number_of_files))
     944                 :             :     {
     945                 :           2 :       json_object_set_int_member (valent_packet_get_body (packet),
     946                 :             :                                   "numberOfFiles",
     947                 :             :                                   1);
     948                 :             :     }
     949                 :             : 
     950         [ +  + ]:           7 :   if (!valent_packet_get_int (packet, "totalPayloadSize", NULL))
     951                 :             :     {
     952                 :           2 :       json_object_set_int_member (valent_packet_get_body (packet),
     953                 :             :                                   "totalPayloadSize",
     954                 :             :                                   valent_packet_get_payload_size (packet));
     955                 :             :     }
     956                 :             : 
     957                 :           7 :   device = valent_extension_get_object (VALENT_EXTENSION (self));
     958                 :           7 :   file = valent_share_plugin_create_download_file (self, filename, TRUE);
     959                 :             : 
     960                 :             :   /* If the packet includes a request to open the file when the transfer
     961                 :             :    * completes, use a separate routine for success/failure. */
     962         [ +  + ]:           7 :   if (valent_packet_check_field (packet, "open"))
     963                 :             :     {
     964                 :           1 :       transfer = valent_device_transfer_new (device, packet, file);
     965                 :           2 :       g_hash_table_replace (self->transfers,
     966                 :           1 :                             valent_transfer_dup_id (transfer),
     967                 :             :                             g_object_ref (transfer));
     968                 :             : 
     969                 :           1 :       valent_transfer_execute (transfer,
     970                 :             :                                NULL,
     971                 :             :                                (GAsyncReadyCallback)valent_share_download_open_cb,
     972                 :             :                                g_object_ref (self));
     973                 :           1 :       valent_share_download_open_notification (self, transfer);
     974                 :           1 :       return;
     975                 :             :     }
     976                 :             : 
     977                 :             :   /* If the packet is missing the `numberOfFiles` field it is a legacy transfer
     978                 :             :    * transfer; use a discrete transfer with standard success/failure handling. */
     979         [ +  + ]:           6 :   if (!number_of_files)
     980                 :             :     {
     981                 :           1 :       transfer = valent_share_download_new (device);
     982                 :           2 :       g_hash_table_replace (self->transfers,
     983                 :           1 :                             valent_transfer_dup_id (transfer),
     984                 :             :                             g_object_ref (transfer));
     985                 :             : 
     986                 :           1 :       valent_share_download_add_file (VALENT_SHARE_DOWNLOAD (transfer),
     987                 :             :                                       file,
     988                 :             :                                       packet);
     989                 :             : 
     990                 :           1 :       valent_transfer_execute (transfer,
     991                 :             :                                NULL,
     992                 :             :                                (GAsyncReadyCallback)valent_share_download_file_cb,
     993                 :             :                                g_object_ref (self));
     994                 :           1 :       valent_share_download_file_notification (self, transfer);
     995                 :           1 :       return;
     996                 :             :     }
     997                 :             : 
     998                 :             :   /* Otherwise the file will appended to a multi-file transfer */
     999         [ +  + ]:           5 :   if (self->download != NULL)
    1000                 :             :     {
    1001                 :           1 :       transfer = g_object_ref (self->download);
    1002                 :             :     }
    1003                 :             :   else
    1004                 :             :     {
    1005                 :           4 :       transfer = valent_share_download_new (device);
    1006                 :           8 :       g_hash_table_replace (self->transfers,
    1007                 :           4 :                             valent_transfer_dup_id (transfer),
    1008                 :             :                             g_object_ref (transfer));
    1009                 :             :     }
    1010                 :             : 
    1011                 :           5 :   valent_share_download_add_file (VALENT_SHARE_DOWNLOAD (transfer),
    1012                 :             :                                   file,
    1013                 :             :                                   packet);
    1014                 :             : 
    1015         [ +  + ]:           5 :   if (self->download != transfer)
    1016                 :           4 :     g_set_object (&self->download, transfer);
    1017                 :             : 
    1018         [ +  + ]:           5 :   if (valent_transfer_get_state (transfer) == VALENT_TRANSFER_STATE_PENDING)
    1019                 :             :     {
    1020                 :           4 :       valent_transfer_execute (transfer,
    1021                 :             :                                NULL,
    1022                 :             :                                (GAsyncReadyCallback)valent_share_download_file_cb,
    1023                 :             :                                g_object_ref (self));
    1024                 :             :     }
    1025                 :             : 
    1026         [ +  - ]:           5 :   valent_share_download_file_notification (self, transfer);
    1027                 :             : }
    1028                 :             : 
    1029                 :             : static void
    1030                 :           1 : valent_share_plugin_handle_file_update (ValentSharePlugin *self,
    1031                 :             :                                         JsonNode          *packet)
    1032                 :             : {
    1033         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
    1034         [ -  + ]:           1 :   g_assert (VALENT_IS_PACKET (packet));
    1035                 :             : 
    1036         [ -  + ]:           1 :   if (self->download == NULL)
    1037                 :             :     return;
    1038                 :             : 
    1039         [ #  # ]:           0 :   if (!valent_packet_check_field (packet, "numberOfFiles"))
    1040                 :             :     {
    1041                 :           0 :       g_debug ("%s(): expected \"numberOfFiles\" field holding an integer",
    1042                 :             :                G_STRFUNC);
    1043                 :           0 :       return;
    1044                 :             :     }
    1045                 :             : 
    1046         [ #  # ]:           0 :   if (!valent_packet_check_field (packet, "totalPayloadSize"))
    1047                 :             :     {
    1048                 :           0 :       g_debug ("%s(): expected \"totalPayloadSize\" field holding an integer",
    1049                 :             :                G_STRFUNC);
    1050                 :           0 :       return;
    1051                 :             :     }
    1052                 :             : 
    1053                 :           0 :   valent_share_download_update (VALENT_SHARE_DOWNLOAD (self->download), packet);
    1054                 :           0 :   valent_share_download_file_notification (self, self->download);
    1055                 :             : }
    1056                 :             : 
    1057                 :             : static void
    1058                 :           0 : valent_share_plugin_handle_text_cb (GFile        *file,
    1059                 :             :                                     GAsyncResult *result,
    1060                 :             :                                     gpointer      user_data)
    1061                 :             : {
    1062                 :           0 :   g_autoptr (GError) error = NULL;
    1063                 :             : 
    1064         [ #  # ]:           0 :   if (!g_file_replace_contents_finish (file, result, NULL, &error))
    1065                 :           0 :     g_warning ("Saving \"%s\": %s", g_file_peek_path (file), error->message);
    1066                 :           0 : }
    1067                 :             : 
    1068                 :             : static void
    1069                 :           1 : valent_share_plugin_handle_text (ValentSharePlugin *self,
    1070                 :             :                                  const char        *text)
    1071                 :             : {
    1072                 :           1 :   ValentExtension *extension = VALENT_EXTENSION (self);
    1073                 :           1 :   const char *name = NULL;
    1074                 :           1 :   GtkWindow *window;
    1075                 :             : 
    1076         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
    1077         [ -  + ]:           1 :   g_assert (text != NULL);
    1078                 :             : 
    1079                 :           1 :   name = valent_device_get_name (valent_extension_get_object (extension));
    1080                 :             : 
    1081         [ -  + ]:           1 :   if (!gtk_is_initialized ())
    1082                 :             :     {
    1083                 :           1 :       g_autoptr (GBytes) bytes = NULL;
    1084         [ #  # ]:           0 :       g_autoptr (GDateTime) date = NULL;
    1085         [ #  # ]:           0 :       g_autofree char *date_str = NULL;
    1086                 :           0 :       g_autoptr (GFile) file = NULL;
    1087         [ #  # ]:           0 :       g_autofree char *filename = NULL;
    1088                 :             : 
    1089                 :           0 :       bytes = g_bytes_new (text, strlen (text));
    1090                 :           0 :       date = g_date_time_new_now_local ();
    1091                 :           0 :       date_str = g_date_time_format (date, "%F %T");
    1092                 :           0 :       filename = g_strdup_printf ("Text from %s (%s).txt", date_str, name);
    1093                 :           0 :       file = valent_share_plugin_create_download_file (self, filename, TRUE);
    1094                 :             : 
    1095                 :           0 :       g_file_replace_contents_bytes_async (file,
    1096                 :             :                                            bytes,
    1097                 :             :                                            NULL,
    1098                 :             :                                            FALSE,
    1099                 :             :                                            G_FILE_CREATE_REPLACE_DESTINATION,
    1100                 :             :                                            NULL,
    1101                 :             :                                            (GAsyncReadyCallback)valent_share_plugin_handle_text_cb,
    1102                 :             :                                            NULL);
    1103                 :             :     }
    1104                 :             :   else
    1105                 :             :     {
    1106                 :           1 :       window = g_object_new (VALENT_TYPE_SHARE_TEXT_DIALOG,
    1107                 :             :                              "body", name,
    1108                 :             :                              "text", text,
    1109                 :             :                              NULL);
    1110                 :           1 :       g_signal_connect_data (window,
    1111                 :             :                              "destroy",
    1112                 :             :                              G_CALLBACK (g_ptr_array_remove),
    1113                 :           1 :                              g_ptr_array_ref (self->windows),
    1114                 :             :                              (void *)g_ptr_array_unref,
    1115                 :             :                              G_CONNECT_SWAPPED);
    1116                 :           1 :       g_ptr_array_add (self->windows, window);
    1117                 :             : 
    1118                 :           1 :       gtk_window_present (window);
    1119                 :             :     }
    1120                 :           1 : }
    1121                 :             : 
    1122                 :             : static void
    1123                 :           1 : valent_share_plugin_handle_url (ValentSharePlugin *self,
    1124                 :             :                                 const char        *url)
    1125                 :             : {
    1126         [ +  - ]:           1 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
    1127         [ -  + ]:           1 :   g_assert (url != NULL);
    1128                 :             : 
    1129                 :           1 :   g_app_info_launch_default_for_uri_async (url, NULL, NULL, NULL, NULL);
    1130                 :           1 : }
    1131                 :             : 
    1132                 :             : /*
    1133                 :             :  * ValentDevicePlugin
    1134                 :             :  */
    1135                 :             : static void
    1136                 :          36 : valent_share_plugin_update_state (ValentDevicePlugin *plugin,
    1137                 :             :                                   ValentDeviceState   state)
    1138                 :             : {
    1139                 :          36 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (plugin);
    1140                 :          36 :   gboolean available;
    1141                 :             : 
    1142         [ +  - ]:          36 :   g_assert (VALENT_IS_SHARE_PLUGIN (plugin));
    1143                 :             : 
    1144                 :          36 :   available = (state & VALENT_DEVICE_STATE_CONNECTED) != 0 &&
    1145                 :             :               (state & VALENT_DEVICE_STATE_PAIRED) != 0;
    1146                 :             : 
    1147                 :             :   /* If the device has been unpaired it should be considered untrusted, so
    1148                 :             :    * cancel any ongoing transfers. */
    1149         [ +  + ]:          36 :   if ((state & VALENT_DEVICE_STATE_PAIRED) == 0)
    1150                 :             :     {
    1151                 :           3 :       GHashTableIter iter;
    1152                 :           3 :       ValentTransfer *transfer;
    1153                 :             : 
    1154                 :           3 :       g_hash_table_iter_init (&iter, self->transfers);
    1155                 :             : 
    1156         [ -  + ]:           3 :       while (g_hash_table_iter_next (&iter, NULL, (void **)&transfer))
    1157                 :             :         {
    1158                 :           0 :           valent_transfer_cancel (transfer);
    1159                 :           0 :           g_hash_table_iter_remove (&iter);
    1160                 :             :         }
    1161                 :             : 
    1162         [ -  + ]:           3 :       g_clear_object (&self->download);
    1163         [ -  + ]:           3 :       g_clear_object (&self->upload);
    1164                 :             :     }
    1165                 :             : 
    1166                 :          36 :   valent_extension_toggle_actions (VALENT_EXTENSION (plugin), available);
    1167                 :          36 : }
    1168                 :             : 
    1169                 :             : static void
    1170                 :          10 : valent_share_plugin_handle_packet (ValentDevicePlugin *plugin,
    1171                 :             :                                    const char         *type,
    1172                 :             :                                    JsonNode           *packet)
    1173                 :             : {
    1174                 :          10 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (plugin);
    1175                 :          10 :   const char *text;
    1176                 :          10 :   const char *url;
    1177                 :             : 
    1178         [ +  - ]:          10 :   g_assert (VALENT_IS_SHARE_PLUGIN (self));
    1179         [ -  + ]:          10 :   g_assert (type != NULL);
    1180         [ -  + ]:          10 :   g_assert (VALENT_IS_PACKET (packet));
    1181                 :             : 
    1182         [ +  + ]:          10 :   if (g_str_equal (type, "kdeconnect.share.request"))
    1183                 :             :     {
    1184         [ +  + ]:           9 :       if (valent_packet_check_field (packet, "filename"))
    1185                 :           7 :         valent_share_plugin_handle_file (self, packet);
    1186                 :             : 
    1187         [ +  + ]:           2 :       else if (valent_packet_get_string (packet, "text", &text))
    1188                 :           1 :         valent_share_plugin_handle_text (self, text);
    1189                 :             : 
    1190         [ +  - ]:           1 :       else if (valent_packet_get_string (packet, "url", &url))
    1191                 :           1 :         valent_share_plugin_handle_url (self, url);
    1192                 :             : 
    1193                 :             :       else
    1194                 :           0 :         g_warning ("%s(): unsupported share request", G_STRFUNC);
    1195                 :             :     }
    1196         [ +  - ]:           1 :   else if (g_str_equal (type, "kdeconnect.share.request.update"))
    1197                 :             :     {
    1198                 :           1 :       valent_share_plugin_handle_file_update (self, packet);
    1199                 :             :     }
    1200                 :             :   else
    1201                 :           0 :     g_assert_not_reached ();
    1202                 :          10 : }
    1203                 :             : 
    1204                 :             : /*
    1205                 :             :  * ValentObject
    1206                 :             :  */
    1207                 :             : static void
    1208                 :          20 : valent_share_plugin_destroy (ValentObject *object)
    1209                 :             : {
    1210                 :          20 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (object);
    1211                 :          20 :   ValentDevicePlugin *plugin = VALENT_DEVICE_PLUGIN (object);
    1212                 :          20 :   GHashTableIter iter;
    1213                 :          20 :   ValentTransfer *transfer;
    1214                 :             : 
    1215                 :             :   /* Cancel active transfers */
    1216                 :          20 :   g_hash_table_iter_init (&iter, self->transfers);
    1217                 :             : 
    1218         [ -  + ]:          20 :   while (g_hash_table_iter_next (&iter, NULL, (void **)&transfer))
    1219                 :             :     {
    1220                 :           0 :       valent_transfer_cancel (transfer);
    1221                 :           0 :       g_hash_table_iter_remove (&iter);
    1222                 :             :     }
    1223                 :             : 
    1224         [ -  + ]:          20 :   g_clear_object (&self->download);
    1225         [ -  + ]:          20 :   g_clear_object (&self->upload);
    1226                 :             : 
    1227                 :             :   /* Close open windows */
    1228                 :          20 :   g_ptr_array_foreach (self->windows, (void *)gtk_window_destroy, NULL);
    1229                 :          20 :   g_ptr_array_remove_range (self->windows, 0, self->windows->len);
    1230                 :             : 
    1231                 :          20 :   valent_device_plugin_set_menu_item (plugin, "device.share.chooser", NULL);
    1232                 :             : 
    1233                 :          20 :   VALENT_OBJECT_CLASS (valent_share_plugin_parent_class)->destroy (object);
    1234                 :          20 : }
    1235                 :             : 
    1236                 :             : /*
    1237                 :             :  * GObject
    1238                 :             :  */
    1239                 :             : static void
    1240                 :          11 : valent_share_plugin_constructed (GObject *object)
    1241                 :             : {
    1242                 :          11 :   ValentDevicePlugin *plugin = VALENT_DEVICE_PLUGIN (object);
    1243                 :             : 
    1244                 :          11 :   g_action_map_add_action_entries (G_ACTION_MAP (plugin),
    1245                 :             :                                    actions,
    1246                 :             :                                    G_N_ELEMENTS (actions),
    1247                 :             :                                    plugin);
    1248                 :          11 :   valent_device_plugin_set_menu_action (plugin,
    1249                 :             :                                         "device.share.chooser",
    1250                 :          11 :                                         _("Send Files"),
    1251                 :             :                                         "document-send-symbolic");
    1252                 :             : 
    1253                 :          11 :   G_OBJECT_CLASS (valent_share_plugin_parent_class)->constructed (object);
    1254                 :          11 : }
    1255                 :             : 
    1256                 :             : static void
    1257                 :          10 : valent_share_plugin_finalize (GObject *object)
    1258                 :             : {
    1259                 :          10 :   ValentSharePlugin *self = VALENT_SHARE_PLUGIN (object);
    1260                 :             : 
    1261         [ +  - ]:          10 :   g_clear_pointer (&self->transfers, g_hash_table_unref);
    1262         [ +  - ]:          10 :   g_clear_pointer (&self->windows, g_ptr_array_unref);
    1263                 :             : 
    1264                 :          10 :   G_OBJECT_CLASS (valent_share_plugin_parent_class)->finalize (object);
    1265                 :          10 : }
    1266                 :             : 
    1267                 :             : static void
    1268                 :           6 : valent_share_plugin_class_init (ValentSharePluginClass *klass)
    1269                 :             : {
    1270                 :           6 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
    1271                 :           6 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
    1272                 :           6 :   ValentDevicePluginClass *plugin_class = VALENT_DEVICE_PLUGIN_CLASS (klass);
    1273                 :             : 
    1274                 :           6 :   object_class->constructed = valent_share_plugin_constructed;
    1275                 :           6 :   object_class->finalize = valent_share_plugin_finalize;
    1276                 :             : 
    1277                 :           6 :   vobject_class->destroy = valent_share_plugin_destroy;
    1278                 :             : 
    1279                 :           6 :   plugin_class->handle_packet = valent_share_plugin_handle_packet;
    1280                 :           6 :   plugin_class->update_state = valent_share_plugin_update_state;
    1281                 :             : }
    1282                 :             : 
    1283                 :             : static void
    1284                 :          11 : valent_share_plugin_init (ValentSharePlugin *self)
    1285                 :             : {
    1286                 :          11 :   self->transfers = g_hash_table_new_full (g_str_hash,
    1287                 :             :                                            g_str_equal,
    1288                 :             :                                            g_free,
    1289                 :             :                                            g_object_unref);
    1290                 :          11 :   self->windows = g_ptr_array_new ();
    1291                 :          11 : }
    1292                 :             : 
        

Generated by: LCOV version 2.0-1