LCOV - code coverage report
Current view: top level - src/plugins/sftp - valent-sftp-plugin.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 37.3 % 405 151
Test Date: 2025-10-15 22:22:13 Functions: 45.7 % 35 16
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 18.0 % 300 54

             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-sftp-plugin"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <glib/gi18n.h>
       9                 :             : #include <gio/gio.h>
      10                 :             : #include <json-glib/json-glib.h>
      11                 :             : #include <valent.h>
      12                 :             : 
      13                 :             : #include "valent-sftp-plugin.h"
      14                 :             : 
      15                 :             : 
      16                 :             : typedef struct _ValentSftpSession ValentSftpSession;
      17                 :             : 
      18                 :             : struct _ValentSftpPlugin
      19                 :             : {
      20                 :             :   ValentDevicePlugin  parent_instance;
      21                 :             : 
      22                 :             :   GDBusConnection    *connection;
      23                 :             :   GVolumeMonitor     *monitor;
      24                 :             :   ValentSftpSession  *session;
      25                 :             :   unsigned int        privkey_ready : 1;
      26                 :             : };
      27                 :             : 
      28                 :             : static void   valent_sftp_plugin_mount_volume   (ValentSftpPlugin *self);
      29                 :             : static void   valent_sftp_plugin_unmount_volume (ValentSftpPlugin *self);
      30                 :             : static void   valent_sftp_plugin_update_menu    (ValentSftpPlugin *self);
      31                 :             : 
      32   [ +  +  +  - ]:          59 : G_DEFINE_FINAL_TYPE (ValentSftpPlugin, valent_sftp_plugin, VALENT_TYPE_DEVICE_PLUGIN)
      33                 :             : 
      34                 :             : /*< private >
      35                 :             :  * get_device_host:
      36                 :             :  * @self: a `ValentSftpPlugin`
      37                 :             :  *
      38                 :             :  * Try to find a IP-based device channel with a host.
      39                 :             :  *
      40                 :             :  * Returns: (nullable) (transfer full): a hostname or IP address
      41                 :             :  */
      42                 :             : static char *
      43                 :           7 : get_device_host (ValentSftpPlugin *self)
      44                 :             : {
      45                 :           7 :   ValentDevice *device;
      46                 :           7 :   char *host = NULL;
      47                 :             : 
      48         [ -  + ]:           7 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
      49                 :             : 
      50                 :           7 :   device = valent_resource_get_source (VALENT_RESOURCE (self));
      51         [ +  - ]:           7 :   if (device != NULL)
      52                 :             :     {
      53                 :           7 :       GListModel *channels;
      54                 :           7 :       unsigned int n_channels;
      55                 :             : 
      56                 :           7 :       channels = valent_device_get_channels (device);
      57                 :           7 :       n_channels = g_list_model_get_n_items (channels);
      58         [ +  + ]:           7 :       for (unsigned int i = 0; i < n_channels; i++)
      59                 :             :         {
      60                 :           4 :           g_autoptr (ValentChannel) channel = NULL;
      61                 :           4 :           GParamSpec *pspec = NULL;
      62                 :             : 
      63                 :           4 :           channel = g_list_model_get_item (channels, i);
      64                 :           4 :           pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (channel),
      65                 :             :                                                 "host");
      66         [ +  - ]:           4 :           if (pspec != NULL)
      67                 :             :             {
      68                 :           4 :               g_object_get (channel, "host", &host, NULL);
      69                 :           4 :               break;
      70                 :             :             }
      71                 :             :         }
      72                 :             :     }
      73                 :             : 
      74                 :           7 :   return g_steal_pointer (&host);
      75                 :             : }
      76                 :             : 
      77                 :             : /**
      78                 :             :  * ValentSftpSession:
      79                 :             :  * @host: Host name or IP
      80                 :             :  * @port: Port
      81                 :             :  * @username: Username (deprecated)
      82                 :             :  * @password: Password (deprecated)
      83                 :             :  * @mount: A `GMount` for the session
      84                 :             :  *
      85                 :             :  * `ValentSftpSession` is a simple representation of a SFTP session.
      86                 :             :  */
      87                 :             : typedef struct _ValentSftpSession
      88                 :             : {
      89                 :             :   char       *host;
      90                 :             :   uint16_t    port;
      91                 :             :   char       *username;
      92                 :             :   char       *password;
      93                 :             :   GHashTable *paths;
      94                 :             : 
      95                 :             :   /* Gvfs state */
      96                 :             :   GMount     *mount;
      97                 :             :   char       *uri;
      98                 :             : } ValentSftpSession;
      99                 :             : 
     100                 :             : 
     101                 :             : static ValentSftpSession *
     102                 :           0 : sftp_session_new (ValentSftpPlugin *self,
     103                 :             :                   JsonNode         *packet)
     104                 :             : {
     105                 :           0 :   ValentSftpSession *session;
     106                 :           0 :   g_autofree char *host = NULL;
     107                 :           0 :   int64_t port;
     108                 :           0 :   const char *password;
     109                 :           0 :   const char *username;
     110                 :           0 :   JsonArray *multi_paths = NULL;
     111                 :           0 :   JsonArray *path_names = NULL;
     112                 :             : 
     113                 :             :   /* Ultimately, these are the only packet fields we really need */
     114         [ #  # ]:           0 :   if (!valent_packet_get_int (packet, "port", &port) ||
     115         [ #  # ]:           0 :       (port < 0 || port > G_MAXUINT16))
     116                 :             :     {
     117                 :           0 :       g_debug ("%s(): expected \"port\" field holding a uint16",
     118                 :             :                G_STRFUNC);
     119                 :           0 :       return NULL;
     120                 :             :     }
     121                 :             : 
     122         [ #  # ]:           0 :   if ((host = get_device_host (self)) == NULL)
     123                 :             :     {
     124                 :           0 :       g_warning ("%s(): failed to get host address",
     125                 :             :                  G_STRFUNC);
     126                 :           0 :       return NULL;
     127                 :             :     }
     128                 :             : 
     129                 :             :   // Create a session struct
     130                 :           0 :   session = g_new0 (ValentSftpSession, 1);
     131                 :           0 :   session->host = g_steal_pointer (&host);
     132                 :           0 :   session->port = (uint16_t)port;
     133                 :           0 :   session->paths = g_hash_table_new_full (g_str_hash, g_str_equal,
     134                 :             :                                           g_free, g_free);
     135                 :           0 :   session->uri = g_strdup_printf ("sftp://%s:%u/", session->host, session->port);
     136                 :             : 
     137         [ #  # ]:           0 :   if (valent_packet_get_string (packet, "user", &username))
     138         [ #  # ]:           0 :     session->username = g_strdup (username);
     139                 :             : 
     140         [ #  # ]:           0 :   if (valent_packet_get_string (packet, "password", &password))
     141         [ #  # ]:           0 :     session->password = g_strdup (password);
     142                 :             : 
     143   [ #  #  #  # ]:           0 :   if (valent_packet_get_array (packet, "multiPaths", &multi_paths) &&
     144                 :           0 :       valent_packet_get_array (packet, "pathNames", &path_names))
     145                 :             :     {
     146                 :           0 :       unsigned int n_paths = json_array_get_length (multi_paths);
     147                 :           0 :       unsigned int n_names = json_array_get_length (path_names);
     148                 :             : 
     149         [ #  # ]:           0 :       for (unsigned int i = 0; i < n_paths && i < n_names; i++)
     150                 :             :         {
     151                 :           0 :           const char *path = json_array_get_string_element (multi_paths, i);
     152                 :           0 :           const char *name = json_array_get_string_element (path_names, i);
     153                 :           0 :           g_autofree char *uri = NULL;
     154                 :             : 
     155                 :           0 :           uri = g_strdup_printf ("sftp://%s:%u%s",
     156                 :             :                                  session->host,
     157                 :             :                                  session->port,
     158                 :             :                                  path);
     159         [ #  # ]:           0 :           g_hash_table_replace (session->paths,
     160                 :             :                                 g_steal_pointer (&uri),
     161                 :           0 :                                 g_strdup (name));
     162                 :             :         }
     163                 :             :     }
     164                 :             : 
     165                 :             :   return session;
     166                 :             : }
     167                 :             : 
     168                 :             : static void
     169                 :           0 : sftp_session_free (gpointer data)
     170                 :             : {
     171                 :           0 :   ValentSftpSession *session = data;
     172                 :             : 
     173         [ #  # ]:           0 :   g_clear_pointer (&session->host, g_free);
     174         [ #  # ]:           0 :   g_clear_pointer (&session->username, g_free);
     175         [ #  # ]:           0 :   g_clear_pointer (&session->password, g_free);
     176         [ #  # ]:           0 :   g_clear_pointer (&session->paths, g_hash_table_unref);
     177                 :             : 
     178         [ #  # ]:           0 :   g_clear_object (&session->mount);
     179         [ #  # ]:           0 :   g_clear_pointer (&session->uri, g_free);
     180                 :             : 
     181                 :           0 :   g_free (session);
     182                 :           0 : }
     183                 :             : 
     184                 :             : static void
     185                 :           0 : sftp_session_end_cb (GMount       *mount,
     186                 :             :                      GAsyncResult *result,
     187                 :             :                      gpointer      user_data)
     188                 :             : {
     189                 :           0 :   g_autoptr (GError) error = NULL;
     190                 :             : 
     191         [ #  # ]:           0 :   if (!g_mount_unmount_with_operation_finish (mount, result, &error))
     192                 :           0 :     g_debug ("Failed unmounting: %s", error->message);
     193                 :           0 : }
     194                 :             : 
     195                 :             : static void
     196                 :           0 : sftp_session_end (gpointer data)
     197                 :             : {
     198                 :           0 :   ValentSftpSession *session = data;
     199                 :           0 :   g_autoptr (GMount) mount = NULL;
     200                 :           0 :   g_autoptr (GMountOperation) op = NULL;
     201                 :             : 
     202                 :           0 :   mount = g_steal_pointer (&session->mount);
     203                 :           0 :   sftp_session_free (session);
     204                 :             : 
     205         [ #  # ]:           0 :   if (mount == NULL)
     206                 :             :     return;
     207                 :             : 
     208                 :           0 :   op = g_mount_operation_new ();
     209         [ #  # ]:           0 :   g_mount_unmount_with_operation (mount,
     210                 :             :                                   G_MOUNT_UNMOUNT_FORCE,
     211                 :             :                                   op,
     212                 :             :                                   NULL,
     213                 :             :                                   (GAsyncReadyCallback)sftp_session_end_cb,
     214                 :             :                                   NULL);
     215                 :             : }
     216                 :             : 
     217                 :             : static gboolean
     218                 :           7 : sftp_session_find (ValentSftpPlugin *self)
     219                 :             : {
     220                 :          14 :   g_autofree char *host = NULL;
     221                 :           7 :   g_autofree char *host_pattern = NULL;
     222                 :           7 :   g_autoptr (GRegex) regex = NULL;
     223         [ +  + ]:           7 :   g_autolist (GMount) mounts = NULL;
     224                 :             : 
     225   [ -  +  -  - ]:           7 :   if (self->session && self->session->mount)
     226                 :             :     return TRUE;
     227                 :             : 
     228         [ +  + ]:           7 :   if ((host = get_device_host (self)) == NULL)
     229                 :             :     return FALSE;
     230                 :             : 
     231                 :             :   // TODO: is this reasonable?
     232                 :           4 :   host_pattern = g_strdup_printf ("sftp://(%s):([22-65535])", host);
     233                 :           4 :   regex = g_regex_new (host_pattern, G_REGEX_OPTIMIZE, 0, NULL);
     234                 :             : 
     235                 :             :   /* Search through each mount in the volume monitor... */
     236                 :           4 :   mounts = g_volume_monitor_get_mounts (self->monitor);
     237                 :             : 
     238         [ -  + ]:           4 :   for (const GList *iter = mounts; iter; iter = iter->next)
     239                 :             :     {
     240                 :           7 :       g_autoptr (GFile) root = NULL;
     241   [ #  #  #  # ]:           0 :       g_autofree char *uri = NULL;
     242                 :             : 
     243                 :           0 :       root = g_mount_get_root (iter->data);
     244                 :           0 :       uri = g_file_get_uri (root);
     245                 :             : 
     246                 :             :       /* The URI matches our mount */
     247         [ #  # ]:           0 :       if (g_regex_match (regex, uri, 0, NULL))
     248                 :             :         {
     249         [ #  # ]:           0 :           if (self->session == NULL)
     250                 :           0 :             self->session = g_new0 (ValentSftpSession, 1);
     251                 :             : 
     252                 :           0 :           g_set_object (&self->session->mount, iter->data);
     253                 :           0 :           g_set_str (&self->session->uri, uri);
     254                 :             : 
     255                 :           0 :           valent_sftp_plugin_update_menu (self);
     256                 :           0 :           return TRUE;
     257                 :             :         }
     258                 :             :     }
     259                 :             : 
     260                 :             :   return FALSE;
     261                 :             : }
     262                 :             : 
     263                 :             : 
     264                 :             : /*
     265                 :             :  * GVolumeMonitor Callbacks
     266                 :             :  */
     267                 :             : static void
     268                 :           0 : on_mount_added (GVolumeMonitor   *volume_monitor,
     269                 :             :                 GMount           *mount,
     270                 :             :                 ValentSftpPlugin *self)
     271                 :             : {
     272                 :           0 :   g_autoptr (GFile) root = NULL;
     273         [ #  # ]:           0 :   g_autofree char *uri = NULL;
     274                 :             : 
     275         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     276                 :             : 
     277         [ #  # ]:           0 :   if (self->session == NULL)
     278                 :           0 :     return;
     279                 :             : 
     280                 :           0 :   root = g_mount_get_root (mount);
     281                 :           0 :   uri = g_file_get_uri (root);
     282                 :             : 
     283         [ #  # ]:           0 :   if (g_strcmp0 (self->session->uri, uri) == 0)
     284                 :             :     {
     285                 :           0 :       g_set_object (&self->session->mount, mount);
     286                 :           0 :       valent_sftp_plugin_update_menu (self);
     287                 :             :     }
     288                 :             : }
     289                 :             : 
     290                 :             : static void
     291                 :           0 : on_mount_removed (GVolumeMonitor   *volume_monitor,
     292                 :             :                   GMount           *mount,
     293                 :             :                   ValentSftpPlugin *self)
     294                 :             : {
     295                 :           0 :   g_autoptr (GFile) root = NULL;
     296         [ #  # ]:           0 :   g_autofree char *uri = NULL;
     297                 :             : 
     298         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     299                 :             : 
     300         [ #  # ]:           0 :   if (self->session == NULL)
     301                 :           0 :     return;
     302                 :             : 
     303                 :           0 :   root = g_mount_get_root (mount);
     304                 :           0 :   uri = g_file_get_uri (root);
     305                 :             : 
     306         [ #  # ]:           0 :   if (g_strcmp0 (self->session->uri, uri) == 0)
     307                 :             :     {
     308         [ #  # ]:           0 :       g_clear_object (&self->session->mount);
     309                 :           0 :       valent_sftp_plugin_update_menu (self);
     310                 :             :     }
     311                 :             : }
     312                 :             : 
     313                 :             : /**
     314                 :             :  * remove_host_key:
     315                 :             :  * @host: An IP or hostname
     316                 :             :  *
     317                 :             :  * Remove all host keys associated with @host from the ssh-agent.
     318                 :             :  */
     319                 :             : static void
     320                 :           0 : remove_host_key (const char *host)
     321                 :             : {
     322         [ #  # ]:           0 :   g_assert (host != NULL);
     323                 :             : 
     324         [ #  # ]:           0 :   for (uint16_t port = 1739; port <= 1764; port++)
     325                 :             :     {
     326                 :           0 :       g_autoptr (GSubprocess) proc = NULL;
     327         [ #  # ]:           0 :       g_autofree char *match = NULL;
     328                 :             : 
     329                 :           0 :       match = g_strdup_printf ("[%s]:%d", host, port);
     330                 :           0 :       proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
     331                 :             :                                G_SUBPROCESS_FLAGS_STDERR_MERGE,
     332                 :             :                                NULL,
     333                 :             :                                "ssh-keygen", "-R", match,
     334                 :             :                                NULL);
     335                 :             : 
     336         [ #  # ]:           0 :       if (proc != NULL)
     337                 :           0 :         g_subprocess_wait_async (proc, NULL, NULL, NULL);
     338                 :             :     }
     339                 :           0 : }
     340                 :             : 
     341                 :             : /*
     342                 :             :  * GMountOperation
     343                 :             :  */
     344                 :             : static void
     345                 :           0 : ask_password_cb (GMountOperation   *operation,
     346                 :             :                  char              *message,
     347                 :             :                  char              *default_user,
     348                 :             :                  char              *default_domain,
     349                 :             :                  GAskPasswordFlags  flags,
     350                 :             :                  ValentSftpPlugin  *self)
     351                 :             : {
     352         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     353         [ #  # ]:           0 :   g_return_if_fail (self->session != NULL);
     354                 :             : 
     355                 :             :   /* The username/password are only set in response to a request, to prefer
     356                 :             :    * public key authentication when possible.
     357                 :             :    */
     358         [ #  # ]:           0 :   if ((flags & G_ASK_PASSWORD_NEED_USERNAME) != 0)
     359                 :           0 :     g_mount_operation_set_username (operation, self->session->username);
     360                 :             : 
     361         [ #  # ]:           0 :   if ((flags & G_ASK_PASSWORD_NEED_PASSWORD) != 0)
     362                 :             :     {
     363                 :           0 :       g_mount_operation_set_password (operation, self->session->password);
     364                 :           0 :       g_mount_operation_set_password_save (operation, G_PASSWORD_SAVE_NEVER);
     365                 :             :     }
     366                 :             : 
     367                 :           0 :   g_mount_operation_reply (operation, G_MOUNT_OPERATION_HANDLED);
     368                 :             : }
     369                 :             : 
     370                 :             : static void
     371                 :           0 : ask_question_cb (GMountOperation *operation,
     372                 :             :                  char            *message,
     373                 :             :                  GStrv            choices,
     374                 :             :                  gpointer         user_data)
     375                 :             : {
     376                 :             :   /* Host keys are automatically accepted, since we use the host address of
     377                 :             :    * the authenticated device connection.
     378                 :             :    */
     379                 :           0 :   g_mount_operation_reply (operation, G_MOUNT_OPERATION_HANDLED);
     380                 :           0 : }
     381                 :             : 
     382                 :             : static void
     383                 :           0 : g_file_mount_enclosing_volume_cb (GFile        *file,
     384                 :             :                                   GAsyncResult *result,
     385                 :             :                                   gpointer      user_data)
     386                 :             : {
     387                 :           0 :   g_autoptr (ValentSftpPlugin) self = VALENT_SFTP_PLUGIN (g_steal_pointer (&user_data));
     388                 :           0 :   g_autoptr (GError) error = NULL;
     389                 :             : 
     390         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     391         [ #  # ]:           0 :   g_return_if_fail (self->session != NULL);
     392                 :             : 
     393                 :             :   /* On success we will acquire the mount from the volume monitor */
     394         [ #  # ]:           0 :   if (g_file_mount_enclosing_volume_finish (file, result, &error))
     395                 :             :     return;
     396                 :             : 
     397                 :             :   /* On the off-chance this happens, we will just ensure we have the mount */
     398   [ #  #  #  # ]:           0 :   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ALREADY_MOUNTED) &&
     399                 :           0 :       sftp_session_find (self))
     400                 :             :     return;
     401                 :             : 
     402                 :             :   /* On failure, we're particularly interested in host key failures so that
     403                 :             :    * we can remove those from the ssh-agent. These are reported by GVfs as
     404                 :             :    * G_IO_ERROR_FAILED with a localized string, so we just assume. */
     405         [ #  # ]:           0 :   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED))
     406                 :             :     {
     407                 :           0 :       g_warning ("%s(): Error mounting: %s", G_STRFUNC, error->message);
     408                 :             : 
     409   [ #  #  #  # ]:           0 :       if (self->session && self->session->host)
     410                 :           0 :         remove_host_key (self->session->host);
     411                 :             :     }
     412                 :             : 
     413   [ #  #  #  # ]:           0 :   g_clear_pointer (&self->session, sftp_session_free);
     414                 :             : }
     415                 :             : 
     416                 :             : static void
     417                 :           0 : valent_sftp_plugin_mount_volume (ValentSftpPlugin *self)
     418                 :             : {
     419                 :           0 :   g_autoptr (GFile) file = NULL;
     420         [ #  # ]:           0 :   g_autoptr (GMountOperation) operation = NULL;
     421         [ #  # ]:           0 :   g_autoptr (GCancellable) destroy = NULL;
     422                 :             : 
     423         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     424         [ #  # ]:           0 :   g_return_if_fail (self->session != NULL);
     425                 :             : 
     426                 :           0 :   file = g_file_new_for_uri (self->session->uri);
     427                 :           0 :   operation = g_mount_operation_new ();
     428                 :           0 :   g_signal_connect_object (operation,
     429                 :             :                            "ask-password",
     430                 :             :                            G_CALLBACK (ask_password_cb),
     431                 :             :                            self,
     432                 :             :                            G_CONNECT_DEFAULT);
     433                 :           0 :   g_signal_connect_object (operation,
     434                 :             :                            "ask-question",
     435                 :             :                            G_CALLBACK (ask_question_cb),
     436                 :             :                            self,
     437                 :             :                            G_CONNECT_DEFAULT);
     438                 :             : 
     439                 :           0 :   destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
     440         [ #  # ]:           0 :   g_file_mount_enclosing_volume (file,
     441                 :             :                                  G_MOUNT_MOUNT_NONE,
     442                 :             :                                  operation,
     443                 :             :                                  destroy,
     444                 :             :                                  (GAsyncReadyCallback)g_file_mount_enclosing_volume_cb,
     445                 :             :                                  g_object_ref (self));
     446                 :             : 
     447                 :             : }
     448                 :             : 
     449                 :             : static void
     450                 :           0 : g_mount_unmount_with_operation_cb (GMount       *mount,
     451                 :             :                                    GAsyncResult *result,
     452                 :             :                                    gpointer      user_data)
     453                 :             : {
     454                 :           0 :   g_autoptr (GError) error = NULL;
     455                 :             : 
     456         [ #  # ]:           0 :   if (!g_mount_unmount_with_operation_finish (mount, result, &error))
     457                 :             :     {
     458         [ #  # ]:           0 :       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     459                 :           0 :         g_warning ("%s(): Error unmounting: %s", G_STRFUNC, error->message);
     460                 :             : 
     461         [ #  # ]:           0 :       return;
     462                 :             :     }
     463                 :             : }
     464                 :             : 
     465                 :             : static void
     466                 :           0 : valent_sftp_plugin_unmount_volume (ValentSftpPlugin *self)
     467                 :             : {
     468                 :           0 :   g_autoptr (GMountOperation) operation = NULL;
     469         [ #  # ]:           0 :   g_autoptr (GCancellable) destroy = NULL;
     470                 :             : 
     471         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     472         [ #  # ]:           0 :   g_return_if_fail (self->session != NULL);
     473                 :             : 
     474         [ #  # ]:           0 :   if (self->session->mount == NULL)
     475                 :             :     return;
     476                 :             : 
     477                 :           0 :   operation = g_mount_operation_new ();
     478                 :           0 :   destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
     479         [ #  # ]:           0 :   g_mount_unmount_with_operation (self->session->mount,
     480                 :             :                                   G_MOUNT_UNMOUNT_NONE,
     481                 :             :                                   operation,
     482                 :             :                                   destroy,
     483                 :             :                                   (GAsyncReadyCallback)g_mount_unmount_with_operation_cb,
     484                 :             :                                   NULL);
     485                 :             : }
     486                 :             : 
     487                 :             : static void
     488                 :           0 : valent_sftp_plugin_register_privkey_cb (GSubprocess  *proc,
     489                 :             :                                         GAsyncResult *result,
     490                 :             :                                         gpointer      user_data)
     491                 :             : {
     492                 :           0 :   g_autoptr (ValentSftpPlugin) self = VALENT_SFTP_PLUGIN (g_steal_pointer (&user_data));
     493                 :           0 :   g_autoptr (GError) error = NULL;
     494                 :             : 
     495         [ #  # ]:           0 :   if (!g_subprocess_wait_check_finish (proc, result, &error))
     496                 :             :     {
     497         [ #  # ]:           0 :       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     498                 :             :         {
     499                 :           0 :           g_warning ("%s(): Failed to register private key: %s",
     500                 :             :                      G_STRFUNC,
     501                 :             :                      error->message);
     502                 :             :         }
     503                 :             : 
     504         [ #  # ]:           0 :       g_clear_pointer (&self->session, sftp_session_free);
     505         [ #  # ]:           0 :       return;
     506                 :             :     }
     507                 :             : 
     508                 :           0 :   self->privkey_ready = TRUE;
     509         [ #  # ]:           0 :   valent_sftp_plugin_mount_volume (self);
     510                 :             : }
     511                 :             : 
     512                 :             : static void
     513                 :           0 : valent_sftp_plugin_register_privkey (ValentSftpPlugin  *self)
     514                 :             : {
     515                 :           0 :   g_autoptr (ValentContext) context = NULL;
     516   [ #  #  #  # ]:           0 :   g_autoptr (GSubprocess) proc = NULL;
     517         [ #  # ]:           0 :   g_autoptr (GFile) private_key = NULL;
     518   [ #  #  #  # ]:           0 :   g_autoptr (GCancellable) destroy = NULL;
     519   [ #  #  #  # ]:           0 :   g_autoptr (GError) error = NULL;
     520                 :             : 
     521         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     522         [ #  # ]:           0 :   g_return_if_fail (self->session != NULL);
     523                 :             : 
     524                 :             :   /* Get the root context and add the private key to the ssh-agent */
     525                 :           0 :   context = valent_context_new (NULL, NULL, NULL);
     526                 :           0 :   private_key = valent_context_get_config_file (context, "private.pem");
     527                 :           0 :   proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
     528                 :             :                            G_SUBPROCESS_FLAGS_STDERR_MERGE,
     529                 :             :                            &error,
     530                 :             :                            "ssh-add", g_file_peek_path (private_key),
     531                 :             :                            NULL);
     532                 :             : 
     533         [ #  # ]:           0 :   if (proc == NULL)
     534                 :             :     {
     535                 :           0 :       g_warning ("%s(): Failed to add host key: %s", G_STRFUNC, error->message);
     536         [ #  # ]:           0 :       g_clear_pointer (&self->session, sftp_session_free);
     537                 :           0 :       return;
     538                 :             :     }
     539                 :             : 
     540                 :           0 :   destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
     541         [ #  # ]:           0 :   g_subprocess_wait_check_async (proc,
     542                 :             :                                  destroy,
     543                 :             :                                  (GAsyncReadyCallback)valent_sftp_plugin_register_privkey_cb,
     544                 :             :                                  g_object_ref (self));
     545                 :             : }
     546                 :             : 
     547                 :             : /*
     548                 :             :  * Packet Handlers
     549                 :             :  */
     550                 :             : static void
     551                 :           1 : handle_sftp_error (ValentSftpPlugin *self,
     552                 :             :                    JsonNode         *packet)
     553                 :             : {
     554                 :           1 :   ValentDevice *device;
     555                 :           2 :   g_autoptr (GNotification) notification = NULL;
     556         [ +  - ]:           1 :   g_autoptr (GIcon) error_icon = NULL;
     557         [ +  - ]:           1 :   g_autofree char *error_title = NULL;
     558                 :           1 :   const char *error_message;
     559                 :           1 :   const char *device_name;
     560                 :           1 :   JsonObject *body;
     561                 :             : 
     562         [ -  + ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     563                 :             : 
     564                 :           1 :   body = valent_packet_get_body (packet);
     565                 :             : 
     566                 :           1 :   device = valent_resource_get_source (VALENT_RESOURCE (self));
     567                 :           1 :   device_name = valent_device_get_name (device);
     568                 :             : 
     569                 :           1 :   error_icon = g_themed_icon_new ("dialog-error-symbolic");
     570                 :           1 :   error_title = g_strdup_printf ("%s: SFTP", device_name);
     571                 :           1 :   error_message = json_object_get_string_member (body, "errorMessage");
     572                 :             : 
     573                 :             :   /* Send notification */
     574                 :           1 :   notification = g_notification_new (error_title);
     575                 :           1 :   g_notification_set_body (notification, error_message);
     576                 :           1 :   g_notification_set_icon (notification, error_icon);
     577                 :           1 :   g_notification_set_priority (notification, G_NOTIFICATION_PRIORITY_HIGH);
     578                 :           1 :   valent_device_plugin_show_notification (VALENT_DEVICE_PLUGIN (self),
     579                 :             :                                           "sftp-error",
     580                 :             :                                           notification);
     581                 :           1 : }
     582                 :             : 
     583                 :             : static void
     584                 :           0 : handle_sftp_mount (ValentSftpPlugin *self,
     585                 :             :                    JsonNode         *packet)
     586                 :             : {
     587         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     588                 :             : 
     589                 :             :   /* Check if we're already mounted or mounting */
     590         [ #  # ]:           0 :   if (self->session != NULL)
     591                 :             :     return;
     592                 :             : 
     593                 :             :   /* Parse the connection data */
     594                 :           0 :   self->session = sftp_session_new (self, packet);
     595         [ #  # ]:           0 :   if (self->session != NULL)
     596                 :             :     {
     597         [ #  # ]:           0 :       if (self->privkey_ready)
     598                 :           0 :         valent_sftp_plugin_mount_volume (self);
     599                 :             :       else
     600                 :           0 :         valent_sftp_plugin_register_privkey (self);
     601                 :             :     }
     602                 :             : }
     603                 :             : 
     604                 :             : static void
     605                 :           1 : valent_sftp_plugin_handle_sftp (ValentSftpPlugin *self,
     606                 :             :                                 JsonNode         *packet)
     607                 :             : {
     608         [ -  + ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     609                 :             : 
     610                 :             :   /* The request for mount information failed, most likely due to the remote
     611                 :             :    * device not being setup yet.
     612                 :             :    */
     613         [ +  - ]:           1 :   if (valent_packet_check_field (packet, "errorMessage"))
     614                 :           1 :     handle_sftp_error (self, packet);
     615                 :             : 
     616                 :             :   /* Otherwise we've been sent the information necessary to open an SSH/SFTP
     617                 :             :    * connection to the remote device.
     618                 :             :    */
     619                 :             :   else
     620                 :           0 :     handle_sftp_mount (self, packet);
     621                 :           1 : }
     622                 :             : 
     623                 :             : /*
     624                 :             :  * Packet Providers
     625                 :             :  */
     626                 :             : static void
     627                 :           1 : valent_sftp_plugin_handle_request (ValentSftpPlugin *self,
     628                 :             :                                    JsonNode         *packet)
     629                 :             : {
     630                 :           1 :   GSettings *settings;
     631                 :           1 :   g_autoptr (JsonBuilder) builder = NULL;
     632   [ -  -  -  + ]:           1 :   g_autoptr (JsonNode) response = NULL;
     633                 :             : 
     634         [ -  + ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     635                 :             : 
     636         [ -  + ]:           1 :   if (!valent_packet_check_field (packet, "startBrowsing"))
     637         [ #  # ]:           0 :     return;
     638                 :             : 
     639                 :           1 :   settings = valent_extension_get_settings (VALENT_EXTENSION (self));
     640                 :           1 :   valent_packet_init (&builder, "kdeconnect.sftp");
     641                 :             : 
     642         [ -  + ]:           1 :   if (g_settings_get_boolean (settings, "local-allow"))
     643                 :             :     {
     644                 :           0 :       uint16_t local_port;
     645                 :             : 
     646                 :           0 :       json_builder_set_member_name (builder, "user");
     647                 :           0 :       json_builder_add_string_value (builder, g_get_user_name ());
     648                 :             : 
     649                 :           0 :       local_port = g_settings_get_uint (settings, "local-port");
     650                 :           0 :       json_builder_set_member_name (builder, "port");
     651                 :           0 :       json_builder_add_int_value (builder, local_port);
     652                 :             : 
     653                 :           0 :       json_builder_set_member_name (builder, "multiPaths");
     654                 :           0 :       json_builder_begin_array (builder);
     655                 :           0 :       json_builder_add_string_value (builder, g_get_home_dir ());
     656                 :           0 :       json_builder_end_array (builder);
     657                 :             : 
     658                 :           0 :       json_builder_set_member_name (builder, "pathNames");
     659                 :           0 :       json_builder_begin_array (builder);
     660                 :           0 :       json_builder_add_string_value (builder, _("Home"));
     661                 :           0 :       json_builder_end_array (builder);
     662                 :             :     }
     663                 :             :   else
     664                 :             :     {
     665                 :           1 :       json_builder_set_member_name (builder, "errorMessage");
     666                 :           1 :       json_builder_add_string_value (builder, _("Permission denied"));
     667                 :             :     }
     668                 :             : 
     669                 :           1 :   response = valent_packet_end (&builder);
     670         [ +  - ]:           1 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), response);
     671                 :             : }
     672                 :             : 
     673                 :             : static void
     674                 :           1 : valent_sftp_plugin_sftp_request (ValentSftpPlugin *self)
     675                 :             : {
     676                 :           1 :   g_autoptr (JsonBuilder) builder = NULL;
     677   [ -  -  -  + ]:           1 :   g_autoptr (JsonNode) packet = NULL;
     678                 :             : 
     679         [ -  + ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     680                 :             : 
     681         [ -  + ]:           1 :   if (sftp_session_find (self))
     682         [ #  # ]:           0 :     return;
     683                 :             : 
     684                 :           1 :   valent_packet_init (&builder, "kdeconnect.sftp.request");
     685                 :           1 :   json_builder_set_member_name (builder, "startBrowsing");
     686                 :           1 :   json_builder_add_boolean_value (builder, TRUE);
     687                 :           1 :   packet = valent_packet_end (&builder);
     688                 :             : 
     689         [ +  - ]:           1 :   valent_device_plugin_queue_packet (VALENT_DEVICE_PLUGIN (self), packet);
     690                 :             : }
     691                 :             : 
     692                 :             : /*
     693                 :             :  * GActions
     694                 :             :  */
     695                 :             : static void
     696                 :           0 : valent_sftp_plugin_open_uri (ValentSftpPlugin *self,
     697                 :             :                              const char       *uri)
     698                 :             : {
     699         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     700         [ #  # ]:           0 :   g_assert (uri != NULL);
     701                 :             : 
     702         [ #  # ]:           0 :   if (self->connection != NULL)
     703                 :             :     {
     704                 :           0 :       g_dbus_connection_call (self->connection,
     705                 :             :                               "org.freedesktop.FileManager1",
     706                 :             :                               "/org/freedesktop/FileManager1",
     707                 :             :                               "org.freedesktop.FileManager1",
     708                 :             :                               "ShowFolders",
     709                 :             :                               g_variant_new_parsed ("([%s], '')", uri),
     710                 :             :                               NULL,
     711                 :             :                               G_DBUS_CALL_FLAGS_NONE,
     712                 :             :                               -1,
     713                 :             :                               NULL, NULL, NULL);
     714                 :             :     }
     715                 :             :   else
     716                 :             :     {
     717                 :           0 :       g_app_info_launch_default_for_uri_async (uri, NULL, NULL, NULL, NULL);
     718                 :             :     }
     719                 :           0 : }
     720                 :             : 
     721                 :             : static void
     722                 :           1 : mount_action (GSimpleAction *action,
     723                 :             :               GVariant      *parameter,
     724                 :             :               gpointer       user_data)
     725                 :             : {
     726                 :           1 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (user_data);
     727                 :             : 
     728         [ -  + ]:           1 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     729                 :             : 
     730         [ +  - ]:           1 :   if (self->session == NULL)
     731                 :           1 :     valent_sftp_plugin_sftp_request (self);
     732         [ #  # ]:           0 :   else if (self->session->mount == NULL)
     733                 :           0 :     valent_sftp_plugin_mount_volume (self);
     734                 :           1 : }
     735                 :             : 
     736                 :             : static void
     737                 :           0 : unmount_action (GSimpleAction *action,
     738                 :             :                 GVariant      *parameter,
     739                 :             :                 gpointer       user_data)
     740                 :             : {
     741                 :           0 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (user_data);
     742                 :             : 
     743         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     744                 :             : 
     745   [ #  #  #  # ]:           0 :   if (self->session != NULL && self->session->mount != NULL)
     746                 :           0 :     valent_sftp_plugin_unmount_volume (self);
     747                 :           0 : }
     748                 :             : 
     749                 :             : static void
     750                 :           0 : open_uri_action (GSimpleAction *action,
     751                 :             :                  GVariant      *parameter,
     752                 :             :                  gpointer       user_data)
     753                 :             : {
     754                 :           0 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (user_data);
     755                 :           0 :   const char *uri = NULL;
     756                 :             : 
     757         [ #  # ]:           0 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     758                 :             : 
     759                 :           0 :   uri = g_variant_get_string (parameter, NULL);
     760                 :           0 :   valent_sftp_plugin_open_uri (self, uri);
     761                 :           0 : }
     762                 :             : 
     763                 :             : static const GActionEntry actions[] = {
     764                 :             :     {"browse",   mount_action,    NULL, NULL, NULL},
     765                 :             :     {"unmount",  unmount_action,  NULL, NULL, NULL},
     766                 :             :     {"open-uri", open_uri_action, "s",  NULL, NULL},
     767                 :             : };
     768                 :             : 
     769                 :             : /*
     770                 :             :  * ValentSftpPlugin
     771                 :             :  */
     772                 :             : static void
     773                 :           6 : valent_sftp_plugin_update_menu (ValentSftpPlugin *self)
     774                 :             : {
     775                 :           6 :   ValentDevicePlugin *plugin = VALENT_DEVICE_PLUGIN (self);
     776                 :             : 
     777         [ -  + ]:           6 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     778                 :             : 
     779         [ -  + ]:           6 :   if (sftp_session_find (self))
     780                 :             :     {
     781                 :           0 :       GHashTableIter iter;
     782                 :           0 :       const char *uri = NULL;
     783                 :           0 :       const char *name = NULL;
     784                 :           0 :       g_autoptr (GMenuItem) item = NULL;
     785         [ #  # ]:           0 :       g_autoptr (GIcon) icon = NULL;
     786         [ #  # ]:           0 :       g_autoptr (GMenu) submenu = NULL;
     787         [ #  # ]:           0 :       g_autoptr (GMenuItem) unmount_item = NULL;
     788         [ #  # ]:           0 :       g_autoptr (GIcon) unmount_icon = NULL;
     789                 :             : 
     790                 :           0 :       icon = g_themed_icon_new ("folder-remote-symbolic");
     791                 :           0 :       item = g_menu_item_new (_("Browse Folders"), "device.sftp.browse");
     792                 :           0 :       g_menu_item_set_icon (item, icon);
     793                 :           0 :       g_menu_item_set_attribute (item, "hidden-when", "s", "action-disabled");
     794                 :             : 
     795                 :           0 :       submenu = g_menu_new ();
     796                 :           0 :       g_menu_item_set_submenu (item, G_MENU_MODEL (submenu));
     797                 :             : 
     798                 :           0 :       g_hash_table_iter_init (&iter, self->session->paths);
     799         [ #  # ]:           0 :       while (g_hash_table_iter_next (&iter, (void **)&uri, (void **)&name))
     800                 :             :         {
     801                 :           0 :           g_autofree char *action_name = NULL;
     802                 :             : 
     803                 :           0 :           action_name = g_strdup_printf ("device.sftp.open-uri::%s", uri);
     804                 :           0 :           g_menu_append (submenu, name, action_name);
     805                 :             :         }
     806                 :             : 
     807                 :           0 :       unmount_icon = g_themed_icon_new ("media-eject-symbolic");
     808                 :           0 :       unmount_item = g_menu_item_new (_("Unmount"), "device.sftp.unmount");
     809                 :           0 :       g_menu_item_set_icon (unmount_item, unmount_icon);
     810                 :           0 :       g_menu_append_item (submenu, unmount_item);
     811                 :             : 
     812         [ #  # ]:           0 :       valent_device_plugin_set_menu_item (plugin, "device.sftp.browse", item);
     813                 :             :     }
     814                 :             :   else
     815                 :             :     {
     816                 :           6 :       valent_device_plugin_set_menu_action (plugin,
     817                 :             :                                             "device.sftp.browse",
     818                 :           6 :                                             _("Mount"),
     819                 :             :                                             "folder-remote-symbolic");
     820                 :             :     }
     821                 :           6 : }
     822                 :             : 
     823                 :             : /*
     824                 :             :  * ValentDevicePlugin
     825                 :             :  */
     826                 :             : static void
     827                 :           6 : valent_sftp_plugin_update_state (ValentDevicePlugin *plugin,
     828                 :             :                                  ValentDeviceState   state)
     829                 :             : {
     830                 :           6 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (plugin);
     831                 :           6 :   gboolean available;
     832                 :             : 
     833         [ -  + ]:           6 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     834                 :             : 
     835         [ +  + ]:           6 :   available = (state & VALENT_DEVICE_STATE_CONNECTED) != 0 &&
     836         [ -  + ]:           3 :               (state & VALENT_DEVICE_STATE_PAIRED) != 0;
     837                 :             : 
     838                 :           6 :   valent_extension_toggle_actions (VALENT_EXTENSION (plugin), available);
     839                 :             : 
     840                 :             :   // FIXME: device may be in destruction when `get_device_host()` is invoked
     841                 :           6 :   valent_sftp_plugin_update_menu (self);
     842                 :             : 
     843         [ +  + ]:           6 :   if (available)
     844                 :             :     {
     845                 :           3 :       GSettings *settings;
     846                 :             : 
     847                 :           3 :       settings = valent_extension_get_settings (VALENT_EXTENSION (plugin));
     848         [ -  + ]:           3 :       if (g_settings_get_boolean (settings, "auto-mount"))
     849                 :           0 :         valent_sftp_plugin_sftp_request (self);
     850                 :             :     }
     851         [ -  + ]:           3 :   else if ((state & VALENT_DEVICE_STATE_PAIRED) == 0)
     852                 :             :     {
     853         [ #  # ]:           0 :       g_clear_pointer (&self->session, sftp_session_end);
     854                 :             :     }
     855         [ +  - ]:           3 :   else if ((state & VALENT_DEVICE_STATE_CONNECTED) == 0)
     856                 :             :     {
     857         [ -  + ]:           3 :       g_clear_pointer (&self->session, sftp_session_free);
     858                 :             :     }
     859                 :           6 : }
     860                 :             : 
     861                 :             : static void
     862                 :           2 : valent_sftp_plugin_handle_packet (ValentDevicePlugin *plugin,
     863                 :             :                                   const char         *type,
     864                 :             :                                   JsonNode           *packet)
     865                 :             : {
     866                 :           2 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (plugin);
     867                 :             : 
     868         [ -  + ]:           2 :   g_assert (VALENT_IS_SFTP_PLUGIN (self));
     869         [ +  - ]:           2 :   g_assert (type != NULL);
     870         [ +  - ]:           2 :   g_assert (VALENT_IS_PACKET (packet));
     871                 :             : 
     872         [ +  + ]:           2 :   if (g_str_equal (type, "kdeconnect.sftp"))
     873                 :           1 :     valent_sftp_plugin_handle_sftp (self, packet);
     874                 :             : 
     875         [ +  - ]:           1 :   else if (g_str_equal (type, "kdeconnect.sftp.request"))
     876                 :           1 :     valent_sftp_plugin_handle_request (self, packet);
     877                 :             : 
     878                 :             :   else
     879                 :           0 :     g_warn_if_reached ();
     880                 :           2 : }
     881                 :             : 
     882                 :             : /*
     883                 :             :  * ValentObject
     884                 :             :  */
     885                 :             : static void
     886                 :           6 : valent_sftp_plugin_destroy (ValentObject *object)
     887                 :             : {
     888                 :           6 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (object);
     889                 :           6 :   ValentDevicePlugin *plugin = VALENT_DEVICE_PLUGIN (object);
     890                 :             : 
     891                 :             :   /* Stop watching the volume monitor and unmount any current session */
     892         [ +  + ]:           6 :   if (self->monitor != NULL)
     893                 :             :     {
     894                 :           3 :       g_signal_handlers_disconnect_by_data (self->monitor, self);
     895         [ +  - ]:           3 :       g_clear_object (&self->monitor);
     896                 :             :     }
     897         [ -  + ]:           6 :   g_clear_pointer (&self->session, sftp_session_end);
     898         [ +  + ]:           6 :   g_clear_object (&self->connection);
     899                 :             : 
     900                 :           6 :   valent_device_plugin_set_menu_item (plugin, "device.sftp.browse", NULL);
     901                 :             : 
     902                 :           6 :   VALENT_OBJECT_CLASS (valent_sftp_plugin_parent_class)->destroy (object);
     903                 :           6 : }
     904                 :             : 
     905                 :             : /*
     906                 :             :  * GObject
     907                 :             :  */
     908                 :             : static void
     909                 :           3 : valent_sftp_plugin_constructed (GObject *object)
     910                 :             : {
     911                 :           3 :   ValentSftpPlugin *self = VALENT_SFTP_PLUGIN (object);
     912                 :           3 :   ValentDevicePlugin *plugin = VALENT_DEVICE_PLUGIN (object);
     913                 :             : 
     914                 :           3 :   G_OBJECT_CLASS (valent_sftp_plugin_parent_class)->constructed (object);
     915                 :             : 
     916                 :           3 :   g_action_map_add_action_entries (G_ACTION_MAP (plugin),
     917                 :             :                                    actions,
     918                 :             :                                    G_N_ELEMENTS (actions),
     919                 :             :                                    plugin);
     920                 :             : 
     921                 :           3 :   self->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
     922                 :           3 :   self->monitor = g_volume_monitor_get ();
     923                 :           3 :   g_signal_connect_object (self->monitor,
     924                 :             :                            "mount-added",
     925                 :             :                            G_CALLBACK (on_mount_added),
     926                 :             :                            self,
     927                 :             :                            G_CONNECT_DEFAULT);
     928                 :           3 :   g_signal_connect_object (self->monitor,
     929                 :             :                            "mount-removed",
     930                 :             :                            G_CALLBACK (on_mount_removed),
     931                 :             :                            self,
     932                 :             :                            G_CONNECT_DEFAULT);
     933                 :           3 : }
     934                 :             : 
     935                 :             : static void
     936                 :          11 : valent_sftp_plugin_class_init (ValentSftpPluginClass *klass)
     937                 :             : {
     938                 :          11 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     939                 :          11 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
     940                 :          11 :   ValentDevicePluginClass *plugin_class = VALENT_DEVICE_PLUGIN_CLASS (klass);
     941                 :             : 
     942                 :          11 :   object_class->constructed = valent_sftp_plugin_constructed;
     943                 :             : 
     944                 :          11 :   vobject_class->destroy = valent_sftp_plugin_destroy;
     945                 :             : 
     946                 :          11 :   plugin_class->handle_packet = valent_sftp_plugin_handle_packet;
     947                 :          11 :   plugin_class->update_state = valent_sftp_plugin_update_state;
     948                 :             : }
     949                 :             : 
     950                 :             : static void
     951                 :           3 : valent_sftp_plugin_init (ValentSftpPlugin *self)
     952                 :             : {
     953                 :           3 : }
     954                 :             : 
        

Generated by: LCOV version 2.0-1